A LOT updates. Cannot separate. :)
authorPekka Riikonen <priikone@silcnet.org>
Tue, 31 Oct 2000 19:48:31 +0000 (19:48 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 31 Oct 2000 19:48:31 +0000 (19:48 +0000)
70 files changed:
CHANGES
README
TODO
apps/silc/Makefile.am
apps/silc/client_ops.c
apps/silc/client_ops.h
apps/silc/clientutil.c
apps/silc/clientutil.h
apps/silc/screen.c
apps/silc/screen.h
apps/silc/silc.c
apps/silcd/Makefile.am
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/protocol.c
apps/silcd/server.c
apps/silcd/server.h
configure.in
doc/draft-riikonen-silc-ke-auth-01.nroff
doc/draft-riikonen-silc-pp-01.nroff
doc/draft-riikonen-silc-spec-01.nroff
includes/silcincludes.h
lib/Makefile.am
lib/contrib/Makefile.am
lib/silcclient/Makefile.am
lib/silcclient/README
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/command.c
lib/silcclient/command.h
lib/silcclient/command_reply.c
lib/silcclient/command_reply.h
lib/silcclient/idlist.c
lib/silcclient/idlist.h
lib/silcclient/ops.h
lib/silcclient/protocol.c
lib/silccore/Makefile.am
lib/silccore/idcache.c
lib/silccore/silcchannel.h
lib/silccore/silccommand.c
lib/silccore/silccommand.h
lib/silccore/silcnotify.c
lib/silccore/silcnotify.h
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h
lib/silccore/silcpayload.c
lib/silccore/silcpayload.h
lib/silccore/silcprotocol.h
lib/silcmath/Makefile.am
lib/silcsim/Makefile.am
lib/silcske/Makefile.am
lib/silcske/payload.c
lib/silcske/silcske.c
lib/silcske/silcske.h
lib/silcske/silcske_status.h
lib/silcutil/Makefile.am
lib/silcutil/silcbuffer.c
lib/silcutil/silcbuffer.h
lib/silcutil/silcbuffmt.c
lib/silcutil/silcbuffmt.h
lib/silcutil/silclog.c
lib/silcutil/silclog.h
lib/silcutil/silcnet.c
lib/silcutil/silcnet.h
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h
prepare-clean

diff --git a/CHANGES b/CHANGES
index ea457f0ae5860c36955ab5c0fa447435ca5ed3d4..10fd2d91726cd0dfd9662c49eac9df7fe83aa61e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,158 @@
+Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Updated README.
+
+       * Added TRQ (efficient deque and list library) into lib/trq.  This is
+         a very good list library that is currently used in the SILC.  Defined
+         SilcList API over the library because I didn't like the API very
+         much.  See lib/trq/silclist.h for the API and examples of how to
+         use the API.  Fixed various places in the code to use the new
+         SilcList API. The SilcList is meant for lists that has a structure
+         already defined as a list.  It is not suitable to add just some
+         context to the list (in TRQ, the context is the list actually).
+
+         So, I defined SilcDList that can be used for the purpose where 
+         predefined list structure does not exit.  This can be used as
+         such list.  Now some context just can be added to the SilcDList.
+         Currently this list is not used in the SILC just yet, though there
+         are a lot places where this can replace dynamically allocated
+         tables and I will fix these places, later, to use SilcDList.
+         See lib/trq/silcdlist.h for SilcDList (they are all inline functions,
+         and use TRQ internally).
+
+         Also fixed some annoying warning messages that the original TRQ
+         code generated.  Also minor changes to TRQ's Makefile.in.
+
+       * Added support for querying by Client ID to both WHOIS and 
+         IDENTIFY commands into server, as required by the protocol.
+
+       * Removed method function pointers from SilcBuffer structure. They
+         weren't used to anything and just increased the context size for
+         no good reason.  This change also made silc_buffer_alloc and
+         silc_buffer_free functions inline functions.
+
+       * Disabled command flooding detection support until it's fixed so 
+         that it accepts commands in but does not execute them more than once
+         in two seconds.
+
+       * Added silc_net_localhost(), to return local hostname, into
+         lib/silcutil/silcnet.[ch].  Also added client->hostname pointer
+         that must be initialized before calling silc_client_init.
+
+       * Added new function: silc_server_send_notify_on_channels to send
+         notify messages to all channels client has joined.  It is assured
+         that the message is sent only once per client.
+
+       * Moved silc_log_format (from lib/silcutil/silclog.[ch] into
+         lib/silcutil/silcutil.[ch] as silc_format function.  The new 
+         function is generic and is used by server as well, not only by
+         the logging routines.
+
+       * Added new SKE status type: SILC_SKE_STATUS_BAD_VERSION to indicate
+         the provided version string was not acceptable.  Added new function:
+         silc_ske_check_version into lib/silcske/silcske.h.  The function
+         must be implemented by the application (client or server) and it
+         does not reside in the SKE library.  The function checks the version
+         string remote end sent.
+
+       * Added back pointers (to opaque context and to SilcSocketConnection) 
+         into SilcPacketContext structure into lib/silccore/silcpacket.h.
+
+       * Added silc_packet_context_dup into lib/silccore/silcpacket.[ch] to
+         duplicate packet context structure.
+
+       * Changed `notify' client operation to send same arguments as client
+         receives from server except for ID's.  ID's are mapped to correct
+         ID entry and that is returned.  Also, if channel entry is not sent
+         by server but the notify is for channel the channel entry is sent
+         to application (otherwise application doesn't know that it is for
+         channel (library gets it from packet's Destination ID)).
+
+       * Added silc_client_remove_from_channels into client library to 
+         remove a client from all channels it has joined to.  Used when 
+         received SIGNOFF notify from server.  Added also new function
+         silc_client_replace_from_channels to replace old ID entry with
+         new ID entry on all channels.  Used when received NICK_CHANGE
+         notify from server.
+
+       * Fixed ID Cache list handling in silc_idlist_get_client in 
+         lib/silcclient/idlist.c.  Also, added silc_idlist_get_client_by_id
+         to get (or query) client by ID.
+
+       * Updated TODO list.
+
+       * Added connection authentication status message defined by the
+         protocol: SILC_CONN_AUTH_OK and SILC_CONN_AUTH_FAILED and added the
+         support for these into the code in client and server side.
+
+       * Added generic function silc_client_send_command to send any command
+         with variable argument list.  Application should use this function
+         to send commands if the command functions provided by the library
+         does not suite for the application's user interface needs.
+
+       * Added new `failure' client operation.  Application is notified about
+         received failure packet if client is executing a protocol.  In this
+         case the protocol's execution has failed.
+
+       * Added SKE's end notify to send the SKE_SUCCESS notify message that
+         is required by the protocol.
+
+       * Added SILC_PROTOCOL_STATE_FAILURE to indicate received failure
+         packet from remote.  SILC_PROTOCOL_STATE_ERROR indicates local
+         error at our end.
+
+       * Added status flag to SilcSKE object to indicate realtime status
+         of the SKE protocol.
+
+       * Application receives now exactly same command reply arguments as
+         the library receives from server.  However, if ID is received the
+         corresponding ID entry is returned to the application (eg. Client
+         ID is mapped to correct SilcClientEntry entry and that is returned).
+         Changed command_reply client operation due to this change.
+
+       * Changed all ID's in commands and in command replys as ID Payloads.
+         Change affected both client and server side codes.
+
+         All ID's sent in SILC network (with execption of ID's in SILC
+         Packet header) are sent in ID Payload to support variable length
+         ID's.
+
+       * Server now notifies nick changes and notifies all clients on
+         the channels about the new nickname (about the new Client ID,
+         actually).
+
+       * Implemented CMODE command to change channel modes. Supports all
+         channel modes defined by the protocol specs except ban and invite
+         lists. (Also, private channel key mode is supported but support for
+         setting private channel key in client is missing, thus, this mode
+         has no effect on client side (except that server requires that the
+         client uses private channel key and normal channel traffic does not
+         work anymore)).
+
+         Also, invite mode works per se, but INVITE command does not work
+         yet correctly, so you can set channel as invite only channel but
+         inviting clients to the channel does not work (it is yet to be
+         thought what's the best way to do it).
+
+       * Added new command SILC_COMMAND_CUMODE to change user mode on the
+         channel.  Defined user modes: CHANNEL_FOUNDER and CHANNEL_OPERATOR.
+         Implemented CUMODE command to change user's mode on the channel.
+         Supports all modes defined by the protocol specs.
+
+       * Added NAMES command reply to return users modes on the channel.
+
+       * Removed unnecessary and slow ciphers from lib/silccrypt.
+
+       * Set SO_KEEPALIVE option to connection sockets by default.
+
+       * Added new command reply status: SILC_STATUS_USER_NOT_ON_CHANNEL.
+
+       * Added notify types: MOTD, CMODE_CHANGE and CUMODE_CHANGE.  Also,
+         redefined the Notify Payload into protocol specs.
+
+       * Added silc_id_payload_parse_id to get ID directly from raw
+         ID payload data.
+
 Mon Oct  9 20:57:02 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Changed SILC_COMMAND_IDENTIFY in protocol specification to 
diff --git a/README b/README
index 7ca53522c21cb5dbd754eb0dc8535d8bf161417c..f37377ac669adbe8ba05199805ef02746635b58e 100644 (file)
--- a/README
+++ b/README
@@ -71,6 +71,53 @@ Following commands has been, at least partly, implemented:
                Leaves the channel.  If /leave * is given the client
                leaves the current channel.
 
+       /CMODE  <channel> +|-<modes> [{ <arguments>}]
+
+               Changes/sets channel mode.  Most of the modes require
+               special privileges, such as channel operator or channel
+               founder privileges to work.  The mode is added by adding
+               + before the option(s) and removed by adding - before
+               the option(s).  Following modes are available:
+
+               p               Set/unset channel as private channel
+               s               Set/unset channel as secret channel
+               k               Set/unset that channel uses private channel key
+               i               Set/unset channel as invite only channel
+               t               Set/unset that only channel operator or 
+                               founder may set channel topic
+               l <limit>       Set/unset channel's user limit
+               a <passphrase>  Set/unset passphrase for channel that must
+                               be provided when joining to the channel.
+               b <username!nickname@server>    
+                               Add client to/remove client from ban list
+               I <username!nickname@server>    
+                               Add client to/remove client from invite list
+               c <cipher>[:<keylen>]
+                               Set/unset channel's cipher
+
+               Multiple modes can be set/unset at once if the modes does not
+               require any arguments.  If mode requires an argument then only
+               one mode can be set at once.
+
+       /CUMODE <channel> +|-<modes> <nickname>[@<server>]
+
+               Changes/set user's mode on a channel.  Most of the modes 
+               require that the client who changes some client's mode must
+               be channel founder or channel operator.  Following channel
+               user modes are available:
+
+               a <nickname>[@<server>]
+                               Set/unset all modes (cannot be used to set
+                               both founder and operator rights, can be used
+                               only to remove both modes at once).
+               f <nickname>[@<server>]
+                               Unset channel founder.  Channel founder rights
+                               cannot be set by user (only by server) so this
+                               can be used only to unset the mode.
+               o <nickname>[@<server>]
+                               Set/unset channel operator.  Requires that 
+                               you are channel operator or channel founder.
+
        /MSG    <nickname> <message>
 
                Sends private message to remote client.  Support for
diff --git a/TODO b/TODO
index 9dacbbb69ac60fa233a3d2eb2eaa53230f7ae6a5..f4819f5dc5a4755dd0deccb882082ca0da103753 100644 (file)
--- a/TODO
+++ b/TODO
@@ -15,6 +15,23 @@ help is really appreciated - and needed.
 New features TODO
 =================
 
+ o We should replace all short, int, long, unsigned short, unsigned int,
+   unsigned long with some pre-defined datatypes that really are what
+   we want on all platforms.  int16, uint16, int32, uint32 etc. are
+   what we could use or maybe SilcInt16, SilcUInt16 etc.  Also, boolean
+   datatype should be defined.
+
+ o Add boolean (or bool), typedef of unsigned char.
+
+ o More platform supports should be added.  The code is pretty much
+   generic but there are some parts that require porting (SIM).  Also, 
+   some support for different platforms is needed into configure.in.
+
+ o SILC requires currently GCC to work because we use GCC specific 
+   compilation options.  Generally any compiler that supports inline
+   functions and can build shared libraries (for SIMs) should work.  
+   These cases should be included into configure.in.
+
  o Extended SIM (SILC Module) support.  Currently only SILC Cipher API
    and SILC Hash API may be used as SIM's.  What I have in mind is to
    have extended support for SIM's so that basically any SILC API could
@@ -35,28 +52,8 @@ New features TODO
    example code (code that we could use directly pretty easily) for
    other platforms.
 
- o We should replace all short, int, long, unsigned short, unsigned int,
-   unsigned long with some pre-defined datatypes that really are what
-   we want on all platforms.  int16, uint16, int32, uint32 etc. are
-   what we could use or maybe SilcInt16, SilcUInt16 etc.  Also, boolean
-   datatype should be defined.
-
- o More platform supports should be added.  The code is pretty much
-   generic but there are some parts that require porting (SIM).  Also, 
-   some support for different platforms is needed into configure.in.
-
- o SILC requires currently GCC to work because we use GCC specific 
-   compilation options.  Generally any compiler that supports inline
-   functions and can build shared libraries (for SIMs) should work.  
-   These cases should be included into configure.in.
-
-
-TODO In SILC Client
-===================
-
- o Implement all commands.  A lot of commands are still yet to be
-   implemented.  Most of them are trivial but some will require some
-   planning.  Go see the command.c for unimplemented commands.
+TODO In SILC Client Library
+===========================
 
  o Non-blocking connection on the background must be stopped if some
    other connection on same window has established.  Now it is possible
@@ -64,9 +61,6 @@ TODO In SILC Client
    we already have a working connection to some other place; things
    goes bad.
 
- o Finish WHOIS, finish JOIN and other commands that are partly
-   implemented.
-
  o Input line on UI is buggy.  Cursor movement etc bugs.  Too lazy to
    fix it.
 
@@ -87,43 +81,20 @@ TODO In SILC Client
    from file and using them (see corresponding code in server, it should
    support public key authentication already).
 
- o Multiple windows support.  Basic support for multiple windows already
-   exists but a lot is still missing to get it working.  Also, some
-   of the existing stuff probably needs to be tweaked a bit before the
-   multiple windows support could be done.  And of course the actual
-   commands that control the windows needs to be written (/WINDDOW).
-
- o Implement /KEYMAP (or similiar) command to remap control and function
-   keys.
-
- o Implement /ALIAS command to make command aliases.
-
- o Implement /set/if/do/while etc as in IRC2.  Maybe post 1.0 task.
-   Some scripting would be good.
-
  o Connection Authentication request resolving is missing and must be
    done.  This is required by the protocol.
 
+ o Move ssh_client_notify_by_server to its own file (like notify.[ch]).
+
  o Key Exchange protocol's responder side is missing from client.  
    Generally it is possible for the client to be responder so it should
    be implemented (See corresponding code from server).  Error handling
    in the KE protocol is also in pretty bad shape in client.
 
- o Configuration file 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
@@ -145,14 +116,8 @@ TODO In SILC Server
  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 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*.
@@ -177,8 +142,6 @@ TODO In SILC Server
  o Statistics are totally missing from the server.  It would be nice
    to gather some statistics.
 
- o All allocations and freeing needs to be checked for memory leaks.
-
 
 TODO In SILC Libraries
 ======================
@@ -187,27 +150,18 @@ TODO In SILC Libraries
    server, actually).  If PFS is set, re-key must cause new key exchange.
    This is required by the SILC protocol.
 
- o Re-key in general is actually missing (from everywhere) and must be done.
+ o silc_id_str2id must also take ID length as argument. Otherwise, variable
+   length ID's (after we add IPv6) will not work.
 
- o SKE does not send correct status types.  Types are defined but not
-   sent.
+ o Re-key in general is actually missing (from everywhere) and must be done.
 
- o Connection authentication protocol does not send correct status types.
-   These types are not defined currently at all.
+ o ID Cache expiry does not work.
 
  o PKCS#1 style RSA public key encryption/decryption/sign/verify is 
    missing, and should be added for interoperability reasons.  The thing 
    I've done now is bad and should be removed as soon as possible (or 
    the protocol should then state the method of how they should be done).
 
- o 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
@@ -233,26 +187,12 @@ TODO In SILC Libraries
    cleaner.  Introducing silc_cipher_encrypt/decrypt/set_key etc.
    functions (I actually don't understand why have I left these un-done).
 
- o 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 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
@@ -311,10 +251,4 @@ TODO After 1.0
    nice as SSH is widely used all over the place.  SILC Protocol 
    supports SSH2 public keys.
 
- o IRC support for SILC client.  This would be nice to have on client
-   as it could be used to connect to SILC and IRC.  People wouldn't
-   have to have two different clients when same would work on both.
-   I'd like to see this done as SIM, after the extended SIM support
-   has been added to SILC.
-
  o Cipher optimizations (asm, that this) at least for i386 would be nice.
index 91cab5844579e0120f1abb837e6b664553508304..ce3f90f98a56aa83cae4245550e94212d5d89c70 100644 (file)
@@ -37,4 +37,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/silcclient -I../lib/silcutil \
-       -I../lib/silcmath/gmp
+       -I../lib/silcmath/gmp -I../lib/trq
index 4df32f6168c55a0dd89b7baa3a516862ee434384..a127140ce0b0fc7112542f2683b24431fcdb9edd 100644 (file)
@@ -65,62 +65,160 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
 }
 
 
-/* Notify message to the client.  The `notify_payload' is the Notify
-   Payload received from server.  Client library may parse it to cache
-   some data received from the payload but it is the application's 
-   responsiblity to retrieve the message and arguments from the payload.
-   The message in the payload sent by server is implementation specific
-   thus it is recommended that application will generate its own message. */
-/* XXX should generate own messages based on notify type. */
+/* Notify message to the client. The notify arguments are sent in the
+   same order as servers sends them. The arguments are same as received
+   from the server except for ID's.  If ID is received application receives
+   the corresponding entry to the ID. For example, if Client ID is received
+   application receives SilcClientEntry.  Also, if the notify type is
+   for channel the channel entry is sent to application (even if server
+   does not send it). */
 
 void silc_notify(SilcClient client, SilcClientConnection conn, 
-                SilcNotifyPayload notify_payload)
+                SilcNotifyType type, ...)
 {
-  SilcNotifyType type;
-  SilcArgumentPayload args;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  va_list vp;
   char message[4096];
-  char *msg;
+  SilcClientEntry client_entry, client_entry2;
+  SilcChannelEntry channel_entry;
+  char *tmp;
+  unsigned int tmp_int;
 
-  type = silc_notify_get_type(notify_payload);
-  msg = silc_notify_get_message(notify_payload);
-  args = silc_notify_get_args(notify_payload);
+  va_start(vp, type);
 
   memset(message, 0, sizeof(message));
 
   /* Get arguments (defined by protocol in silc-pp-01 -draft) */
   switch(type) {
   case SILC_NOTIFY_TYPE_NONE:
-    strncat(message, msg, strlen(msg));
+    tmp = va_arg(vp, char *);
+    if (!tmp)
+      return;
+    strcpy(message, tmp);
     break;
+
   case SILC_NOTIFY_TYPE_INVITE:
-    snprintf(message, sizeof(message), msg, 
-            silc_argument_get_arg_type(args, 1, NULL),
-            silc_argument_get_arg_type(args, 2, NULL));
+    client_entry = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    snprintf(message, sizeof(message), "%s invites you to channel %s", 
+            client_entry->nickname, channel_entry->channel_name);
     break;
+
   case SILC_NOTIFY_TYPE_JOIN:
-    snprintf(message, sizeof(message), msg, 
-            silc_argument_get_arg_type(args, 2, NULL),
-            silc_argument_get_arg_type(args, 3, NULL),
-            silc_argument_get_arg_type(args, 4, NULL),
-            silc_argument_get_arg_type(args, 6, NULL));
+    client_entry = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    snprintf(message, sizeof(message), "%s (%s) has joined channel %s", 
+            client_entry->nickname, client_entry->username, 
+            channel_entry->channel_name);
     break;
+
   case SILC_NOTIFY_TYPE_LEAVE:
-    snprintf(message, sizeof(message), msg, 
-            silc_argument_get_arg_type(args, 1, NULL),
-            silc_argument_get_arg_type(args, 2, NULL),
-            silc_argument_get_arg_type(args, 4, NULL));
+    client_entry = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (client_entry->server)
+      snprintf(message, sizeof(message), "%s@%s has left channel %s", 
+              client_entry->nickname, client_entry->server, 
+              channel_entry->channel_name);
+    else
+      snprintf(message, sizeof(message), "%s has left channel %s", 
+              client_entry->nickname, channel_entry->channel_name);
     break;
+
   case SILC_NOTIFY_TYPE_SIGNOFF:
-    snprintf(message, sizeof(message), msg, 
-            silc_argument_get_arg_type(args, 1, NULL),
-            silc_argument_get_arg_type(args, 2, NULL));
+    client_entry = va_arg(vp, SilcClientEntry);
+    if (client_entry->server)
+      snprintf(message, sizeof(message), "Signoff: %s@%s", 
+              client_entry->nickname, client_entry->server);
+    else
+      snprintf(message, sizeof(message), "Signoff: %s", 
+              client_entry->nickname);
     break;
+
   case SILC_NOTIFY_TYPE_TOPIC_SET:
-    snprintf(message, sizeof(message), msg, 
-            silc_argument_get_arg_type(args, 3, NULL),
-            silc_argument_get_arg_type(args, 4, NULL),
-            silc_argument_get_arg_type(args, 2, NULL));
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp = va_arg(vp, char *);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (client_entry->server)
+      snprintf(message, sizeof(message), "%s@%s set topic on %s: %s", 
+              client_entry->nickname, client_entry->server,
+              channel_entry->channel_name, tmp);
+    else
+      snprintf(message, sizeof(message), "%s set topic on %s: %s", 
+              client_entry->nickname, channel_entry->channel_name, tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_NICK_CHANGE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    client_entry2 = va_arg(vp, SilcClientEntry);
+    if (client_entry->server && client_entry2->server)
+      snprintf(message, sizeof(message), "%s@%s is known as %s@%s", 
+              client_entry->nickname, client_entry->server,
+              client_entry2->nickname, client_entry2->server);
+    else
+      snprintf(message, sizeof(message), "%s is known as %s", 
+              client_entry->nickname, client_entry2->nickname);
     break;
+
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp = silc_client_chmode(va_arg(vp, unsigned int));
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (tmp)
+      snprintf(message, sizeof(message), "%s changed channel mode to +%s", 
+              client_entry->nickname, tmp);
+    else
+      snprintf(message, sizeof(message), "%s removed all channel modes", 
+              client_entry->nickname);
+    if (app->screen->bottom_line->channel_mode)
+      silc_free(app->screen->bottom_line->channel_mode);
+    app->screen->bottom_line->channel_mode = tmp;
+    silc_screen_print_bottom_line(app->screen, 0);
+    break;
+
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp_int = va_arg(vp, unsigned int);
+    tmp = silc_client_chumode(tmp_int);
+    client_entry2 = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (tmp)
+      snprintf(message, sizeof(message), "%s changed %s mode to +%s", 
+              client_entry->nickname, client_entry2->nickname, tmp);
+    else
+      snprintf(message, sizeof(message), "%s removed %s modes", 
+              client_entry->nickname, client_entry2->nickname);
+    if (client_entry2 == conn->local_entry) {
+      if (app->screen->bottom_line->mode)
+       silc_free(app->screen->bottom_line->mode);
+      app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
+      silc_screen_print_bottom_line(app->screen, 0);
+    }
+    silc_free(tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_MOTD:
+    {
+      char line[256];
+      int i;
+      tmp = va_arg(vp, unsigned char *);
+
+      i = 0;
+      while(tmp[i] != 0) {
+       if (tmp[i++] == '\n') {
+         memset(line, 0, sizeof(line));
+         strncat(line, tmp, i - 1);
+         tmp += i;
+         
+         silc_say(client, conn, "%s", line);
+         
+         if (!strlen(tmp))
+           break;
+         i = 0;
+       }
+      }
+    }
+    return;
+
   default:
     break;
   }
@@ -183,29 +281,54 @@ void silc_command(SilcClient client, SilcClientConnection conn,
 
 void silc_command_reply(SilcClient client, SilcClientConnection conn,
                        SilcCommandPayload cmd_payload, int success,
-                       SilcCommandStatus status, SilcCommand command, ...)
+                       SilcCommand command, SilcCommandStatus status, ...)
 {
   SilcClientInternal app = (SilcClientInternal)client->application;
   va_list vp;
+  int i;
 
   if (!success)
     return;
 
-  va_start(vp, command);
+  va_start(vp, status);
 
   switch(command)
     {
 
     case SILC_COMMAND_JOIN:
-      app->screen->bottom_line->channel = va_arg(vp, char *);
-      silc_screen_print_bottom_line(app->screen, 0);
+      {
+       unsigned int mode;
+
+       app->screen->bottom_line->channel = va_arg(vp, char *);
+       (void)va_arg(vp, void *);
+       mode = va_arg(vp, unsigned int);
+       app->screen->bottom_line->channel_mode = silc_client_chmode(mode);
+       silc_screen_print_bottom_line(app->screen, 0);
+      }
       break;
 
     case SILC_COMMAND_NICK:
-      app->screen->bottom_line->nickname = va_arg(vp, char *);
-      silc_screen_print_bottom_line(app->screen, 0);
+      {
+       SilcClientEntry entry;
+
+       entry = va_arg(vp, SilcClientEntry);
+       silc_say(client, conn, "Your current nickname is %s", entry->nickname);
+       app->screen->bottom_line->nickname = entry->nickname;
+       silc_screen_print_bottom_line(app->screen, 0);
+      }
       break;
 
+    case SILC_COMMAND_NAMES:
+      for (i = 0; i < conn->current_channel->clients_count; i++)
+       if (conn->current_channel->clients[i].client == conn->local_entry) {
+         if (app->screen->bottom_line->mode)
+           silc_free(app->screen->bottom_line->mode);
+         app->screen->bottom_line->mode = 
+           silc_client_chumode_char(conn->current_channel->clients[i].mode);
+         silc_screen_print_bottom_line(app->screen, 0);
+         break;
+       }
+      break;
     }
 }
 
@@ -460,6 +583,20 @@ int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
   return FALSE;
 }
 
+/* Notifies application that failure packet was received.  This is called
+   if there is some protocol active in the client.  The `protocol' is the
+   protocol context.  The `failure' is opaque pointer to the failure
+   indication.  Note, that the `failure' is protocol dependant and application
+   must explicitly cast it to correct type.  Usually `failure' is 32 bit
+   failure type (see protocol specs for all protocol failure types). */
+
+void silc_failure(SilcClient client, SilcClientConnection conn, 
+                 SilcProtocol protocol, void *failure)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+}
+
 /* SILC client operations */
 SilcClientOperations ops = {
   say:                  silc_say,
@@ -473,4 +610,5 @@ SilcClientOperations ops = {
   get_auth_method:      silc_get_auth_method,
   verify_server_key:    silc_verify_server_key,
   ask_passphrase:       silc_ask_passphrase,
+  failure:              silc_failure,
 };
index ea8bd9a42ba93decd7155b1c7bd300d2bcab9431..db8f1af9b3dbac01eb07f60d364fa7d848f53b5c 100644 (file)
@@ -27,13 +27,13 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
 void silc_private_message(SilcClient client, SilcClientConnection conn,
                          char *sender, char *msg);
 void silc_notify(SilcClient client, SilcClientConnection conn, 
-                SilcNotifyPayload notify_payload);
+                SilcNotifyType type, ...);
 void silc_command(SilcClient client, SilcClientConnection conn, 
                  SilcClientCommandContext cmd_context, int success,
                  SilcCommand command);
 void silc_command_reply(SilcClient client, SilcClientConnection conn,
                        SilcCommandPayload cmd_payload, int success,
-                       SilcCommandStatus status, SilcCommand command, ...);
+                       SilcCommand command, SilcCommandStatus status, ...);
 void silc_connect(SilcClient client, SilcClientConnection conn, int success);
 void silc_disconnect(SilcClient client, SilcClientConnection conn);
 unsigned char *silc_ask_passphrase(SilcClient client, 
@@ -46,5 +46,7 @@ int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
                         SilcProtocolAuthMeth *auth_meth,
                         unsigned char **auth_data,
                         unsigned int *auth_data_len);
+void silc_failure(SilcClient client, SilcClientConnection conn, 
+                 SilcProtocol protocol, void *failure);
 
 #endif
index 210f50b02c5d2307f6a8bb4bf12a211bb97e6c38..321160d49055a73f705825eb99be4f0d331f2449 100644 (file)
@@ -729,3 +729,80 @@ int silc_client_load_keys(SilcClient client)
 
   return TRUE;
 }
+
+/* Parses mode mask and returns the mode as string. */
+
+char *silc_client_chmode(unsigned int mode)
+{
+  char string[20];
+
+  if (!mode)
+    return NULL;
+
+  memset(string, 0, sizeof(string));
+
+  if (mode & SILC_CHANNEL_MODE_PRIVATE)
+    strncat(string, "p", 1);
+
+  if (mode & SILC_CHANNEL_MODE_SECRET)
+    strncat(string, "s", 1);
+
+  if (mode & SILC_CHANNEL_MODE_PRIVKEY)
+    strncat(string, "k", 1);
+
+  if (mode & SILC_CHANNEL_MODE_INVITE)
+    strncat(string, "i", 1);
+
+  if (mode & SILC_CHANNEL_MODE_TOPIC)
+    strncat(string, "t", 1);
+
+  if (mode & SILC_CHANNEL_MODE_ULIMIT)
+    strncat(string, "l", 1);
+
+  if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
+    strncat(string, "a", 1);
+
+  /* Rest of mode is ignored */
+
+  return strdup(string);
+}
+
+/* Parses channel user mode mask and returns te mode as string */
+
+char *silc_client_chumode(unsigned int mode)
+{
+  char string[4];
+
+  if (!mode)
+    return NULL;
+
+  memset(string, 0, sizeof(string));
+
+  if (mode & SILC_CHANNEL_UMODE_CHANFO)
+    strncat(string, "f", 1);
+
+  if (mode & SILC_CHANNEL_UMODE_CHANOP)
+    strncat(string, "o", 1);
+
+  return strdup(string);
+}
+
+/* Parses channel user mode and returns it as special mode character. */
+
+char *silc_client_chumode_char(unsigned int mode)
+{
+  char string[4];
+
+  if (!mode)
+    return NULL;
+
+  memset(string, 0, sizeof(string));
+
+  if (mode & SILC_CHANNEL_UMODE_CHANFO)
+    strncat(string, "*", 1);
+
+  if (mode & SILC_CHANNEL_UMODE_CHANOP)
+    strncat(string, "@", 1);
+
+  return strdup(string);
+}
index 38f0d9e857b7cfc88e28c0f6cd3c85f093c242cf..b682a1271a087df147c264f045936d6cfb46656f 100644 (file)
@@ -43,5 +43,8 @@ int silc_client_create_key_pair(char *pkcs_name, int bits,
                                SilcPrivateKey *ret_prv_key);
 int silc_client_check_silc_dir();
 int silc_client_load_keys(SilcClient client);
+char *silc_client_chmode(unsigned int mode);
+char *silc_client_chumode(unsigned int mode);
+char *silc_client_chumode_char(unsigned int mode);
 
 #endif
index 3cbae77e3592e8dc777afd9e90572cb43590dd70..dba669258178f72b5f6f179b0ce7f635334afa56 100644 (file)
  * old version of the SILC client dating back to 1997.
  */
 /* XXX: Input line handling is really buggy! */
-/*
- * $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
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "clientincludes.h"
 
@@ -226,6 +207,14 @@ void silc_screen_print_bottom_line(SilcScreen screen, int win_index)
            SILC_SCREEN_MAX_CHANNEL_LEN : len);
   }
 
+  if (line->channel_mode) {
+    len = strlen(line->channel_mode);
+    strncat(buf, " (+", 3);
+    strncat(buf, line->channel_mode, len > SILC_SCREEN_MAX_CHANNEL_LEN ?
+           SILC_SCREEN_MAX_CHANNEL_LEN : len);
+    strncat(buf, ")", 2);
+  }
+
   if (line->away)
     strncat(buf, " (away)", 8);
 
index a1fe8ce32522b326703790a9ef2b092412f8cb89..ffa89ffd511fa656f78f8c3e89850e7f634056ce 100644 (file)
@@ -26,6 +26,7 @@ typedef struct {
   char *nickname;
   char *connection;
   char *channel;
+  char *channel_mode;
   int away;
 } *SilcScreenBottomLine;
 
index ce9f7ee028dd58d84490abbb52132efcb99cef88..938a27babaf11f7a66cbb4c29c7fc5cad1b1f11a 100644 (file)
@@ -267,6 +267,7 @@ SILC Secure Internet Live Conferencing, version %s\n",
 
   /* Get user information */
   silc->username = silc_get_username();
+  silc->hostname = silc_net_localhost();
   silc->realname = silc_get_real_name();
 
   /* Register all configured ciphers, PKCS and hash functions. */
index 6709db5b6ae84afb1392efb8287b2a8f0c1d2801..230ff60f5db0c33312257755085bc2b9db8cf82a 100644 (file)
@@ -41,4 +41,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/silcutil \
-       -I../lib/silcmath/gmp
+       -I../lib/silcmath/gmp -I../lib/trq
index 97b6d047f93f5ae44440419bdcc3ab9fafef2276..dbad3bf3689fd06d372e94e038ce2deb4551a733 100644 (file)
@@ -60,6 +60,7 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(restart, RESTART, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
@@ -120,6 +121,7 @@ void silc_server_command_process(SilcServer server,
   SilcServerCommandContext ctx;
   SilcServerCommand *cmd;
 
+#if 0
   /* Check whether it is allowed for this connection to execute any
      command. */
   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
@@ -137,6 +139,7 @@ void silc_server_command_process(SilcServer server,
     /* Update access time */
     client->last_command = curtime;
   }
+#endif
   
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
@@ -295,10 +298,10 @@ SILC_SERVER_CMD_FUNC(whois)
   SilcServer server = cmd->server;
   char *tmp, *nick = NULL, *server_name = NULL;
   unsigned int i, argc, count = 0, len, clients_count;
-  SilcClientEntry entry;
-  SilcBuffer packet;
-  unsigned char *id_string;
-  SilcClientEntry *clients;
+  int use_id = FALSE;
+  SilcClientID *client_id = NULL;
+  SilcBuffer packet, idp;
+  SilcClientEntry *clients = NULL, entry;
   SilcCommandStatus status;
 
   SILC_LOG_DEBUG(("Start"));
@@ -309,33 +312,42 @@ SILC_SERVER_CMD_FUNC(whois)
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  if (argc > 2) {
+  if (argc > 3) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                          SILC_STATUS_ERR_TOO_MANY_PARAMS);
     goto out;
   }
 
-  /* Get the nickname@server string and parse it. */
-  tmp = silc_argument_get_first_arg(cmd->args, NULL);
-  if (tmp) {
-    if (strchr(tmp, '@')) {
-      len = strcspn(tmp, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      memcpy(nick, tmp, len);
-      server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
-      memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+  /* If client ID is in the command it must be used instead of nickname */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
+
+    /* No ID, get the nickname@server string and parse it. */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+    if (tmp) {
+      if (strchr(tmp, '@')) {
+       len = strcspn(tmp, "@");
+       nick = silc_calloc(len + 1, sizeof(char));
+       memcpy(nick, tmp, len);
+       server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+       memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+      } else {
+       nick = strdup(tmp);
+      }
     } else {
-      nick = strdup(tmp);
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
     }
   } else {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
+    /* Command includes ID, use that */
+    client_id = silc_id_payload_parse_id(tmp, len);
+    use_id = TRUE;
   }
 
   /* Get the max count of reply messages allowed */
-  if (argc == 2) {
-    tmp = silc_argument_get_next_arg(cmd->args, NULL);
+  if (argc == 3) {
+    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                            SILC_STATUS_ERR_TOO_MANY_PARAMS);
@@ -349,11 +361,21 @@ SILC_SERVER_CMD_FUNC(whois)
   }
 
   /* Get all clients matching that nickname */
-  clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                               nick, server_name,
-                                               &clients_count);
-  if (!clients) {
+  if (!use_id) {
+    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                 nick, server_name,
+                                                 &clients_count);
+  } else {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+    if (entry) {
+      clients = silc_calloc(1, sizeof(*clients));
+      clients[0] = entry;
+      clients_count = 1;
+    }
+  }
 
+  if (!clients) {
+    
     /* If we are normal server and are connected to a router we will
        make global query from the router. */
     if (server->server_type == SILC_SERVER && !server->standalone) {
@@ -382,8 +404,8 @@ SILC_SERVER_CMD_FUNC(whois)
   }
 
  ok:
-  /* XXX, works only for local server info */
 
+  /* XXX, works only for local server info */
 
   status = SILC_STATUS_OK;
   if (clients_count > 1)
@@ -402,7 +424,7 @@ SILC_SERVER_CMD_FUNC(whois)
       status = SILC_STATUS_LIST_END;
 
     /* Send WHOIS reply */
-    id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+    idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
     tmp = silc_argument_get_first_arg(cmd->args, NULL);
     
     /* XXX */
@@ -434,7 +456,7 @@ SILC_SERVER_CMD_FUNC(whois)
        packet = 
          silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
                                               status, 0, 5, 
-                                              2, id_string, SILC_ID_CLIENT_LEN,
+                                              2, idp->data, idp->len,
                                               3, nh, strlen(nh),
                                               4, uh, strlen(uh),
                                               5, entry->userinfo, 
@@ -444,7 +466,7 @@ SILC_SERVER_CMD_FUNC(whois)
        packet = 
          silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
                                               status, 0, 4, 
-                                              2, id_string, SILC_ID_CLIENT_LEN,
+                                              2, idp->data, idp->len,
                                               3, nh, strlen(nh),
                                               4, uh, strlen(uh),
                                               7, idle, 4);
@@ -454,7 +476,7 @@ SILC_SERVER_CMD_FUNC(whois)
       packet = 
        silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, 
                                             status, 0, 3, 
-                                            2, id_string, SILC_ID_CLIENT_LEN,
+                                            2, idp->data, idp->len,
                                             3, entry->nickname, 
                                             strlen(entry->nickname),
                                             4, tmp, strlen(tmp)); /* XXX */
@@ -462,10 +484,14 @@ SILC_SERVER_CMD_FUNC(whois)
     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_buffer_free(idp);
+    silc_free(clients);
   }
-    
+
+  if (client_id)
+    silc_free(client_id);
+
  out:
   silc_server_command_free(cmd);
 }
@@ -480,9 +506,10 @@ SILC_SERVER_CMD_FUNC(identify)
   SilcServer server = cmd->server;
   char *tmp, *nick = NULL, *server_name = NULL;
   unsigned int argc, count = 0, len;
+  int use_id = FALSE;
+  SilcClientID *client_id = NULL;
   SilcClientEntry entry;
-  SilcBuffer packet;
-  unsigned char *id_string;
+  SilcBuffer packet, idp;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -492,33 +519,42 @@ SILC_SERVER_CMD_FUNC(identify)
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  if (argc > 2) {
+  if (argc > 3) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                          SILC_STATUS_ERR_TOO_MANY_PARAMS);
     goto out;
   }
 
-  /* Get the nickname@server string and parse it. */
-  tmp = silc_argument_get_first_arg(cmd->args, NULL);
-  if (tmp) {
-    if (strchr(tmp, '@')) {
-      len = strcspn(tmp, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      memcpy(nick, tmp, len);
-      server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
-      memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+  /* If client ID is in the command it must be used instead of nickname */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
+
+    /* Get the nickname@server string and parse it. */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+    if (tmp) {
+      if (strchr(tmp, '@')) {
+       len = strcspn(tmp, "@");
+       nick = silc_calloc(len + 1, sizeof(char));
+       memcpy(nick, tmp, len);
+       server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+       memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+      } else {
+       nick = strdup(tmp);
+      }
     } else {
-      nick = strdup(tmp);
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
     }
   } else {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
+    /* Command includes ID, use that */
+    client_id = silc_id_payload_parse_id(tmp, len);
+    use_id = TRUE;
   }
 
   /* Get the max count of reply messages allowed */
-  if (argc == 2) {
-    tmp = silc_argument_get_next_arg(cmd->args, NULL);
+  if (argc == 3) {
+    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                            SILC_STATUS_ERR_TOO_MANY_PARAMS);
@@ -528,11 +564,15 @@ SILC_SERVER_CMD_FUNC(identify)
   }
 
   /* 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 (!use_id) {
+    entry = silc_idlist_find_client_by_nickname(server->local_list,
+                                               nick, NULL);
+    if (!entry)
+      entry = silc_idlist_find_client_by_hash(server->global_list,
+                                             nick, server->md5hash);
+  } else {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+  }
 
   /* 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. */
@@ -566,12 +606,11 @@ SILC_SERVER_CMD_FUNC(identify)
   }
 
   /* Send IDENTIFY reply */
-  id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+  idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
   tmp = silc_argument_get_first_arg(cmd->args, NULL);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                                SILC_STATUS_OK, 0, 2,
-                                               2, id_string, 
-                                               SILC_ID_CLIENT_LEN,
+                                               2, idp->data, idp->len, 
                                                3, nick, strlen(nick));
   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
@@ -586,8 +625,10 @@ SILC_SERVER_CMD_FUNC(identify)
                            packet->data, packet->len, FALSE);
   }
 
-  silc_free(id_string);
   silc_buffer_free(packet);
+  silc_buffer_free(idp);
+  if (client_id)
+    silc_free(client_id);
 
  out:
   if (nick)
@@ -620,11 +661,10 @@ static int silc_server_command_bad_chars(char *nick)
 SILC_SERVER_CMD_FUNC(nick)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServer server = cmd->server;
-  SilcBuffer packet;
+  SilcBuffer packet, nidp, oidp;
   SilcClientID *new_id;
-  char *id_string;
   char *nick;
 
   SILC_LOG_DEBUG(("Start"));
@@ -653,7 +693,7 @@ SILC_SERVER_CMD_FUNC(nick)
      ID and ask to replace it with the old one. */
   if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
     silc_server_send_replace_id(server, server->id_entry->router->connection, 
-                               FALSE, id_entry->id,
+                               FALSE, client->id,
                                SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
                                new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
 
@@ -661,42 +701,51 @@ SILC_SERVER_CMD_FUNC(nick)
      routers in SILC. */
   if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
     silc_server_send_replace_id(server, server->id_entry->router->connection,  
-                               TRUE, id_entry->id,
+                               TRUE, client->id,
                                SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
                                new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
 
   /* Remove old cache entry */
   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
-                        id_entry->id); 
-  
+                        client->id); 
+
+  oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
   /* Free old ID */
-  if (id_entry->id) {
-    memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
-    silc_free(id_entry->id);
+  if (client->id) {
+    memset(client->id, 0, SILC_ID_CLIENT_LEN);
+    silc_free(client->id);
   }
 
   /* Save the nickname as this client is our local client */
-  if (id_entry->nickname)
-    silc_free(id_entry->nickname);
+  if (client->nickname)
+    silc_free(client->nickname);
 
-  id_entry->nickname = strdup(nick);
-  id_entry->id = new_id;
+  client->nickname = strdup(nick);
+  client->id = new_id;
 
   /* Update client cache */
-  silc_idcache_add(server->local_list->clients, id_entry->nickname, 
-                  SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
+  silc_idcache_add(server->local_list->clients, client->nickname, 
+                  SILC_ID_CLIENT, client->id, (void *)client, TRUE);
+
+  nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+  /* Send NICK_CHANGE notify */
+  silc_server_send_notify_on_channels(server, client, 
+                                     SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+                                     oidp->data, oidp->len, 
+                                     nidp->data, nidp->len);
 
   /* Send the new Client ID as reply command back to client */
-  id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
                                                SILC_STATUS_OK, 0, 1, 
-                                               2, id_string, 
-                                               SILC_ID_CLIENT_LEN);
+                                               2, nidp->data, nidp->len);
   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                          0, packet->data, packet->len, FALSE);
 
-  silc_free(id_string);
   silc_buffer_free(packet);
+  silc_buffer_free(nidp);
+  silc_buffer_free(oidp);
   
  out:
   silc_server_command_free(cmd);
@@ -716,10 +765,10 @@ SILC_SERVER_CMD_FUNC(topic)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcChannelID *channel_id;
   SilcChannelEntry channel;
-  SilcBuffer packet;
-  SilcBuffer id_payload;
-  unsigned char *tmp, *id_string;
-  unsigned int argc;
+  SilcChannelClientEntry chl;
+  SilcBuffer packet, idp;
+  unsigned char *tmp;
+  unsigned int argc, tmp_len;
 
   /* Check number of arguments */
   argc = silc_argument_get_arg_num(cmd->args);
@@ -735,13 +784,13 @@ SILC_SERVER_CMD_FUNC(topic)
   }
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
     goto out;
   }
-  channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+  channel_id = silc_id_payload_parse_id(tmp, tmp_len);
 
   /* Check whether the channel exists */
   channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
@@ -766,46 +815,52 @@ SILC_SERVER_CMD_FUNC(topic)
       goto out;
     }
 
+    /* See whether has rights to change topic */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client == client) {
+       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+         goto out;
+       } else {
+         break;
+       }
+      }
+    }
+
     /* Set the topic for channel */
     if (channel->topic)
       silc_free(channel->topic);
     channel->topic = strdup(tmp);
 
-    id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
-                                       SILC_ID_CHANNEL);
+    idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
     /* Send notify about topic change to all clients on the channel */
     silc_server_send_notify_to_channel(server, channel,
-                                      SILC_NOTIFY_TYPE_TOPIC_SET, 4, FALSE,
-                                      "%s@%s set topic: %s",
-                                      id_payload->data, id_payload->len,
-                                      tmp, strlen(tmp),
-                                      client->nickname, 
-                                      strlen(client->nickname),
-                                      cmd->sock->hostname,
-                                      strlen(cmd->sock->hostname));
-    silc_buffer_free(id_payload);
+                                      SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+                                      idp->data, idp->len,
+                                      channel->topic, strlen(channel->topic));
+    silc_buffer_free(idp);
   }
 
   /* Send the topic to client as reply packet */
-  id_string = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
   if (channel->topic)
     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
                                                  SILC_STATUS_OK, 0, 2, 
-                                                 2, id_string, 
-                                                 SILC_ID_CHANNEL_LEN,
+                                                 2, idp->data, idp->len,
                                                  3, channel->topic, 
                                                  strlen(channel->topic));
   else
     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
                                                  SILC_STATUS_OK, 0, 1, 
-                                                 2, id_string,
-                                                 SILC_ID_CHANNEL_LEN);
+                                                 2, idp->data, idp->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_buffer_free(idp);
   silc_free(channel_id);
 
  out:
@@ -823,8 +878,9 @@ SILC_SERVER_CMD_FUNC(invite)
   SilcClientID *dest_id;
   SilcChannelEntry channel;
   SilcChannelID *channel_id;
+  SilcBuffer sidp;
+  unsigned char *tmp;
   unsigned int argc, len;
-  unsigned char *id_string;
 
   /* Check number of arguments */
   argc = silc_argument_get_arg_num(cmd->args);
@@ -840,22 +896,22 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Get destination ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!id_string) {
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NO_CLIENT_ID);
     goto out;
   }
-  dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+  dest_id = silc_id_payload_parse_id(tmp, len);
 
   /* Get Channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 2, &len);
-  if (!id_string) {
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
     goto out;
   }
-  channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+  channel_id = silc_id_payload_parse_id(tmp, len);
 
   /* Check whether the channel exists */
   channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
@@ -866,7 +922,7 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Check whether the sender of this command is on the channel. */
-  sender = (SilcClientEntry )sock->user_data;
+  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);
@@ -875,7 +931,20 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Check whether the channel is invite-only channel. If yes then the
      sender of this command must be at least channel operator. */
-  /* XXX */
+  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+    SilcChannelClientEntry chl;
+
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+      if (chl->client == sender) {
+       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+         goto out;
+       }
+       break;
+      }
+  }
 
   /* Find the connection data for the destination. If it is local we will
      send it directly otherwise we will send it to router for routing. */
@@ -895,18 +964,19 @@ SILC_SERVER_CMD_FUNC(invite)
     goto out;
   }
 
+  sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+
   /* Send notify to the client that is invited to the channel */
   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
-                              SILC_NOTIFY_TYPE_INVITE, 2, FALSE,
-                              "%s invites you to channel %s",
-                              sender->nickname, strlen(sender->nickname),
-                              channel->channel_name,
-                              strlen(channel->channel_name));
+                              SILC_NOTIFY_TYPE_INVITE, 2, 
+                              sidp->data, sidp->len, tmp, len);
 
   /* Send command reply */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                        SILC_STATUS_OK);
 
+  silc_buffer_free(sidp);
+
  out:
   silc_server_command_free(cmd);
 }
@@ -957,9 +1027,8 @@ SILC_SERVER_CMD_FUNC(info)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcBuffer packet;
+  SilcBuffer packet, idp;
   unsigned int argc;
-  unsigned char *id_string;
   char info_string[256], *dest_server;
 
   argc = silc_argument_get_arg_num(cmd->args);
@@ -992,19 +1061,18 @@ SILC_SERVER_CMD_FUNC(info)
             server->config->admin_info->admin_name,
             server->config->admin_info->admin_email);
 
-    id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
+    idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
 
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                          SILC_STATUS_OK, 0, 2,
-                                          2, id_string, SILC_ID_SERVER_LEN,
-                                          3, info_string, 
-                                          strlen(info_string));
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                                 SILC_STATUS_OK, 0, 2,
+                                                 2, idp->data, idp->len,
+                                                 3, info_string, 
+                                                 strlen(info_string));
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                            packet->data, packet->len, FALSE);
     
-    silc_free(id_string);
     silc_buffer_free(packet);
+    silc_buffer_free(idp);
   } else {
     /* Send this command to the requested server */
 
@@ -1032,8 +1100,8 @@ SILC_SERVER_CMD_FUNC(ping)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcServerID *id;
-  unsigned int argc;
-  unsigned char *id_string;
+  unsigned int argc, len;
+  unsigned char *tmp;
 
   argc = silc_argument_get_arg_num(cmd->args);
   if (argc < 1) {
@@ -1048,13 +1116,13 @@ SILC_SERVER_CMD_FUNC(ping)
   }
 
   /* Get Server ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  if (!id_string) {
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_ERR_NO_SERVER_ID);
     goto out;
   }
-  id = silc_id_str2id(id_string, SILC_ID_SERVER);
+  id = silc_id_payload_parse_id(tmp, len);
 
   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
     /* Send our reply */
@@ -1091,26 +1159,15 @@ SILC_TASK_CALLBACK(silc_server_command_join_notify)
   JoinInternalContext *ctx = (JoinInternalContext *)context;
 
   if (ctx->channel->key && ctx->channel->key_len) {
-    SilcBuffer channel_idp, client_idp;
+    SilcBuffer clidp;
 
-    channel_idp = silc_id_payload_encode(ctx->channel->id, SILC_ID_CHANNEL_LEN,
-                                        SILC_ID_CHANNEL);
-    client_idp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT_LEN,
-                                       SILC_ID_CLIENT);
+    clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
 
     silc_server_send_notify_to_channel(ctx->server, ctx->channel,
-                                      SILC_NOTIFY_TYPE_JOIN, 6, FALSE,
-                                      "%s (%s@%s) has joined channel %s",
-                                      client_idp->data, client_idp->len,
-                                      ctx->nickname, strlen(ctx->nickname),
-                                      ctx->username, strlen(ctx->username),
-                                      ctx->hostname, strlen(ctx->hostname),
-                                      channel_idp->data, channel_idp->len,
-                                      ctx->channel_name,
-                                      strlen(ctx->channel_name));
-
-    silc_buffer_free(client_idp);
-    silc_buffer_free(channel_idp);
+                                      SILC_NOTIFY_TYPE_JOIN, 1,
+                                      clidp->data, clidp->len);
+
+    silc_buffer_free(clidp);
     silc_free(ctx);
   } else {
     silc_task_register(ctx->server->timeout_queue, fd,
@@ -1128,12 +1185,11 @@ void silc_server_command_send_names(SilcServer server,
                                    SilcChannelEntry channel)
 {
   SilcServerCommandContext cmd;
-  SilcBuffer buffer;
-  unsigned char *id_string;
+  SilcBuffer buffer, idp;
 
-  id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
-                                         1, id_string, SILC_ID_CHANNEL_LEN);
+                                         1, idp->data, idp->len);
 
   cmd = silc_calloc(1, sizeof(*cmd));
   cmd->payload = silc_command_payload_parse(buffer);
@@ -1143,8 +1199,8 @@ void silc_server_command_send_names(SilcServer server,
   cmd->pending = FALSE;
 
   silc_server_command_names((void *)cmd);
-  silc_free(id_string);
   silc_free(buffer);
+  silc_free(idp);
 }
 
 /* Server side of command JOIN. Joins client into requested channel. If 
@@ -1156,12 +1212,14 @@ SILC_SERVER_CMD_FUNC(join)
   SilcServer server = cmd->server;
   SilcSocketConnection sock = cmd->sock;
   SilcBuffer buffer = cmd->packet->buffer;
-  int argc, i, tmp_len;
-  char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
-  unsigned char *passphrase, mode[4];
+  int argc, i, k, tmp_len;
+  char *tmp, *channel_name = NULL, *cipher = NULL;
+  unsigned char *passphrase = NULL, mode[4];
+  unsigned int umode = 0;
   SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
   SilcServerID *router_id;
-  SilcBuffer packet;
+  SilcBuffer packet, idp;
   SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
@@ -1181,9 +1239,14 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 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) {
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  channel_name = tmp;
+
+  if (silc_server_command_bad_chars(channel_name) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_BAD_CHANNEL);
     silc_free(channel_name);
@@ -1210,8 +1273,10 @@ SILC_SERVER_CMD_FUNC(join)
        the channel by  ourselves. */
     if (server->standalone) {
       router_id = server->id;
-      channel = silc_server_new_channel(server, router_id, 
-                                       cipher, channel_name);
+      channel = silc_server_new_channel(server, router_id, cipher, 
+                                       channel_name);
+      umode |= SILC_CHANNEL_UMODE_CHANOP;
+      umode |= SILC_CHANNEL_UMODE_CHANFO;
       if (!channel)
        goto out;
 
@@ -1256,6 +1321,50 @@ SILC_SERVER_CMD_FUNC(join)
 
  join_channel:
 
+  /*
+   * Check channel modes
+   */
+
+  /* Check invite list if channel is invite-only channel */
+  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
+      /* Invite list is specified. Check whether client is invited in the
+        list. If not, then check whether it has been invited otherwise. */
+
+    } else {
+      /* XXX client must be invited to be able to join the channel */
+    }
+  }
+
+  /* Check ban list if set */
+  if (channel->mode & SILC_CHANNEL_MODE_BAN) {
+
+  }
+
+  /* Check the channel passphrase if set. */
+  if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
+                             strlen(channel->mode_data.passphrase))) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                           SILC_STATUS_ERR_BAD_PASSWORD);
+      goto out;
+    }
+  }
+
+  /* Check user count limit if set. */
+  if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+    if (silc_list_count(channel->user_list) + 1 > 
+       channel->mode_data.user_limit) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                           SILC_STATUS_ERR_CHANNEL_IS_FULL);
+      goto out;
+    }
+  }
+
+  /*
+   * Client is allowed to join to the channel. Make it happen.
+   */
+
   /* If the JOIN request was forwarded to us we will make a bit slower
      query to get the client pointer. Otherwise, we get the client pointer
      real easy. */
@@ -1275,24 +1384,30 @@ SILC_SERVER_CMD_FUNC(join)
   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++;
+  /* Join the client to the channel by adding it to channel's user list */
+  chl = silc_calloc(1, sizeof(*chl));
+  chl->mode = umode;
+  chl->client = client;
+  silc_list_add(channel->user_list, chl);
 
   /* Add the channel to client's channel list */
   i = client->channel_count;
-  client->channel = silc_realloc(client->channel, 
-                                sizeof(*client->channel) * (i + 1));
-  client->channel[i] = channel;
-  client->channel_count++;
+  for (k = 0; k < client->channel_count; k++) {
+    if (client->channel[k] == NULL) {
+      client->channel[k] = channel;
+      break;
+    }
+  }
+  if (k >= i) {
+    i = client->channel_count;
+    client->channel = silc_realloc(client->channel, 
+                                  sizeof(*client->channel) * (i + 1));
+    client->channel[i] = channel;
+    client->channel_count++;
+  }
 
   /* Notify router about new user on channel. If we are normal server
      we send it to our router, if we are router we send it to our
@@ -1304,7 +1419,7 @@ SILC_SERVER_CMD_FUNC(join)
   /* 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);
+    idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
     SILC_PUT32_MSB(channel->mode, mode);
 
     if (!channel->topic)
@@ -1313,7 +1428,7 @@ SILC_SERVER_CMD_FUNC(join)
                                             SILC_STATUS_OK, 0, 3,
                                             2, channel_name, 
                                             strlen(channel_name),
-                                            3, id_string, SILC_ID_CHANNEL_LEN,
+                                            3, idp->data, idp->len,
                                             4, mode, 4);
     else
       packet = 
@@ -1321,7 +1436,7 @@ SILC_SERVER_CMD_FUNC(join)
                                             SILC_STATUS_OK, 0, 4, 
                                             2, channel_name, 
                                             strlen(channel_name),
-                                            3, id_string, SILC_ID_CHANNEL_LEN,
+                                            3, idp->data, idp->len,
                                             4, mode, 4,
                                             5, channel->topic, 
                                             strlen(channel->topic));
@@ -1336,56 +1451,38 @@ SILC_SERVER_CMD_FUNC(join)
     } else
       silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
                              packet->data, packet->len, FALSE);
-    
     silc_buffer_free(packet);
-  }
 
-  /* Send channel key to the client. Client cannot start transmitting
-     to the channel until we have sent the key. */
-  if (!cmd->pending) {
+    /* Send channel key to the client. Client cannot start transmitting
+       to the channel until we have sent the key. */
     tmp_len = strlen(channel->channel_key->cipher->name);
     packet = 
-      silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, 
-                                     id_string, tmp_len, 
+      silc_channel_key_payload_encode(idp->len, idp->data, 
+                                     strlen(channel->channel_key->
+                                            cipher->name),
                                      channel->channel_key->cipher->name,
                                      channel->key_len / 8, channel->key);
     
     silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                            packet->data, packet->len, FALSE);
+
     silc_buffer_free(packet);
+    silc_buffer_free(idp);
   }
 
-  if (id_string)
-    silc_free(id_string);
-
   /* Finally, send notify message to all clients on the channel about
      new user on the channel. */
   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
     if (!cmd->pending) {
-      SilcBuffer channel_idp, client_idp;
-
-      channel_idp = silc_id_payload_encode(channel->id, 
-                                          SILC_ID_CHANNEL_LEN,
-                                          SILC_ID_CHANNEL);
-      client_idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT_LEN,
-                                         SILC_ID_CLIENT);
+      SilcBuffer clidp;
 
+      clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+      
       silc_server_send_notify_to_channel(server, channel,
-                                        SILC_NOTIFY_TYPE_JOIN, 6, FALSE,
-                                        "%s (%s@%s) has joined channel %s",
-                                        client_idp->data, client_idp->len,
-                                        client->nickname, 
-                                        strlen(client->nickname),
-                                        client->username,
-                                        strlen(client->username),
-                                        sock->hostname,
-                                        strlen(sock->hostname),
-                                        channel_idp->data, channel_idp->len,
-                                        channel_name,
-                                        strlen(channel_name));
-
-      silc_buffer_free(client_idp);
-      silc_buffer_free(channel_idp);
+                                        SILC_NOTIFY_TYPE_JOIN, 1,
+                                        clidp->data, clidp->len);
+      
+      silc_buffer_free(clidp);
     } else {
       /* This is pending command request. Send the notify after we have
         received the key for the channel from the router. */
@@ -1418,7 +1515,6 @@ SILC_SERVER_CMD_FUNC(motd)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock;
   unsigned int argc;
   char *motd;
   int motd_len;
@@ -1466,12 +1562,646 @@ SILC_SERVER_CMD_FUNC(umode)
 {
 }
 
+/* Checks that client has rights to add or remove channel modes. If any
+   of the checks fails FALSE is returned. */
+
+int silc_server_check_cmode_rights(SilcChannelEntry channel,
+                                  SilcChannelClientEntry client,
+                                  unsigned int mode)
+{
+  int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
+  int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
+
+  /* Check whether has rights to change anything */
+  if (!is_op && !is_fo)
+    return FALSE;
+
+  /* Check whether has rights to change everything */
+  if (is_op && is_fo)
+    return TRUE;
+
+  /* We know that client is channel operator, check that they are not
+     changing anything that requires channel founder rights. Rest of the
+     modes are available automatically for channel operator. */
+
+  if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+  
+  if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+
+  if (mode & SILC_CHANNEL_MODE_CIPHER) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+  
+  return TRUE;
+}
+
+/* Server side command of CMODE. Changes channel mode */
+
 SILC_SERVER_CMD_FUNC(cmode)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcChannelID *channel_id;
+  SilcClientID *client_id;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcBuffer packet, cidp;
+  unsigned char *tmp, *tmp_id, *tmp_mask;
+  unsigned int argc, mode_mask, tmp_len, tmp_len2;
+  int i;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 8) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
+  if (!tmp_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
+
+  /* Get the channel mode mask */
+  tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!tmp_mask) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  SILC_GET32_MSB(mode_mask, tmp_mask);
+
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether this client is on the channel */
+  if (!silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Get entry to the channel user list */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+    if (chl->client == client)
+      break;
+
+  /* Check that client has rights to change any requested channel modes */
+  if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+    goto out;
+  }
+
+  /*
+   * Check the modes. Modes that requires nothing special operation are
+   * not checked here.
+   */
+
+  if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
+    /* Channel uses private keys to protect traffic. Client(s) has set the
+       key locally they want to use, server does not know that key. */
+    /* Nothing interesting to do here now */
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+      /* The mode is removed and we need to generate and distribute
+        new channel key. Clients are not using private channel keys
+        anymore after this. */
+      unsigned int key_len;
+      unsigned char channel_key[32];
+
+      /* XXX Duplicated code, make own function for this!! LEAVE uses this
+        as well */
+
+      /* Re-generate channel key */
+      key_len = channel->key_len / 8;
+      for (i = 0; i < key_len; i++)
+       channel_key[i] = silc_rng_get_byte(server->rng);
+      channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                           channel_key, key_len);
+      memset(channel->key, 0, key_len);
+      silc_free(channel->key);
+      channel->key = silc_calloc(key_len, sizeof(*channel->key));
+      memcpy(channel->key, channel_key, key_len);
+      memset(channel_key, 0, sizeof(channel_key));
+      
+      /* Encode channel key payload to be distributed on the channel */
+      packet = 
+       silc_channel_key_payload_encode(tmp_len2, tmp_id,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       key_len, channel->key);
+      
+      /* If we are normal server then we will send it to our router.  If we
+        are router we will send it to all local servers that has clients on
+        the channel */
+      if (server->server_type == SILC_SERVER) {
+       if (!server->standalone)
+         silc_server_packet_send(server, 
+                                 cmd->server->id_entry->router->connection,
+                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                                 packet->len, TRUE);
+      } else {
+       
+      }
+      
+      /* Send to locally connected clients on the channel */
+      silc_server_packet_send_local_channel(server, channel, 
+                                           SILC_PACKET_CHANNEL_KEY, 0,
+                                           packet->data, packet->len, FALSE);
+      silc_buffer_free(packet);
+    }
+  }
+  
+  if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
+    /* User limit is set on channel */
+    unsigned int user_limit;
+      
+    /* Get user limit */
+    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+    if (!tmp) {
+      if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+    } else {
+      SILC_GET32_MSB(user_limit, tmp);
+      channel->mode_data.user_limit = user_limit;
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+      /* User limit mode is unset. Remove user limit */
+      channel->mode_data.user_limit = 0;
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
+      /* Passphrase has been set to channel */
+      
+      /* Get the passphrase */
+      tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      /* Save the passphrase */
+      channel->mode_data.passphrase = strdup(tmp);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+      /* Passphrase mode is unset. remove the passphrase */
+      if (channel->mode_data.passphrase) {
+       silc_free(channel->mode_data.passphrase);
+       channel->mode_data.passphrase = NULL;
+      }
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_BAN) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
+      /* Ban list is specified for channel */
+
+      /* Get ban list */
+      tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      /* XXX check that channel founder is not banned */
+
+      /* Save the ban list */
+      channel->mode_data.ban_list = strdup(tmp);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_BAN) {
+      /* Ban mode is unset. Remove the entire ban list */
+      if (channel->mode_data.ban_list) {
+       silc_free(channel->mode_data.ban_list);
+       channel->mode_data.ban_list = NULL;
+      }
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
+      /* Invite list is specified for channel */
+
+      /* Get invite list */
+      tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      /* Save the invite linst */
+      channel->mode_data.invite_list = strdup(tmp);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
+      /* Invite list mode is unset. Remove the entire invite list */
+      if (channel->mode_data.invite_list) {
+       silc_free(channel->mode_data.invite_list);
+       channel->mode_data.invite_list = NULL;
+      }
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
+      /* Cipher to use protect the traffic */
+      unsigned int key_len = 128;
+      unsigned char channel_key[32];
+      char *cp;
+
+      /* Get cipher */
+      tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      cp = strchr(tmp, ':');
+      if (cp) {
+       key_len = atoi(cp);
+       *cp = '\0';
+      }
+
+      /* XXX Duplicated code, make own function for this!! */
+    
+      /* Delete old cipher and allocate the new one */
+      silc_cipher_free(channel->channel_key);
+      silc_cipher_alloc(tmp, &channel->channel_key);
+
+      /* Re-generate channel key */
+      key_len /= 8;
+      if (key_len > sizeof(channel_key))
+       key_len = sizeof(channel_key);
+
+      for (i = 0; i < key_len; i++)
+       channel_key[i] = silc_rng_get_byte(server->rng);
+      channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                           channel_key, key_len);
+      memset(channel->key, 0, key_len);
+      silc_free(channel->key);
+      channel->key = silc_calloc(key_len, sizeof(*channel->key));
+      memcpy(channel->key, channel_key, key_len);
+      memset(channel_key, 0, sizeof(channel_key));
+    
+      /* Encode channel key payload to be distributed on the channel */
+      packet = 
+       silc_channel_key_payload_encode(tmp_len2, tmp_id,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       key_len, channel->key);
+    
+      /* If we are normal server then we will send it to our router.  If we
+        are router we will send it to all local servers that has clients on
+        the channel */
+      if (server->server_type == SILC_SERVER) {
+       if (!server->standalone)
+         silc_server_packet_send(server, 
+                                 cmd->server->id_entry->router->connection,
+                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                                 packet->len, TRUE);
+      } else {
+       
+      }
+    
+      /* Send to locally connected clients on the channel */
+      silc_server_packet_send_local_channel(server, channel, 
+                                           SILC_PACKET_CHANNEL_KEY, 0,
+                                         packet->data, packet->len, FALSE);
+      silc_buffer_free(packet);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+      /* Cipher mode is unset. Remove the cipher and revert back to 
+        default cipher */
+      unsigned int key_len;
+      unsigned char channel_key[32];
+
+      if (channel->mode_data.cipher) {
+       silc_free(channel->mode_data.cipher);
+       channel->mode_data.cipher = NULL;
+       channel->mode_data.key_len = 0;
+      }
+
+      /* Generate new cipher and key for the channel */
+
+      /* XXX Duplicated code, make own function for this!! */
+
+      /* Delete old cipher and allocate default one */
+      silc_cipher_free(channel->channel_key);
+      if (!channel->cipher)
+       silc_cipher_alloc("twofish", &channel->channel_key);
+      else
+       silc_cipher_alloc(channel->cipher, &channel->channel_key);
+
+      /* Re-generate channel key */
+      key_len = channel->key_len / 8;
+      for (i = 0; i < key_len; i++)
+       channel_key[i] = silc_rng_get_byte(server->rng);
+      channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                           channel_key, key_len);
+      memset(channel->key, 0, key_len);
+      silc_free(channel->key);
+      channel->key = silc_calloc(key_len, sizeof(*channel->key));
+      memcpy(channel->key, channel_key, key_len);
+      memset(channel_key, 0, sizeof(channel_key));
+      
+      /* Encode channel key payload to be distributed on the channel */
+      packet = 
+       silc_channel_key_payload_encode(tmp_len2, tmp_id,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       key_len, channel->key);
+      
+      /* If we are normal server then we will send it to our router.  If we
+        are router we will send it to all local servers that has clients on
+        the channel */
+      if (server->server_type == SILC_SERVER) {
+       if (!server->standalone)
+         silc_server_packet_send(server, 
+                                 cmd->server->id_entry->router->connection,
+                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                                 packet->len, TRUE);
+      } else {
+       
+      }
+      
+      /* Send to locally connected clients on the channel */
+      silc_server_packet_send_local_channel(server, channel, 
+                                           SILC_PACKET_CHANNEL_KEY, 0,
+                                           packet->data, packet->len, FALSE);
+      silc_buffer_free(packet);
+    }
+  }
+
+  /* Finally, set the mode */
+  channel->mode = mode_mask;
+
+  /* Send CMODE_CHANGE notify */
+  cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+  silc_server_send_notify_to_channel(server, channel, 
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
+                                    cidp->data, cidp->len, 
+                                    tmp_mask, tmp_len);
+  silc_free(cidp);
+
+  /* Send command reply to sender */
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
+                                               SILC_STATUS_OK, 0, 1,
+                                               2, tmp_mask, 4);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+    
+  silc_buffer_free(packet);
+  silc_free(channel_id);
+
+ out:
+  silc_server_command_free(cmd);
+}
+
+/* Server side of CUMODE command. Changes client's mode on a channel. */
+
+SILC_SERVER_CMD_FUNC(cumode)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcChannelID *channel_id;
+  SilcClientID *client_id;
+  SilcChannelEntry channel;
+  SilcClientEntry target_client;
+  SilcChannelClientEntry chl;
+  SilcBuffer packet, idp;
+  unsigned char *tmp, *tmp_id, *tmp_mask;
+  unsigned int argc, target_mask, sender_mask, tmp_len;
+  int i, notify = FALSE;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 3) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 3) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether sender is on the channel */
+  if (!silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Check that client has rights to change other's rights */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    if (chl->client == client) {
+      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+
+      sender_mask = chl->mode;
+      break;
+    }
+  }
+  
+  /* Get the target client's channel mode mask */
+  tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp_mask) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  SILC_GET32_MSB(target_mask, tmp_mask);
+
+  /* Get target Client ID */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  if (!tmp_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+
+  /* Get target client's entry */
+  target_client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  if (!client) {
+    /* XXX If target client is not one of mine send to primary route */
+  }
+
+  /* Check whether target client is on the channel */
+  if (!silc_server_client_on_channel(target_client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Get entry to the channel user list */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+    if (chl->client == target_client)
+      break;
+
+  /* 
+   * Change the mode 
+   */
+
+  /* If the target client is founder, no one else can change their mode
+     but themselves. */
+  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_YOU);
+    goto out;
+  }
+
+  if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
+    /* Cannot promote anyone to channel founder */
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_YOU);
+    goto out;
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      if (target_client == client) {
+       /* Remove channel founder rights from itself */
+       chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+       notify = TRUE;
+      } else {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NOT_YOU);
+       goto out;
+      }
+    }
+  }
+
+  if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
+    /* Promote to operator */
+    if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+      chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
+      notify = TRUE;
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+      /* Demote to normal user */
+      chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+      notify = TRUE;
+    }
+  }
+
+  /* Send notify to channel, notify only if mode was actually changed. */
+  if (notify) {
+    idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    silc_server_send_notify_to_channel(server, channel,
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                      idp->data, idp->len,
+                                      tmp_mask, 4, tmp_id, tmp_len);
+    silc_buffer_free(idp);
+  }
+
+  /* Send command reply to sender */
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
+                                               SILC_STATUS_OK, 0, 2,
+                                               2, tmp_mask, 4,
+                                               3, tmp_id, tmp_len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+    
+  silc_buffer_free(packet);
+  silc_free(channel_id);
+  silc_free(client_id);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
+/* Server side of KICK command. Kicks client out of channel. */
+
 SILC_SERVER_CMD_FUNC(kick)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+
 }
 
 SILC_SERVER_CMD_FUNC(restart)
@@ -1501,7 +2231,7 @@ SILC_SERVER_CMD_FUNC(leave)
   SilcChannelID *id;
   SilcChannelEntry channel;
   SilcBuffer packet;
-  unsigned int i, argc, key_len;
+  unsigned int i, argc, key_len, len;
   unsigned char *tmp, channel_key[32];
 
   SILC_LOG_DEBUG(("Start"));
@@ -1519,13 +2249,13 @@ SILC_SERVER_CMD_FUNC(leave)
   }
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
     goto out;
   }
-  id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+  id = silc_id_payload_parse_id(tmp, len);
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list, id);
@@ -1574,7 +2304,7 @@ SILC_SERVER_CMD_FUNC(leave)
 
   /* Encode channel key payload to be distributed on the channel */
   packet = 
-    silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
+    silc_channel_key_payload_encode(len, tmp,
                                    strlen(channel->channel_key->cipher->name),
                                    channel->channel_key->cipher->name,
                                    key_len, channel->key);
@@ -1613,12 +2343,14 @@ SILC_SERVER_CMD_FUNC(names)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
   SilcChannelID *id;
   SilcBuffer packet;
-  unsigned int i, len, len2, argc;
+  unsigned int i, len, len2, tmp_len, argc;
   unsigned char *tmp;
   char *name_list = NULL, *n;
   SilcBuffer client_id_list;
+  SilcBuffer client_mode_list;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1635,13 +2367,13 @@ SILC_SERVER_CMD_FUNC(names)
   }
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
     goto out;
   }
-  id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+  id = silc_id_payload_parse_id(tmp, tmp_len);
 
   /* Check whether the channel exists. If we are normal server and the
      channel does not exist we will send this same command to our router
@@ -1665,11 +2397,10 @@ SILC_SERVER_CMD_FUNC(names)
   /* 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;
+  silc_list_start(channel->user_list);
+  i = 0;
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    n = chl->client->nickname;
     if (n) {
       len2 = strlen(n);
       len += len2;
@@ -1677,51 +2408,63 @@ SILC_SERVER_CMD_FUNC(names)
       memcpy(name_list + (len - len2), n, len2);
       name_list[len] = 0;
 
-      if (i == channel->user_list_count - 1)
+      if (i == silc_list_count(channel->user_list) - 1)
        break;
       memcpy(name_list + len, ",", 1);
       len++;
+      i++;
     }
   }
   if (!name_list)
     name_list = "";
 
   /* Assemble the Client ID list now */
-  client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN * 
-                                    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);
+  client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
+                                    silc_list_count(channel->user_list));
+  silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    SilcBuffer idp;
+
+    idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
     silc_buffer_format(client_id_list,
-                      SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+                      SILC_STR_UI_XNSTRING(idp->data, idp->len),
                       SILC_STR_END);
-    silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
-    silc_free(id_string);
+    silc_buffer_pull(client_id_list, idp->len);
+    silc_buffer_free(idp);
   }
   silc_buffer_push(client_id_list, 
                   client_id_list->data - client_id_list->head);
 
+  /* Assemble mode list */
+  client_mode_list = silc_buffer_alloc(4 * 
+                                      silc_list_count(channel->user_list));
+  silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    SILC_PUT32_MSB(chl->mode, client_mode_list->data);
+    silc_buffer_pull(client_mode_list, 4);
+  }
+  silc_buffer_push(client_mode_list, 
+                  client_mode_list->data - client_mode_list->head);
+
   /* Send reply */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
-                                               SILC_STATUS_OK, 0, 3,
-                                               2, tmp, SILC_ID_CHANNEL_LEN,
+                                               SILC_STATUS_OK, 0, 4,
+                                               2, tmp, tmp_len,
                                                3, name_list, 
                                                strlen(name_list),
                                                4, client_id_list->data,
-                                               client_id_list->len);
+                                               client_id_list->len,
+                                               5, client_mode_list->data,
+                                               client_mode_list->len);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
   silc_buffer_free(packet);
   silc_free(name_list);
   silc_buffer_free(client_id_list);
+  silc_buffer_free(client_mode_list);
   silc_free(id);
 
  out:
index 70ff20c82c9feb95360d03e133029b413f8d714d..1ced0891082df4ea576fa14e50edf7a0a3154f43 100644 (file)
@@ -138,6 +138,7 @@ SILC_SERVER_CMD_FUNC(join);
 SILC_SERVER_CMD_FUNC(motd);
 SILC_SERVER_CMD_FUNC(umode);
 SILC_SERVER_CMD_FUNC(cmode);
+SILC_SERVER_CMD_FUNC(cumode);
 SILC_SERVER_CMD_FUNC(kick);
 SILC_SERVER_CMD_FUNC(ignore);
 SILC_SERVER_CMD_FUNC(restart);
index e094321df445b9f2ccf73c8551e940476f09e365..4ec3a8c37629d2d4a2a34d30b1efcfff8dafa10f 100644 (file)
@@ -86,6 +86,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   SilcCommandStatus status;
   SilcChannelID *id;
   SilcChannelEntry entry;
+  unsigned int len;
   unsigned char *id_string;
   char *channel_name, *tmp;
 
@@ -102,19 +103,22 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     goto out;
 
   /* Get channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 3, NULL);
+  id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
   if (!id_string)
     goto out;
 
   channel_name = strdup(tmp);
 
   /* Add the channel to our local list. */
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+  id = silc_id_payload_parse_id(id_string, len);
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, id, 
                                  server->id_entry->router, NULL);
-  if (!entry)
+  if (!entry) {
+    silc_free(channel_name);
+    silc_free(id);
     goto out;
+  }
 
   entry->global_users = TRUE;
 
@@ -136,29 +140,27 @@ 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_argument_get_arg_type(cmd->args, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
   if (status != SILC_STATUS_OK)
     goto out;
 
   /* Process one identify reply */
   if (status == SILC_STATUS_OK) {
     SilcClientID *client_id;
+    unsigned int len;
     unsigned char *id_data;
     char *nickname, *username;
 
-    id_data = silc_argument_get_arg_type(cmd->args, 2, NULL);
+    id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
     nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!id_data || !nickname)
       goto out;
 
     username = silc_argument_get_arg_type(cmd->args, 4, NULL);
-
-    client_id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+    client_id = silc_id_payload_parse_id(id_data, len);
 
     /* Add the client always to our global list. If normal or router server
        ever gets here it means they don't have this client's information
index 1df174e4c4245dec9958ccfbcbdb848e0463e6d4..358bef33f467826ace5549b419c4c4dc7652fcf5 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.8  2000/10/06 08:10:23  priikone
- *     Added WHOIS to send multiple replies if multiple nicknames are
- *     found.
- *     Added MOTD command and [motd] config section and server also sends
- *     motd to client on connection now.
- *     Fixed TOPIC command some more.
- *
- * Revision 1.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
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "idlist.h"
@@ -412,6 +377,8 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
   channel->id = id;
   channel->router = router;
   channel->channel_key = channel_key;
+  silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct, 
+                next);
 
   if (!silc_idcache_add(id_list->channels, channel->channel_name, 
                        SILC_ID_CHANNEL, (void *)channel->id, 
@@ -428,6 +395,8 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
 void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
 {
   if (entry) {
+    SilcChannelClientEntry chl;
+
     /* Remove from cache */
     if (entry->id)
       silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL, 
@@ -447,9 +416,12 @@ void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
       silc_free(entry->key);
     }
     memset(entry->iv, 0, sizeof(entry->iv));
-
-    if (entry->user_list_count)
-      silc_free(entry->user_list);
+    
+    silc_list_start(entry->user_list);
+    while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
+      silc_list_del(entry->user_list, chl);
+      silc_free(chl);
+    }
   }
 }
 
index 6a40147f6bce6f04be4029eeee15e509fb389d6c..aa444f46f59b78a92ad7f440f83780407bbf4ea2 100644 (file)
@@ -232,7 +232,7 @@ struct SilcClientEntryStruct {
   /* Pointer to the router */
   SilcServerEntry router;
 
-  /* Pointers to channels this client has joined */
+  /* List of channels client has joined to */
   SilcChannelEntry *channel;
   unsigned int channel_count;
 
@@ -258,14 +258,15 @@ struct SilcClientEntryStruct {
 
        Pointer to the client list. This is the client currently on channel.
 
-   int mode
+   unsigned int mode
 
        Client's current mode on the channel.
 
 */
 typedef struct SilcChannelClientEntryStruct {
   SilcClientEntry client;
-  int mode;
+  unsigned int mode;
+  struct SilcChannelClientEntryStruct *next;
 } *SilcChannelClientEntry;
 
 /* 
@@ -290,9 +291,10 @@ typedef struct SilcChannelClientEntryStruct {
 
        Logical name of the channel.
 
-   int mode
+   unsigned int mode
 
-       Current mode of the channel.
+       Current mode of the channel.  See lib/silccore/silcchannel.h for
+       all modes.
 
    SilcChannelID *id
 
@@ -313,6 +315,11 @@ typedef struct SilcChannelClientEntryStruct {
 
        Current topic of the channel.
 
+   char *cipher
+
+       Default cipher of the channel. If this is NULL then server picks
+       the cipher to be used. This can be set at SILC_COMMAND_JOIN.
+
    SilcServerEntry router
 
        This is a pointer to the server list. This is the router server 
@@ -336,14 +343,24 @@ typedef struct SilcChannelClientEntryStruct {
 */
 struct SilcChannelEntryStruct {
   char *channel_name;
-  int mode;
+  unsigned int mode;
   SilcChannelID *id;
   int global_users;
   char *topic;
+  char *cipher;
+
+  /* Data that is related to different channel modes. */
+  struct {
+    unsigned int user_limit;
+    unsigned char *passphrase;
+    unsigned char *ban_list;
+    unsigned char *invite_list;
+    unsigned char *cipher;
+    unsigned int key_len;
+  } mode_data;
 
   /* List of users on channel */
-  SilcChannelClientEntry user_list;
-  unsigned int user_list_count;
+  SilcList user_list;
 
   /* Pointer to the router */
   SilcServerEntry router;
index cf4e07fe2de6af98238b3305d242f51e9fb7c1e3..b8cb0090fd7fc50774b5da577f0319edbc5a3252 100644 (file)
 /*
  * Server side of the protocols.
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.10  2000/10/09 11:41:17  priikone
- *     Changed to use new generic payloads.
- *     Implemented new protocol compliant notify messages.
- *     Implemented protocol compliant channel messages.
- *     Bugfixes.
- *
- * 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
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
@@ -158,6 +113,14 @@ static void silc_server_protocol_ke_set_keys(SilcSKE ske,
   sock->user_data = (void *)conn_data;
 }
 
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+                                    unsigned int len)
+{
+  return SILC_SKE_STATUS_OK;
+}
+
 /* Performs key exchange protocol. This is used for both initiator
    and responder key exchange. This is performed always when accepting
    new connection to the server. This may be called recursively. */
@@ -350,6 +313,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
       protocol->state = SILC_PROTOCOL_STATE_END;
     }
     break;
+
   case SILC_PROTOCOL_STATE_END:
     {
       /* 
@@ -386,11 +350,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        silc_protocol_free(protocol);
     }
     break;
+
   case SILC_PROTOCOL_STATE_ERROR:
     /*
      * Error occured
      */
 
+    /* Send abort notification */
+    silc_ske_abort(ctx->ske, ctx->ske->status, 
+                  silc_server_protocol_ke_send_packet,
+                  context);
+
     /* Unregister the timeout task since the protocol has ended. 
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
@@ -403,6 +373,25 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     else
       silc_protocol_free(protocol);
     break;
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * We have received failure from remote
+     */
+
+    /* Unregister the timeout task since the protocol has ended. 
+       This was the timeout task to be executed if the protocol is
+       not completed fast enough. */
+    if (ctx->timeout_task)
+      silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
@@ -880,10 +869,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
       /* 
        * End protocol
        */
+      unsigned char ok[4];
+
+      SILC_PUT32_MSB(SILC_CONN_AUTH_OK, ok);
 
-      /* Succesfully authenticated */
-      silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS, 
-                             0, NULL, 0, TRUE);
+      /* Authentication failed */
+      silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
+                             0, ok, 4, TRUE);
 
       /* Unregister the timeout task since the protocol has ended. 
         This was the timeout task to be executed if the protocol is
@@ -901,12 +893,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
   case SILC_PROTOCOL_STATE_ERROR:
     {
       /*
-       * Error 
+       * Error. Send notify to remote.
        */
+      unsigned char error[4];
+
+      SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
 
       /* Authentication failed */
       silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
-                             0, NULL, 0, TRUE);
+                             0, error, 4, TRUE);
 
       /* Unregister the timeout task since the protocol has ended. 
         This was the timeout task to be executed if the protocol is
@@ -921,6 +916,25 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        silc_protocol_free(protocol);
     }
     break;
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * We have received failure from remote
+     */
+
+    /* Unregister the timeout task since the protocol has ended. 
+       This was the timeout task to be executed if the protocol is
+       not completed fast enough. */
+    if (ctx->timeout_task)
+      silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
index 07a071dd6522cd8c9160c03586c48f807273944b..64b3319ba0b333718a7d6ea5307e332834068c4d 100644 (file)
@@ -1196,6 +1196,10 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 
  out:
   silc_buffer_clear(sock->inbuf);
+  if (packet->src_id)
+    silc_free(packet->src_id);
+  if (packet->dst_id)
+    silc_free(packet->dst_id);
   silc_free(packet);
   silc_free(parse_ctx);
 }
@@ -1262,7 +1266,18 @@ void silc_server_packet_parse_type(SilcServer server,
     }
     break;
   case SILC_PACKET_FAILURE:
+    /*
+     * Failure received for something. For now we can have only
+     * one protocol for connection executing at once hence this
+     * failure message is for whatever protocol is executing currently.
+     */
     SILC_LOG_DEBUG(("Failure packet"));
+    if (sock->protocol) {
+      /* XXX Audit the failure type */
+      sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
+      sock->protocol->execute(server->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    }
     break;
   case SILC_PACKET_REJECT:
     SILC_LOG_DEBUG(("Reject packet"));
@@ -1713,7 +1728,9 @@ void silc_server_packet_forward(SilcServer server,
 }
 
 /* Internal routine to actually create the channel packet and send it
-   to network. This is common function in channel message sending. */
+   to network. This is common function in channel message sending. If
+   `channel_message' is TRUE this encrypts the message as it is strictly
+   a channel message. If FALSE normal encryption process is used. */
 
 static void
 silc_server_packet_send_to_channel_real(SilcServer server,
@@ -1774,6 +1791,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
+  SilcChannelClientEntry chl;
   unsigned int routed_count = 0;
   SilcCipher cipher;
   SilcHmac hmac;
@@ -1818,8 +1836,9 @@ void silc_server_packet_send_to_channel(SilcServer server,
   }
 
   /* Send the message to clients on the channel's client list. */
-  for (i = 0; i < channel->user_list_count; i++) {
-    client = channel->user_list[i].client;
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     /* If client has router set it is not locally connected client and
        we will route the message to the router set in the client. */
@@ -1829,7 +1848,9 @@ void silc_server_packet_send_to_channel(SilcServer server,
       /* Check if we have sent the packet to this route already */
       for (k = 0; k < routed_count; k++)
        if (routed[k] == client->router)
-         continue;
+         break;
+      if (k < routed_count)
+       continue;
 
       /* Get data used in packet header encryption, keys and stuff. */
       sock = (SilcSocketConnection)client->router->connection;
@@ -1897,6 +1918,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
+  SilcChannelClientEntry chl;
   unsigned int routed_count = 0;
   SilcCipher cipher;
   SilcHmac hmac;
@@ -1942,8 +1964,9 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   }
 
   /* Send the message to clients on the channel's client list. */
-  for (i = 0; i < channel->user_list_count; i++) {
-    client = channel->user_list[i].client;
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     if (client) {
 
@@ -1968,7 +1991,9 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        /* Check if we have sent the packet to this route already */
        for (k = 0; k < routed_count; k++)
          if (routed[k] == client->router)
-           continue;
+           break;
+       if (k < routed_count)
+         continue;
        
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)client->router->connection;
@@ -2015,7 +2040,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
    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. */
+   the client, this means these are not _to the channel_ but _to the client_
+   on the channel. */
 
 void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcChannelEntry channel,
@@ -2027,13 +2053,15 @@ void silc_server_packet_send_local_channel(SilcServer server,
 {
   int i;
   SilcClientEntry client;
+  SilcChannelClientEntry chl;
   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;
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     if (client) {
       sock = (SilcSocketConnection)client->connection;
@@ -2219,7 +2247,12 @@ void silc_server_remove_from_channels(SilcServer server,
 {
   int i, k;
   SilcChannelEntry channel;
-  SilcBuffer id_payload;
+  SilcChannelClientEntry chl;
+  SilcBuffer chidp, clidp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Remove the client from all channels. The client is removed from
      the channels' user list. */
@@ -2228,16 +2261,16 @@ void silc_server_remove_from_channels(SilcServer server,
     if (!channel)
       continue;
 
-    id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
-                                       SILC_ID_CHANNEL);
+    chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
 
     /* Remove from channel */
-    for (k = 0; k < channel->user_list_count; k++) {
-      if (channel->user_list[k].client == client) {
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client == client) {
 
        /* If this client is last one on the channel the channel
           is removed all together. */
-       if (channel->user_list_count == 1) {
+       if (silc_list_count(channel->user_list) == 1) {
 
          /* However, if the channel has marked global users then the 
             channel is not created locally, and this does not remove the
@@ -2245,44 +2278,31 @@ void silc_server_remove_from_channels(SilcServer server,
             notify that this client has left the channel. */
          if (channel->global_users)
            silc_server_send_notify_to_channel(server, channel,
-                                              SILC_NOTIFY_TYPE_SIGNOFF, 3,
-                                              FALSE,
-                                              "Signoff: %s@%s",
-                                              client->nickname,
-                                              strlen(client->nickname),
-                                              sock->hostname,
-                                              strlen(sock->hostname),
-                                              id_payload->data,
-                                              id_payload->len);
+                                              SILC_NOTIFY_TYPE_SIGNOFF, 1,
+                                              clidp->data, clidp->len);
 
          silc_idlist_del_channel(server->local_list, channel);
          break;
        }
 
-       channel->user_list[k].client = NULL;
-       channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+       silc_list_del(channel->user_list, chl);
+       silc_free(chl);
 
        /* Send notify to channel about client leaving SILC and thus
           the entire channel. */
        silc_server_send_notify_to_channel(server, channel,
-                                          SILC_NOTIFY_TYPE_SIGNOFF, 3,
-                                          FALSE,
-                                          "Signoff: %s@%s",
-                                          client->nickname, 
-                                          strlen(client->nickname),
-                                          sock->hostname,
-                                          strlen(sock->hostname),
-                                          id_payload->data,
-                                          id_payload->len);
+                                          SILC_NOTIFY_TYPE_SIGNOFF, 1,
+                                          clidp->data, clidp->len);
       }
     }
 
-    silc_free(id_payload);
+    silc_buffer_free(chidp);
   }
 
   if (client->channel_count)
     silc_free(client->channel);
   client->channel = NULL;
+  silc_buffer_free(clidp);
 }
 
 /* Removes client from one channel. This is used for example when client
@@ -2299,10 +2319,12 @@ int silc_server_remove_from_one_channel(SilcServer server,
 {
   int i, k;
   SilcChannelEntry ch;
-  SilcBuffer id_payload;
+  SilcChannelClientEntry chl;
+  SilcBuffer clidp;
+
+  SILC_LOG_DEBUG(("Start"));
 
-  id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
-                                     SILC_ID_CHANNEL);
+  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Remove the client from the channel. The client is removed from
      the channel's user list. */
@@ -2311,59 +2333,41 @@ int silc_server_remove_from_one_channel(SilcServer server,
     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) {
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client == client) {
        
        /* If this client is last one on the channel the channel
           is removed all together. */
-       if (channel->user_list_count == 1) {
+       if (silc_list_count(channel->user_list) == 1) {
          /* Notify about leaving client if this channel has global users,
             ie. the channel is not created locally. */
          if (notify && channel->global_users)
            silc_server_send_notify_to_channel(server, channel,
-                                              SILC_NOTIFY_TYPE_LEAVE, 4,
-                                              FALSE,
-                                              "%s@%s has left channel %s",
-                                              client->nickname,
-                                              strlen(client->nickname),
-                                              sock->hostname,
-                                              strlen(sock->hostname),
-                                              id_payload->data,
-                                              id_payload->len,
-                                              channel->channel_name,
-                                              strlen(channel->channel_name));
+                                              SILC_NOTIFY_TYPE_LEAVE, 1,
+                                              clidp->data, clidp->len);
 
          silc_idlist_del_channel(server->local_list, channel);
-         silc_buffer_free(id_payload);
+         silc_buffer_free(clidp);
          return FALSE;
        }
        
-       channel->user_list[k].client = NULL;
-       channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+       silc_list_del(channel->user_list, chl);
+       silc_free(chl);
 
        /* Send notify to channel about client leaving the channel */
        if (notify)
          silc_server_send_notify_to_channel(server, channel,
-                                            SILC_NOTIFY_TYPE_LEAVE, 4,
-                                            FALSE,
-                                            "%s@%s has left channel %s",
-                                            client->nickname,
-                                            strlen(client->nickname),
-                                            sock->hostname,
-                                            strlen(sock->hostname),
-                                            id_payload->data,
-                                            id_payload->len,
-                                            channel->channel_name,
-                                            strlen(channel->channel_name));
+                                            SILC_NOTIFY_TYPE_LEAVE, 1,
+                                            clidp->data, clidp->len);
       }
     }
   }
 
-  silc_buffer_free(id_payload);
+  silc_buffer_free(clidp);
   return TRUE;
 }
 
@@ -2371,7 +2375,6 @@ int silc_server_remove_from_one_channel(SilcServer server,
    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)
@@ -2545,6 +2548,7 @@ void silc_server_channel_message(SilcServer server,
                                 SilcPacketContext *packet)
 {
   SilcChannelEntry channel = NULL;
+  SilcChannelClientEntry chl;
   SilcClientEntry client = NULL;
   SilcChannelID *id = NULL;
   void *sender = NULL;
@@ -2575,12 +2579,12 @@ void silc_server_channel_message(SilcServer server,
   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))
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
        break;
     }
-    if (i >= channel->user_list_count)
+    if (chl == SILC_LIST_END)
       goto out;
   }
 
@@ -2612,9 +2616,10 @@ void silc_server_channel_key(SilcServer server,
   SilcChannelKeyPayload payload = NULL;
   SilcChannelID *id = NULL;
   SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
   SilcClientEntry client;
-  unsigned char *key;
-  unsigned int key_len;
+  unsigned char *tmp;
+  unsigned int tmp_len;
   char *cipher;
   int i;
 
@@ -2630,7 +2635,8 @@ void silc_server_channel_key(SilcServer server,
   }
 
   /* Get channel ID */
-  id = silc_id_str2id(silc_channel_key_get_id(payload, NULL), SILC_ID_CHANNEL);
+  tmp = silc_channel_key_get_id(payload, &tmp_len);
+  id = silc_id_payload_parse_id(tmp, tmp_len);
   if (!id)
     goto out;
 
@@ -2642,22 +2648,26 @@ void silc_server_channel_key(SilcServer server,
   }
 
   /* Save the key for us as well */
-  key = silc_channel_key_get_key(payload, &key_len);
-  if (!key)
+  tmp = silc_channel_key_get_key(payload, &tmp_len);
+  if (!tmp)
     goto out;
   cipher = silc_channel_key_get_cipher(payload, NULL);;
   if (!cipher)
     goto out;
-  channel->key_len = key_len * 8;
-  channel->key = silc_calloc(key_len, sizeof(unsigned char));
-  memcpy(channel->key, key, key_len);
-  silc_cipher_alloc(cipher, &channel->channel_key);
+  if (!silc_cipher_alloc(cipher, &channel->channel_key))
+    goto out;
+
+  channel->key_len = tmp_len * 8;
+  channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
+  memcpy(channel->key, tmp, tmp_len);
   channel->channel_key->cipher->set_key(channel->channel_key->context, 
-                                       key, key_len);
+                                       tmp, tmp_len);
 
   /* Distribute the key to all clients on the channel */
-  for (i = 0; i < channel->user_list_count; i++) {
-    client = channel->user_list[i].client;
+  /* XXX Some other sender should be used, I think this is not correct */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     if (client)
       silc_server_packet_send_dest(server, client->connection,
@@ -2679,9 +2689,8 @@ void silc_server_channel_key(SilcServer server,
 void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock)
 {
-  char *motd, *cp;
-  char line[256];
-  int i, motd_len;
+  char *motd;
+  int motd_len;
 
   if (server->config && server->config->motd && 
       server->config->motd->motd_file) {
@@ -2690,27 +2699,8 @@ void silc_server_send_motd(SilcServer server,
     if (!motd)
       return;
 
-    /* Send motd */
-    i = 0;
-    cp = motd;
-    while(cp[i] != 0) {
-      if (cp[i++] == '\n') {
-       memset(line, 0, sizeof(line));
-       strncat(line, cp, i - 1);
-       cp += i;
-
-       if (i == 1)
-         line[0] = ' ';
-
-       silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_NONE, 
-                               0, FALSE, line);
-
-       if (!strlen(cp))
-         break;
-       i = 0;
-      }
-    }
-
+    silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+                           motd, motd_len);
     silc_free(motd);
   }
 }
@@ -2734,37 +2724,22 @@ void silc_server_send_error(SilcServer server,
                          buf, strlen(buf), FALSE);
 }
 
-/* Sends notify message. If `format' is TRUE then the message and the
-   arguments sent are formatted and that message is sent to the other
-   end, if FALSE then arguments are encoded into argument payloads and
-   the message is sent as is. */
+/* Sends notify message. If format is TRUE the variable arguments are
+   formatted and the formatted string is sent as argument payload. If it is
+   FALSE then each argument is sent as separate argument and their format
+   in the argument list must be { argument data, argument length }. */
 
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
                             SilcNotifyType type,
-                            unsigned int argc,
-                            unsigned int format,
-                            const char *fmt, ...)
+                            unsigned int argc, ...)
 {
   va_list ap;
-  char *cp;
-  unsigned char buf[4096];
   SilcBuffer packet;
 
-  cp = (char *)fmt;
-
-  if (argc)
-    va_start(ap, fmt);
+  va_start(ap, argc);
 
-  if (format && argc) {
-    memset(buf, 0, sizeof(buf));
-    vsprintf(buf, fmt, ap);
-    va_end(ap);
-    argc = 0;
-    cp = buf;
-  }
-
-  packet = silc_notify_payload_encode(type, cp, argc, ap);
+  packet = silc_notify_payload_encode(type, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
@@ -2777,29 +2752,14 @@ void silc_server_send_notify_dest(SilcServer server,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
-                                 unsigned int argc,
-                                 unsigned int format,
-                                 const char *fmt, ...)
+                                 unsigned int argc, ...)
 {
   va_list ap;
-  char *cp;
-  unsigned char buf[4096];
   SilcBuffer packet;
 
-  cp = (char *)fmt;
-
-  if (argc)
-    va_start(ap, fmt);
+  va_start(ap, argc);
 
-  if (format && argc) {
-    memset(buf, 0, sizeof(buf));
-    vsprintf(buf, fmt, ap);
-    va_end(ap);
-    argc = 0;
-    cp = buf;
-  }
-
-  packet = silc_notify_payload_encode(type, cp, argc, ap);
+  packet = silc_notify_payload_encode(type, argc, ap);
   silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, 
                               dest_id, dest_id_type,
                               packet->data, packet->len, FALSE);
@@ -2812,35 +2772,158 @@ void silc_server_send_notify_dest(SilcServer server,
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
                                        SilcNotifyType type,
-                                       unsigned int argc,
-                                       unsigned int format,
-                                       const char *fmt, ...)
+                                       unsigned int argc, ...)
 {
   va_list ap;
-  char *cp;
-  unsigned char buf[4096];
   SilcBuffer packet;
 
-  cp = (char *)fmt;
+  va_start(ap, argc);
 
-  if (argc)
-    va_start(ap, fmt);
-
-  if (format && argc) {
-    memset(buf, 0, sizeof(buf));
-    vsprintf(buf, fmt, ap);
-    va_end(ap);
-    argc = 0;
-    cp = buf;
-  }
-
-  packet = silc_notify_payload_encode(type, cp, argc, ap);
+  packet = silc_notify_payload_encode(type, argc, ap);
   silc_server_packet_send_to_channel(server, channel, 
                                     SILC_PACKET_NOTIFY,
                                     packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 }
 
+/* Send notify message to all clients the client has joined. It is quaranteed
+   that the message is sent only once to a client (ie. if a client is joined
+   on two same channel it will receive only one notify message). Also, this
+   sends only to local clients (locally connected if we are server, and to
+   local servers if we are router). */
+
+void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry client,
+                                        SilcNotifyType type,
+                                        unsigned int argc, ...)
+{
+  int i, j, k;
+  SilcSocketConnection sock = NULL;
+  SilcPacketContext packetdata;
+  SilcClientEntry c;
+  SilcClientEntry *sent_clients = NULL;
+  unsigned int sent_clients_count = 0;
+  SilcServerEntry *routed = NULL;
+  unsigned int routed_count = 0;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcCipher cipher;
+  SilcHmac hmac;
+  SilcBuffer packet;
+  unsigned char *data;
+  unsigned int data_len;
+  int force_send = FALSE;
+  va_list ap;
+
+  if (!client->channel_count)
+    return;
+
+  va_start(ap, argc);
+  packet = silc_notify_payload_encode(type, argc, ap);
+  data = packet->data;
+  data_len = packet->len;
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_NOTIFY;
+  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_type = SILC_ID_SERVER;
+  packetdata.rng = server->rng;
+
+  for (i = 0; i < client->channel_count; i++) {
+    channel = client->channel[i];
+
+    /* Send the message to clients on the channel's client list. */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      c = chl->client;
+      
+      /* Check if we have sent the packet to this client already */
+      for (k = 0; k < sent_clients_count; k++)
+       if (sent_clients[k] == c)
+         break;
+      if (k < sent_clients_count)
+       continue;
+
+      /* If we are router and if this client has router set it is not
+        locally connected client and we will route the message to the
+        router set in the client. */
+      if (c && c->router && server->server_type == SILC_ROUTER) {
+       /* Check if we have sent the packet to this route already */
+       for (k = 0; k < routed_count; k++)
+         if (routed[k] == c->router)
+           break;
+       if (k < routed_count)
+         continue;
+       
+       /* Get data used in packet header encryption, keys and stuff. */
+       sock = (SilcSocketConnection)c->router->connection;
+       cipher = c->router->send_key;
+       hmac = c->router->hmac;
+       
+       packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
+       packetdata.dst_id_len = SILC_ID_SERVER_LEN;
+       packetdata.dst_id_type = SILC_ID_SERVER;
+       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+         packetdata.src_id_len + packetdata.dst_id_len;
+       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+       /* Send the packet */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               cipher, hmac, data,
+                                               data_len, FALSE, force_send);
+       
+       silc_free(packetdata.dst_id);
+
+       /* We want to make sure that the packet is routed to same router
+          only once. Mark this route as sent route. */
+       k = routed_count;
+       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+       routed[k] = c->router;
+       routed_count++;
+
+       continue;
+      }
+
+      /* Send to locally connected client */
+      if (c) {
+       
+       /* Get data used in packet header encryption, keys and stuff. */
+       sock = (SilcSocketConnection)c->connection;
+       cipher = c->send_key;
+       hmac = c->hmac;
+       
+       packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
+       packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+       packetdata.dst_id_type = SILC_ID_CLIENT;
+       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+         packetdata.src_id_len + packetdata.dst_id_len;
+       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+       /* Send the packet */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               cipher, hmac, data,
+                                               data_len, FALSE, force_send);
+
+       silc_free(packetdata.dst_id);
+
+       /* Make sure that we send the notify only once per client. */
+       sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) * 
+                                   (sent_clients_count + 1));
+       sent_clients[sent_clients_count] = c;
+       sent_clients_count++;
+      }
+    }
+  }
+
+  if (routed_count)
+    silc_free(routed);
+  if (sent_clients_count)
+    silc_free(sent_clients);
+  silc_free(packetdata.src_id);
+}
+
 /* Sends New ID Payload to remote end. The packet is used to distribute
    information about new registered clients, servers, channel etc. usually
    to routers so that they can keep these information up to date. 
@@ -2853,26 +2936,13 @@ void silc_server_send_new_id(SilcServer server,
                             void *id, SilcIdType id_type, 
                             unsigned int id_len)
 {
-  SilcBuffer packet;
-  unsigned char *id_string;
-
-  id_string = silc_id_id2str(id, id_type);
-  if (!id_string)
-    return;
-
-  packet = silc_buffer_alloc(2 + 2 + id_len);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(id_type),
-                    SILC_STR_UI_SHORT(id_len),
-                    SILC_STR_UI_XNSTRING(id_string, id_len),
-                    SILC_STR_END);
+  SilcBuffer idp;
 
+  idp = silc_id_payload_encode(id, id_type);
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
-                         packet->data, packet->len, FALSE);
-  silc_free(id_string);
-  silc_buffer_free(packet);
+                         idp->data, idp->len, FALSE);
+  silc_buffer_free(idp);
 }
 
 /* Sends Replace ID payload to remote end. This is used to replace old
@@ -3063,17 +3133,23 @@ SilcChannelEntry silc_server_new_channel(SilcServer server,
   silc_cipher_alloc(cipher, &key);
   key->cipher->set_key(key->context, channel_key, key_len);
 
+  channel_name = strdup(channel_name);
+
   /* Create the channel */
   silc_id_create_channel_id(router_id, server->rng, &channel_id);
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
                                  NULL, key);
-  if (!entry)
+  if (!entry) {
+    silc_free(channel_name);
     return NULL;
+  }
 
+#if 0
   /* Add to cache */
   silc_idcache_add(server->local_list->channels, channel_name,
                   SILC_ID_CHANNEL, channel_id, (void *)entry, TRUE);
+#endif
 
   entry->key = silc_calloc(key_len, sizeof(*entry->key));
   entry->key_len = key_len * 8;
@@ -3181,27 +3257,23 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                          reply->data, reply->len, FALSE);
   silc_free(id_string);
   silc_buffer_free(reply);
-  
+
   /* Send some nice info to the client */
-  silc_server_send_notify(server, sock, 
-                         SILC_NOTIFY_TYPE_NONE, 2, TRUE,
-                         "Welcome to the SILC Network %s@%s",
-                         username, sock->hostname);
-  silc_server_send_notify(server, sock,
-                         SILC_NOTIFY_TYPE_NONE, 2, TRUE, 
-                         "Your host is %s, running version %s",
-                         server->config->server_info->server_name,
-                         server_version);
-  silc_server_send_notify(server, sock, 
-                         SILC_NOTIFY_TYPE_NONE, 2, TRUE, 
-                         "Your connection is secured with %s cipher, "
-                         "key length %d bits",
-                         client->send_key->cipher->name,
-                         client->send_key->cipher->key_len);
-  silc_server_send_notify(server, sock, 
-                         SILC_NOTIFY_TYPE_NONE, 1, TRUE, 
-                         "Your current nickname is %s",
-                         client->nickname);
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Welcome to the SILC Network %s@%s",
+                          username, sock->hostname));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your host is %s, running version %s",
+                          server->config->server_info->server_name,
+                          server_version));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your connection is secured with %s cipher, "
+                          "key length %d bits",
+                          client->send_key->cipher->name,
+                          client->send_key->cipher->key_len));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your current nickname is %s",
+                          client->nickname));
 
   /* Send motd */
   silc_server_send_motd(server, sock);
@@ -3226,6 +3298,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   SilcIDCacheEntry cache;
   SilcServerID *server_id;
   unsigned char *server_name, *id_string;
+  unsigned short id_len;
 
   SILC_LOG_DEBUG(("Creating new server"));
 
@@ -3245,12 +3318,18 @@ SilcServerEntry silc_server_new_server(SilcServer server,
 
   /* Parse the incoming packet */
   silc_buffer_unformat(buffer,
-                      SILC_STR_UI16_STRING_ALLOC(&id_string),
+                      SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
                       SILC_STR_UI16_STRING_ALLOC(&server_name),
                       SILC_STR_END);
 
+  if (id_len > buffer->len) {
+    silc_free(id_string);
+    silc_free(server_name);
+    return NULL;
+  }
+
   /* Get Server ID */
-  server_id = silc_id_str2id(id_string, SILC_ID_SERVER);
+  server_id = silc_id_payload_parse_id(id_string, id_len);
   silc_free(id_string);
 
   /* Update client entry */
@@ -3286,8 +3365,8 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
   SilcIDList id_list;
   SilcServerEntry tmpserver, router;
   SilcSocketConnection router_sock;
+  SilcIDPayload idp;
   SilcIdType id_type;
-  unsigned char *id_string;
   void *id, *tmpid;
 
   SILC_LOG_DEBUG(("Processing new ID"));
@@ -3297,16 +3376,17 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
       packet->src_id_type != SILC_ID_SERVER)
     return;
 
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_SHORT(&id_type),
-                      SILC_STR_UI16_STRING_ALLOC(&id_string),
-                      SILC_STR_END);
+  idp = silc_id_payload_parse(buffer);
+  if (!idp)
+    return;
+
+  id_type = silc_id_payload_get_type(idp);
 
   /* Normal server cannot have other normal server connections */
   if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
     goto out;
 
-  id = silc_id_str2id(id_string, id_type);
+  id = silc_id_payload_get_id(idp);
   if (!id)
     goto out;
 
@@ -3361,12 +3441,11 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
     break;
 
   default:
-    goto out;
     break;
   }
 
  out:
-  silc_free(id_string);
+  silc_id_payload_free(idp);
 }
 
 /* Received packet to remove a user from a channel. Routers notify other
index 0e2457cfee655a66f08524206763188a4ecbe115..41379eab36342905ccee30bce80c8503f9dbf17a 100644 (file)
@@ -33,6 +33,18 @@ typedef struct SilcServerObjectStruct *SilcServer;
 #define SILC_SERVER 0
 #define SILC_ROUTER 1
 
+/* Macros */
+
+/* This macro is used to send notify messages with formatted string. The
+   string is formatted with arguments and the formatted string is sent as
+   argument. */
+#define SILC_SERVER_SEND_NOTIFY(server, sock, type, fmt)                   \
+do {                                                                       \
+  char *__fmt__ = silc_format fmt;                                         \
+  silc_server_send_notify(server, sock, type, 1, __fmt__, strlen(__fmt__)); \
+  silc_free(__fmt__);                                                      \
+} while(0);
+
 /* Prototypes */
 int silc_server_alloc(SilcServer *new_server);
 void silc_server_free(SilcServer server);
@@ -121,23 +133,21 @@ void silc_server_send_error(SilcServer server,
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
                             SilcNotifyType type,
-                            unsigned int argc,
-                            unsigned int format,
-                            const char *fmt, ...);
+                            unsigned int argc, ...);
 void silc_server_send_notify_dest(SilcServer server,
                                  SilcSocketConnection sock,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
-                                 unsigned int argc,
-                                 unsigned int format,
-                                 const char *fmt, ...);
+                                 unsigned int argc, ...);
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
                                        SilcNotifyType type,
-                                       unsigned int argc,
-                                       unsigned int format,
-                                       const char *fmt, ...);
+                                       unsigned int argc, ...);
+void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry client,
+                                        SilcNotifyType type,
+                                        unsigned int argc, ...);
 void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             int broadcast,
index b211f1a1d021a61bb5835c1b0f59a4843385e867..2a3b4ad0a1228c7fa201e0a523d6d2caf0cc8853 100644 (file)
@@ -33,7 +33,7 @@ case "$target" in
     ;;
 esac
 
-AM_INIT_AUTOMAKE(silc, 20001009)
+AM_INIT_AUTOMAKE(silc, 20001101)
 AC_PREREQ(2.3)
 AM_CONFIG_HEADER(includes/silcdefs.h)
 
@@ -119,7 +119,6 @@ AC_ARG_ENABLE(debug,
 esac ], CFLAGS="-O2 -g $CFLAGS"
         AC_MSG_RESULT(no))
 
-
 # SOCKS4 support checking
 AC_MSG_CHECKING(whether to support SOCKS4)
 AC_ARG_WITH(socks4,
@@ -232,6 +231,7 @@ AC_ARG_WITH(silcd-config-file,
 # Other configure scripts
 #AC_CONFIG_SUBDIRS(lib/zlib)
 AC_CONFIG_SUBDIRS(lib/silcmath/gmp)
+AC_CONFIG_SUBDIRS(lib/trq)
 
 AC_OUTPUT( \
 Makefile
index 9b5ec7badea7b6e13ab1741568c35c2a00924480..8f71edce74510b0987e17f730115dde7fa7d8cf3 100644 (file)
@@ -752,7 +752,8 @@ returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets to
 indicate the status of the protocol.  Implementations may map the
 status types to human readable error message.  All types except the
 SILC_SKE_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
-Following status types are defined:
+The length of status is 32 bits (4 bytes). Following status types are 
+defined:
 
 .in 6
 0   SILC_SKE_STATUS_OK
@@ -798,6 +799,11 @@ Following status types are defined:
 8   SILC_SKE_STATUS_INCORRECT_SIGNATURE
 
     Provided signature was incorrect.
+
+
+9   SILC_SKE_STATUS_BAD_VERSION
+
+    Provided version string was not acceptable.
 .in 3
 
 
@@ -971,7 +977,8 @@ may be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
 to indicate the status of the protocol.  Implementations may map the
 status types to human readable error message.  All types except the
 SILC_AUTH_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
-Following status types are defined:
+The length of status is 32 bits (4 bytes). Following status types are 
+defined:
 
 0   SILC_AUTH_OK
 
index d6cccf552f533665c60b3d082da990bb8611cfa5..2e3527f16393bb324f2830284c9b1991447b2640 100644 (file)
@@ -435,9 +435,7 @@ List of SILC Packet types are defined as follows.
           server to client, although it may be sent from server to another
           server as well.  Client never sends this packet.  Server may
           send this packet to channel as well when the packet is 
-          distributed to all clients on the channel.  Receiver of this 
-          packet may ignore the packet if it chooses so.  However, it 
-          should not be ignored.
+          distributed to all clients on the channel.
 
           Payload of the packet:  See section 2.3.7 Notify Payload.
 
@@ -656,6 +654,9 @@ List of SILC Packet types are defined as follows.
           packet maybe sent to entity that is indirectly connected to
           the sender.
 
+          When received, the server or router must distribute
+          SILC_NOTIFY_TYPE_JOIN to local clients on the channel.
+
           Payload of the packet:  See section 2.3.21 New Channel User
                                   Payload
 
@@ -678,6 +679,9 @@ List of SILC Packet types are defined as follows.
           packet SILC_PACKET_NEW_CHANNEL_USER except that it may
           include several payloads.  Client must not send this packet.
 
+          When received, the server or router must distribute
+          SILC_NOTIFY_TYPE_JOIN to local clients on the channel.
+
           Payload of the packet:  See section 2.3.23 New Channel User
                                   List Payload
 
@@ -692,6 +696,12 @@ List of SILC Packet types are defined as follows.
           packet.  This packet maybe sent to entity that is indirectly
           connected to the sender.
 
+          When received and the replaced ID is Client ID the server or
+          router must distribute SILC_NOTIFY_TYPE_NICK_CHANGE to the
+          local clients on the channels (if any) of the client whose
+          ID was changed.  However, the notify type must be sent only
+          once per client.
+
           Payload of the packet:  See section 2.3.24 Replace ID Payload
 
 
@@ -702,6 +712,12 @@ List of SILC Packet types are defined as follows.
           this packet.  This packet maybe sent to entity that is
           indirectly connected to the sender.
 
+          When received and the replaced ID is Client ID the server or
+          router must distribute SILC_NOTIFY_TYPE_SIGNOFF to the
+          local clients on the channels (if any) of the client whose
+          ID was changed.  However, the notify type must be sent only
+          once per client.
+
           Payload of the packet:  See section 2.3.25 Remove ID Payload
 
 
@@ -712,6 +728,9 @@ List of SILC Packet types are defined as follows.
           client has left a channel.  This packet maybe sent to entity
           that is indirectly connected to the sender.
 
+          When received, the server or router must distribute
+          SILC_NOTIFY_TYPE_LEAVEW to local clients on the channel.
+
           Payload of the packet:  See section 2.3.26 Remove Channel User
                                   Payload
 
@@ -1007,9 +1026,10 @@ o Reject Indication (variable length) - Indication of
 
 Notify payload is used to send notify messages.  The payload is usually
 sent from server to client, however, server may send it to another
-server as well.  Client must not send this payload.  The receiver of
-this payload may totally ignore the contents of the payload, however,
-notify message should be noted and possibly logged.
+server as well.  This payload may also be sent to a channel.  Client must
+not send this payload.  The receiver of this payload may totally ignore the
+contents of the payload, however, notify message should be noted and
+possibly logged.
 
 The payload may only be sent with SILC_PACKET_NOTIFY packet.  It must
 not be sent in any other packet type.  Following diagram represents the
@@ -1020,14 +1040,10 @@ Notify 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
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|          Notify Type          |        Message Length         |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Argument Nums |                                               |
-+-+-+-+-+-+-+-+-+                                               +
-|                                                               |
-~                        Notify Message                         ~
-|                                                               |
+|          Notify Type          |        Payload Length         |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Argument Nums |
++-+-+-+-+-+-+-+-+
 .in 3
 
 .ce
@@ -1038,70 +1054,148 @@ Figure 9:  Notify Payload
 o Notify Type (2 bytes) - Indicates the type of the notify
   message.
 
-o Message Length (2 bytes) - Length of the Notify Message area 
-  not ncluding the length of any other fields in the payload.
+o Payload Length (2 bytes) - Length of the entire Notify Payload
+  including any associated Argument Payloads.
 
 o Argument Nums (2 bytes) - Indicates the number of Argument
   Payloads associated to this payload.  Notify types may define
   arguments to be send along the notify message.
-
-o Notify Message (variable length) - Human readable notify
-  message.  The format of this message is implementation specific.
-  The message can be for example "%s has joined channel %s".
 .in 3
 
-Following notify types has been defined:
+Following list of currently defined notify types.  The format for notify
+arguments is same as in SILC commands described in [SILC1].  Also, all
+ID's sent in arguments are sent inside ID Payload.
 
 .in 6
 0     SILC_NOTIFY_TYPE_NONE
 
-      If no specific notify type apply for the notify
-      message this type may be used.
+      If no specific notify type apply for the notify message this type
+      may be used.
+
+      Max Arguments:  1
+          Arguments:  (1) <message>
+
+      The <message> is implementation specific free text string.  Receiver
+      may ignore this message.
 
-      No arguments associated to this type.
 
 1     SILC_NOTIFY_TYPE_INVITE
 
-      Sent when receiver has been invited to a channel.
+      Sent when receiver has been invited to a channel.  This type must be
+      sent directly to the invited client.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <Channel ID>
+
+      The <Client ID> is the client who invites the receiver of this type 
+      to channel indicated by <Channel ID>.
 
-      This type includes two arguments: nickname and channel name.
 
 2     SILC_NOTIFY_TYPE_JOIN
 
-      Sent when client has joined to a channel.
+      Sent when client has joined to a channel.  The server must distribute
+      this type only to the local clients on the channel and then send
+      SILC_PACKET_NEW_CHANNEL_USER packet to its primary route.  The router
+      or server receiving the packet distributes this type to the local
+      clients on the channel.  See description of SILC_PACKET_NEW_CHANNEL_USER
+      packet for more information.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client that joined to the channel.
 
-      This type includes six arguments: Client ID, nickname, username,
-      hostname, Channel ID and channel name.  The Client ID and Channel ID
-      are sent inside ID Payload.
 
 3     SILC_NOTIFY_TYPE_LEAVE
 
-      Sent when client has left a channel.
+      Sent when client has left a channel.  The server must distribute
+      this type only to the local clients on the channel and then send
+      SILC_PACKET_REMOVE_CHANNEL_USER packet to its primary route.  The
+      router or server receiving the packet distributes this type to the
+      local clients on the channel.  See description of 
+      SILC_PACKET_REMOVE_CHANNEL_USER packet for more information.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client who left the channel.
 
-      This type includes four arguments: nickname, server name,
-      Channel ID and channel name.  The Channel ID is sent inside ID
-      Payload.
 
 4     SILC_NOTIFY_TYPE_SIGNOFF
 
-      Sent when client signoffs from SILC network.
+      Sent when client signoffs from SILC network.  This type is sent only
+      if the client was joined to any channel.  This type is sent by server
+      or router when SILC_PACKET_REMOVE_ID packet has been received.  See
+      detailed information from description of SILC_PACKET_REMOVE_ID packet.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client who left SILC network.
 
-      This type includes three arguments: nickname, server name and
-      Channel ID.  The Channel ID is sent inside ID Payload.
 
 5     SILC_NOTIFY_TYPE_TOPIC_SET
 
-      Sent when topic is set/changed on a channel.
+      Sent when topic is set/changed on a channel.  This type must be sent
+      only to the clients who is joined on the channel whose topic was
+      set or changed.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <topic>
+
+      The <Client ID> is the client who set or changed the <topic>.
 
-      This type includes four arguments: Channel ID, topic, nickname and
-      hostname.  The Channel ID is sent inside ID Payload.
 
 6     SILC_NOTIFY_TYPE_NICK_CHANGE
 
-      Sent when client changes nick on a channel.
+      Sent when client changes nick on a channel.  This type is sent only if
+      the client has joined to any channel.  This type is sent by server or
+      router when SILC_PACKET_REPLACE_ID packet has been received.  See 
+      detailed information from description of SILC_PACKET_REPLACE_ID packet.
+
+      Max Arguments:  2
+          Arguments:  (1) <Old Client ID>  (2) <New Client ID>
+
+      The <Old Client ID> is the old ID of the client who changed the 
+      nickname.  The <New Client ID> is the new ID generated by the change
+      of the nickname.
+
+
+7     SILC_NOTIFY_TYPE_CMODE_CHANGE
+
+      Sent when channel mode has changed.  This type must be sent only to
+      the clients who is joined on the channel whose mode was changed.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <mode mask>
+
+      The <Client ID> is the client who changed the mode.  The <mode mask>
+      is the new mode mask of the channel.
+
+
+8     SILC_NOTIFY_TYPE_CUMODE_CHANGE
+
+      Sent when user mode on channel has changed.  This type must be sent
+      only to the clients who is joined on the channel where the target 
+      client is on.
+
+      Max Arguments: 3
+          Arguments:  (1) <Client ID>  (2) <mode mask>
+                      (3) <Target Client ID>
+
+      The <Client ID> is the client who changed the mode.  The <mode mask>
+      is the new mode mask of the channel.  The <Target Client ID> is the
+      client whose mode was changed.
+
+
+9     SILC_NOTIFY_TYPE_MOTD
+
+      Sent when Message of the Day (motd) is sent to client.
+
+      Max Arguments:  1
+          Arguments:  (1) <motd>
 
-      This type includes two arguments: nickname and Channel ID.
-      The Channel ID is sent inside ID Payload.
+      The <motd> is the Message of the Day.
 .in 3
 
 Notify types starting from 16384 are reserved for private notify
index a78e9865372af1affff668672756c0f8c1fedaea..33555f1ac8a96766a47818b8fada00fb2c6e610d 100644 (file)
@@ -823,11 +823,7 @@ about packet forwarding.
 Note that the command reply is usually sent only after client has sent
 the command request but server is allowed to send command reply packet
 to client even if client has not requested the command.  Client may,
-however, choose not to accept the command reply, but there are some
-command replies that the client should accept.  Example of a such
-command reply is reply to SILC_COMMAND_CMODE command that the server
-uses to distribute the channel mode on all clients on the channel
-when the mode has changed.
+however, choose ignore the command reply, but should not.
 
 It is expected that some of the commands may be miss-used by clients
 resulting various problems on the server side.  Every implementation
@@ -1727,7 +1723,7 @@ List of all defined commands in SILC follows.
    1    SILC_COMMAND_WHOIS
 
         Max Arguments:  3
-            Arguments:  (1) <nickname>[@<server>]  (2) [<Client ID>]
+            Arguments:  (1) [<nickname>[@<server>]]  (2) [<Client ID>]
                         (3) [<count>]
 
         Whois command is used to query various information about specific
@@ -1840,7 +1836,7 @@ List of all defined commands in SILC follows.
    3    SILC_COMMAND_IDENTIFY
 
         Max Arguments:  2
-            Arguments:  (1) <nickname>[@<server>]  (2) [<Client ID>]
+            Arguments:  (1) [<nickname>[@<server>]]  (2) [<Client ID>]
                         (3) [<count>]
 
         Identify.  Identify command is almost analogous to WHOIS command,
@@ -1865,7 +1861,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
-        command as it is hardly a command that would be used a end user.
+        command as it is hardly a command that would be used by an end user.
         However, it must be implemented as it is used with private message
         sending.
 
@@ -1913,6 +1909,12 @@ List of all defined commands in SILC follows.
         nicknames in SILC are case-sensitive which must be taken into
         account when searching clients by nickname.
 
+        When nickname is changed new Client ID is generated.  Server must
+        distribute SILC_NOTIFY_TYPE_NICK_CHANGE to local clients on the
+        channels (if any) the client is joined on.  Then it must send
+        SILC_PACKET_REPLACE_ID to its primary route to replace the old
+        Client ID with the new one.
+
         Reply messages to the command:
 
         Max Arguments:  2
@@ -1935,10 +1937,6 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_TOO_MANY_PARAMS
 
 
-
-
-
-
    5    SILC_COMMAND_LIST
 
         Max Arguments:  2
@@ -2225,9 +2223,6 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_AUTH_FAILED
 
 
-
-
-
    14   SILC_COMMAND_JOIN
 
         Max Arguments:  3
@@ -2268,7 +2263,7 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  5
+        Max Arguments:  6
             Arguments:  (1) <Status Payload>  (2) <channel> 
                         (3) <Channel ID>      (4) <channel mode mask>
                         (5) [<ban mask>]      (6) [<invite list>]
@@ -2388,11 +2383,11 @@ List of all defined commands in SILC follows.
 
    17   SILC_COMMAND_CMODE
 
-        Max Arguments:  8
+        Max Arguments:  7
             Arguments:  (1) <Channel ID>    (2) <channel mode mask>
                         (3) [<user limit>]  (4) [<passphrase>]
                         (5) [<ban mask>]    (6) [<invite list>]
-                        (7) [<Client ID>]   (8) [<cipher>[:<key len>]]
+                        (7) [<cipher>[:<key len>]]
 
         This command is used by client to set or change channel flags on
         a channel.  Channel has several modes that set various properties
@@ -2402,6 +2397,9 @@ List of all defined commands in SILC follows.
         the same channel and poses sufficient privileges to be able to
         change the mode.
 
+        When the mode is changed SILC_NOTIFY_TYPE_CMODE_CHANGE notify
+        type is distributed to the channel.
+
         Following channel modes are defined:
 
            0x0000    SILC_CMODE_NONE
@@ -2525,13 +2523,18 @@ List of all defined commands in SILC follows.
               unsetting a ban mask the mask must be provided as
               argument.  Channel founder and channel operator may
               set/unset this mode.  Channel founder may not be
-              added to the ban list.
+              added to the ban list.  <ban mask> is comma (`,') separated
+              list of banned clients in following format:
+
+                [<nickname>!][<username>]@[<hostname>]
+
+              Wildcards maybe used when banning clients.
 
               Typical implementation would use [+|-]b on user interface
               to set/unset this mode.
 
 
-           0x0100    SILC_CMODE_INVITE
+           0x0100    SILC_CMODE_INVITE_LIST
 
               Invite list has been set to the channel.  The invite list
               can be used to mark the clients that is able to join
@@ -2539,32 +2542,28 @@ List of all defined commands in SILC follows.
               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.
+              channel operator may set/unset this mode.  The <invite list>
+              is command (`,') separated list of invited clients in following
+              format:
 
-              Typical implementation would use [+|-]I on user interface
-              to set/unset this mode.
+                [<nickname>!][<username>]@[<hostname>]
 
-        
-           0x0200    SILC_CMODE_OPERATOR
+              Wildcards maybe used when setting the invite list.
 
-              Sets channel operator privileges on the channel for a
-              client on the channel.  The <Client ID> argument is the
-              target client on the channel.  Channel founder and
-              channel operator may set/unset (promote/demote) this
-              mode.
-
-              Typical implementation would use [+|-]o on user interface
+              Typical implementation would use [+|-]I on user interface
               to set/unset this mode.
 
-
-           0x0400    SILC_CMODE_CIPHER
+        
+           0x0200    SILC_CMODE_CIPHER
 
               Sets specific cipher to be used to protect channel
               traffic.  The <cipher> argument is the requested cipher.
               When set or unset the server must re-generate new
               channel key.  If <key len> argument is specified with
               <cipher> argument the new key is generated of <key len>
-              length.
+              length in bits.  Only channel founder may set the cipher of 
+              the channel.  When unset the new key is generated using
+              default cipher for the channel.
 
               Typical implementation would use [+|-]c on user interface
               to set/unset this mode.
@@ -2585,9 +2584,7 @@ List of all defined commands in SILC follows.
             Arguments:  (1) <Status Payload>  (2) <channel mode mask>
 
         This command replies with the changed channel mode mask that
-        client is required to keep locally.  The same mask is also
-        sent to all clients on channel by sending additional command
-        reply to them.
+        client is required to keep locally.
 
         Status messages:
 
@@ -2601,12 +2598,76 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CHANNEL_ID
             SILC_STATUS_ERR_NO_CHANNEL_PRIV
             SILC_STATUS_ERR_UNKNOWN_MODE
-            SILC_STATUS_ERR_NO_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+
+   19   SILC_COMMAND_CUMODE
+
+        Max Arguments:  3
+            Arguments:  (1) <Channel ID>  (2) <mode mask>
+                        (3) <Client ID>
+
+        This command is used by client to change channel user modes on
+        channel.  Users on channel may have some special modes and this
+        command is used by channel operators to set or change these modes.
+        The <Channel ID> is the ID of the target channel.  The <mode mask>
+        is OR'ed mask of modes.  The <Client ID> is the target client.
+        The client changing channel user modes must be on the same channel
+        as the target client and poses sufficient privileges to be able to
+        change the mode.
+
+        When the mode is changed SILC_NOTIFY_TYPE_CUMODE_CHANGE notify
+        type is distributed to the channel.
+
+        Following channel modes are defined:
 
+           0x0000    SILC_CUMODE_NONE
 
+              No specific mode.  This is the normal situation for client.
+              Also, this is the mode set when removing all modes from client.
 
 
-   18   SILC_COMMAND_KICK
+           0x0001    SILC_CUMODE_FOUNDER
+
+              The client is channel founder of the channel.  This mode
+              cannot be set by other client, it is set by the server when
+              the channel was founded (created).  The mode is provided 
+              because client may remove the founder rights from itself.
+
+
+           0x0002    SILC_CUMODE_OPERATOR
+
+              Sets channel operator privileges on the channel for a
+              client on the channel.  Channel founder and channel operator
+              may set/unset (promote/demote) this mode.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <channel user mode mask>
+                        (3) <Client ID>
+
+        This command replies with the changed channel user mode mask that
+        client is required to keep locally.  The <Client ID> is the target
+        client.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+
+   19   SILC_COMMAND_KICK
 
         Max Arguments:  3
             Arguments:  (1) <channel>  (2) <Client ID>  
@@ -2637,7 +2698,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CLIENT_ID
 
 
-   19   SILC_COMMAND_RESTART
+   20   SILC_COMMAND_RESTART
 
         Max Arguments:  0
             Arguments:  None
@@ -2662,7 +2723,7 @@ List of all defined commands in SILC follows.
 
 
 
-   20   SILC_COMMAND_CLOSE
+   21   SILC_COMMAND_CLOSE
 
         Max Arguments:  1
             Arguments:  (1) <Server ID>
@@ -2689,7 +2750,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SUCH_SERVER_ID
 
 
-   21   SILC_COMMAND_DIE
+   22   SILC_COMMAND_DIE
 
         Max Arguments:  0
             Arguments:  None
@@ -2714,7 +2775,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SERVER_PRIV
 
 
-   22   SILC_COMMAND_SILCOPER
+   23   SILC_COMMAND_SILCOPER
 
         Max Arguments:  2
             Arguments:  (1) <username>  (2) <authentication data>
@@ -2754,7 +2815,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_AUTH_FAILED
 
 
-   23   SILC_COMMAND_LEAVE
+   24   SILC_COMMAND_LEAVE
 
         Max Arguments:  1
             Arguments:  (1) <Channel ID>
@@ -2782,7 +2843,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CHANNEL_ID
 
 
-   24   SILC_COMMAND_NAMES
+   25   SILC_COMMAND_NAMES
 
         Max Arguments:  1
             Arguments:  (1) <Channel ID>
@@ -2797,21 +2858,26 @@ List of all defined commands in SILC follows.
         command must not send the list of users, as private and secret
         channels cannot be seen by outside.  In this case the returned
         name list may include a indication that the server could not 
-        resolve the names of the users on the channel.
+        resolve the names of the users on the channel.  Also, in this case
+        Client ID's or client modes are not sent either.
 
         Reply messages to the command:
 
-        Max Arguments:  3
+        Max Arguments:  5
             Arguments:  (1) <Status Payload>  (2) <Channel ID>
                         (3) <name list>       (4) <Client ID list>
+                        (5) <client mode list>
 
         This command replies with the Channel ID of the requested channel,
         comma separated list of users on the channel and Client ID list
         of the users on the list.  The Client ID list has Client ID's
         of all users in the list.  First Client ID in the list must be
-        the Client ID of the first user in <name list>.  The Client ID
-        List is formed by adding Client ID's each after each.  Note that
-        the Client ID list is binary data.
+        the Client ID of the first user in <name list>.  The <Client ID
+        list> is formed by adding Client ID's each after each.  Note that
+        the Client ID list is binary data and the length of each ID must
+        be snooped from the data.  The <client mode list> is formed by
+        adding client's user modes on the channel each after each (4 bytes 
+        each).
 
         Status messages:
 
@@ -2825,7 +2891,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NOT_ON_CHANNEL
 
 
-   25 - 199
+   26 - 199
 
         Currently undefined commands.
 
@@ -2995,95 +3061,100 @@ List of all defined command status messages following.
    25   SILC_STATUS_ERR_NOT_ON_CHANNEL
 
         "You are not on that channel".  The command were specified for
-        client user is not currently on.
+        channel user is not currently on.
+
+   26   SILC_STATUS_ERR_USER_NOT_ON_CHANNEL
+
+        "They are not on channel".  The requested target client is not
+        on requested channel.
 
-   26   SILC_STATUS_ERR_USER_ON_CHANNEL
+   27   SILC_STATUS_ERR_USER_ON_CHANNEL
 
         "User already on channel".  User were invited on channel they
         already are on.
 
-   27   SILC_STATUS_ERR_NOT_REGISTERED
+   28   SILC_STATUS_ERR_NOT_REGISTERED
 
         "You have not registered".  User executed command that requires
         the client to be registered on the server before it may be
         executed.
 
-   28   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+   29   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
 
         "Not enough parameters".  Command requires more parameters
         than provided.
 
-   29   SILC_STATUS_ERR_TOO_MANY_PARAMS
+   30   SILC_STATUS_ERR_TOO_MANY_PARAMS
 
         "Too many parameters".  Too many parameters were provided
         for the command.
 
-   30   SILC_STATUS_ERR_PERM_DENIED
+   31   SILC_STATUS_ERR_PERM_DENIED
 
         "Your host is not among the privileged".  The client tried to
         register on server that does not allow this host to connect.
 
-   31   SILC_STATUS_ERR_BANNED_FROM_SERVER
+   32   SILC_STATUS_ERR_BANNED_FROM_SERVER
 
         "You are banned from this server".  The client tried to register
         on server that has explicitly denied this host to connect.
 
-   32   SILC_STATUS_ERR_BAD_PASSWORD
+   33   SILC_STATUS_ERR_BAD_PASSWORD
 
         "Cannot join channel. Incorrect password".  Password provided for 
         channel were not accepted.
 
-   33   SILC_STATUS_ERR_CHANNEL_IS_FULL
+   34   SILC_STATUS_ERR_CHANNEL_IS_FULL
 
         "Cannot join channel. Channel is full".  The channel is full
         and client cannot be joined to it.
 
-   34   SILC_STATUS_ERR_NOT_INVITED
+   35   SILC_STATUS_ERR_NOT_INVITED
 
         "Cannot join channel. You have not been invited".  The channel
         is invite only channel and client has not been invited.
 
-   35   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+   36   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
 
         "Cannot join channel. You have been banned".  The client has
         been banned from the channel.
 
-   36   SILC_STATUS_ERR_UNKNOWN_MODE
+   37   SILC_STATUS_ERR_UNKNOWN_MODE
 
         "Unknown mode".  Mode provided by the client were unknown to
         the server.
 
-   37   SILC_STATUS_ERR_NOT_YOU
+   38   SILC_STATUS_ERR_NOT_YOU
 
         "Cannot change mode for other users".  User tried to change
         someone else's mode.
 
-   38   SILC_STATUS_ERR_NO_CHANNEL_PRIV
+   39   SILC_STATUS_ERR_NO_CHANNEL_PRIV
 
         "Permission denied. You are not channel operator".  Command may 
         be executed only by channel operator.
 
-   39   SILC_STATUS_ERR_NO_SERVER_PRIV
+   40   SILC_STATUS_ERR_NO_SERVER_PRIV
 
         "Permission denied. You are not server operator".  Command may
         be executed only by server operator.
 
-   40   SILC_STATUS_ERR_NO_ROUTER_PRIV
+   41   SILC_STATUS_ERR_NO_ROUTER_PRIV
 
         "Permission denied. You are not SILC operator".  Command may be
         executed only by router (SILC) operator.
 
-   41   SILC_STATUS_ERR_BAD_NICKNAME
+   42   SILC_STATUS_ERR_BAD_NICKNAME
 
         "Bad nickname".  Nickname requested contained illegal characters
         or were malformed.
 
-   42   SILC_STATUS_ERR_BAD_CHANNEL
+   43   SILC_STATUS_ERR_BAD_CHANNEL
 
         "Bad channel name".  Channel requested contained illegal characters
         or were malformed.
 
-   43   SILC_STATUS_ERR_AUTH_FAILED
+   44   SILC_STATUS_ERR_AUTH_FAILED
 
         "Authentication failed".  The authentication data sent as 
         argument were wrong and thus authentication failed.
index 2115e1b80ea0a00d7443fc97a622fcb451f76a93..92ba83273be470f11e85a6dbbb98ca8c1adfbc24 100644 (file)
 #include "silcpacket.h"
 #include "silcnotify.h"
 
+/* TRQ (SilcList API and SilcDList API) */
+#include "silclist.h"
+#include "silcdlist.h"
+
 #ifdef SILC_SIM
 /* SILC Module library includes */
 #include "silcsim.h"
index dd537292c10feac7edd8fb95a4edb740f84c84d1..b755b781fb57cb60e74565ca916154c28320677c 100644 (file)
@@ -26,7 +26,8 @@ SUBDIRS = \
        silcmath \
        silcske \
        silcutil \
-       silcclient
+       silcclient \
+       trq
 #        zlib
 
 # SILC Library dirs
@@ -37,7 +38,8 @@ SILCLIB_DIRS = \
        silcsim \
        silcmath \
        silcske \
-       silcutil
+       silcutil \
+       trq
 
 # SILC Client Library dirs
 SILCCLIENTLIB_DIRS = \
index b8bde5f04924fc8ed40713d2ce49cd71d1be87f5..516e97be3f27cb2136dfc873984ce3f85a1493c6 100644 (file)
@@ -28,4 +28,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
        -I../silcsim -I../.. -I../../includes -I../silccore -I../silcutil \
-       -I../silcmath/gmp
+       -I../silcmath/gmp -I../trq
index 8f914cf7f80019108ca6b8b9b1f7fca1bac638ef..07df38868eb88168e429badd02bd3316bdf437e9 100644 (file)
@@ -32,4 +32,4 @@ EXTRA_DIST = *.h
 INCLUDES = -I. -I.. -I../silccore -I../silccrypt -I../silcutil \
        -I../silcmath -I../silcske -I../silcsim \
        -I../../includes \
-       -I../silcmath/gmp
+       -I../silcmath/gmp -I../trq
index ab4b152192f5e151c314397f5015fb429c35c572..cdd1011cf1aec58e555ee30bc1e64c479a2f31ff 100644 (file)
@@ -65,6 +65,7 @@ some other tasks that must be done before initializing the client.  Following
 pointers must be set before calling the initializing function:
 
        client->username
+       client->hostname
        client->realname
        client->pkcs
        client->public_key
index 1c1cd3017df14628e7571f198be9e69292e2a724..4cb6fc7a5ec7abb7ab8060166a1215d039dd0c72 100644 (file)
@@ -649,6 +649,10 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real)
 
  out:
   silc_buffer_clear(buffer);
+  if (packet->src_id)
+    silc_free(packet->src_id);
+  if (packet->dst_id)
+    silc_free(packet->dst_id);
   silc_free(packet);
   silc_free(parse_ctx);
 }
@@ -703,9 +707,21 @@ void silc_client_packet_parse_type(SilcClient client,
      * protocol and it will call the final callback.
      */
     if (sock->protocol) {
-      sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+      sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
       sock->protocol->execute(client->timeout_queue, 0,
                              sock->protocol, sock->sock, 0, 0);
+
+      /* XXX We have only two protocols currently thus we know what this
+        failure indication is. */
+      if (buffer->len >= 4) {
+       unsigned int failure;
+
+       SILC_GET32_MSB(failure, buffer->data);
+
+       /* Notify application */
+       client->ops->failure(client, sock->user_data, sock->protocol,
+                            (void *)failure);
+      }
     }
     break;
   case SILC_PACKET_REJECT:
@@ -715,7 +731,7 @@ void silc_client_packet_parse_type(SilcClient client,
     /*
      * Received notify message 
      */
-    silc_client_notify_by_server(client, sock, buffer);
+    silc_client_notify_by_server(client, sock, packet);
     break;
 
   case SILC_PACKET_ERROR:
@@ -816,19 +832,14 @@ void silc_client_packet_parse_type(SilcClient client,
        * 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)
+      SilcIDPayload idp;
+
+      idp = silc_id_payload_parse(buffer);
+      if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
        break;
 
-      silc_client_receive_new_id(client, sock, id_string);
-      silc_free(id_string);
+      silc_client_receive_new_id(client, sock, idp);
+      silc_id_payload_free(idp);
       break;
     }
 
@@ -1249,12 +1260,29 @@ void silc_client_error_by_server(SilcClient client,
   silc_free(msg);
 }
 
+/* Called when notify is received and some async operation (such as command)
+   is required before processing the notify message. This calls again the
+   silc_client_notify_by_server and reprocesses the original notify packet. */
+
+static void silc_client_notify_by_server_pending(void *context)
+{
+  SilcPacketContext *p = (SilcPacketContext *)context;
+  silc_client_notify_by_server(p->context, p->sock, p);
+  if (p->src_id)
+    silc_free(p->src_id);
+  if (p->dst_id)
+    silc_free(p->dst_id);
+  silc_buffer_free(p->buffer);
+  silc_free(p);
+}
+
 /* Received notify message from server */
 
 void silc_client_notify_by_server(SilcClient client,
                                  SilcSocketConnection sock,
-                                 SilcBuffer message)
+                                 SilcPacketContext *packet)
 {
+  SilcBuffer buffer = packet->buffer;
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcNotifyPayload payload;
   SilcNotifyType type;
@@ -1263,63 +1291,98 @@ void silc_client_notify_by_server(SilcClient client,
 
   SilcClientID *client_id = NULL;
   SilcChannelID *channel_id = NULL;
-  SilcIDPayload idp;
   SilcClientEntry client_entry;
+  SilcClientEntry client_entry2;
   SilcChannelEntry channel;
   SilcIDCacheEntry id_cache = NULL;
   unsigned char *tmp;
-  unsigned int tmp_len;
+  unsigned int tmp_len, mode;
 
-  payload = silc_notify_payload_parse(message);
+  payload = silc_notify_payload_parse(buffer);
   type = silc_notify_get_type(payload);
   args = silc_notify_get_args(payload);
+  if (!args)
+    goto out;
 
   switch(type) {
   case SILC_NOTIFY_TYPE_NONE:
+    /* Notify application */
+    client->ops->notify(client, conn, type, 
+                       silc_argument_get_arg_type(args, 1, NULL));
     break;
+
   case SILC_NOTIFY_TYPE_INVITE:
     /* 
-     * Someone invited me to a channel. Nothing interesting to do here.
+     * Someone invited me to a channel. Find Client and Channel entries
+     * for the application.
      */
+    
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry and if not found query it */
+    client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+    if (!client_entry) {
+      SilcPacketContext *p = silc_packet_context_dup(packet);
+      p->context = (void *)client;
+      p->sock = sock;
+      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+                                 silc_client_notify_by_server_pending, p);
+      goto out;
+    }
+
+    /* Get Channel ID */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* XXX Will ALWAYS fail because currently we don't have way to resolve
+       channel information for channel that we're not joined to. */
+    /* XXX ways to fix: use (extended) LIST command, or define the channel
+       name to the notfy type when name resolving is not mandatory. */
+    /* Find channel entry */
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      goto out;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, client_entry, channel);
     break;
+
   case SILC_NOTIFY_TYPE_JOIN:
     /*
      * Someone has joined to a channel. Get their ID and nickname and
      * cache them for later use.
      */
 
-    /* Get client ID (it's in ID payload) */
+    /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    idp = silc_id_payload_parse_data(tmp, tmp_len);
-    client_id = silc_id_payload_get_id(idp);
-    silc_id_payload_free(idp);
+    if (!tmp)
+      goto out;
 
-    /* If it's my ID, ignore */
-    if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
-      break;
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
 
-    /* Check if we have that ID already */
-    if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
-                                    SILC_ID_CLIENT, &id_cache)) {
-      /* Add client to cache */
-      client_entry = silc_calloc(1, sizeof(*client_entry));
-      client_entry->id = client_id;
-      client_entry->nickname = 
-       strdup(silc_argument_get_arg_type(args, 2, NULL));
-      silc_idcache_add(conn->client_cache, client_entry->nickname, 
-                      SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
-      client_id = NULL;
-    } else {
-      client_entry = (SilcClientEntry)id_cache->context;
+    /* Find Client entry and if not found query it */
+    client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+    if (!client_entry) {
+      SilcPacketContext *p = silc_packet_context_dup(packet);
+      p->context = (void *)client;
+      p->sock = sock;
+      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+                                 silc_client_notify_by_server_pending, p);
+      goto out;
     }
 
-    /* Get Channel ID (it's in ID payload) */
-    tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
-    idp = silc_id_payload_parse_data(tmp, tmp_len);
-    channel_id = silc_id_payload_get_id(idp);
-    silc_id_payload_free(idp);
-
-    /* Find channel entry */
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
@@ -1328,8 +1391,8 @@ void silc_client_notify_by_server(SilcClient client,
 
     /* Add client to channel */
     for (i = 0; i < channel->clients_count; i++) {
-      if (channel->clients[i] == NULL) {
-       channel->clients[channel->clients_count] = client_entry;
+      if (channel->clients[i].client == NULL) {
+       channel->clients[channel->clients_count].client = client_entry;
        channel->clients_count++;
        break;
       }
@@ -1339,149 +1402,331 @@ void silc_client_notify_by_server(SilcClient client,
       channel->clients = silc_realloc(channel->clients, 
                                      sizeof(*channel->clients) * 
                                      (channel->clients_count + 1));
-      channel->clients[channel->clients_count] = client_entry;
+      channel->clients[channel->clients_count].client = client_entry;
+      channel->clients[channel->clients_count].mode = 0;
       channel->clients_count++;
     }
 
     /* XXX add support for multiple same nicks on same channel. Check
        for them here */
+
+    /* Notify application. The channel entry is sent last as this notify
+       is for channel but application don't know it from the arguments
+       sent by server. */
+    client->ops->notify(client, conn, type, client_entry, channel);
     break;
+
   case SILC_NOTIFY_TYPE_LEAVE:
     /*
      * Someone has left a channel. We will remove it from the channel but
      * we'll keep it in the cache in case we'll need it later.
      */
     
-    /* Get nickname */
-    /* XXX Protocol must be changed to send Client ID */
+    /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    
-    /* Find channel entry */
-    /* XXX this can return wrong entry */
-    client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
     if (!client_entry)
-      break;
-    
-    /* Get Channel ID (it's in ID payload) */
-    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-    idp = silc_id_payload_parse_data(tmp, tmp_len);
-    channel_id = silc_id_payload_get_id(idp);
-    silc_id_payload_free(idp);
-    
-    /* Find channel entry */
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
-    
+
     channel = (SilcChannelEntry)id_cache->context;
-    
+
     /* Remove client from channel */
     for (i = 0; i < channel->clients_count; i++) {
-      if (channel->clients[i] == client_entry) {
-       channel->clients[i] = NULL;
+      if (channel->clients[i].client == client_entry) {
+       channel->clients[i].client = NULL;
        channel->clients_count--;
        break;
       }
     }
+
+    /* Notify application. The channel entry is sent last as this notify
+       is for channel but application don't know it from the arguments
+       sent by server. */
+    client->ops->notify(client, conn, type, client_entry, channel);
     break;
+
   case SILC_NOTIFY_TYPE_SIGNOFF:
     /*
-     * Someone left SILC. We'll remove it from the channel and from cache.
+     * Someone left SILC. We'll remove it from all channels and from cache.
      */
 
-    /* Get nickname */
-    /* XXX Protocol must be changed to send Client ID */
+    /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    
-    /* Find channel entry */
-    /* XXX this can return wrong entry */
-    client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
     if (!client_entry)
-      break;
-    
-    /* Get Channel ID (it's in ID payload) */
-    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-    idp = silc_id_payload_parse_data(tmp, tmp_len);
-    channel_id = silc_id_payload_get_id(idp);
-    silc_id_payload_free(idp);
-    
-    /* Find channel entry */
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                    SILC_ID_CHANNEL, &id_cache))
-      break;
-    
-    channel = (SilcChannelEntry)id_cache->context;
-    
-    /* Remove client from channel */
-    for (i = 0; i < channel->clients_count; i++) {
-      if (channel->clients[i] == client_entry) {
-       channel->clients[i] = NULL;
-       channel->clients_count--;
-       break;
-      }
-    }
+      goto out;
+
+    /* Remove from all channels */
+    silc_client_remove_from_channels(client, conn, client_entry);
 
     /* Remove from cache */
     silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
                           client_entry->id);
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, client_entry);
+
+    /* Free data */
+    if (client_entry->nickname)
+      silc_free(client_entry->nickname);
+    if (client_entry->server)
+      silc_free(client_entry->server);
+    if (client_entry->id)
+      silc_free(client_entry->id);
+    if (client_entry->send_key)
+      silc_cipher_free(client_entry->send_key);
+    if (client_entry->receive_key)
+      silc_cipher_free(client_entry->receive_key);
     break;
+
   case SILC_NOTIFY_TYPE_TOPIC_SET:
     /*
-     * Someone set the topic on a channel. Nothing interesting to do here.
+     * Someone set the topic on a channel.
      */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Get topic */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Notify application. The channel entry is sent last as this notify
+       is for channel but application don't know it from the arguments
+       sent by server. */
+    client->ops->notify(client, conn, type, client_entry, tmp, channel);
     break;
+
   case SILC_NOTIFY_TYPE_NICK_CHANGE:
     /*
-     * Someone changed their nickname. Cache the new Client ID.
+     * Someone changed their nickname. If we don't have entry for the new
+     * ID we will query it and return here after it's done. After we've
+     * returned we fetch the old entry and free it and notify the 
+     * application.
      */
 
-    /* XXX Protocol must be changed to send the old Client ID and the
-       new Client ID. Now we get only nickname, thus, we'll make NAMES
-       to receive the new ID. Other choice is to do IDENTIFY but I'm
-       doing NAMES for now. */
+    /* Get new Client ID */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
 
-    /* Get nickname */
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Ignore my ID */
+    if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
+      break;
+
+    /* Find Client entry and if not found query it */
+    client_entry2 = 
+      silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+    if (!client_entry2) {
+      SilcPacketContext *p = silc_packet_context_dup(packet);
+      p->context = (void *)client;
+      p->sock = sock;
+      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+                                 silc_client_notify_by_server_pending, p);
+      goto out;
+    }
+
+    /* Get old Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    
-    /* Find channel entry */
-    /* XXX this can return wrong entry */
-    client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find old Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Remove the old from cache */
+    silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
+                          client_entry->id);
+
+    /* Replace old ID entry with new one on all channels. */
+    silc_client_replace_from_channels(client, conn, client_entry,
+                                     client_entry2);
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, client_entry, client_entry2);
+
+    /* Free data */
+    if (client_entry->nickname)
+      silc_free(client_entry->nickname);
+    if (client_entry->server)
+      silc_free(client_entry->server);
+    if (client_entry->id)
+      silc_free(client_entry->id);
+    if (client_entry->send_key)
+      silc_cipher_free(client_entry->send_key);
+    if (client_entry->receive_key)
+      silc_cipher_free(client_entry->receive_key);
+    break;
+
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    /*
+     * Someone changed a channel mode
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
     if (!client_entry)
+      goto out;
+
+    /* Get the mode */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    SILC_GET32_MSB(mode, tmp);
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
       break;
-    
-    /* Get Channel ID (it's in ID payload) */
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Save the new mode */
+    channel->mode = mode;
+
+    /* Notify application. The channel entry is sent last as this notify
+       is for channel but application don't know it from the arguments
+       sent by server. */
+    client->ops->notify(client, conn, type, client_entry, mode, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    /*
+     * Someone changed user's mode on a channel
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Get the mode */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    idp = silc_id_payload_parse_data(tmp, tmp_len);
-    channel_id = silc_id_payload_get_id(idp);
-    silc_id_payload_free(idp);
-    
-    /* Find channel entry */
+    if (!tmp)
+      goto out;
+
+    SILC_GET32_MSB(mode, tmp);
+
+    /* Get target Client ID */
+    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    silc_free(client_id);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find target Client entry */
+    client_entry2 = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry2)
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
-    
+
     channel = (SilcChannelEntry)id_cache->context;
-    
-    {
-      SilcClientCommandContext ctx;
-      char names[512];
-      
-      ctx = silc_calloc(1, sizeof(*ctx));
-      ctx->client = client;
-      ctx->conn = conn;
-      ctx->command = silc_client_command_find("NAMES");
-      memset(names, 0, sizeof(names));
-      snprintf(names, sizeof(names), "NAMES %s", channel->channel_name);
-      silc_parse_command_line(names, &ctx->argv, &ctx->argv_lens, 
-                             &ctx->argv_types, &ctx->argc, 2);
-      ctx->command->cb(ctx);
+
+    /* Save the mode */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == client_entry2) {
+       channel->clients[i].mode = mode;
+       break;
+      }
     }
+
+    /* Notify application. The channel entry is sent last as this notify
+       is for channel but application don't know it from the arguments
+       sent by server. */
+    client->ops->notify(client, conn, type, client_entry, mode, 
+                       client_entry2, channel);
     break;
+
+  case SILC_NOTIFY_TYPE_MOTD:
+    /*
+     * Received Message of the day
+     */
+
+    /* Get motd */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    
+    /* Notify application */
+    client->ops->notify(client, conn, type, tmp);
+    break;
+    
   default:
     break;
   }
 
-  client->ops->notify(client, conn, payload);
+ out:
   silc_notify_payload_free(payload);
   if (client_id)
     silc_free(client_id);
@@ -1494,7 +1739,7 @@ void silc_client_notify_by_server(SilcClient client,
 
 void silc_client_receive_new_id(SilcClient client,
                                SilcSocketConnection sock,
-                               unsigned char *id_string)
+                               SilcIDPayload idp)
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
 
@@ -1504,16 +1749,24 @@ void silc_client_receive_new_id(SilcClient client,
   /* 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;
+
+  conn->local_id = silc_id_payload_get_id(idp);
+  conn->local_id_data = silc_id_payload_get_data(idp);
+  conn->local_id_data_len = silc_id_payload_get_len(idp);;
+
   if (!conn->local_entry)
     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
+
   conn->local_entry->nickname = conn->nickname;
+  if (!conn->local_entry->username) {
+    conn->local_entry->username = 
+      silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
+                 sizeof(conn->local_entry->username));
+    sprintf(conn->local_entry->username, "%s@%s", client->username,
+           client->hostname);
+  }
   conn->local_entry->id = conn->local_id;
   
   /* Put it to the ID cache */
@@ -1527,25 +1780,22 @@ 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)
+                               unsigned int mode, SilcIDPayload idp)
 {
   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->id = silc_id_payload_get_id(idp);
   channel->mode = mode;
   conn->current_channel = channel;
-  
+
   /* Put it to the ID cache */
   silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
-                  (void *)id, (void *)channel, TRUE);
+                  (void *)channel->id, (void *)channel, TRUE);
 }
 
 /* Processes received key for channel. The received key will be used
@@ -1559,7 +1809,7 @@ void silc_client_receive_channel_key(SilcClient client,
                                     SilcBuffer packet)
 {
   unsigned char *id_string, *key, *cipher;
-  unsigned int key_len;
+  unsigned int tmp_len;
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcChannelID *id;
   SilcIDCacheEntry id_cache = NULL;
@@ -1572,35 +1822,34 @@ void silc_client_receive_channel_key(SilcClient client,
   if (!payload)
     return;
 
-  id_string = silc_channel_key_get_id(payload, NULL);
+  id_string = silc_channel_key_get_id(payload, &tmp_len);
   if (!id_string) {
     silc_channel_key_payload_free(payload);
     return;
   }
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+  id = silc_id_payload_parse_id(id_string, tmp_len);
 
   /* Find channel. */
   if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
                                   SILC_ID_CHANNEL, &id_cache))
     goto out;
-  
+    
   /* Save the key */
-  key = silc_channel_key_get_key(payload, &key_len);
+  key = silc_channel_key_get_key(payload, &tmp_len);
   cipher = silc_channel_key_get_cipher(payload, NULL);
 
   channel = (SilcChannelEntry)id_cache->context;
-  channel->key_len = key_len;
-  channel->key = silc_calloc(key_len, sizeof(*channel->key));
-  memcpy(channel->key, key, key_len);
+  channel->key_len = tmp_len;
+  channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
+  memcpy(channel->key, key, tmp_len);
 
-  silc_cipher_alloc(cipher, &channel->channel_key);
-  if (!channel->channel_key) {
+  if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
     client->ops->say(client, conn,
                     "Cannot talk to channel: unsupported cipher %s", cipher);
     goto out;
   }
   channel->channel_key->cipher->set_key(channel->channel_key->context, 
-                                       key, key_len);
+                                       key, tmp_len);
 
   /* Client is now joined to the channel */
   channel->on_channel = TRUE;
@@ -1658,9 +1907,9 @@ void silc_client_channel_message(SilcClient client,
   /* Find nickname */
   nickname = "[unknown]";
   for (i = 0; i < channel->clients_count; i++) {
-    if (channel->clients[i] && 
-       !SILC_ID_CLIENT_COMPARE(channel->clients[i]->id, client_id))
-      nickname = channel->clients[i]->nickname;
+    if (channel->clients[i].client && 
+       !SILC_ID_CLIENT_COMPARE(channel->clients[i].client->id, client_id))
+      nickname = channel->clients[i].client->nickname;
   }
 
   /* Pass the message to application */
@@ -1726,7 +1975,8 @@ void silc_client_private_message(SilcClient client,
        /* Allocate client entry */
        remote_client = silc_calloc(1, sizeof(*remote_client));
        remote_client->id = remote_id;
-       remote_client->nickname = strdup(nickname);
+       silc_parse_nickname(nickname, &remote_client->nickname, 
+                           &remote_client->server, &remote_client->num);
 
        /* Save the client to cache */
        silc_idcache_add(conn->client_cache, remote_client->nickname,
@@ -1748,3 +1998,84 @@ void silc_client_private_message(SilcClient client,
   silc_free(message);
   silc_free(nickname);
 }
+
+/* Removes a client entry from all channel it has joined. This really is
+   a performance killer (client_entry should have pointers to channel 
+   entry list). */
+
+void silc_client_remove_from_channels(SilcClient client,
+                                     SilcClientConnection conn,
+                                     SilcClientEntry client_entry)
+{
+  SilcIDCacheEntry id_cache;
+  SilcIDCacheList list;
+  SilcChannelEntry channel;
+  int i;
+
+  if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+                              SILC_ID_CHANNEL, &list))
+    return;
+
+  silc_idcache_list_first(list, &id_cache);
+  channel = (SilcChannelEntry)id_cache->context;
+  
+  while (channel) {
+    
+    /* Remove client from channel */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == client_entry) {
+       channel->clients[i].client = NULL;
+       channel->clients_count--;
+       break;
+      }
+    }
+
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+    
+    channel = (SilcChannelEntry)id_cache->context;
+  }
+
+  silc_idcache_list_free(list);
+}
+
+/* Replaces `old' client entries from all channels to `new' client entry.
+   This can be called for example when nickname changes and old ID entry
+   is replaced from ID cache with the new one. If the old ID entry is only
+   updated, then this fucntion needs not to be called. */
+
+void silc_client_replace_from_channels(SilcClient client, 
+                                      SilcClientConnection conn,
+                                      SilcClientEntry old,
+                                      SilcClientEntry new)
+{
+  SilcIDCacheEntry id_cache;
+  SilcIDCacheList list;
+  SilcChannelEntry channel;
+  int i;
+
+  if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+                              SILC_ID_CHANNEL, &list))
+    return;
+
+  silc_idcache_list_first(list, &id_cache);
+  channel = (SilcChannelEntry)id_cache->context;
+  
+  while (channel) {
+    
+    /* Remove client from channel */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == old) {
+       channel->clients[i].client = new;
+       break;
+      }
+    }
+
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+    
+    channel = (SilcChannelEntry)id_cache->context;
+  }
+
+  silc_idcache_list_free(list);
+}
index 06d09ad776270e887b8674f5752fbd4292df7676..84cfa3244dea8770a53de4cd7fa66bdaf2bc6946 100644 (file)
@@ -118,7 +118,7 @@ struct SilcClientConnectionObject {
   SilcClientAway *away;
 
   /* Pointer back to the SilcClient. This object is passed to the application
-     and the actual client object is accesible thourh this pointer. */
+     and the actual client object is accesible through this pointer. */
   SilcClient client;
 
   /* User data context. Library does not touch this. */
@@ -132,8 +132,9 @@ struct SilcClientObject {
    * of this structure.
    */
 
-  /* Users's username and realname. */
+  /* Users's username, hostname and realname. */
   char *username;
+  char *hostname;
   char *realname;
 
   /* Private and public key of the user. */
@@ -263,15 +264,14 @@ void silc_client_error_by_server(SilcClient client,
                                 SilcBuffer message);
 void silc_client_notify_by_server(SilcClient client,
                                  SilcSocketConnection sock,
-                                 SilcBuffer message);
+                                 SilcPacketContext *packet);
 void silc_client_receive_new_id(SilcClient client,
                                SilcSocketConnection sock,
-                               unsigned char *id_string);
+                               SilcIDPayload idp);
 void silc_client_new_channel_id(SilcClient client,
                                SilcSocketConnection sock,
                                char *channel_name,
-                               unsigned int mode,
-                               unsigned char *id_string);
+                               unsigned int mode, SilcIDPayload idp);
 void silc_client_receive_channel_key(SilcClient client,
                                     SilcSocketConnection sock,
                                     SilcBuffer packet);
@@ -281,4 +281,11 @@ void silc_client_channel_message(SilcClient client,
 void silc_client_private_message(SilcClient client, 
                                 SilcSocketConnection sock, 
                                 SilcPacketContext *packet);
+void silc_client_remove_from_channels(SilcClient client,
+                                     SilcClientConnection conn,
+                                     SilcClientEntry client_entry);
+void silc_client_replace_from_channels(SilcClient client, 
+                                      SilcClientConnection conn,
+                                      SilcClientEntry old,
+                                      SilcClientEntry new);
 #endif
index 30c4cba3902a6729c5d442c9d1e6b0a509e3a1b3..1d21505886126dcc6b51d273d21620ac6d928812 100644 (file)
@@ -41,10 +41,11 @@ SilcClientCommand silc_command_list[] =
   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(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 4),
   SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
+  SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
   SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(restart, RESTART, "RESTART",
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
@@ -76,6 +77,24 @@ SilcClientCommand silc_command_list[] =
 /* List of pending commands. */
 SilcClientCommandPending *silc_command_pending = NULL;
 
+/* Generic function to send any command. The arguments must be sent already
+   encoded into correct form in correct order. */
+
+void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+                             SilcCommand command, unsigned int argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+  silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
+                         NULL, 0, NULL, NULL, packet->data, 
+                         packet->len, TRUE);
+  silc_buffer_free(packet);
+}
+
 /* Finds and returns a pointer to the command list. Return NULL if the
    command is not found. */
 
@@ -264,6 +283,9 @@ SILC_CLIENT_CMD_FUNC(nick)
     goto out;
   }
 
+  if (!strncmp(conn->nickname, cmd->argv[1], cmd->argv_lens[1]))
+    goto out;
+
   /* Show current nickname */
   if (cmd->argc < 2) {
     if (cmd->conn) {
@@ -274,6 +296,7 @@ SILC_CLIENT_CMD_FUNC(nick)
       cmd->client->ops->say(cmd->client, conn, 
                            "Your nickname is %s", conn->nickname);
     }
+
     /* XXX Notify application */
     COMMAND;
     goto out;
@@ -314,8 +337,7 @@ SILC_CLIENT_CMD_FUNC(topic)
   SilcClientConnection conn = cmd->conn;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
-  SilcBuffer buffer;
-  unsigned char *id_string;
+  SilcBuffer buffer, idp;
   char *name;
 
   if (!cmd->conn) {
@@ -358,19 +380,20 @@ SILC_CLIENT_CMD_FUNC(topic)
   channel = (SilcChannelEntry)id_cache->context;
 
   /* Send TOPIC command to the server */
-  id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   if (cmd->argc > 2)
     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2, 
-                                           1, id_string, SILC_ID_CHANNEL_LEN,
+                                           1, idp->data, idp->len,
                                            2, cmd->argv[2], 
                                            strlen(cmd->argv[2]));
   else
     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1, 
-                                           1, id_string, SILC_ID_CHANNEL_LEN,
+                                           1, idp->data, idp->len,
                                            0);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
+  silc_buffer_free(idp);
 
   /* Notify application */
   COMMAND;
@@ -388,10 +411,9 @@ SILC_CLIENT_CMD_FUNC(invite)
   SilcClientConnection conn = cmd->conn;
   SilcClientEntry client_entry;
   SilcChannelEntry channel_entry;
-  SilcBuffer buffer;
+  SilcBuffer buffer, clidp, chidp;
   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);
@@ -416,32 +438,37 @@ SILC_CLIENT_CMD_FUNC(invite)
   /* Find client entry */
   client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
   if (!client_entry) {
+    if (nickname)
+      silc_free(nickname);
+    if (server)
+      silc_free(server);
+
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
     silc_client_command_pending(SILC_COMMAND_IDENTIFY, 
                                silc_client_command_invite, context);
     return;
   }
-  
-  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);
-
+  /* Send command */
+  clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+  chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
   buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
-                                         1, client_id, SILC_ID_CLIENT_LEN,
-                                         2, channel_id, SILC_ID_CHANNEL_LEN);
+                                         1, clidp->data, clidp->len,
+                                         2, chidp->data, chidp->len);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
+  silc_buffer_free(clidp);
+  silc_buffer_free(chidp);
 
   cmd->client->ops->say(cmd->client, conn, 
                        "Inviting %s to channel %s", cmd->argv[1], 
@@ -553,8 +580,6 @@ SILC_CLIENT_CMD_FUNC(ping)
   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_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
                                          1, conn->remote_id_data, 
@@ -563,6 +588,8 @@ SILC_CLIENT_CMD_FUNC(ping)
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
+  id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
+
   /* Start counting time */
   for (i = 0; i < conn->ping_count; i++) {
     if (conn->ping[i].dest_id == NULL) {
@@ -636,15 +663,26 @@ SILC_CLIENT_CMD_FUNC(join)
   }
 
   /* Send JOIN command to the server */
-  buffer = silc_command_payload_encode(SILC_COMMAND_JOIN,
-                                      cmd->argc - 1, ++cmd->argv,
-                                      ++cmd->argv_lens, ++cmd->argv_types, 0);
+  if (cmd->argc == 2)
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 1,
+                                    1, cmd->argv[1], cmd->argv_lens[1]);
+  else if (cmd->argc == 3)
+    /* XXX Buggy */
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
+                                    1, cmd->argv[1], cmd->argv_lens[1],
+                                    2, cmd->argv[2], cmd->argv_lens[2]);
+  else
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
+                                    1, cmd->argv[1], cmd->argv_lens[1],
+                                    2, cmd->argv[2], cmd->argv_lens[2],
+                                    3, cmd->argv[3], cmd->argv_lens[3]);
+
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
-  cmd->argv--;
-  cmd->argv_lens--;
-  cmd->argv_types--;
 
   /* Notify application */
   COMMAND;
@@ -653,6 +691,8 @@ SILC_CLIENT_CMD_FUNC(join)
   silc_client_command_free(cmd);
 }
 
+/* MOTD command. Requests motd from server. */
+
 SILC_CLIENT_CMD_FUNC(motd)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -687,16 +727,340 @@ SILC_CLIENT_CMD_FUNC(motd)
   silc_client_command_free(cmd);
 }
 
+/* UMODE. Set user mode in SILC. */
+
 SILC_CLIENT_CMD_FUNC(umode)
 {
+
 }
 
+/* CMODE command. Sets channel mode. Modes that does not require any arguments
+   can be set several at once. Those modes that require argument must be set
+   separately (unless set with modes that does not require arguments). */
+
 SILC_CLIENT_CMD_FUNC(cmode)
 {
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, chidp;
+  unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
+  unsigned int mode, add, type, len, arg_len = 0;
+  int i;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 3) {
+    cmd->client->ops->say(cmd->client, conn, 
+                 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    channel = conn->current_channel;
+  } else {
+    name = cmd->argv[1];
+
+    channel = silc_idlist_get_channel(cmd->client, conn, name);
+    if (!channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+  }
+
+  mode = channel->mode;
+
+  /* Are we adding or removing mode */
+  if (cmd->argv[2][0] == '-')
+    add = FALSE;
+  else
+    add = TRUE;
+
+  /* Argument type to be sent to server */
+  type = 0;
+
+  /* Parse mode */
+  cp = cmd->argv[2] + 1;
+  len = strlen(cp);
+  for (i = 0; i < len; i++) {
+    switch(cp[i]) {
+    case 'p':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_PRIVATE;
+      else
+       mode &= ~SILC_CHANNEL_MODE_PRIVATE;
+      break;
+    case 's':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_SECRET;
+      else
+       mode &= ~SILC_CHANNEL_MODE_SECRET;
+      break;
+    case 'k':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_PRIVKEY;
+      else
+       mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
+      break;
+    case 'i':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_INVITE;
+      else
+       mode &= ~SILC_CHANNEL_MODE_INVITE;
+      break;
+    case 't':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_TOPIC;
+      else
+       mode &= ~SILC_CHANNEL_MODE_TOPIC;
+      break;
+    case 'l':
+      if (add) {
+       int ll;
+       mode |= SILC_CHANNEL_MODE_ULIMIT;
+       type = 3;
+       ll = atoi(cmd->argv[3]);
+       SILC_PUT32_MSB(ll, tmp);
+       arg = tmp;
+       arg_len = 4;
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_ULIMIT;
+      }
+      break;
+    case 'a':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_PASSPHRASE;
+       type = 4;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
+      }
+      break;
+    case 'b':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_BAN;
+       type = 5;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_BAN;
+      }
+      break;
+    case 'I':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_INVITE_LIST;
+       type = 6;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
+      }
+      break;
+    case 'c':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_CIPHER;
+       type = 8;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_CIPHER;
+      }
+      break;
+    default:
+      COMMAND_ERROR;
+      goto out;
+      break;
+    }
+  }
+
+  if (type && cmd->argc < 3) {
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  SILC_PUT32_MSB(mode, modebuf);
+
+  /* Send the command packet. We support sending only one mode at once
+     that requires an argument. */
+  if (type && arg) {
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, 
+                                    1, chidp->data, chidp->len, 
+                                    2, modebuf, sizeof(modebuf),
+                                    type, arg, arg_len);
+  } else {
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, 
+                                    1, chidp->data, chidp->len, 
+                                    2, modebuf, sizeof(modebuf));
+  }
+
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(chidp);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* CUMODE command. Changes client's mode on a channel. */
+
+SILC_CLIENT_CMD_FUNC(cumode)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcChannelEntry channel;
+  SilcClientEntry client_entry;
+  SilcBuffer buffer, clidp, chidp;
+  unsigned char *name, *cp, modebuf[4];
+  unsigned int mode = 0, add, len;
+  char *nickname = NULL, *server = NULL;
+  unsigned int num = 0;
+  int i;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 4) {
+    cmd->client->ops->say(cmd->client, conn, 
+                 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    channel = conn->current_channel;
+  } else {
+    name = cmd->argv[1];
+
+    channel = silc_idlist_get_channel(cmd->client, conn, name);
+    if (!channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+  }
+
+  /* Parse the typed nickname. */
+  if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
+    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Find client entry */
+  client_entry = silc_idlist_get_client(cmd->client, conn, 
+                                       nickname, server, num);
+  if (!client_entry) {
+    /* Client entry not found, it was requested thus mark this to be
+       pending command. */
+    silc_client_command_pending(SILC_COMMAND_CUMODE, 
+                               silc_client_command_cumode, context);
+    return;
+  }
+  
+  for (i = 0; i < channel->clients_count; i++)
+    if (channel->clients[i].client == client_entry) {
+      mode = channel->clients[i].mode;
+      break;
+    }
+
+  /* Are we adding or removing mode */
+  if (cmd->argv[2][0] == '-')
+    add = FALSE;
+  else
+    add = TRUE;
+
+  /* Parse mode */
+  cp = cmd->argv[2] + 1;
+  len = strlen(cp);
+  for (i = 0; i < len; i++) {
+    switch(cp[i]) {
+    case 'a':
+      if (add) {
+       mode |= SILC_CHANNEL_UMODE_CHANFO;
+       mode |= SILC_CHANNEL_UMODE_CHANOP;
+      } else {
+       mode = SILC_CHANNEL_UMODE_NONE;
+      }
+      break;
+    case 'f':
+      if (add)
+       mode |= SILC_CHANNEL_UMODE_CHANFO;
+      else
+       mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+      break;
+    case 'o':
+      if (add)
+       mode |= SILC_CHANNEL_UMODE_CHANOP;
+      else
+       mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+      break;
+    default:
+      COMMAND_ERROR;
+      goto out;
+      break;
+    }
+  }
+
+  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  SILC_PUT32_MSB(mode, modebuf);
+  clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+
+  /* Send the command packet. We support sending only one mode at once
+     that requires an argument. */
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3, 
+                                         1, chidp->data, chidp->len, 
+                                         2, modebuf, 4,
+                                         3, clidp->data, clidp->len);
+
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(chidp);
+  silc_buffer_free(clidp);
+  
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
 }
 
+/* KICK command. Kicks a client out of channel. */
+
 SILC_CLIENT_CMD_FUNC(kick)
 {
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+
 }
 
 SILC_CLIENT_CMD_FUNC(restart)
@@ -723,8 +1087,7 @@ SILC_CLIENT_CMD_FUNC(leave)
   SilcClientConnection conn = cmd->conn;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
-  SilcBuffer buffer;
-  unsigned char *id_string;
+  SilcBuffer buffer, idp;
   char *name;
 
   if (!cmd->conn) {
@@ -766,12 +1129,13 @@ SILC_CLIENT_CMD_FUNC(leave)
   channel = (SilcChannelEntry)id_cache->context;
 
   /* Send LEAVE command to the server */
-  id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
-                                         1, id_string, SILC_ID_CHANNEL_LEN);
+                                         1, idp->data, idp->len);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
+  silc_buffer_free(idp);
 
   /* We won't talk anymore on this channel */
   cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
@@ -784,7 +1148,6 @@ SILC_CLIENT_CMD_FUNC(leave)
   silc_free(channel->key);
   silc_cipher_free(channel->channel_key);
   silc_free(channel);
-  silc_free(id_string);
 
   /* Notify application */
   COMMAND;
@@ -801,9 +1164,8 @@ SILC_CLIENT_CMD_FUNC(names)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcIDCacheEntry id_cache = NULL;
-  SilcBuffer buffer;
+  SilcBuffer buffer, idp;
   char *name;
-  unsigned char *id_string;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -832,19 +1194,19 @@ SILC_CLIENT_CMD_FUNC(names)
   }
 
   /* Send NAMES command to the server */
-  id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1, 
-                                         1, id_string, SILC_ID_CHANNEL_LEN);
+                                         1, idp->data, idp->len);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
-  silc_free(id_string);
+  silc_buffer_free(idp);
 
   /* Register dummy pending command that will tell the reply command
      that user called this command. Server may send reply to this command
      even if user did not send this command thus we want to handle things
      differently when user sent the command. This is dummy and won't be
-     execute. */
+     executed. */
   /* XXX this is kludge and should be removed after pending command reply 
      support is added. Currently only commands may be pending not command
      replies. */
index edb714505f12fec5e244134fa14487939455a3c7..11163ac4b2ba52220dcbf9ca31f89c4fa3803229 100644 (file)
@@ -128,6 +128,8 @@ do {                                                        \
 
 /* Prototypes */
 void silc_client_command_free(SilcClientCommandContext cmd);
+void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+                             SilcCommand command, unsigned int argc, ...);
 SilcClientCommand *silc_client_command_find(const char *name);
 void silc_client_command_pending(SilcCommand reply_cmd,
                                 SilcClientCommandCallback callback,
@@ -150,6 +152,7 @@ SILC_CLIENT_CMD_FUNC(join);
 SILC_CLIENT_CMD_FUNC(motd);
 SILC_CLIENT_CMD_FUNC(umode);
 SILC_CLIENT_CMD_FUNC(cmode);
+SILC_CLIENT_CMD_FUNC(cumode);
 SILC_CLIENT_CMD_FUNC(kick);
 SILC_CLIENT_CMD_FUNC(restart);
 SILC_CLIENT_CMD_FUNC(close);
index 666114022716e4d8771dba227abbc80e245b3e15..5ed0a3b1fe9935d3003ecd6ece3c66927e179ce0 100644 (file)
 /*
  * Command reply functions are "the otherside" of the command functions.
  * Reply to a command sent by server is handled by these functions.
+ *
+ * The arguments received from server are also passed to the calling
+ * application through command_reply client operation.  The arguments are
+ * exactly same and in same order as the server sent it.  However, ID's are
+ * not sent to the application.  Instead, corresponding ID entry is sent
+ * to the application.  For example, instead of sending Client ID the 
+ * corresponding SilcClientEntry is sent to the application.  The case is
+ * same with for example Channel ID's.  This way application has all the
+ * necessary data already in hand without redundant searching.  If ID is
+ * received but ID entry does not exist, NULL is sent.
  */
 /* $Id$ */
 
@@ -45,6 +55,7 @@ SilcClientCommandReply silc_command_reply_list[] =
   SILC_CLIENT_CMD_REPLY(motd, MOTD),
   SILC_CLIENT_CMD_REPLY(umode, UMODE),
   SILC_CLIENT_CMD_REPLY(cmode, CMODE),
+  SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
   SILC_CLIENT_CMD_REPLY(kick, KICK),
   SILC_CLIENT_CMD_REPLY(restart, RESTART),
   SILC_CLIENT_CMD_REPLY(close, CLOSE),
@@ -82,7 +93,8 @@ const SilcCommandStatusMessage silc_command_status_messages[] = {
   { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
   { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
   { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
-  { STAT(USER_ON_CHANNEL),   "User already on channel" },
+  { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
+  { STAT(USER_ON_CHANNEL),   "User already on the channel" },
   { STAT(NOT_REGISTERED),    "You have not registered" },
   { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
   { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
@@ -108,12 +120,12 @@ const SilcCommandStatusMessage silc_command_status_messages[] = {
    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, status, silc_command_get(cmd->payload)
+             cmd->payload, TRUE, silc_command_get(cmd->payload), status
 
 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
-  cmd->sock->user_data, cmd->payload, FALSE, status, \
-  silc_command_get(cmd->payload))
+  cmd->sock->user_data, cmd->payload, FALSE, \
+  silc_command_get(cmd->payload), status)
 
 /* Process received command reply. */
 
@@ -186,12 +198,22 @@ silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
   unsigned char *id_data;
   char *nickname = NULL, *username = NULL;
   char *realname = NULL;
+  SilcClientID *client_id;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client_entry = NULL;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   
   memset(buf, 0, sizeof(buf));
   
   argc = silc_argument_get_arg_num(cmd->args);
-  id_data = silc_argument_get_arg_type(cmd->args, 2, NULL);
+
+  id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!id_data) {
+    COMMAND_REPLY_ERROR;
+    return;
+  }
+  
+  client_id = silc_id_payload_parse_id(id_data, len);
   
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
   if (nickname) {
@@ -211,15 +233,33 @@ silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
     strncat(buf, ")", 1);
   }
   
-  cmd->client->ops->say(cmd->client, conn, "%s", buf);
-  
+  /* Check if we have this client cached already. */
+  if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+                                  SILC_ID_CLIENT, &id_cache)) {
+    client_entry = silc_calloc(1, sizeof(*client_entry));
+    client_entry->id = client_id;
+    silc_parse_nickname(nickname, &client_entry->nickname, 
+                       &client_entry->server, &client_entry->num);
+    client_entry->username = strdup(username);
+    
+    /* Add client to cache */
+    silc_idcache_add(conn->client_cache, client_entry->nickname,
+                    SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
+  } else {
+    client_entry = (SilcClientEntry)id_cache->context;
+    silc_free(client_id);
+  }
+
+  if (!cmd->callback)
+    cmd->client->ops->say(cmd->client, conn, "%s", buf);
+
   /* Notify application */
-  COMMAND_REPLY((ARGS));
+  COMMAND_REPLY((ARGS, client_entry, nickname, 
+                username, realname, NULL, NULL));
 }
 
 /* Received reply for WHOIS command. This maybe called several times
    for one WHOIS command as server may reply with list of results. */
-/* Sends to application: (no arguments) */
 
 SILC_CLIENT_CMD_REPLY_FUNC(whois)
 {
@@ -279,8 +319,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois)
   silc_client_command_reply_free(cmd);
 }
 
+/* Received reply for WHOWAS command. */
+
 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
 {
+
 }
 
 /* Received reply for IDENTIFY command. This maybe called several times
@@ -321,16 +364,23 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify)
 
   /* Display one whois reply */
   if (status == SILC_STATUS_OK) {
+    unsigned int len;
     unsigned char *id_data;
     char *nickname;
+    char *username;
 
-    id_data = silc_argument_get_arg_type(cmd->args, 2, NULL);
+    id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
     nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
+    username = silc_argument_get_arg_type(cmd->args, 4, NULL);
 
     /* Allocate client entry */
     client_entry = silc_calloc(1, sizeof(*client_entry));
-    client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
-    client_entry->nickname = strdup(nickname);
+    client_entry->id = silc_id_payload_parse_id(id_data, len);
+    if (nickname)
+      silc_parse_nickname(nickname, &client_entry->nickname, 
+                         &client_entry->server, &client_entry->num);
+    if (username)
+      client_entry->username = strdup(username);
 
     /* Save received Client ID to ID cache */
     silc_idcache_add(conn->client_cache, client_entry->nickname,
@@ -353,20 +403,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify)
 
 /* 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;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
-  unsigned char *tmp, *id_string;
-  int argc;
+  SilcIDPayload idp;
+  unsigned char *tmp;
+  unsigned int argc, len;
 
   SILC_LOG_DEBUG(("Start"));
 
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
   if (status != SILC_STATUS_OK) {
     cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s", 
             silc_client_command_status_message(status));
@@ -383,11 +432,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   }
 
   /* Take received Client ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
-
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  idp = silc_id_payload_parse_data(tmp, len);
+  silc_client_receive_new_id(cmd->client, cmd->sock, idp);
+    
   /* Notify application */
-  COMMAND_REPLY((ARGS, conn->nickname));
+  COMMAND_REPLY((ARGS, conn->local_entry));
 
  out:
   silc_client_command_reply_free(cmd);
@@ -398,7 +448,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(list)
 }
 
 /* Received reply to topic command. */
-/* Sends to application: SilcChannelID * (channel_id) and char * (topic) */
 
 SILC_CLIENT_CMD_REPLY_FUNC(topic)
 {
@@ -408,17 +457,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
   SilcChannelEntry channel;
   SilcChannelID *channel_id = NULL;
   SilcIDCacheEntry id_cache = NULL;
-  unsigned char *tmp, *id_string;
+  unsigned char *tmp;
   char *topic;
-  int argc;
+  unsigned int argc, len;
 
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
   if (status != SILC_STATUS_OK) {
     cmd->client->ops->say(cmd->client, conn,
             "%s", silc_client_command_status_message(status));
-    silc_client_command_reply_free(cmd);
     COMMAND_REPLY_ERROR;
+    silc_client_command_reply_free(cmd);
     return;
   }
 
@@ -429,20 +477,21 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
   }
 
   /* Take Channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  if (!id_string)
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp)
     goto out;
 
-  channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-
   /* Take topic */
   topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
   if (!topic)
     goto out;
 
+  channel_id = silc_id_payload_parse_id(tmp, len);
+
   /* Get the channel name */
   if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                   SILC_ID_CHANNEL, &id_cache)) {
+    silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
@@ -454,16 +503,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
                        topic);
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, channel_id, topic));
+  COMMAND_REPLY((ARGS, channel, topic));
 
  out:
-  if (channel_id)
-    silc_free(channel_id);
   silc_client_command_reply_free(cmd);
 }
 
 /* Received reply to invite command. */
-/* Sends to application: (no arguments) */
 
 SILC_CLIENT_CMD_REPLY_FUNC(invite)
 {
@@ -477,8 +523,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
   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;
+    silc_client_command_reply_free(cmd);
     return;
   }
 
@@ -498,7 +544,6 @@ 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)
 {
@@ -513,8 +558,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(info)
   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;
+    silc_client_command_reply_free(cmd);
     return;
   }
 
@@ -533,7 +578,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info)
   client->ops->say(cmd->client, conn, "Info: %s", tmp);
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, (char *)tmp));
+  COMMAND_REPLY((ARGS, NULL, (char *)tmp));
 
  out:
   silc_client_command_reply_free(cmd);
@@ -544,7 +589,6 @@ 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)
 {
@@ -552,12 +596,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping)
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
   void *id;
-  char *tmp;
   int i;
   time_t diff, curtime;
 
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
   if (status != SILC_STATUS_OK) {
     cmd->client->ops->say(cmd->client, conn,
             "%s", silc_client_command_status_message(status));
@@ -584,10 +626,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping)
 
       /* Notify application */
       COMMAND_REPLY((ARGS));
-      goto out;
+      break;
     }
   }
 
+  silc_free(id);
+
  out:
   silc_client_command_reply_free(cmd);
 }
@@ -604,14 +648,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcClient client = cmd->client;
   SilcCommandStatus status;
-  unsigned int argc, mode;
-  unsigned char *id_string;
+  SilcIDPayload idp;
+  unsigned int argc, mode, len;
   char *topic, *tmp, *channel_name;
 
   SILC_LOG_DEBUG(("Start"));
 
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
   if (status != SILC_STATUS_OK) {
     cmd->client->ops->say(cmd->client, conn,
             "%s", silc_client_command_status_message(status));
@@ -638,13 +681,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   channel_name = strdup(tmp);
 
   /* Get Channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 3, NULL);
-  if (!id_string) {
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (!tmp) {
     cmd->client->ops->say(cmd->client, conn, 
                          "Cannot join channel: Bad reply packet");
     COMMAND_REPLY_ERROR;
     goto out;
   }
+  idp = silc_id_payload_parse_data(tmp, len);
 
   /* Get channel mode */
   tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
@@ -658,21 +702,22 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
 
   /* Save received Channel ID */
   silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, 
-                            mode, id_string);
+                            mode, idp);
+  silc_id_payload_free(idp);
 
   if (topic)
     client->ops->say(cmd->client, conn, 
                     "Topic for %s: %s", channel_name, topic);
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, channel_name, topic));
+  COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
+                NULL, NULL, topic));
 
  out:
   silc_client_command_reply_free(cmd);
 }
 
 /* Received reply for MOTD command */
-/* Sends to application: char * (motd) */
 
 SILC_CLIENT_CMD_REPLY_FUNC(motd)
 {
@@ -736,8 +781,85 @@ SILC_CLIENT_CMD_REPLY_FUNC(umode)
 {
 }
 
+/* Received reply for CMODE command. */
+
 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get channel mode */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, tmp));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+/* Received reply for CUMODE command */
+
+SILC_CLIENT_CMD_REPLY_FUNC(cumode)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientID *client_id;
+  unsigned char *tmp, *id;
+  unsigned int len;
+  
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  
+  /* Get channel mode */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get Client ID */
+  id = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (!id) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  client_id = silc_id_payload_parse_id(id, len);
+  
+  /* Get client entry */
+  if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+                                  SILC_ID_CLIENT, &id_cache)) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
+  silc_free(client_id);
+  
+ out:
+  silc_client_command_reply_free(cmd);
 }
 
 SILC_CLIENT_CMD_REPLY_FUNC(kick)
@@ -761,7 +883,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
 }
 
 /* Reply to LEAVE command. */
-/* Sends to application: (no arguments) */
 
 SILC_CLIENT_CMD_REPLY_FUNC(leave)
 {
@@ -797,6 +918,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   SilcChannelEntry channel;
   SilcChannelID *channel_id = NULL;
   SilcBuffer client_id_list;
+  SilcBuffer client_mode_list;
   unsigned char *tmp;
   char *name_list, *cp;
   int i, k, len1, len2, list_count = 0;
@@ -813,14 +935,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   }
 
   /* Get channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len1);
   if (!tmp) {
     cmd->client->ops->say(cmd->client, conn, 
-                         "Cannot get user list: Bad reply packet");
+                         "Cannot Channel ID: Bad reply packet");
     COMMAND_REPLY_ERROR;
     goto out;
   }
-  channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+  channel_id = silc_id_payload_parse_id(tmp, len1);
 
   /* Get the name list of the channel */
   name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
@@ -844,6 +966,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   silc_buffer_pull_tail(client_id_list, len2);
   silc_buffer_put(client_id_list, tmp, len2);
 
+  /* Get client mode list */
+  tmp = silc_argument_get_arg_type(cmd->args, 5, &len2);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  client_mode_list = silc_buffer_alloc(len2);
+  silc_buffer_pull_tail(client_mode_list, len2);
+  silc_buffer_put(client_mode_list, tmp, len2);
+
   /* Get the channel name */
   if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                   SILC_ID_CHANNEL, &id_cache)) {
@@ -888,29 +1023,38 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   /* Allocate room for clients in the channel */
   channel->clients = silc_calloc(list_count, sizeof(*channel->clients));
 
-  /* Cache the received name list and client ID's. This cache expires
+  /* Cache the received name list, client ID's and modes. This cache expires
      whenever server sends notify message to channel. It means two things;
      some user has joined or leaved the channel. */
   cp = name_list;
   for (i = 0; i < list_count; i++) {
     int nick_len = strcspn(name_list, " ");
-    char *nickname = silc_calloc(nick_len, sizeof(*nickname));
+    unsigned short idp_len;
+    unsigned int mode;
+    char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
     SilcClientID *client_id;
     SilcClientEntry client;
 
     memcpy(nickname, name_list, nick_len);
-    client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT);
-    silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
+    SILC_GET16_MSB(idp_len, client_id_list->data + 2);
+    idp_len += 4;
+    client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
+    silc_buffer_pull(client_id_list, idp_len);
+    
+    SILC_GET32_MSB(mode, client_mode_list->data);
+    silc_buffer_pull(client_mode_list, 4);
 
     /* Check if we have this client cached already. */
     if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
                                     SILC_ID_CLIENT, &id_cache)) {
       client = silc_calloc(1, sizeof(*client));
       client->id = client_id;
-      client->nickname = nickname;
+      silc_parse_nickname(nickname, &client->nickname, &client->server, 
+                         &client->num);
+      silc_free(nickname);
 
       /* Add client to cache */
-      silc_idcache_add(conn->client_cache, nickname, SILC_ID_CLIENT,
+      silc_idcache_add(conn->client_cache, client->nickname, SILC_ID_CLIENT,
                       client_id, (void *)client, TRUE);
     } else {
       client = (SilcClientEntry)id_cache->context;
@@ -919,7 +1063,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
       id_cache = NULL;
     }
 
-    channel->clients[channel->clients_count] = client;
+    channel->clients[channel->clients_count].client = client;
+    channel->clients[channel->clients_count].mode = mode;
     channel->clients_count++;
 
     name_list += nick_len + 1;
@@ -929,13 +1074,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   for (i = 0; i < list_count; i++) {
     int c;
     int nick_len = strcspn(name_list, " ");
-    char *nickname = silc_calloc(nick_len, sizeof(*nickname));
+    char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
     memcpy(nickname, name_list, nick_len);
 
     for (c = 0, k = 0; k < channel->clients_count; k++) {
-      if (channel->clients[k] && 
-         !strncmp(channel->clients[k]->nickname, 
-                  nickname, strlen(channel->clients[k]->nickname))) {
+      if (channel->clients[k].client && 
+         !strncmp(channel->clients[k].client->nickname, 
+                  nickname, strlen(channel->clients[k].client->nickname))) {
        char t[8];
        
        if (!c) {
@@ -944,12 +1089,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
        }
        
        memset(t, 0, sizeof(t));
-       channel->clients[k]->nickname = 
-         silc_calloc(strlen(nickname) + 8, 
-                     sizeof(*channel->clients[k]->nickname));
-       strncat(channel->clients[k]->nickname, nickname, strlen(nickname));
+       channel->clients[k].client->nickname = 
+         silc_calloc(strlen(nickname) + 8, sizeof(*channel->clients[k].
+                                                  client->nickname));
+       strncat(channel->clients[k].client->nickname, nickname, 
+               strlen(nickname));
        snprintf(t, sizeof(t), " [%d]", c++);
-       strncat(channel->clients[k]->nickname, t, strlen(t));
+       strncat(channel->clients[k].client->nickname, t, strlen(t));
       }
     }
 
@@ -959,7 +1105,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   name_list = NULL;
   len1 = 0;
   for (k = 0; k < channel->clients_count; k++) {
-    char *n = channel->clients[k]->nickname;
+    char *n = channel->clients[k].client->nickname;
     len2 = strlen(n);
     len1 += len2;
     name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 1));
@@ -975,8 +1121,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   cmd->client->ops->say(cmd->client, conn,
                        "Users on %s: %s", channel->channel_name, name_list);
 
+  /* Notify application */
+  COMMAND_REPLY((ARGS, channel, name_list, client_id_list->head,
+                client_mode_list->head));
+
   silc_free(name_list);
   silc_buffer_free(client_id_list);
+  silc_buffer_free(client_mode_list);
 
  out:
   if (channel_id)
index 1268867082ec8980b1d32049a234625870934ac0..76bddc1a0a8afa8c4fa0693189d8448d43e6baa1 100644 (file)
@@ -95,6 +95,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join);
 SILC_CLIENT_CMD_REPLY_FUNC(motd);
 SILC_CLIENT_CMD_REPLY_FUNC(umode);
 SILC_CLIENT_CMD_REPLY_FUNC(cmode);
+SILC_CLIENT_CMD_REPLY_FUNC(cumode);
 SILC_CLIENT_CMD_REPLY_FUNC(kick);
 SILC_CLIENT_CMD_REPLY_FUNC(restart);
 SILC_CLIENT_CMD_REPLY_FUNC(close);
index 7f632e965ed30ab389f56df3622bebdd5ce66cc3..edd2df0449943a1ece111c5077317c2c1953a8f4 100644 (file)
@@ -72,21 +72,23 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
     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;
-
+    silc_idcache_list_first(list, &id_cache);
+    entry = (SilcClientEntry)id_cache->context;
+    
+    while (entry) {
       if (server && entry->server && 
-         strncasecmp(server, entry->server, strlen(server))) {
-       entry = NULL;
-       continue;
-      }
+         !strncasecmp(server, entry->server, strlen(server)))
+       break;
       
-      if (num && entry->num != num) {
+      if (num && entry->num == num)
+       break;
+
+      if (!silc_idcache_list_next(list, &id_cache)) {
        entry = NULL;
-       continue;
+       break;
       }
 
-      break;
+      entry = (SilcClientEntry)id_cache->context;
     }
 
     /* If match weren't found, request it */
@@ -100,6 +102,32 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
   return entry;
 }
 
+/* Finds client entry from cache by Client ID. If the entry is not found
+   from the cache this function can query it from the server. */
+
+SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcClientID *client_id,
+                                            int query)
+{
+  SilcIDCacheEntry id_cache;
+
+  /* Find ID from cache */
+  if (!silc_idcache_find_by_id_one(conn->client_cache, client_id, 
+                                  SILC_ID_CLIENT, &id_cache)) {
+    if (!query) {
+      return NULL;
+    } else {
+      SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+      silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, 1,
+                              2, idp->data, idp->len);
+      return NULL;
+    }
+  }
+
+  return (SilcClientEntry)id_cache->context;
+}
+
 /* Finds channel entry from ID cache by channel name. */
 
 SilcChannelEntry silc_idlist_get_channel(SilcClient client,
index 1b2d9d7b73818d5e66228933547c057fedf7af17..b71a0fa13d3ceb47615d95ca1b060faadbe72e8c 100644 (file)
@@ -26,8 +26,9 @@
    client entry. This entry also includes the private message keys if
    they are used. */
 typedef struct SilcClientEntryStruct {
-  char *nickname;
-  char *server;
+  char *nickname;             /* nickname[@server] */
+  char *username;            /* username[@host] */
+  char *server;                      /* SILC server name */
   unsigned int num;
   SilcClientID *id;
 
@@ -39,6 +40,12 @@ typedef struct SilcClientEntryStruct {
 
 typedef SilcClientEntryObject *SilcClientEntry;
 
+/* Client and its mode on a channel */
+typedef struct {
+  SilcClientEntry client;
+  unsigned int mode;
+} SilcChannelUsers;
+
 /* Channel entry context. This is allocate for every channel client has
    joined to. This includes for example the channel specific keys */
 /* XXX channel_key is the server generated key. Later this context must 
@@ -49,7 +56,7 @@ typedef struct SilcChannelEntryStruct {
   unsigned int mode;
   int on_channel;
 
-  SilcClientEntry *clients;
+  SilcChannelUsers *clients;
   unsigned int clients_count;
 
   /* Channel keys */
@@ -68,6 +75,10 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
                                       char *nickname,
                                       char *server,
                                       unsigned int num);
+SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcClientID *client_id,
+                                            int query);
 SilcChannelEntry silc_idlist_get_channel(SilcClient client,
                                         SilcClientConnection conn,
                                         char *channel);
index ad63d1970a02c373899dc02b4dda3d622954039e..5c619192c2856dad9c5814ce44cae859de7c9305 100644 (file)
@@ -38,13 +38,13 @@ typedef struct {
   void (*private_message)(SilcClient client, SilcClientConnection conn,
                          char *sender, char *msg);
   void (*notify)(SilcClient client, SilcClientConnection conn, 
-                SilcNotifyPayload notify_payload);
+                SilcNotifyType type, ...);
   void (*command)(SilcClient client, SilcClientConnection conn, 
                  SilcClientCommandContext cmd_context, int success,
                  SilcCommand command);
   void (*command_reply)(SilcClient client, SilcClientConnection conn,
                        SilcCommandPayload cmd_payload, int success,
-                       SilcCommandStatus status, SilcCommand command, ...);
+                       SilcCommand command, SilcCommandStatus status, ...);
   void (*connect)(SilcClient client, SilcClientConnection conn, int success);
   void (*disconnect)(SilcClient client, SilcClientConnection conn);
   int (*get_auth_method)(SilcClient client, SilcClientConnection conn,
@@ -57,6 +57,8 @@ typedef struct {
                           SilcSKEPKType pk_type);
   unsigned char *(*ask_passphrase)(SilcClient client, 
                                   SilcClientConnection conn);
+  void (*failure)(SilcClient client, SilcClientConnection conn, 
+                 SilcProtocol protocol, void *failure);
 } SilcClientOperations;
 
 /* 
@@ -82,15 +84,16 @@ typedef struct {
    sender received in the packet.
 
 
-   void (*notify)(SilcClient client, SilcClientConnection conn, 
-                 SilcNotifyPayload notify_payload);
+   void (*notify)(SilcClient client, SilcClientConnection conn, ...);
 
-   Notify message to the client.  The `notify_payload' is the Notify
-   Payload received from server.  Client library may parse it to cache
-   some data received from the payload but it is the application's 
-   responsiblity to retrieve the message and arguments from the payload.
-   The message in the payload sent by server is implementation specific
-   thus it is recommended that application will generate its own message.
+   Notify message to the client. The notify arguments are sent in the
+   same order as servers sends them. The arguments are same as received
+   from the server except for ID's.  If ID is received application receives
+   the corresponding entry to the ID. For example, if Client ID is received
+   application receives SilcClientEntry.  Also, if the notify type is
+   for channel the channel entry is sent to application (even if server
+   does not send it because client library gets the channel entry from
+   the Channel ID in the packet's header).
 
 
    void (*command)(SilcClient client, SilcClientConnection conn, 
@@ -170,6 +173,17 @@ typedef struct {
    Ask (interact, that is) a passphrase from user. Returns the passphrase
    or NULL on error. 
 
+
+   void (*failure)(SilcClient client, SilcClientConnection conn, 
+                   SilcProtocol protocol, void *failure);
+
+   Notifies application that failure packet was received.  This is called
+   if there is some protocol active in the client.  The `protocol' is the
+   protocol context.  The `failure' is opaque pointer to the failure
+   indication.  Note, that the `failure' is protocol dependant and application
+   must explicitly cast it to correct type.  Usually `failure' is 32 bit
+   failure type (see protocol specs for all protocol failure types).
+
 */
 
 #endif
index b1b9099ab1beebfbe46b5aa0b471b247ea03726a..33203777ca9172e94b6ebb2c2727d6da88cdee6b 100644 (file)
@@ -119,6 +119,14 @@ static void silc_client_protocol_ke_set_keys(SilcSKE ske,
   silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
 }
 
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+                                    unsigned int len)
+{
+  return SILC_SKE_STATUS_OK;
+}
+
 /* Performs key exchange protocol. This is used for both initiator
    and responder key exchange. This may be called recursively. */
 
@@ -314,6 +322,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       protocol->state = SILC_PROTOCOL_STATE_END;
     }
     break;
+
   case SILC_PROTOCOL_STATE_END:
     {
       /* 
@@ -338,8 +347,29 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        silc_protocol_free(protocol);
     }
     break;
+
   case SILC_PROTOCOL_STATE_ERROR:
+    /*
+     * Error during protocol
+     */
     
+    /* Send abort notification */
+    silc_ske_abort(ctx->ske, ctx->ske->status, 
+                  silc_client_protocol_ke_send_packet,
+                  context);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * Received failure from remote.
+     */
+
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
@@ -448,13 +478,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   case SILC_PROTOCOL_STATE_ERROR:
     {
       /* 
-       * Error
+       * Error. Send notify to remote.
        */
+      unsigned char error[4];
+
+      SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
 
       /* Error in protocol. Send FAILURE packet. Although I don't think
         this could ever happen on client side. */
       silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
-                             NULL, 0, NULL, NULL, NULL, 0, TRUE);
+                             NULL, 0, NULL, NULL, error, 4, TRUE);
 
       /* On error the final callback is always called. */
       if (protocol->final_callback)
@@ -462,7 +495,19 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
       else
        silc_protocol_free(protocol);
     }
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * Received failure from remote.
+     */
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
     break;
+
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
index 72fd28d049f9f1ec33b55c0633da32ce301f260f..36036ce139bbbb851a175a56e49c2b515577bfe0 100644 (file)
@@ -35,4 +35,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
        -I../silcsim -I../.. -I../silcutil -I../../includes \
-       -I../silcmath/gmp
+       -I../silcmath/gmp -I../trq
index 8955fff940d2884c1222e37a544a70f4306f3163..9dc176f3c84401806870adab7decc839a0427924 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $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
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 #include "idcache.h"
index 9517db1b2ccbb4c549bf3dfcb48677b2de10d2b8..e3382e7b8361db8b04184811835942f59a0a964a 100644 (file)
@@ -30,16 +30,22 @@ typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
 typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
 
 /* Channel modes */
-#define SILC_CHANNEL_MODE_NONE       0x0000
-#define SILC_CHANNEL_MODE_PRIVATE    0x0001 /* private channel */
-#define SILC_CHANNEL_MODE_SECRET     0x0002 /* secret channel */
-#define SILC_CHANNEL_MODE_PRIVKEY    0x0004 /* channel has private key */
-#define SILC_CHANNEL_MODE_INVITE     0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_NONE        0x0000
+#define SILC_CHANNEL_MODE_PRIVATE     0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET      0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY     0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE      0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_TOPIC       0x0010 /* topic setting by operator */
+#define SILC_CHANNEL_MODE_ULIMIT      0x0020 /* user limit set */
+#define SILC_CHANNEL_MODE_PASSPHRASE  0x0040 /* passphrase set */
+#define SILC_CHANNEL_MODE_BAN         0x0080 /* ban list set */
+#define SILC_CHANNEL_MODE_INVITE_LIST 0x0100 /* invite list set */
+#define SILC_CHANNEL_MODE_CIPHER      0x0200 /* sets cipher of channel */
 
 /* User modes on channel */
-#define SILC_CHANNEL_UMODE_NONE      0x0000
-#define SILC_CHANNEL_UMODE_CHANFO    0x0001 /* channel founder */
-#define SILC_CHANNEL_UMODE_CHANOP    0x0002 /* channel operator */
+#define SILC_CHANNEL_UMODE_NONE       0x0000 /* Normal user */
+#define SILC_CHANNEL_UMODE_CHANFO     0x0001 /* channel founder */
+#define SILC_CHANNEL_UMODE_CHANOP     0x0002 /* channel operator */
 
 /* Prototypes */
 SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer);
index b9bd78f037f2e6cb7b4468b72cb8f29fe7dc9f8e..6c45cdb87535ad3908406e2b1f10b1c12935f9fa 100644 (file)
@@ -176,6 +176,47 @@ SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
   return buffer;
 }
 
+/* Same as above but with va_list. */
+
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
+                                          unsigned short ident, 
+                                          unsigned int argc, va_list ap)
+{
+  unsigned char **argv;
+  unsigned int *argv_lens = NULL, *argv_types = NULL;
+  unsigned char *x;
+  unsigned int x_len;
+  unsigned int x_type;
+  SilcBuffer buffer;
+  int i;
+
+  argv = silc_calloc(argc, sizeof(unsigned char *));
+  argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  argv_types = silc_calloc(argc, sizeof(unsigned int));
+
+  for (i = 0; i < argc; i++) {
+    x_type = va_arg(ap, unsigned int);
+    x = va_arg(ap, unsigned char *);
+    x_len = va_arg(ap, unsigned int);
+
+    argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+    memcpy(argv[i], x, x_len);
+    argv_lens[i] = x_len;
+    argv_types[i] = x_type;
+  }
+
+  buffer = silc_command_payload_encode(cmd, argc, argv, 
+                                      argv_lens, argv_types, ident);
+
+  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'
index 0912b76de7bc93a24e5108cf068c8d33114eb943..bdca206b0dfa84b029fa69dc8bb4eb4a37193a6d 100644 (file)
@@ -34,21 +34,21 @@ typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
 /* Command flags. These set how the commands behave on different
    situations. These can be OR'ed together to set multiple flags. */
 typedef enum {
-  SILC_CF_NONE = 0,
+  SILC_CF_NONE           = 0,
 
   /* Command may only be used once per (about) 2 seconds */
-  SILC_CF_LAG = (1L << 1),
+  SILC_CF_LAG            = (1L << 1),
 
   /* Command is available for registered connections (connections
      whose ID has been created. */
-  SILC_CF_REG = (1L << 2),
+  SILC_CF_REG            = (1L << 2),
 
   /* Command is available only for server operators */
-  SILC_CF_OPER = (1L << 3),
+  SILC_CF_OPER           = (1L << 3),
 
   /* Command is available only for SILC (router) operators. If this 
      is set SILC_CF_OPER is not necessary to be set. */
-  SILC_CF_SILC_OPER = (1L << 4),
+  SILC_CF_SILC_OPER      = (1L << 4),
 
 } SilcCommandFlag;
 
@@ -72,13 +72,14 @@ typedef enum {
 #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
+#define SILC_COMMAND_CUMODE            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
 
 /* Reserved */
 #define SILC_COMMAND_RESERVED           255
@@ -107,24 +108,25 @@ typedef unsigned short SilcCommandStatus;
 #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
+#define SILC_STATUS_ERR_USER_NOT_ON_CHANNEL 26
+#define SILC_STATUS_ERR_USER_ON_CHANNEL     27
+#define SILC_STATUS_ERR_NOT_REGISTERED      28
+#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS   29
+#define SILC_STATUS_ERR_TOO_MANY_PARAMS     30
+#define SILC_STATUS_ERR_PERM_DENIED         31
+#define SILC_STATUS_ERR_BANNED_FROM_SERVER  32
+#define SILC_STATUS_ERR_BAD_PASSWORD        33
+#define SILC_STATUS_ERR_CHANNEL_IS_FULL     34
+#define SILC_STATUS_ERR_NOT_INVITED         35
+#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 36
+#define SILC_STATUS_ERR_UNKNOWN_MODE        37
+#define SILC_STATUS_ERR_NOT_YOU             38
+#define SILC_STATUS_ERR_NO_CHANNEL_PRIV     39
+#define SILC_STATUS_ERR_NO_SERVER_PRIV      40
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV      41
+#define SILC_STATUS_ERR_BAD_NICKNAME        42
+#define SILC_STATUS_ERR_BAD_CHANNEL         43
+#define SILC_STATUS_ERR_AUTH_FAILED         44
 
 /* Prototypes */
 SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer);
@@ -137,6 +139,9 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd,
 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
                                          unsigned short ident, 
                                          unsigned int argc, ...);
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
+                                          unsigned short ident, 
+                                          unsigned int argc, va_list ap);
 SilcBuffer 
 silc_command_reply_payload_encode_va(SilcCommand cmd, 
                                     SilcCommandStatus status,
index 028ae025591ec1dfad9f09c1c78a3a378b7e5ec5..b76d675275c9f3cfd44da3be54c0da7e344a4658 100644 (file)
@@ -31,7 +31,6 @@
 struct SilcNotifyPayloadStruct {
   SilcNotifyType type;
   unsigned int argc;
-  unsigned char *message;
   SilcArgumentPayload args;
 };
 
@@ -55,19 +54,12 @@ SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer)
   if (len > buffer->len)
     goto err;
 
-  silc_buffer_pull(buffer, 5);
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_XNSTRING_ALLOC(&new->message, len),
-                      SILC_STR_END);
-
   if (new->argc) {
-    silc_buffer_pull(buffer, len);
+    silc_buffer_pull(buffer, 5);
     new->args = silc_argument_payload_parse(buffer, new->argc);
-    silc_buffer_push(buffer, len);
+    silc_buffer_push(buffer, 5);
   }
 
-  silc_buffer_push(buffer, 5);
-
   return new;
 
  err:
@@ -79,8 +71,8 @@ SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer)
    argument payloads will be associated to the notify payload. Variable
    arguments must be {usigned char *, unsigned int (len)}. */
 
-SilcBuffer silc_notify_payload_encode(SilcNotifyType type, char *message,
-                                     unsigned int argc, va_list ap)
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc, 
+                                     va_list ap)
 {
   SilcBuffer buffer;
   SilcBuffer args = NULL;
@@ -114,25 +106,22 @@ SilcBuffer silc_notify_payload_encode(SilcNotifyType type, char *message,
     silc_free(argv_lens);
     silc_free(argv_types);
   }
-    
-  i = strlen(message);
-  len += 5 + i;
+
+  len += 5;
   buffer = silc_buffer_alloc(len);
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
-
   silc_buffer_format(buffer,
                     SILC_STR_UI_SHORT(type),
-                    SILC_STR_UI_SHORT(i),
+                    SILC_STR_UI_SHORT(len),
                     SILC_STR_UI_CHAR(argc),
-                    SILC_STR_UI_XNSTRING(message, i),
                     SILC_STR_END);
 
   if (argc) {
-    silc_buffer_pull(buffer, 5 + i);
+    silc_buffer_pull(buffer, 5);
     silc_buffer_format(buffer,
                       SILC_STR_UI_XNSTRING(args->data, args->len),
                       SILC_STR_END);
-    silc_buffer_push(buffer, 5 + i);
+    silc_buffer_push(buffer, 5);
     silc_buffer_free(args);
   }
 
@@ -145,7 +134,6 @@ void silc_notify_payload_free(SilcNotifyPayload payload)
 {
   if (payload) {
     silc_argument_payload_free(payload->args);
-    silc_free(payload->message);
     silc_free(payload);
   }
 }
@@ -164,13 +152,6 @@ unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload)
   return payload->argc;
 }
 
-/* Return notify message */
-
-unsigned char *silc_notify_get_message(SilcNotifyPayload payload)
-{
-  return payload->message;
-}
-
 /* Return argument payload */
 
 SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload)
index 9215e2b48a1bd4752a23982f30467308fbdf8fae..3362d7fc3df95464014de1df8ccd580f20bfffb4 100644 (file)
@@ -37,15 +37,17 @@ typedef unsigned short SilcNotifyType;
 #define SILC_NOTIFY_TYPE_SIGNOFF         4 /* "signoff" */
 #define SILC_NOTIFY_TYPE_TOPIC_SET       5 /* "topic has been changed" */
 #define SILC_NOTIFY_TYPE_NICK_CHANGE     6 /* "has changed nickname" */
+#define SILC_NOTIFY_TYPE_CMODE_CHANGE    7 /* "has changed channel mode" */
+#define SILC_NOTIFY_TYPE_CUMODE_CHANGE   8 /* "has change mode" */
+#define SILC_NOTIFY_TYPE_MOTD            9 /* message of the day */
 
 /* Prototypes */
 SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer);
-SilcBuffer silc_notify_payload_encode(SilcNotifyType type, char *message,
-                                     unsigned int argc, va_list ap);
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc, 
+                                     va_list ap);
 void silc_notify_payload_free(SilcNotifyPayload payload);
 SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload);
 unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload);
-unsigned char *silc_notify_get_message(SilcNotifyPayload payload);
 SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload);
 
 #endif
index bfd237b1923a4e8a40d741fd3ec119cb11097f7f..63f179aea402b2d441648286fad2151b35121cf2 100644 (file)
@@ -368,6 +368,11 @@ void silc_packet_receive_process(SilcSocketConnection sock,
   SilcPacketParserContext *parse_ctx;
   int packetlen, paddedlen, count, mac_len = 0;
 
+  /* We need at least 2 bytes of data to be able to start processing
+     the packet. */
+  if (sock->inbuf->len < 2)
+    return;
+
   if (hmac)
     mac_len = hmac->hash->hash->hash_len;
 
@@ -380,7 +385,7 @@ void silc_packet_receive_process(SilcSocketConnection sock,
 
     if (packetlen < SILC_PACKET_MIN_LEN) {
       SILC_LOG_DEBUG(("Received invalid packet, dropped"));
-      continue;
+      return;
     }
 
     if (sock->inbuf->len < paddedlen + mac_len) {
@@ -727,3 +732,37 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
 
   return ctx->type;
 }
+
+/* Duplicates packet context. Duplicates the entire context and its
+   contents. */
+
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
+{
+  SilcPacketContext *new;
+
+  new = silc_calloc(1, sizeof(*new));
+  new->buffer = silc_buffer_copy(ctx->buffer);
+  new->type = ctx->type;
+  new->flags = ctx->flags;
+
+  new->src_id = silc_calloc(ctx->src_id_len, sizeof(*new->src_id));
+  memcpy(new->src_id, ctx->src_id, ctx->src_id_len);
+  new->src_id_len = ctx->src_id_len;
+  new->src_id_type = ctx->src_id_type;
+
+  new->dst_id = silc_calloc(ctx->dst_id_len, sizeof(*new->dst_id));
+  memcpy(new->dst_id, ctx->dst_id, ctx->dst_id_len);
+  new->dst_id_len = ctx->dst_id_len;
+  new->dst_id_type = ctx->dst_id_type;
+
+  new->truelen = ctx->truelen;
+  new->padlen = ctx->padlen;
+
+  new->rng = ctx->rng;
+  new->context = ctx->context;
+  new->sock = ctx->sock;
+
+  return new;
+}
+
+
index fae8271521c5cbe1392fcbc12073b8b82f263237..fe0c81f436ea9f0f8bd125139bb8a35d8d284f54 100644 (file)
@@ -124,6 +124,10 @@ typedef struct {
 
   /* For padding generation */
   SilcRng rng;
+
+  /* Back pointers */
+  void *context;
+  SilcSocketConnection sock;
 } SilcPacketContext;
 
 /* 
@@ -243,5 +247,6 @@ void silc_packet_receive_process(SilcSocketConnection sock,
                                 void *context);
 SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx);
 
 #endif
index 5d2cacabdce0f0c983790841038c6b6f3e53d2d8..add747ceb89ca3b83bec6108bc1e31e2b6274475 100644 (file)
@@ -107,17 +107,54 @@ SilcIDPayload silc_id_payload_parse_data(unsigned char *data,
   return NULL;
 }
 
+/* Return the ID directly from the raw payload data. */
+
+void *silc_id_payload_parse_id(unsigned char *data, unsigned int len)
+{
+  SilcBuffer buffer;
+  SilcIdType type;
+  unsigned short idlen;
+  unsigned char *id;
+
+  buffer = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_put(buffer, data, len);
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&type),
+                      SILC_STR_UI_SHORT(&idlen),
+                      SILC_STR_END);
+
+  silc_buffer_pull(buffer, 4);
+
+  if (idlen > buffer->len)
+    goto err;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING_ALLOC(&id, idlen),
+                      SILC_STR_END);
+
+  silc_buffer_free(buffer);
+
+  return silc_id_str2id(id, type);
+
+ err:
+  silc_buffer_free(buffer);
+  return NULL;
+}
+
 /* Encodes ID Payload */
 
-SilcBuffer silc_id_payload_encode(void *id, unsigned short len,
-                                 SilcIdType type)
+SilcBuffer silc_id_payload_encode(void *id, SilcIdType type)
 {
   SilcBuffer buffer;
   unsigned char *id_data;
+  unsigned int len;
 
   SILC_LOG_DEBUG(("Parsing ID payload"));
 
   id_data = silc_id_id2str(id, type);
+  len = silc_id_get_len(type);
 
   buffer = silc_buffer_alloc(4 + len);
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
@@ -154,6 +191,22 @@ void *silc_id_payload_get_id(SilcIDPayload payload)
   return silc_id_str2id(payload->id, payload->type);
 }
 
+/* Get raw ID data. Data is duplicated. */
+
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
+{
+  unsigned char *ret = silc_calloc(payload->len, sizeof(*ret));
+  memcpy(ret, payload->id, payload->len);
+  return ret;
+}
+
+/* Get length of ID */
+
+unsigned int silc_id_payload_get_len(SilcIDPayload payload)
+{
+  return payload->len;
+}
+
 /******************************************************************************
 
                              Argument Payload
index 1517b2d862105a0ec7edde60cffd88d0966bf221..e58171e22f4fb38275c82f5bab808d8dd0838b9f 100644 (file)
@@ -27,15 +27,17 @@ typedef struct SilcArgumentPayloadStruct *SilcArgumentPayload;
 
 /* Prototypes */
 SilcIDPayload silc_id_payload_parse(SilcBuffer buffer);
-SilcBuffer silc_id_payload_encode(void *id, unsigned short len,
-                                 SilcIdType type);
 SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer,
                                                unsigned int argc);
 SilcIDPayload silc_id_payload_parse_data(unsigned char *data, 
                                         unsigned int len);
+void *silc_id_payload_parse_id(unsigned char *data, unsigned int len);
+SilcBuffer silc_id_payload_encode(void *id, SilcIdType type);
 void silc_id_payload_free(SilcIDPayload payload);
 SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
 void *silc_id_payload_get_id(SilcIDPayload payload);
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
+unsigned int silc_id_payload_get_len(SilcIDPayload payload);
 SilcBuffer silc_argument_payload_encode(unsigned int argc,
                                        unsigned char **argv,
                                        unsigned int *argv_lens,
index 620ca85b7027ce4fe253f259e7a72e2350f19434..6d5ef0b529d89455536b9fea1c5bf02ab06feb4c 100644 (file)
@@ -31,14 +31,20 @@ typedef unsigned char SilcProtocolState;
    the START state or you break every protocol. */
 #define SILC_PROTOCOL_STATE_UNKNOWN 0
 #define SILC_PROTOCOL_STATE_START 1
-#define SILC_PROTOCOL_STATE_END 253
-#define SILC_PROTOCOL_STATE_ERROR 254
+#define SILC_PROTOCOL_STATE_END 252
+#define SILC_PROTOCOL_STATE_FAILURE 253         /* Received failure from remote */
+#define SILC_PROTOCOL_STATE_ERROR 254    /* Local error at our end */
 
 /* Connection Authentication protocols' authentication methods */
 #define SILC_PROTOCOL_CONN_AUTH_NONE 0
 #define SILC_PROTOCOL_CONN_AUTH_PASSWORD 1
 #define SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY 2
 
+/* XXX These don't belong here really! */
+/* Connection authentication protocol status message */
+#define SILC_CONN_AUTH_OK 0
+#define SILC_CONN_AUTH_FAILED 1
+
 /* Type definition for above auth methods */
 typedef unsigned char SilcProtocolAuthMeth;
 
index fd3ebd7b616c218455a54985c4089eab0109c022..91be08de53f680ed2efdfb799afe3c2f9d3257a2 100644 (file)
@@ -31,4 +31,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcske \
        -I../silcsim -I../.. -I../silcutil -I../../includes \
-       -I./gmp
+       -I./gmp -I../trq
index 0c4f30bfb50f3f91b4bdf6b45f95caf444a94c87..3d761a4d76b8418c7c83573fb2e5bb3a8b132563 100644 (file)
@@ -72,4 +72,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
        -I../silccore -I../.. -I../silcutil -I../../includes \
-       -I../silcmath/gmp
+       -I../silcmath/gmp -I../trq
index eb4e5f1a055cd6d4eea892ba3acc18c2227e1208..c8338ad1f215d52f03807d7f98e887e353a83d45 100644 (file)
@@ -29,4 +29,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcutil \
        -I../silcsim -I../silcmath -I../.. -I../../includes \
-        -I../silcmath/gmp
+        -I../silcmath/gmp -I../trq
index c5163358d17b37fb556e9319f2d33973afb9aac2..718e6bc2d94a331ebc586c3ab81c70f3d39c80a1 100644 (file)
@@ -22,6 +22,9 @@
 /*
  * $Id$
  * $Log$
+ * Revision 1.6  2000/10/31 19:48:31  priikone
+ *     A LOT updates. Cannot separate. :)
+ *
  * Revision 1.5  2000/07/19 07:04:37  priikone
  *     Added version detection support to SKE. Minor bugfixes.
  *
@@ -257,6 +260,7 @@ silc_ske_payload_start_decode(SilcSKE ske,
  err:
   silc_ske_payload_start_free(payload);
 
+  ske->status = status;
   return status;
 }
 
@@ -388,6 +392,7 @@ SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
 
  err:
   silc_free(payload);
+  ske->status = status;
   return status;
 }
 
@@ -530,6 +535,7 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
   if (payload->sign_data)
     silc_free(payload->sign_data);
   silc_free(payload);
+  ske->status = status;
   return status;
 }
 
index 1ca94b0f815b26579b04c3fd74c5304c62c5874a..0dac063376bdd3490cf231c9c9faefc128fd3afa 100644 (file)
@@ -32,6 +32,7 @@ SilcSKE silc_ske_alloc()
   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
 
   ske = silc_calloc(1, sizeof(*ske));
+  ske->status = SILC_SKE_STATUS_OK;
 
   return ske;
 }
@@ -200,6 +201,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -368,6 +370,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -425,6 +428,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -499,6 +503,7 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -640,6 +645,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -651,18 +657,22 @@ SilcSKEStatus silc_ske_end(SilcSKE ske,
                           SilcSKESendPacketCb send_packet,
                           void *context)
 {
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer packet;
 
   SILC_LOG_DEBUG(("Start"));
 
-  packet = silc_buffer_alloc(1);
-  packet->len = 0;
+  packet = silc_buffer_alloc(4);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
+                    SILC_STR_END);
 
   if (send_packet)
     (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
 
-  return status;
+  silc_buffer_free(packet);
+
+  return SILC_SKE_STATUS_OK;
 }
 
 /* Aborts the Key Exchange protocol. This is called if error occurs
@@ -781,7 +791,8 @@ silc_ske_select_security_properties(SilcSKE ske,
   payload->cookie_len = SILC_SKE_COOKIE_LEN;
   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
 
-  /* XXX Do version check */
+  /* Check version string */
+  silc_ske_check_version(ske, rp->version, rp->version_len);
 
   /* Put our version to our reply */
   payload->version = strdup(version);
index b087e4f692a51003a880c32d862cfff47509ef2d..55613e4cf3f9fdecf03e2cf886aec541bd3b5172 100644 (file)
@@ -31,13 +31,12 @@ typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties;
 
 /* Supported Public Key Types, defined by the protocol */
 typedef enum {
-  SILC_SKE_PK_TYPE_SILC = 1,   /* Mandatory type */
-  /* Optional types. These are not implemented currently
-  SILC_SKE_PK_TYPE_SSH2 = 2,
-  SILC_SKE_PK_TYPE_X509V3 = 3,
+  SILC_SKE_PK_TYPE_SILC    = 1,        /* Mandatory type */
+  /* Optional types. These are not implemented currently */
+  SILC_SKE_PK_TYPE_SSH2    = 2,
+  SILC_SKE_PK_TYPE_X509V3  = 3,
   SILC_SKE_PK_TYPE_OPENPGP = 4,
-  SILC_SKE_PK_TYPE_SPKI = 5
-  */
+  SILC_SKE_PK_TYPE_SPKI    = 5
 } SilcSKEPKType;
 
 /* Packet sending callback. Caller of the SKE routines must provide
@@ -136,6 +135,9 @@ struct SilcSKEStruct {
   /* Pointer to the what ever user data. This is set by the caller
      and is not touched by the SKE. The caller must also free this one. */
   void *user_data;
+
+  /* Current status of SKE */
+  SilcSKEStatus status;
 };
 
 /* Prototypes */
@@ -207,4 +209,7 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
                                            unsigned int req_enc_key_len,
                                            unsigned int req_hmac_key_len,
                                            SilcSKEKeyMaterial *key);
+SilcSKEStatus silc_ske_check_version(SilcSKE ske,
+                                    unsigned char *version,
+                                    unsigned int version_len);
 #endif
index f512354f1179aee5c0a0cdcaa0ba50546a2768cd..d81ed54cd8c586f18f398348f5802260f68344aa 100644 (file)
 /* Status flags returned by all SKE routines */
 typedef enum {
   /* These are defined by the protocol */
-  SILC_SKE_STATUS_OK = 0,
-  SILC_SKE_STATUS_ERROR = 1,
-  SILC_SKE_STATUS_BAD_PAYLOAD = 2,
-  SILC_SKE_STATUS_UNKNOWN_GROUP = 3,
-  SILC_SKE_STATUS_UNKNOWN_CIPHER = 4,
-  SILC_SKE_STATUS_UNKNOWN_PKCS = 5,
-  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION = 6,
+  SILC_SKE_STATUS_OK                     = 0,
+  SILC_SKE_STATUS_ERROR                  = 1,
+  SILC_SKE_STATUS_BAD_PAYLOAD            = 2,
+  SILC_SKE_STATUS_UNKNOWN_GROUP          = 3,
+  SILC_SKE_STATUS_UNKNOWN_CIPHER         = 4,
+  SILC_SKE_STATUS_UNKNOWN_PKCS           = 5,
+  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION  = 6,
   SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 7,
-  SILC_SKE_STATUS_INCORRECT_SIGNATURE = 8,
+  SILC_SKE_STATUS_INCORRECT_SIGNATURE    = 8,
+  SILC_SKE_STATUS_BAD_VERSION            = 9,
 
   SILC_SKE_STATUS_KEY_EXCHANGE_NOT_ACTIVE,
   SILC_SKE_STATUS_BAD_RESERVED_FIELD,
index fc02b272dca2cd7eff1ff9d40ce2b58f53a351f9..302738d5c2997ee75e8374dc06833f87bc929788 100644 (file)
@@ -36,4 +36,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
        -I../silcsim -I../.. -I../silccore -I../../includes \
-       -I../silcmath/gmp
+       -I../silcmath/gmp -I../trq
index ccaf1f572e7abb704b86d60d29aafc6d72e065d5..a9432a9f55e6fc13e8fba8d0bfbfa3a55e34015c 100644 (file)
@@ -20,6 +20,9 @@
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/10/31 19:48:32  priikone
+ *     A LOT updates. Cannot separate. :)
+ *
  * Revision 1.1  2000/09/13 17:45:15  priikone
  *     Splitted SILC core library. Core library includes now only
  *     SILC protocol specific stuff. New utility library includes the
 #include "silcincludes.h"
 #include "silcbuffer.h"
 
-static unsigned char *silc_buffer_pull_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_pull(sb, len);
-}
-
-static unsigned char *silc_buffer_push_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_push(sb, len);
-}
-
-static unsigned char *silc_buffer_pull_tail_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_pull_tail(sb, len);
-}
-
-static unsigned char *silc_buffer_push_tail_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_push_tail(sb, len);
-}
-
-static unsigned char *silc_buffer_put_head_i(SilcBuffer sb, 
-                                            unsigned char *data,
-                                            unsigned int len)
-{
-  return silc_buffer_put_head(sb, data, len);
-}
-
-static unsigned char *silc_buffer_put_i(SilcBuffer sb, 
-                                       unsigned char *data,
-                                       unsigned int len)
-{
-  return silc_buffer_put(sb, data, len);
-}
+#ifdef SILC_DEBUG              /* If we are doing debugging we won't
+                                  have the optimized inline buffer functions
+                                  available as optimization is not set
+                                  to compiler. These normal routines are
+                                  used in debugging mode. */
 
-static unsigned char *silc_buffer_put_tail_i(SilcBuffer sb, 
-                                            unsigned char *data,
-                                            unsigned int len)
-{
-  return silc_buffer_put_tail(sb, data, len);
-}
+/* XXX These are currenly obsolete as SILC is compiled always with -O
+   flag thus inline functions maybe used always. So, fix these. */
 
 /* Allocates a new SilcBuffer and returns a pointer to it. The data
    area of the new buffer is set to the real beginning of the buffer. 
@@ -109,15 +80,6 @@ SilcBuffer silc_buffer_alloc(unsigned int len)
   sb->tail = data;
   sb->end = data + sb->truelen;
 
-  /* Set the function pointers */
-  sb->pull = silc_buffer_pull_i;
-  sb->push = silc_buffer_push_i;
-  sb->pull_tail = silc_buffer_pull_tail_i;
-  sb->push_tail = silc_buffer_push_tail_i;
-  sb->put = silc_buffer_put_i;
-  sb->put_head = silc_buffer_put_head_i;
-  sb->put_tail = silc_buffer_put_tail_i;
-
   return sb;
 }
 
@@ -132,15 +94,6 @@ void silc_buffer_free(SilcBuffer sb)
   }
 }
 
-#ifdef SILC_DEBUG              /* If we are doing debugging we won't
-                                  have the optimized inline buffer functions
-                                  available as optimization is not set
-                                  to compiler. These normal routines are
-                                  used in debugging mode. */
-
-/* XXX These are currenly obsolte as SILC is compiled always with -O
-   flag thus inline functions maybe used. So, fix these. */
-
 /* Pulls current data area towards end. The length of the currently
    valid data area is also decremented. Returns pointer to the data
    area before pulling. 
index 179c3d0e0567065917c4d402e077eef0887ad61d..d32b046baf34a8836627d7bb40e47dfd87c73cbf 100644 (file)
@@ -116,18 +116,6 @@ typedef struct SilcBufferStruct {
   unsigned char *data;
   unsigned char *tail;
   unsigned char *end;
-
-  /* Method functions. */
-  unsigned char *(*pull)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*push)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*pull_tail)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*push_tail)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*put)(struct SilcBufferStruct *, unsigned char *, 
-                       unsigned int);
-  unsigned char *(*put_head)(struct SilcBufferStruct *, unsigned char *, 
-                            unsigned int);
-  unsigned char *(*put_tail)(struct SilcBufferStruct *, unsigned char *, 
-                            unsigned int);
 } SilcBufferObject;
 
 typedef SilcBufferObject *SilcBuffer;
@@ -145,6 +133,42 @@ typedef SilcBufferObject *SilcBuffer;
  * functions.
  */
 
+extern inline
+SilcBuffer silc_buffer_alloc(unsigned int len)
+{
+  SilcBuffer sb;
+  unsigned char *data;
+
+  /* Allocate new SilcBuffer */
+  sb = silc_calloc(1, sizeof(*sb));
+
+  /* Allocate the actual data area */
+  data = silc_calloc(len, sizeof(*data));
+  memset(data, 0, len);
+
+  /* Set pointers to the new buffer */
+  sb->truelen = len;
+  sb->len = 0;
+  sb->head = data;
+  sb->data = data;
+  sb->tail = data;
+  sb->end = data + sb->truelen;
+
+  return sb;
+}
+
+/* Free's a SilcBuffer */
+
+extern inline
+void silc_buffer_free(SilcBuffer sb)
+{
+  if (sb) {
+    memset(sb->head, 'F', sb->truelen);
+    silc_free(sb->head);
+    silc_free(sb);
+  }
+}
+
 /* Pulls current data area towards end. The length of the currently
    valid data area is also decremented. Returns pointer to the data
    area before pulling. 
@@ -328,9 +352,9 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb,
 #endif /* !SILC_DEBUG */
 
 /* Prototypes */
+#ifdef SILC_DEBUG
 SilcBuffer silc_buffer_alloc(unsigned int len);
 void silc_buffer_free(SilcBuffer sb);
-#ifdef SILC_DEBUG
 unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
 unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
index a481453fdea7bb0776d4f3d3da9d9094f7c82a92..54cf0e2c2a37a38c10d53ce223d93df2b9f51b99 100644 (file)
    is too short. Must be fixed. There are some other obvious bugs as
    well. */
 /*
- * $Id$
- * $Log$
- * Revision 1.2  2000/09/29 07:11:27  priikone
- *     Explcitly cast some va_arg()s as it requires it nowadays.
- *
- * 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
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+ * $Id$ */
 
 #include "silcincludes.h"
 
index 6d9acaeb736327deab7ee84a069cafd441006661..25834505cac375bb383907d7f1f81e8b512c4b79 100644 (file)
@@ -180,7 +180,7 @@ typedef enum {
 #define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
   SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
 
-/* Marks end of the argument list. This must the at the end of the
+/* Marks end of the argument list. This must be at the end of the
    argument list or error will occur. */
 #define SILC_STR_END SILC_BUFFER_PARAM_END
 
index 24f3ddcee748dabba4de0fbc190fdcd09de08bd5..243ce20e8792902746ebbb0622c39f59c86a278e 100644 (file)
@@ -22,7 +22,7 @@
 #include "silcincludes.h"
 
 /* Set TRUE/FALSE to enable/disable debugging */
-int silc_debug;
+int silc_debug = FALSE;
 
 /* SILC Log name strings. These strings are printed to the log file. */
 const SilcLogTypeName silc_log_types[] =
@@ -55,22 +55,6 @@ static SilcLogCb fatal_cb = NULL;
 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[8192];
-
-  memset(buf, 0, sizeof(buf));
-  va_start(args, fmt);
-  vsnprintf(buf, sizeof(buf) - 1, fmt, args);
-  va_end(args);
-
-  return strdup(buf);
-}
-
 /* Outputs the log message to what ever log file selected. */
 
 void silc_log_output(const char *filename, unsigned int maxsize,
index cd34639f3d1fc994cd0c45ad54b3e11ec7361b5a..4d00f05f0d97220745cb78b744c9e95686521957 100644 (file)
@@ -70,19 +70,19 @@ extern unsigned int log_fatal_size;
 #define SILC_LOG_INFO(fmt) (silc_log_output(log_info_file, \
                                            log_info_size, \
                                           SILC_LOG_INFO, \
-                                          silc_log_format fmt))
+                                          silc_format fmt))
 #define SILC_LOG_WARNING(fmt) (silc_log_output(log_warning_file, \
                                                log_warning_size, \
                                               SILC_LOG_WARNING, \
-                                              silc_log_format fmt))
+                                              silc_format fmt))
 #define SILC_LOG_ERROR(fmt) (silc_log_output(log_error_file, \
                                              log_error_size, \
                                             SILC_LOG_ERROR, \
-                                            silc_log_format fmt))
+                                            silc_format fmt))
 #define SILC_LOG_FATAL(fmt) (silc_log_output(log_fatal_file, \
                                              log_fatal_size, \
                                             SILC_LOG_FATAL, \
-                                            silc_log_format fmt))
+                                            silc_format fmt))
 
 /* Debug macro is a bit different from other logging macros and it
    is compiled in only if debugging is enabled. */
@@ -90,20 +90,19 @@ extern unsigned int log_fatal_size;
 #define SILC_LOG_DEBUG(fmt) (silc_log_output_debug(__FILE__, \
                                                   __FUNCTION__, \
                                                   __LINE__, \
-                                                  silc_log_format fmt))
+                                                  silc_format fmt))
 #define SILC_LOG_HEXDUMP(fmt, data, len) \
   (silc_log_output_hexdump(__FILE__, \
                           __FUNCTION__, \
                           __LINE__, \
                            (data), (len), \
-                          silc_log_format fmt))
+                          silc_format fmt))
 #else
 #define SILC_LOG_DEBUG(fmt)
 #define SILC_LOG_HEXDUMP(fmt, data, len)
 #endif
 
 /* Prototypes */
-char *silc_log_format(char *fmt, ...);
 void silc_log_output_debug(char *file, char *function, 
                            int line, char *string);
 void silc_log_output(const char *filename, unsigned int maxsize,
index 68a820f6316ec79b5fdb6dc95dc31a817f849b5f..c4d6d9d7a653a5f00575a4cefcc0daa9541b61f3 100644 (file)
@@ -20,6 +20,9 @@
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/10/31 19:48:32  priikone
+ *     A LOT updates. Cannot separate. :)
+ *
  * Revision 1.1  2000/09/13 17:45:16  priikone
  *     Splitted SILC core library. Core library includes now only
  *     SILC protocol specific stuff. New utility library includes the
@@ -149,8 +152,9 @@ int silc_net_create_connection(int port, char *host)
     return -1;
   }
 
-  /* Set appropriate option */
+  /* Set appropriate options */
   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
 
   SILC_LOG_DEBUG(("Connection created"));
 
@@ -205,8 +209,9 @@ int silc_net_create_connection_async(int port, char *host)
     }
   }
 
-  /* Set appropriate option */
+  /* Set appropriate options */
   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
 
   SILC_LOG_DEBUG(("Connection operation in progress"));
 
@@ -304,3 +309,13 @@ void silc_net_check_host_by_sock(int sock, char **hostname, char **ip)
   memcpy(*ip, host_ip, strlen(host_ip));
   SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
 }
+
+/* Return name of localhost. */
+
+char *silc_net_localhost()
+{
+  char hostname[256];
+  if (!gethostname(hostname, sizeof(hostname)))
+    return strdup(hostname);
+  return NULL;
+}
index d6ef5c07bbd042213f5975eeeb38dff68c735c4c..756f160448cb10760dad1651617263c7eaf25a2d 100644 (file)
@@ -32,5 +32,6 @@ int silc_net_set_socket_nonblock(int sock);
 int silc_net_set_socket_opt(int sock, int level, int option, int on);
 int silc_net_is_ip(const char *addr);
 void silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
+char *silc_net_localhost();
 
 #endif
index f413b1c130f6fb384e9489bb57ac9609ee7b05d9..81b5afe2e41fc76345850024037b214f8a7e1a4c 100644 (file)
@@ -528,3 +528,19 @@ void silc_parse_command_line(unsigned char *buffer,
 
   *parsed_num = argc;
 }
+
+/* Formats arguments to a string and returns it after allocating memory
+   for it. It must be remembered to free it later. */
+
+char *silc_format(char *fmt, ...)
+{
+  va_list args;
+  static char buf[8192];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(args, fmt);
+  vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+  va_end(args);
+
+  return strdup(buf);
+}
index e9c011b3f0f2429039d3da59ebfa987d2c54bc68..1c6f764e1f4df3ccb595d6ccc8e9a3b24d6be295 100644 (file)
@@ -43,5 +43,6 @@ void silc_parse_command_line(unsigned char *buffer,
                             unsigned int **parsed_types,
                             unsigned int *parsed_num,
                             unsigned int max_args);
+char *silc_format(char *fmt, ...);
 
 #endif
index bdd83b42394d84ec36c58350f6da8ce9399ef5b1..2abeabaeb427c6bc2a7b1eb618cf206f73a9e1b0 100755 (executable)
@@ -25,7 +25,8 @@
 
 echo "Cleaning entire SILC source tree..."
 echo "All errors and warnings may be safely ignored."
-make distclean
+make clean -k
+make distclean -k
 rm -f includes/stamp-*
 rm -f includes/silcconfig.*
 rm -f includes/version_internal.h
@@ -43,9 +44,11 @@ rm -f lib/silcmath/Makefile.in
 rm -f lib/silcsim/Makefile.in
 rm -f lib/silcsim/modules/Makefile.in
 rm -f lib/silcske/Makefile.in
+rm -f lib/trq/Makefile
 rm -rf lib/silcmath/gmp/.deps
 rm -f silcd/Makefile.in silcd/log* silcd/*.log
 rm -f silc/Makefile.in silc/log* silc/*.log
 rm -f aclocal.m4
+rm -f config.status
 rm -f configure
 echo "Done."