Splitted server.[ch] and created packet_send.[ch] and
authorPekka Riikonen <priikone@silcnet.org>
Wed, 22 Nov 2000 21:17:43 +0000 (21:17 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 22 Nov 2000 21:17:43 +0000 (21:17 +0000)
packet_receive.[ch].

apps/silcd/packet_receive.c [new file with mode: 0644]
apps/silcd/packet_receive.h [new file with mode: 0644]
apps/silcd/packet_send.c [new file with mode: 0644]
apps/silcd/packet_send.h [new file with mode: 0644]
apps/silcd/server.c
apps/silcd/server.h

diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c
new file mode 100644 (file)
index 0000000..65a60a7
--- /dev/null
@@ -0,0 +1,1005 @@
+/*
+
+  packet_receive.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Server packet routines to handle received packets.
+ */
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+extern char *server_version;
+
+/* Received private message. This resolves the destination of the message 
+   and sends the packet. This is used by both server and router.  If the
+   destination is our locally connected client this sends the packet to
+   the client. This may also send the message for further routing if
+   the destination is not in our server (or router). */
+
+void silc_server_private_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcClientID *id;
+  SilcServerEntry router;
+  SilcSocketConnection dst_sock;
+  SilcClientEntry client;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!packet->dst_id) {
+    SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped"));
+    goto err;
+  }
+
+  /* Decode destination Client ID */
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+  if (!id) {
+    SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+    goto err;
+  }
+
+  /* If the destination belongs to our server we don't have to route
+     the message anywhere but to send it to the local destination. */
+  client = silc_idlist_find_client_by_id(server->local_list, id);
+  if (client) {
+    /* It exists, now deliver the message to the destination */
+    dst_sock = (SilcSocketConnection)client->connection;
+
+    /* If we are router and the client has router then the client is in
+       our cell but not directly connected to us. */
+    if (server->server_type == SILC_ROUTER && client->router) {
+      /* We are of course in this case the client's router thus the real
+        "router" of the client is the server who owns the client. Thus
+        we will send the packet to that server. */
+      router = (SilcServerEntry)dst_sock->user_data;
+      idata = (SilcIDListData)router;
+      //      assert(client->router == server->id_entry);
+
+      silc_server_send_private_message(server, dst_sock,
+                                      idata->send_key,
+                                      idata->hmac,
+                                      packet);
+      return;
+    }
+
+    /* Seems that client really is directly connected to us */
+    idata = (SilcIDListData)client;
+    silc_server_send_private_message(server, dst_sock, 
+                                    idata->send_key,
+                                    idata->hmac, packet);
+    return;
+  }
+
+  /* Destination belongs to someone not in this server. If we are normal
+     server our action is to send the packet to our router. */
+  if (server->server_type == SILC_SERVER && !server->standalone) {
+    router = server->router;
+
+    /* Send to primary route */
+    if (router) {
+      dst_sock = (SilcSocketConnection)router->connection;
+      idata = (SilcIDListData)router;
+      silc_server_send_private_message(server, dst_sock, 
+                                      idata->send_key,
+                                      idata->hmac, packet);
+    }
+    return;
+  }
+
+  /* We are router and we will perform route lookup for the destination 
+     and send the message to fastest route. */
+  if (server->server_type == SILC_ROUTER && !server->standalone) {
+    dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT);
+    router = (SilcServerEntry)dst_sock->user_data;
+    idata = (SilcIDListData)router;
+
+    /* Get fastest route and send packet. */
+    if (router)
+      silc_server_send_private_message(server, dst_sock, 
+                                      idata->send_key,
+                                      idata->hmac, packet);
+    return;
+  }
+
+ err:
+  silc_server_send_error(server, sock, 
+                        "No such nickname: Private message not sent");
+}
+
+/* Relays received command reply packet to the correct destination. The
+   destination must be one of our locally connected client or the packet
+   will be ignored. This is called when server has forwarded one of
+   client's command request to router and router has now replied to the 
+   command. */
+
+void silc_server_packet_relay_command_reply(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientEntry client;
+  SilcClientID *id;
+  SilcSocketConnection dst_sock;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Source must be server or router */
+  if (packet->src_id_type != SILC_ID_SERVER &&
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
+    return;
+
+  /* Destination must be client */
+  if (packet->dst_id_type != SILC_ID_CLIENT)
+    return;
+
+  /* Execute command reply locally for the command */
+  silc_server_command_reply_process(server, sock, buffer);
+
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+
+  /* Destination must be one of ours */
+  client = silc_idlist_find_client_by_id(server->local_list, id);
+  if (!client) {
+    SILC_LOG_ERROR(("Cannot relay command reply to unknown client"));
+    silc_free(id);
+    return;
+  }
+
+  /* Relay the packet to the client */
+
+  dst_sock = (SilcSocketConnection)client->connection;
+  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
+
+  silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+  silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+  idata = (SilcIDListData)client;
+
+  /* Encrypt packet */
+  silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, 
+                     buffer->len);
+    
+  /* Send the packet */
+  silc_server_packet_send_real(server, dst_sock, TRUE);
+
+  silc_free(id);
+}
+
+/* Process received channel message. The message can be originated from
+   client or server. */
+
+void silc_server_channel_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcChannelEntry channel = NULL;
+  SilcChannelClientEntry chl;
+  SilcChannelID *id = NULL;
+  void *sender = NULL;
+
+  SILC_LOG_DEBUG(("Processing channel message"));
+
+  /* Sanity checks */
+  if (packet->dst_id_type != SILC_ID_CHANNEL) {
+    SILC_LOG_ERROR(("Received bad message for channel, dropped"));
+    SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
+    goto out;
+  }
+
+  /* Find channel entry */
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  if (!channel) {
+    SILC_LOG_DEBUG(("Could not find channel"));
+    goto out;
+  }
+
+  /* See that this client is on the channel. If the message is coming
+     from router we won't do the check as the message is from client that
+     we don't know about. Also, if the original sender is not client
+     (as it can be server as well) we don't do the check. */
+  sender = silc_id_str2id(packet->src_id, packet->src_id_type);
+  if (sock->type != SILC_SOCKET_TYPE_ROUTER && 
+      packet->src_id_type == SILC_ID_CLIENT) {
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
+       break;
+    }
+    if (chl == SILC_LIST_END)
+      goto out;
+  }
+
+  /* Distribute the packet to our local clients. This will send the
+     packet for further routing as well, if needed. */
+  silc_server_packet_relay_to_channel(server, sock, channel, sender,
+                                     packet->src_id_type,
+                                     packet->buffer->data,
+                                     packet->buffer->len, FALSE);
+
+ out:
+  if (sender)
+    silc_free(sender);
+  if (id)
+    silc_free(id);
+}
+
+/* Received channel key packet. We distribute the key to all of our locally
+   connected clients on the channel. */
+/* XXX Router must accept this packet and distribute the key to all its
+   server that has clients on the channel */
+
+void silc_server_channel_key(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcChannelKeyPayload payload = NULL;
+  SilcChannelID *id = NULL;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  unsigned char *tmp;
+  unsigned int tmp_len;
+  char *cipher;
+
+  if (packet->src_id_type != SILC_ID_SERVER &&
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
+    goto out;
+
+  /* Decode channel key payload */
+  payload = silc_channel_key_payload_parse(buffer);
+  if (!payload) {
+    SILC_LOG_ERROR(("Bad channel key payload, dropped"));
+    goto out;
+  }
+
+  /* Get channel ID */
+  tmp = silc_channel_key_get_id(payload, &tmp_len);
+  id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!id)
+    goto out;
+
+  /* Get the channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  if (!channel) {
+    SILC_LOG_ERROR(("Received key for non-existent channel"));
+    goto out;
+  }
+
+  /* Save the key for us as well */
+  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;
+  if (!silc_cipher_alloc(cipher, &channel->channel_key))
+    goto out;
+
+  /* Distribute the key to all clients on the channel */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    silc_server_packet_send(server, chl->client->connection,
+                           SILC_PACKET_CHANNEL_KEY, 0,
+                           buffer->data, buffer->len, TRUE);
+  }
+
+  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, 
+                                       tmp, tmp_len);
+ out:
+  if (id)
+    silc_free(id);
+  if (payload)
+    silc_channel_key_payload_free(payload);
+}
+
+/* Received packet to replace a ID. This checks that the requested ID
+   exists and replaces it with the new one. */
+
+void silc_server_replace_id(SilcServer server,
+                           SilcSocketConnection sock,
+                           SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  unsigned char *old_id = NULL, *new_id = NULL;
+  SilcIdType old_id_type, new_id_type;
+  unsigned short old_id_len, new_id_len;
+  void *id = NULL, *id2 = NULL;
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type == SILC_ID_CLIENT)
+    return;
+
+  SILC_LOG_DEBUG(("Replacing ID"));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&old_id_type),
+                      SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len),
+                      SILC_STR_UI_SHORT(&new_id_type),
+                      SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len),
+                      SILC_STR_END);
+
+  if (old_id_type != new_id_type)
+    goto out;
+
+  if (old_id_len != silc_id_get_len(old_id_type) ||
+      new_id_len != silc_id_get_len(new_id_type))
+    goto out;
+
+  id = silc_id_str2id(old_id, old_id_type);
+  if (!id)
+    goto out;
+
+  id2 = silc_id_str2id(new_id, new_id_type);
+  if (!id2)
+    goto out;
+
+  /* If we are router and this packet is not already broadcast packet
+     we will broadcast it. The sending socket really cannot be router or
+     the router is buggy. If this packet is coming from router then it must
+     have the broadcast flag set already and we won't do anything. */
+  if (server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+    SILC_LOG_DEBUG(("Broadcasting received Replace ID packet"));
+    silc_server_packet_send(server, server->router->connection, packet->type,
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+                           buffer->data, buffer->len, FALSE);
+  }
+
+  /* Replace the old ID */
+  switch(old_id_type) {
+  case SILC_ID_CLIENT:
+    if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL)
+      if (server->server_type == SILC_ROUTER)
+       silc_idlist_replace_client_id(server->global_list, id, id2);
+    break;
+
+  case SILC_ID_SERVER:
+    if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL)
+      if (server->server_type == SILC_ROUTER)
+       silc_idlist_replace_server_id(server->global_list, id, id2);
+    break;
+
+  case SILC_ID_CHANNEL:
+    /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be
+       re-generated. */
+    silc_free(id2);
+    break;
+
+  default:
+    silc_free(id2);
+    break;
+  }
+
+ out:
+  if (id)
+    silc_free(id);
+  if (old_id)
+    silc_free(old_id);
+  if (new_id)
+    silc_free(new_id);
+}
+
+
+/* Received New Client packet and processes it.  Creates Client ID for the
+   client. Client becomes registered after calling this functions. */
+
+SilcClientEntry silc_server_new_client(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientEntry client;
+  SilcIDCacheEntry cache;
+  SilcClientID *client_id;
+  SilcBuffer reply;
+  SilcIDListData idata;
+  char *username = NULL, *realname = NULL, *id_string;
+
+  SILC_LOG_DEBUG(("Creating new client"));
+
+  if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+    return NULL;
+
+  /* Take client entry */
+  client = (SilcClientEntry)sock->user_data;
+  idata = (SilcIDListData)client;
+
+  /* Fetch the old client cache entry so that we can update it. */
+  if (!silc_idcache_find_by_context(server->local_list->clients,
+                                   sock->user_data, &cache)) {
+    SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+    return NULL;
+  }
+
+  /* Parse incoming packet */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_STRING_ALLOC(&username),
+                      SILC_STR_UI16_STRING_ALLOC(&realname),
+                      SILC_STR_END);
+
+  /* Create Client ID */
+  silc_id_create_client_id(server->id, server->rng, server->md5hash,
+                          username, &client_id);
+
+  /* Update client entry */
+  idata->registered = TRUE;
+  client->nickname = strdup(username);
+  client->username = username;
+  client->userinfo = realname;
+  client->id = client_id;
+
+  /* Update the cache entry */
+  cache->id = (void *)client_id;
+  cache->type = SILC_ID_CLIENT;
+  cache->data = username;
+  silc_idcache_sort_by_data(server->local_list->clients);
+
+  /* Notify our router about new client on the SILC network */
+  if (!server->standalone)
+    silc_server_send_new_id(server, (SilcSocketConnection) 
+                           server->router->connection, 
+                           server->server_type == SILC_ROUTER ? TRUE : FALSE,
+                           client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+  
+  /* Send the new client ID to the client. */
+  id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
+  reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
+  silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
+  silc_buffer_format(reply,
+                    SILC_STR_UI_SHORT(SILC_ID_CLIENT),
+                    SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+                    SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+                    SILC_STR_END);
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0, 
+                         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,
+                         ("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",
+                          idata->send_key->cipher->name,
+                          idata->send_key->cipher->key_len));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your current nickname is %s",
+                          client->nickname));
+
+  /* Send motd */
+  silc_server_send_motd(server, sock);
+
+  return client;
+}
+
+/* Create new server. This processes received New Server packet and
+   saves the received Server ID. The server is our locally connected
+   server thus we save all the information and save it to local list. 
+   This funtion can be used by both normal server and router server.
+   If normal server uses this it means that its router has connected
+   to the server. If router uses this it means that one of the cell's
+   servers is connected to the router. */
+
+SilcServerEntry silc_server_new_server(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcServerEntry new_server;
+  SilcIDCacheEntry cache;
+  SilcServerID *server_id;
+  SilcIDListData idata;
+  unsigned char *server_name, *id_string;
+  unsigned short id_len;
+
+  SILC_LOG_DEBUG(("Creating new server"));
+
+  if (sock->type != SILC_SOCKET_TYPE_SERVER &&
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
+    return NULL;
+
+  /* Take server entry */
+  new_server = (SilcServerEntry)sock->user_data;
+  idata = (SilcIDListData)new_server;
+
+  /* Fetch the old server cache entry so that we can update it. */
+  if (!silc_idcache_find_by_context(server->local_list->servers,
+                                   sock->user_data, &cache)) {
+    SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
+    return NULL;
+  }
+
+  /* Parse the incoming packet */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_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);
+  silc_free(id_string);
+
+  /* Update client entry */
+  idata->registered = TRUE;
+  new_server->server_name = server_name;
+  new_server->id = server_id;
+
+  /* Update the cache entry */
+  cache->id = (void *)server_id;
+  cache->type = SILC_ID_SERVER;
+  cache->data = server_name;
+  silc_idcache_sort_by_data(server->local_list->servers);
+
+  /* Distribute the information about new server in the SILC network
+     to our router. If we are normal server we won't send anything
+     since this connection must be our router connection. */
+  if (server->server_type == SILC_ROUTER && !server->standalone &&
+      server->router->connection != sock)
+    silc_server_send_new_id(server, server->router->connection,
+                           TRUE, new_server->id, SILC_ID_SERVER, 
+                           SILC_ID_SERVER_LEN);
+
+  return new_server;
+}
+
+/* Processes incoming New ID packet. New ID Payload is used to distribute
+   information about newly registered clients, servers and created 
+   channels. */
+
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+                       SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcIDList id_list;
+  SilcServerEntry tmpserver, router;
+  SilcSocketConnection router_sock;
+  SilcIDPayload idp;
+  SilcIdType id_type;
+  void *id, *tmpid;
+
+  SILC_LOG_DEBUG(("Processing new ID"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      server->server_type == SILC_SERVER ||
+      packet->src_id_type != SILC_ID_SERVER)
+    return;
+
+  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_payload_get_id(idp);
+  if (!id)
+    goto out;
+
+  /* If the sender of this packet is server and we are router we need to
+     broadcast this packet to other routers in the network. */
+  if (!server->standalone && server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+    SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
+    silc_server_packet_send(server, server->router->connection,
+                           packet->type, 
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                           buffer->data, buffer->len, FALSE);
+  }
+
+  /* If the packet is originated from the one who sent it to us we know
+     that the ID belongs to our cell, unless the sender was router. */
+  tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
+  tmpserver = (SilcServerEntry)sock->user_data;
+
+  if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
+      sock->type == SILC_SOCKET_TYPE_SERVER) {
+    id_list = server->local_list;
+    router_sock = sock;
+    router = sock->user_data;
+    /*    router = server->id_entry; */
+  } else {
+    id_list = server->global_list;
+    router_sock = (SilcSocketConnection)server->router->connection;
+    router = server->router;
+  }
+
+  silc_free(tmpid);
+
+  switch(id_type) {
+  case SILC_ID_CLIENT:
+    {
+      SilcClientEntry idlist;
+
+      SILC_LOG_DEBUG(("New client id(%s) from [%s] %s",
+                     silc_id_render(id, SILC_ID_CLIENT),
+                     sock->type == SILC_SOCKET_TYPE_SERVER ?
+                     "Server" : "Router", sock->hostname));
+
+      /* Add the client to our local list. We are router and we keep
+        cell specific local database of all clients in the cell. */
+      idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+                                     id, router, router_sock);
+    }
+    break;
+
+  case SILC_ID_SERVER:
+    {
+      SilcServerEntry idlist;
+
+      SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
+                     silc_id_render(id, SILC_ID_SERVER),
+                     sock->type == SILC_SOCKET_TYPE_SERVER ?
+                     "Server" : "Router", sock->hostname));
+
+      /* Add the server to our local list. We are router and we keep
+        cell specific local database of all servers in the cell. */
+      idlist = silc_idlist_add_server(id_list, NULL, 0, id, router, 
+                                     router_sock);
+    }
+    break;
+
+  case SILC_ID_CHANNEL:
+    SILC_LOG_ERROR(("Channel cannot be registered with NEW_ID packet"));
+#if 0
+    SILC_LOG_DEBUG(("New channel id(%s) from [%s] %s",
+                   silc_id_render(id, SILC_ID_CHANNEL),
+                   sock->type == SILC_SOCKET_TYPE_SERVER ?
+                   "Server" : "Router", sock->hostname));
+
+    /* Add the channel to our local list. We are router and we keep
+       cell specific local database of all channels in the cell. */
+    silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL);
+#endif
+    break;
+
+  default:
+    break;
+  }
+
+ out:
+  silc_id_payload_free(idp);
+}
+
+/* Received Remove Channel User packet to remove a user from a channel. 
+   Routers notify other routers that user has left a channel. Client must
+   not send this packet.. Normal server may send this packet but must not
+   receive it. */
+
+void silc_server_remove_channel_user(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  unsigned char *tmp1 = NULL, *tmp2 = NULL;
+  SilcClientID *client_id = NULL;
+  SilcChannelID *channel_id = NULL;
+  SilcChannelEntry channel;
+  SilcClientEntry client;
+
+  SILC_LOG_DEBUG(("Removing user from channel"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      server->server_type == SILC_SERVER)
+    return;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_STRING_ALLOC(&tmp1),
+                      SILC_STR_UI16_STRING_ALLOC(&tmp2),
+                      SILC_STR_END);
+
+  if (!tmp1 || !tmp2)
+    goto out;
+
+  client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT);
+  channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL);
+  if (!client_id || !channel_id)
+    goto out;
+
+  /* If we are router and this packet is not already broadcast packet
+     we will broadcast it. The sending socket really cannot be router or
+     the router is buggy. If this packet is coming from router then it must
+     have the broadcast flag set already and we won't do anything. */
+  if (!server->standalone && server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+    SILC_LOG_DEBUG(("Broadcasting received Remove Channel User packet"));
+    silc_server_packet_send(server, server->router->connection, packet->type,
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+                           buffer->data, buffer->len, FALSE);
+  }
+
+  /* XXX routers should check server->global_list as well */
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel)
+    goto out;
+  
+  /* XXX routers should check server->global_list as well */
+  /* Get client entry */
+  client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  if (!client)
+    goto out;
+
+  /* Remove from channel */
+  silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
+
+ out:
+  if (tmp1)
+    silc_free(tmp1);
+  if (tmp2)
+    silc_free(tmp2);
+  if (client_id)
+    silc_free(client_id);
+  if (channel_id)
+    silc_free(channel_id);
+}
+
+/* Received New Channel packet. Information about new channels in the 
+   network are distributed using this packet. Save the information about
+   the new channel. */
+
+void silc_server_new_channel(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet)
+{
+  unsigned char *id;
+  SilcChannelID *channel_id;
+  unsigned short channel_id_len;
+  char *channel_name;
+
+  SILC_LOG_DEBUG(("Processing New Channel"));
+
+  if (sock->type != SILC_SOCKET_TYPE_ROUTER ||
+      server->server_type == SILC_SERVER ||
+      packet->src_id_type != SILC_ID_SERVER)
+    return;
+
+  /* Parse payload */
+  if (!silc_buffer_unformat(packet->buffer, 
+                           SILC_STR_UI16_STRING_ALLOC(&channel_name),
+                           SILC_STR_UI16_NSTRING_ALLOC(&id, &channel_id_len),
+                           SILC_STR_END))
+    return;
+    
+  if (!channel_name || !id)
+    return;
+
+  /* Decode the channel ID */
+  channel_id = silc_id_str2id(id, SILC_ID_CHANNEL);
+  if (!channel_id)
+    return;
+  silc_free(id);
+
+  SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
+                 silc_id_render(channel_id, SILC_ID_CHANNEL), 
+                 sock->hostname));
+
+  /* Add the new channel. Add it always to global list since if we receive
+     this packet then it cannot be created by ourselves but some other 
+     router hence global channel. */
+  silc_idlist_add_channel(server->global_list, channel_name, 0, channel_id, 
+                         server->router->connection, NULL);
+}
+
+/* Received notify packet. Server can receive notify packets from router. 
+   Server then relays the notify messages to clients if needed. */
+
+void silc_server_notify(SilcServer server,
+                       SilcSocketConnection sock,
+                       SilcPacketContext *packet)
+{
+  SilcNotifyPayload payload;
+  SilcNotifyType type;
+  SilcArgumentPayload args;
+  int i;
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type != SILC_ID_SERVER)
+    return;
+
+  /* For now we expect that the we are normal server and that the
+     sender is router. Server could send (protocol allows it) notify to
+     router but we don't support it yet. XXX! */
+  if (server->server_type != SILC_SERVER &&
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
+    return;
+
+  payload = silc_notify_payload_parse(packet->buffer);
+  if (!payload)
+    return;
+
+  type = silc_notify_get_type(payload);
+  args = silc_notify_get_args(payload);
+  if (!args)
+    goto out;
+
+  switch(type) {
+  case SILC_NOTIFY_TYPE_JOIN:
+    break;
+
+  case SILC_NOTIFY_TYPE_LEAVE:
+    break;
+
+  case SILC_NOTIFY_TYPE_SIGNOFF:
+    break;
+
+    /* Ignore rest notify types for now */
+  case SILC_NOTIFY_TYPE_NONE:
+  case SILC_NOTIFY_TYPE_INVITE:
+  case SILC_NOTIFY_TYPE_TOPIC_SET:
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+  case SILC_NOTIFY_TYPE_MOTD:
+  default:
+    break;
+  }
+
+ out:
+  silc_notify_payload_free(payload);
+}
+
+/* Received new channel user packet. Information about new users on a
+   channel are distributed between routers using this packet.  The
+   router receiving this will redistribute it and also sent JOIN notify
+   to local clients on the same channel. Normal server sends JOIN notify
+   to its local clients on the channel. */
+
+void silc_server_new_channel_user(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet)
+{
+  unsigned char *tmpid1, *tmpid2;
+  SilcClientID *client_id = NULL;
+  SilcChannelID *channel_id = NULL;
+  unsigned short channel_id_len;
+  unsigned short client_id_len;
+  SilcClientEntry client;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcIDList id_list;
+  SilcServerEntry tmpserver, router;
+  SilcSocketConnection router_sock;
+  SilcBuffer clidp;
+  void *tmpid;
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      server->server_type != SILC_ROUTER ||
+      packet->src_id_type != SILC_ID_SERVER)
+    return;
+
+  /* Parse payload */
+  if (!silc_buffer_unformat(packet->buffer, 
+                           SILC_STR_UI16_NSTRING_ALLOC(&tmpid1, 
+                                                       &channel_id_len),
+                           SILC_STR_UI16_NSTRING_ALLOC(&tmpid2, 
+                                                       &client_id_len),
+                           SILC_STR_END))
+    return;
+
+  if (!tmpid1 || !tmpid2)
+    return;
+
+  /* Decode the channel ID */
+  channel_id = silc_id_str2id(tmpid1, SILC_ID_CHANNEL);
+  if (!channel_id)
+    goto out;
+
+  /* Decode the client ID */
+  client_id = silc_id_str2id(tmpid1, SILC_ID_CLIENT);
+  if (!client_id)
+    goto out;
+
+  /* If the packet is originated from the one who sent it to us we know
+     that the ID belongs to our cell, unless the sender was router. */
+  tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
+  tmpserver = (SilcServerEntry)sock->user_data;
+
+  if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
+      sock->type == SILC_SOCKET_TYPE_SERVER) {
+    id_list = server->local_list;
+    router_sock = sock;
+    router = sock->user_data;
+  } else {
+    id_list = server->global_list;
+    router_sock = (SilcSocketConnection)server->router->connection;
+    router = server->router;
+  }
+  silc_free(tmpid);
+
+  /* Find the channel */
+  channel = silc_idlist_find_channel_by_id(id_list, channel_id);
+  if (!channel) {
+    SILC_LOG_ERROR(("Received channel user for non-existent channel"));
+    goto out;
+  }
+
+  /* If we are router and this packet is not already broadcast packet
+     we will broadcast it. */
+  if (!server->standalone && server->server_type == SILC_ROUTER &&
+      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+    SILC_LOG_DEBUG(("Broadcasting received New Channel User packet"));
+    silc_server_packet_send(server, server->router->connection, packet->type,
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+                           packet->buffer->data, packet->buffer->len, FALSE);
+  }
+
+  /* Get client entry */
+  client = silc_idlist_find_client_by_id(id_list, client_id);
+  if (!client) {
+    /* This is new client to us, add entry to ID list */
+    client = silc_idlist_add_client(id_list, NULL, NULL, NULL, 
+                                   client_id, router, router_sock);
+    if (!client)
+      goto out;
+  }
+
+  /* Join the client to the channel by adding it to channel's user list.
+     Add also the channel to client entry's channels list for fast cross-
+     referencing. */
+  chl = silc_calloc(1, sizeof(*chl));
+  chl->client = client;
+  chl->channel = channel;
+  silc_list_add(channel->user_list, chl);
+  silc_list_add(client->channels, chl);
+
+  /* Send JOIN notify to local clients on the channel. As we are router
+     it is assured that this is sent only to our local clients and locally
+     connected servers if needed. */
+  clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+  silc_server_send_notify_to_channel(server, channel, TRUE,
+                                    SILC_NOTIFY_TYPE_JOIN, 
+                                    1, clidp->data, clidp->len);
+  silc_buffer_free(clidp);
+
+  client_id = NULL;
+
+ out:
+  if (client_id)
+    silc_free(client_id);
+  if (channel_id)
+    silc_free(channel_id);
+  silc_free(tmpid1);
+  silc_free(tmpid2);
+}
diff --git a/apps/silcd/packet_receive.h b/apps/silcd/packet_receive.h
new file mode 100644 (file)
index 0000000..710e88a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+
+  packet_receive.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef PACKET_RECEIVE_H
+#define PACKET_RECEIVE_H
+
+/* Prototypes */
+
+void silc_server_private_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet);
+void silc_server_packet_relay_command_reply(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           SilcPacketContext *packet);
+void silc_server_channel_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet);
+void silc_server_channel_key(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet);
+void silc_server_replace_id(SilcServer server,
+                           SilcSocketConnection sock,
+                           SilcPacketContext *packet);
+SilcClientEntry silc_server_new_client(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet);
+SilcServerEntry silc_server_new_server(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet);
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+                       SilcPacketContext *packet);
+void silc_server_remove_channel_user(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    SilcPacketContext *packet);
+void silc_server_new_channel(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet);
+void silc_server_notify(SilcServer server,
+                       SilcSocketConnection sock,
+                       SilcPacketContext *packet);
+void silc_server_new_channel_user(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet);
+
+#endif
diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c
new file mode 100644 (file)
index 0000000..3b72d89
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+
+  packet_send.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Server packet routines to send packets. 
+ */
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Routine that sends packet or marks packet to be sent. This is used
+   directly only in special cases. Normal cases should use
+   silc_server_packet_send. Returns < 0 error. */
+
+int silc_server_packet_send_real(SilcServer server,
+                                SilcSocketConnection sock,
+                                int force_send)
+{
+  int ret;
+
+  /* Send the packet */
+  ret = silc_packet_send(sock, force_send);
+  if (ret != -2)
+    return ret;
+
+  /* Mark that there is some outgoing data available for this connection. 
+     This call sets the connection both for input and output (the input
+     is set always and this call keeps the input setting, actually). 
+     Actual data sending is performed by silc_server_packet_process. */
+  SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+  /* Mark to socket that data is pending in outgoing buffer. This flag
+     is needed if new data is added to the buffer before the earlier
+     put data is sent to the network. */
+  SILC_SET_OUTBUF_PENDING(sock);
+
+  return 0;
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+   send the packet but creates the packet and fills the outgoing data
+   buffer and marks the packet ready to be sent to network. However, If 
+   argument force_send is TRUE the packet is sent immediately and not put 
+   to queue. Normal case is that the packet is not sent immediately. */
+
+void silc_server_packet_send(SilcServer server,
+                            SilcSocketConnection sock, 
+                            SilcPacketType type, 
+                            SilcPacketFlags flags,
+                            unsigned char *data, 
+                            unsigned int data_len,
+                            int force_send)
+{
+  void *dst_id = NULL;
+  SilcIdType dst_id_type = SILC_ID_NONE;
+
+  if (!sock)
+    return;
+
+  /* Get data used in the packet sending, keys and stuff */
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    dst_id = ((SilcClientEntry)sock->user_data)->id;
+    dst_id_type = SILC_ID_CLIENT;
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    dst_id = ((SilcServerEntry)sock->user_data)->id;
+    dst_id_type = SILC_ID_SERVER;
+    break;
+  default:
+    break;
+  }
+
+  silc_server_packet_send_dest(server, sock, type, flags, dst_id,
+                              dst_id_type, data, data_len, force_send);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+   send the packet but creates the packet and fills the outgoing data
+   buffer and marks the packet ready to be sent to network. However, If 
+   argument force_send is TRUE the packet is sent immediately and not put 
+   to queue. Normal case is that the packet is not sent immediately. 
+   Destination information is sent as argument for this function. */
+
+void silc_server_packet_send_dest(SilcServer server,
+                                 SilcSocketConnection sock, 
+                                 SilcPacketType type, 
+                                 SilcPacketFlags flags,
+                                 void *dst_id,
+                                 SilcIdType dst_id_type,
+                                 unsigned char *data, 
+                                 unsigned int data_len,
+                                 int force_send)
+{
+  SilcPacketContext packetdata;
+  SilcIDListData idata;
+  SilcCipher cipher = NULL;
+  SilcHmac hmac = NULL;
+  unsigned char *dst_id_data = NULL;
+  unsigned int dst_id_len = 0;
+
+  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+  /* Get data used in the packet sending, keys and stuff */
+  idata = (SilcIDListData)sock->user_data;
+
+  if (dst_id) {
+    dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+    dst_id_len = silc_id_get_len(dst_id_type);
+  }
+
+  /* Set the packet context pointers */
+  packetdata.type = type;
+  packetdata.flags = flags;
+  packetdata.src_id = silc_id_id2str(server->id, server->id_type);
+  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_type = server->id_type;
+  packetdata.dst_id = dst_id_data;
+  packetdata.dst_id_len = dst_id_len;
+  packetdata.dst_id_type = dst_id_type;
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.rng = server->rng;
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packetdata.src_id_len + 
+                          packetdata.dst_id_len,
+                          packetdata.padlen,
+                          data_len);
+
+  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Put the data to the buffer */
+  if (data && data_len)
+    silc_buffer_put(sock->outbuf, data, data_len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac;
+  }
+
+  /* Encrypt the packet */
+  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+
+  if (packetdata.src_id)
+    silc_free(packetdata.src_id);
+  if (packetdata.dst_id)
+    silc_free(packetdata.dst_id);
+}
+
+/* Forwards packet. Packets sent with this function will be marked as
+   forwarded (in the SILC header flags) so that the receiver knows that
+   we have forwarded the packet to it. Forwarded packets are handled
+   specially by the receiver as they are not destined to the receiver
+   originally. However, the receiver knows this because the forwarded
+   flag has been set (and the flag is authenticated). */
+
+void silc_server_packet_forward(SilcServer server,
+                               SilcSocketConnection sock,
+                               unsigned char *data, unsigned int data_len,
+                               int force_send)
+{
+  SilcIDListData idata;
+  SilcCipher cipher = NULL;
+  SilcHmac hmac = NULL;
+
+  SILC_LOG_DEBUG(("Forwarding packet"));
+
+  /* Get data used in the packet sending, keys and stuff */
+  idata = (SilcIDListData)sock->user_data;
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 0, 0, data_len);
+
+  /* Put the data to the buffer */
+  if (data && data_len)
+    silc_buffer_put(sock->outbuf, data, data_len);
+
+  /* Add the FORWARDED flag to packet flags */
+  sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
+
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac;
+  }
+
+  /* Encrypt the packet */
+  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+  SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* Broadcast received packet to our primary route. This function is used
+   by router to further route received broadcast packet. It is expected
+   that the broadcast flag from the packet is checked before calling this
+   function. This does not test or set the broadcast flag. */
+
+void silc_server_packet_broadcast(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcIDListData idata;
+  void *id;
+
+  SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
+
+  /* If the packet is originated from our primary route we are
+     not allowed to send the packet. */
+  id = silc_id_str2id(packet->src_id, packet->src_id_type);
+  if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
+    idata = (SilcIDListData)sock->user_data;
+
+    silc_buffer_push(buffer, buffer->data - buffer->head);
+    silc_packet_send_prepare(sock, 0, 0, buffer->len); 
+    silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+    silc_packet_encrypt(idata->send_key, idata->hmac, 
+                       sock->outbuf, sock->outbuf->len);
+
+    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
+                    sock->outbuf->data, sock->outbuf->len);
+
+    /* Now actually send the packet */
+    silc_server_packet_send_real(server, sock, TRUE);
+    silc_free(id);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
+                 "original sender of this packet"));
+  silc_free(id);
+}
+
+/* Internal routine to actually create the channel packet and send it
+   to network. This is common function in channel message sending. If
+   `channel_message' is TRUE this encrypts the message as it is strictly
+   a channel message. If FALSE normal encryption process is used. */
+
+static void
+silc_server_packet_send_to_channel_real(SilcServer server,
+                                       SilcSocketConnection sock,
+                                       SilcPacketContext *packet,
+                                       SilcCipher cipher,
+                                       SilcHmac hmac,
+                                       unsigned char *data,
+                                       unsigned int data_len,
+                                       int channel_message,
+                                       int force_send)
+{
+  packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packet->src_id_len + packet->dst_id_len;
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packet->src_id_len + 
+                          packet->dst_id_len,
+                          packet->padlen,
+                          data_len);
+
+  packet->buffer = sock->outbuf;
+
+  /* Put the data to buffer, assemble and encrypt the packet. The packet
+     is encrypted with normal session key shared with the client. */
+  silc_buffer_put(sock->outbuf, data, data_len);
+  silc_packet_assemble(packet);
+  if (channel_message)
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                       packet->src_id_len + packet->dst_id_len +
+                       packet->padlen);
+  else
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+    
+  SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* This routine is used by the server to send packets to channel. The 
+   packet sent with this function is distributed to all clients on
+   the channel. Usually this is used to send notify messages to the
+   channel, things like notify about new user joining to the channel. 
+   If `route' is FALSE then the packet is sent only locally and will not
+   be routed anywhere. */
+
+void silc_server_packet_send_to_channel(SilcServer server,
+                                       SilcChannelEntry channel,
+                                       SilcPacketType type,
+                                       unsigned char route,
+                                       unsigned char *data,
+                                       unsigned int data_len,
+                                       int force_send)
+{
+  SilcSocketConnection sock = NULL;
+  SilcPacketContext packetdata;
+  SilcClientEntry client = NULL;
+  SilcServerEntry *routed = NULL;
+  SilcChannelClientEntry chl;
+  SilcIDListData idata;
+  unsigned int routed_count = 0;
+
+  /* This doesn't send channel message packets */
+  if (type == SILC_PACKET_CHANNEL_MESSAGE)
+    return;
+  
+  SILC_LOG_DEBUG(("Sending packet to channel"));
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = type;
+  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_type = SILC_ID_SERVER;
+  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_type = SILC_ID_CHANNEL;
+  packetdata.rng = server->rng;
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+  /* If there are global users in the channel we will send the message
+     first to our router for further routing. */
+  if (route && server->server_type == SILC_SERVER && !server->standalone &&
+      channel->global_users) {
+    SilcServerEntry router;
+
+    /* Get data used in packet header encryption, keys and stuff. */
+    router = server->router;
+    sock = (SilcSocketConnection)router->connection;
+    idata = (SilcIDListData)router;
+    
+    SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+
+    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                           idata->send_key, idata->hmac, 
+                                           data, data_len, FALSE, force_send);
+  }
+
+  /* Send the message to clients on the channel's client list. */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
+
+    /* If client has router set it is not locally connected client and
+       we will route the message to the router set in the client. */
+    if (route && client && client->router && 
+       server->server_type == SILC_ROUTER) {
+      int k;
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       continue;
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->router->connection;
+      idata = (SilcIDListData)client->router;
+
+      /* Send the packet */
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             idata->send_key, idata->hmac, 
+                                             data, data_len, FALSE, 
+                                             force_send);
+
+      /* We want to make sure that the packet is routed to same router
+        only once. Mark this route as sent route. */
+      k = routed_count;
+      routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+      routed[k] = client->router;
+      routed_count++;
+
+      continue;
+    }
+
+    /* Send to locally connected client */
+    if (client) {
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->connection;
+      idata = (SilcIDListData)client;
+
+      /* Send the packet */
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             idata->send_key, idata->hmac, 
+                                             data, data_len, FALSE, 
+                                             force_send);
+    }
+  }
+
+  if (routed_count)
+    silc_free(routed);
+  silc_free(packetdata.src_id);
+  silc_free(packetdata.dst_id);
+}
+
+/* This routine is explicitly used to relay messages to some channel.
+   Packets sent with this function we have received earlier and are
+   totally encrypted. This just sends the packet to all clients on
+   the channel. If the sender of the packet is someone on the channel 
+   the message will not be sent to that client. The SILC Packet header
+   is encrypted with the session key shared between us and the client.
+   MAC is also computed before encrypting the header. Rest of the
+   packet will be untouched. */
+
+void silc_server_packet_relay_to_channel(SilcServer server,
+                                        SilcSocketConnection sender_sock,
+                                        SilcChannelEntry channel,
+                                        void *sender, 
+                                        SilcIdType sender_type,
+                                        unsigned char *data,
+                                        unsigned int data_len,
+                                        int force_send)
+{
+  int found = FALSE;
+  SilcSocketConnection sock = NULL;
+  SilcPacketContext packetdata;
+  SilcClientEntry client = NULL;
+  SilcServerEntry *routed = NULL;
+  SilcChannelClientEntry chl;
+  unsigned int routed_count = 0;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Relaying packet to channel"));
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+  packetdata.src_id = silc_id_id2str(sender, sender_type);
+  packetdata.src_id_len = silc_id_get_len(sender_type);
+  packetdata.src_id_type = sender_type;
+  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_type = SILC_ID_CHANNEL;
+  packetdata.rng = server->rng;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* If there are global users in the channel we will send the message
+     first to our router for further routing. */
+  if (server->server_type == SILC_SERVER && !server->standalone &&
+      channel->global_users) {
+    SilcServerEntry router;
+
+    router = server->router;
+
+    /* Check that the sender is not our router. */
+    if (sender_sock != (SilcSocketConnection)router->connection) {
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)router->connection;
+      idata = (SilcIDListData)router;
+
+      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             idata->send_key, idata->hmac, 
+                                             data, data_len, TRUE, 
+                                             force_send);
+    }
+  }
+
+  /* Send the message to clients on the channel's client list. */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
+
+    if (client) {
+
+      /* If sender is one on the channel do not send it the packet. */
+      if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+       found = TRUE;
+       continue;
+      }
+
+      /* If the client has set router it means that it is not locally
+        connected client and we will route the packet further. */
+      if (server->server_type == SILC_ROUTER && client->router) {
+       int k;
+
+       /* Sender maybe server as well so we want to make sure that
+          we won't send the message to the server it came from. */
+       if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
+         found = TRUE;
+         continue;
+       }
+
+       /* Check if we have sent the packet to this route already */
+       for (k = 0; k < routed_count; k++)
+         if (routed[k] == client->router)
+           break;
+       if (k < routed_count)
+         continue;
+       
+       /* Get data used in packet header encryption, keys and stuff. */
+       sock = (SilcSocketConnection)client->router->connection;
+       idata = (SilcIDListData)client->router;
+
+       /* Send the packet */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               idata->send_key, idata->hmac, 
+                                               data, data_len, TRUE, 
+                                               force_send);
+       
+       /* We want to make sure that the packet is routed to same router
+          only once. Mark this route as sent route. */
+       k = routed_count;
+       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+       routed[k] = client->router;
+       routed_count++;
+       
+       continue;
+      }
+
+      /* XXX Check client's mode on the channel. */
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->connection;
+      idata = (SilcIDListData)client;
+
+      SILC_LOG_DEBUG(("Sending packet to client %s", 
+                     sock->hostname ? sock->hostname : sock->ip));
+
+      /* Send the packet */
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             idata->send_key, idata->hmac, 
+                                             data, data_len, TRUE, 
+                                             force_send);
+    }
+  }
+
+  silc_free(packetdata.src_id);
+  silc_free(packetdata.dst_id);
+}
+
+/* This function is used to send packets strictly to all local clients
+   on a particular channel.  This is used for example to distribute new
+   channel key to all our locally connected clients on the channel. 
+   The packets are always encrypted with the session key shared between
+   the client, this means these are not _to the channel_ but _to the client_
+   on the channel. */
+
+void silc_server_packet_send_local_channel(SilcServer server,
+                                          SilcChannelEntry channel,
+                                          SilcPacketType type,
+                                          SilcPacketFlags flags,
+                                          unsigned char *data,
+                                          unsigned int data_len,
+                                          int force_send)
+{
+  SilcClientEntry client;
+  SilcChannelClientEntry chl;
+  SilcSocketConnection sock = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Send the message to clients on the channel's client list. */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
+
+    if (client) {
+      sock = (SilcSocketConnection)client->connection;
+
+      /* Send the packet to the client */
+      silc_server_packet_send_dest(server, sock, type, flags, client->id,
+                                  SILC_ID_CLIENT, data, data_len,
+                                  force_send);
+    }
+  }
+}
+
+/* Routine used to send (relay, route) private messages to some destination.
+   If the private message key does not exist then the message is re-encrypted,
+   otherwise we just pass it along. This really is not used to send new
+   private messages (as server does not send them) but to relay received
+   private messages. */
+
+void silc_server_send_private_message(SilcServer server,
+                                     SilcSocketConnection dst_sock,
+                                     SilcCipher cipher,
+                                     SilcHmac hmac,
+                                     SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+
+  /* Send and re-encrypt if private messge key does not exist */
+  if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    
+    /* Re-encrypt packet */
+    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
+    
+    /* Send the packet */
+    silc_server_packet_send_real(server, dst_sock, FALSE);
+
+  } else {
+    /* Key exist so just send it */
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    silc_server_packet_send_real(server, dst_sock, FALSE);
+  }
+}
+
+/* Sends current motd to client */
+
+void silc_server_send_motd(SilcServer server,
+                          SilcSocketConnection sock)
+{
+  char *motd;
+  int motd_len;
+
+  if (server->config && server->config->motd && 
+      server->config->motd->motd_file) {
+
+    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+    if (!motd)
+      return;
+
+    silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+                           motd, motd_len);
+    silc_free(motd);
+  }
+}
+
+/* Sends error message. Error messages may or may not have any 
+   implications. */
+
+void silc_server_send_error(SilcServer server,
+                           SilcSocketConnection sock,
+                           const char *fmt, ...)
+{
+  va_list ap;
+  unsigned char buf[4096];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  va_end(ap);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, 
+                         buf, strlen(buf), FALSE);
+}
+
+/* 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, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+
+  va_start(ap, argc);
+
+  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);
+}
+
+/* Sends notify message destined to specific entity. */
+
+void silc_server_send_notify_dest(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 void *dest_id,
+                                 SilcIdType dest_id_type,
+                                 SilcNotifyType type,
+                                 unsigned int argc, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+
+  va_start(ap, argc);
+
+  packet = silc_notify_payload_encode(type, argc, ap);
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, 
+                              dest_id, dest_id_type,
+                              packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+}
+
+/* Sends notify message to a channel. The notify message sent is 
+   distributed to all clients on the channel. If `router_notify' is TRUE
+   then the notify may be routed to primary route or to some other routers.
+   If FALSE it is assured that the notify is sent only locally. */
+
+void silc_server_send_notify_to_channel(SilcServer server,
+                                       SilcChannelEntry channel,
+                                       unsigned char route_notify,
+                                       SilcNotifyType type,
+                                       unsigned int argc, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+
+  va_start(ap, argc);
+
+  packet = silc_notify_payload_encode(type, argc, ap);
+  silc_server_packet_send_to_channel(server, channel, 
+                                    SILC_PACKET_NOTIFY, route_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 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, chl2;
+  SilcIDListData idata;
+  SilcBuffer packet;
+  unsigned char *data;
+  unsigned int data_len;
+  int force_send = FALSE;
+  va_list ap;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!silc_list_count(client->channels))
+    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;
+
+  silc_list_start(client->channels);
+  while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
+    channel = chl->channel;
+
+    /* Send the message to all clients on the channel's client list. */
+    silc_list_start(channel->user_list);
+    while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      c = chl2->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;
+       idata = (SilcIDListData)c->router;
+       
+       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,
+                                               idata->send_key, idata->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;
+       idata = (SilcIDListData)c;
+       
+       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,
+                                               idata->send_key, idata->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. 
+   If the argument `broadcast' is TRUE then the packet is sent as
+   broadcast packet. */
+
+void silc_server_send_new_id(SilcServer server,
+                            SilcSocketConnection sock,
+                            int broadcast,
+                            void *id, SilcIdType id_type, 
+                            unsigned int id_len)
+{
+  SilcBuffer idp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  idp = silc_id_payload_encode(id, id_type);
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         idp->data, idp->len, FALSE);
+  silc_buffer_free(idp);
+}
+
+/* Sends Replace ID payload to remote end. This is used to replace old
+   ID with new ID sent in the packet.  This is called for example when
+   user changes nickname and we create new ID for the user.  If the 
+   argument `broadcast' is TRUE then the packet is sent as
+   broadcast packet. */
+/* XXX It would be expected that the new id is same type as the old
+   ID. :) */
+
+void silc_server_send_replace_id(SilcServer server,
+                                SilcSocketConnection sock,
+                                int broadcast,
+                                void *old_id, SilcIdType old_id_type,
+                                unsigned int old_id_len,
+                                void *new_id, SilcIdType new_id_type,
+                                unsigned int new_id_len)
+{
+  SilcBuffer packet;
+  unsigned char *oid;
+  unsigned char *nid;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  oid = silc_id_id2str(old_id, old_id_type);
+  if (!oid)
+    return;
+
+  nid = silc_id_id2str(new_id, new_id_type);
+  if (!nid)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(old_id_type),
+                    SILC_STR_UI_SHORT(old_id_len),
+                    SILC_STR_UI_XNSTRING(oid, old_id_len),
+                    SILC_STR_UI_SHORT(new_id_type),
+                    SILC_STR_UI_SHORT(new_id_len),
+                    SILC_STR_UI_XNSTRING(nid, new_id_len),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+  silc_free(oid);
+  silc_free(nid);
+  silc_buffer_free(packet);
+}
+
+/* This function is used to send Remove Channel User payload. This may sent
+   by server but is usually used only by router to notify other routers that
+   user has left a channel. Normal server sends this packet to its router
+   to notify that the router should not hold a record about this client
+   on a channel anymore. Router distributes it further to other routers. */
+
+void silc_server_send_remove_channel_user(SilcServer server,
+                                         SilcSocketConnection sock,
+                                         int broadcast,
+                                         void *client_id, void *channel_id)
+{
+  SilcBuffer packet;
+  unsigned char *clid, *chid;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
+  if (!clid)
+    return;
+
+  chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+  if (!chid)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+                    SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
+                    SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+                    SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+  silc_free(clid);
+  silc_free(chid);
+  silc_buffer_free(packet);
+}
+
+/* Send New Channel Payload to notify about newly created channel in the
+   SILC network. Normal server nevers sends this packet. Router uses this
+   to notify other routers in the network about new channel. This packet
+   is broadcasted. */
+
+void silc_server_send_new_channel(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 int broadcast,
+                                 char *channel_name,
+                                 void *channel_id, 
+                                 unsigned int channel_id_len)
+{
+  SilcBuffer packet;
+  unsigned char *cid;
+  unsigned int name_len = strlen(channel_name);
+
+  SILC_LOG_DEBUG(("Start"));
+
+  cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+  if (!cid)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + name_len + channel_id_len);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(name_len),
+                    SILC_STR_UI_XNSTRING(channel_name, name_len),
+                    SILC_STR_UI_SHORT(channel_id_len),
+                    SILC_STR_UI_XNSTRING(cid, channel_id_len),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+
+  silc_free(cid);
+  silc_buffer_free(packet);
+}
+
+/* Send New Channel User payload to notify routers in the network about new
+   user on the channel. The packet is may be broadcasted. Normal server
+   can send this but must not receive. Router can send and receive it. */
+
+void silc_server_send_new_channel_user(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      int broadcast,
+                                      void *channel_id, 
+                                      unsigned int channel_id_len,
+                                      void *client_id,
+                                      unsigned int client_id_len)
+{
+  SilcBuffer packet;
+  unsigned char *clid, *chid;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
+  if (!clid)
+    return;
+
+  chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+  if (!chid)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + channel_id_len + client_id_len);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(channel_id_len),
+                    SILC_STR_UI_XNSTRING(chid, channel_id_len),
+                    SILC_STR_UI_SHORT(client_id_len),
+                    SILC_STR_UI_XNSTRING(clid, client_id_len),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL_USER, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+  silc_free(clid);
+  silc_free(chid);
+  silc_buffer_free(packet);
+}
diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h
new file mode 100644 (file)
index 0000000..760095c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+
+  packet_send.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef PACKET_SEND_H
+#define PACKET_SEND_H
+
+/* Prototypes */
+
+int silc_server_packet_send_real(SilcServer server,
+                                SilcSocketConnection sock,
+                                int force_send);
+void silc_server_packet_send(SilcServer server,
+                            SilcSocketConnection sock, 
+                            SilcPacketType type, 
+                            SilcPacketFlags flags,
+                            unsigned char *data, 
+                            unsigned int data_len,
+                            int force_send);
+void silc_server_packet_send_dest(SilcServer server,
+                                 SilcSocketConnection sock, 
+                                 SilcPacketType type, 
+                                 SilcPacketFlags flags,
+                                 void *dst_id,
+                                 SilcIdType dst_id_type,
+                                 unsigned char *data, 
+                                 unsigned int data_len,
+                                 int force_send);
+void silc_server_packet_forward(SilcServer server,
+                               SilcSocketConnection sock,
+                               unsigned char *data, unsigned int data_len,
+                               int force_send);
+void silc_server_packet_broadcast(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet);
+void silc_server_packet_send_to_channel(SilcServer server,
+                                       SilcChannelEntry channel,
+                                       SilcPacketType type,
+                                       unsigned char route,
+                                       unsigned char *data,
+                                       unsigned int data_len,
+                                       int force_send);
+void silc_server_packet_relay_to_channel(SilcServer server,
+                                        SilcSocketConnection sender_sock,
+                                        SilcChannelEntry channel,
+                                        void *sender, 
+                                        SilcIdType sender_type,
+                                        unsigned char *data,
+                                        unsigned int data_len,
+                                        int force_send);
+void silc_server_packet_send_local_channel(SilcServer server,
+                                          SilcChannelEntry channel,
+                                          SilcPacketType type,
+                                          SilcPacketFlags flags,
+                                          unsigned char *data,
+                                          unsigned int data_len,
+                                          int force_send);
+void silc_server_send_private_message(SilcServer server,
+                                     SilcSocketConnection dst_sock,
+                                     SilcCipher cipher,
+                                     SilcHmac hmac,
+                                     SilcPacketContext *packet);
+void silc_server_send_motd(SilcServer server,
+                          SilcSocketConnection sock);
+void silc_server_send_error(SilcServer server,
+                           SilcSocketConnection sock,
+                           const char *fmt, ...);
+void silc_server_send_notify(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcNotifyType type,
+                            unsigned int argc, ...);
+void silc_server_send_notify_dest(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 void *dest_id,
+                                 SilcIdType dest_id_type,
+                                 SilcNotifyType type,
+                                 unsigned int argc, ...);
+void silc_server_send_notify_to_channel(SilcServer server,
+                                       SilcChannelEntry channel,
+                                       unsigned char route_notify,
+                                       SilcNotifyType type,
+                                       unsigned int argc, ...);
+void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry client,
+                                        SilcNotifyType type,
+                                        unsigned int argc, ...);
+void silc_server_send_new_id(SilcServer server,
+                            SilcSocketConnection sock,
+                            int broadcast,
+                            void *id, SilcIdType id_type, 
+                            unsigned int id_len);
+void silc_server_send_replace_id(SilcServer server,
+                                SilcSocketConnection sock,
+                                int broadcast,
+                                void *old_id, SilcIdType old_id_type,
+                                unsigned int old_id_len,
+                                void *new_id, SilcIdType new_id_type,
+                                unsigned int new_id_len);
+void silc_server_send_remove_channel_user(SilcServer server,
+                                         SilcSocketConnection sock,
+                                         int broadcast,
+                                         void *client_id, void *channel_id);
+void silc_server_send_new_channel(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 int broadcast,
+                                 char *channel_name,
+                                 void *channel_id, 
+                                 unsigned int channel_id_len);
+void silc_server_send_new_channel_user(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      int broadcast,
+                                      void *channel_id, 
+                                      unsigned int channel_id_len,
+                                      void *client_id,
+                                      unsigned int client_id_len);
+
+#endif
index f2b7e17ae987e992f237514f97591c3b6f7ef78d..b9336a86005434595008ff7d7ee939134526b0c1 100644 (file)
@@ -39,8 +39,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process);
 SILC_TASK_CALLBACK(silc_server_packet_parse_real);
 SILC_TASK_CALLBACK(silc_server_timeout_remote);
 
-extern char *server_version;
-
 /* Allocates a new SILC server object. This has to be done before the server
    can be used. After allocation one must call silc_server_init to initialize
    the server. The new allocated server object is returned to the new_server
@@ -1036,43 +1034,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   sock->protocol = NULL;
 }
 
-/* Internal routine that sends packet or marks packet to be sent. This
-   is used directly only in special cases. Normal cases should use
-   silc_server_packet_send. Returns < 0 error. */
-
-static int silc_server_packet_send_real(SilcServer server,
-                                       SilcSocketConnection sock,
-                                       int force_send)
-{
-  int ret;
-
-  /* Send the packet */
-  ret = silc_packet_send(sock, force_send);
-  if (ret != -2)
-    return ret;
-
-  /* Mark that there is some outgoing data available for this connection. 
-     This call sets the connection both for input and output (the input
-     is set always and this call keeps the input setting, actually). 
-     Actual data sending is performed by silc_server_packet_process. */
-  SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
-
-  /* Mark to socket that data is pending in outgoing buffer. This flag
-     is needed if new data is added to the buffer before the earlier
-     put data is sent to the network. */
-  SILC_SET_OUTBUF_PENDING(sock);
-
-  return 0;
-}
-
-typedef struct {
-  SilcPacketContext *packetdata;
-  SilcServer server;
-  SilcSocketConnection sock;
-  SilcCipher cipher;
-  SilcHmac hmac;
-} SilcServerInternalPacket;
-
 /* This function is used to read packets from network and send packets to
    network. This is usually a generic task. */
 
@@ -1294,9 +1255,11 @@ void silc_server_packet_parse_type(SilcServer server,
 
   case SILC_PACKET_NOTIFY:
     /*
-     * Received notify packet.
+     * Received notify packet. Server can receive notify packets from
+     * router. Server then relays the notify messages to clients if needed.
      */
     SILC_LOG_DEBUG(("Notify packet"));
+    silc_server_notify(server, sock, packet);
     break;
 
     /* 
@@ -1358,6 +1321,9 @@ void silc_server_packet_parse_type(SilcServer server,
     break;
 
   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+    /*
+     * XXX
+     */
     break;
 
     /*
@@ -1497,15 +1463,40 @@ void silc_server_packet_parse_type(SilcServer server,
     break;
 
   case SILC_PACKET_NEW_CHANNEL:
+    /*
+     * Received new channel packet. Information about new channel in the
+     * network are distributed using this packet.
+     */
+    SILC_LOG_DEBUG(("New Channel packet"));
+    silc_server_new_channel(server, sock, packet);
     break;
 
   case SILC_PACKET_NEW_CHANNEL_USER:
+    /*
+     * Received new channel user packet. Information about new users on a
+     * channel are distributed between routers using this packet.  The
+     * router receiving this will redistribute it and also sent JOIN notify
+     * to local clients on the same channel. Normal server sends JOIN notify
+     * to its local clients on the channel.
+     */
+    SILC_LOG_DEBUG(("New Channel User packet"));
+    silc_server_new_channel_user(server, sock, packet);
     break;
 
   case SILC_PACKET_NEW_CHANNEL_LIST:
+    /*
+     * List of new channel packets received. This is usually received when
+     * existing server or router connects to us and distributes information
+     * of all channels it has.
+     */
     break;
 
   case SILC_PACKET_NEW_CHANNEL_USER_LIST:
+    /*
+     * List of new channel user packets received. This is usually received
+     * when existing server or router connects to us and distributes 
+     * information of all channel users it has.
+     */
     break;
 
   case SILC_PACKET_REPLACE_ID:
@@ -1541,620 +1532,6 @@ void silc_server_packet_parse_type(SilcServer server,
   
 }
 
-/* Assembles a new packet to be sent out to network. This doesn't actually
-   send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If 
-   argument force_send is TRUE the packet is sent immediately and not put 
-   to queue. Normal case is that the packet is not sent immediately. */
-
-void silc_server_packet_send(SilcServer server,
-                            SilcSocketConnection sock, 
-                            SilcPacketType type, 
-                            SilcPacketFlags flags,
-                            unsigned char *data, 
-                            unsigned int data_len,
-                            int force_send)
-{
-  void *dst_id = NULL;
-  SilcIdType dst_id_type = SILC_ID_NONE;
-
-  if (!sock)
-    return;
-
-  /* Get data used in the packet sending, keys and stuff */
-  switch(sock->type) {
-  case SILC_SOCKET_TYPE_CLIENT:
-    dst_id = ((SilcClientEntry)sock->user_data)->id;
-    dst_id_type = SILC_ID_CLIENT;
-    break;
-  case SILC_SOCKET_TYPE_SERVER:
-  case SILC_SOCKET_TYPE_ROUTER:
-    dst_id = ((SilcServerEntry)sock->user_data)->id;
-    dst_id_type = SILC_ID_SERVER;
-    break;
-  default:
-    break;
-  }
-
-  silc_server_packet_send_dest(server, sock, type, flags, dst_id,
-                              dst_id_type, data, data_len, force_send);
-}
-
-/* Assembles a new packet to be sent out to network. This doesn't actually
-   send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If 
-   argument force_send is TRUE the packet is sent immediately and not put 
-   to queue. Normal case is that the packet is not sent immediately. 
-   Destination information is sent as argument for this function. */
-
-void silc_server_packet_send_dest(SilcServer server,
-                                 SilcSocketConnection sock, 
-                                 SilcPacketType type, 
-                                 SilcPacketFlags flags,
-                                 void *dst_id,
-                                 SilcIdType dst_id_type,
-                                 unsigned char *data, 
-                                 unsigned int data_len,
-                                 int force_send)
-{
-  SilcPacketContext packetdata;
-  SilcIDListData idata;
-  SilcCipher cipher = NULL;
-  SilcHmac hmac = NULL;
-  unsigned char *dst_id_data = NULL;
-  unsigned int dst_id_len = 0;
-
-  SILC_LOG_DEBUG(("Sending packet, type %d", type));
-
-  /* Get data used in the packet sending, keys and stuff */
-  idata = (SilcIDListData)sock->user_data;
-
-  if (dst_id) {
-    dst_id_data = silc_id_id2str(dst_id, dst_id_type);
-    dst_id_len = silc_id_get_len(dst_id_type);
-  }
-
-  /* Set the packet context pointers */
-  packetdata.type = type;
-  packetdata.flags = flags;
-  packetdata.src_id = silc_id_id2str(server->id, server->id_type);
-  packetdata.src_id_len = SILC_ID_SERVER_LEN;
-  packetdata.src_id_type = server->id_type;
-  packetdata.dst_id = dst_id_data;
-  packetdata.dst_id_len = dst_id_len;
-  packetdata.dst_id_type = dst_id_type;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-  packetdata.rng = server->rng;
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          data_len);
-
-  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the data to the buffer */
-  if (data && data_len)
-    silc_buffer_put(sock->outbuf, data, data_len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac;
-  }
-
-  /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, force_send);
-
-  if (packetdata.src_id)
-    silc_free(packetdata.src_id);
-  if (packetdata.dst_id)
-    silc_free(packetdata.dst_id);
-}
-
-/* Forwards packet. Packets sent with this function will be marked as
-   forwarded (in the SILC header flags) so that the receiver knows that
-   we have forwarded the packet to it. Forwarded packets are handled
-   specially by the receiver as they are not destined to the receiver
-   originally. However, the receiver knows this because the forwarded
-   flag has been set (and the flag is authenticated). */
-
-void silc_server_packet_forward(SilcServer server,
-                               SilcSocketConnection sock,
-                               unsigned char *data, unsigned int data_len,
-                               int force_send)
-{
-  SilcIDListData idata;
-  SilcCipher cipher = NULL;
-  SilcHmac hmac = NULL;
-
-  SILC_LOG_DEBUG(("Forwarding packet"));
-
-  /* Get data used in the packet sending, keys and stuff */
-  idata = (SilcIDListData)sock->user_data;
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 0, 0, data_len);
-
-  /* Put the data to the buffer */
-  if (data && data_len)
-    silc_buffer_put(sock->outbuf, data, data_len);
-
-  /* Add the FORWARDED flag to packet flags */
-  sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac;
-  }
-
-  /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-
-  SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, force_send);
-}
-
-/* Broadcast received packet to our primary route. This function is used
-   by router to further route received broadcast packet. It is expected
-   that the broadcast flag from the packet is checked before calling this
-   function. This does not test or set the broadcast flag. */
-
-void silc_server_packet_broadcast(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcIDListData idata;
-  void *id;
-
-  SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
-
-  /* If the packet is originated from our primary route we are
-     not allowed to send the packet. */
-  id = silc_id_str2id(packet->src_id, packet->src_id_type);
-  if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
-    idata = (SilcIDListData)sock->user_data;
-
-    silc_buffer_push(buffer, buffer->data - buffer->head);
-    silc_packet_send_prepare(sock, 0, 0, buffer->len); 
-    silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac, 
-                       sock->outbuf, sock->outbuf->len);
-
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
-                    sock->outbuf->data, sock->outbuf->len);
-
-    /* Now actually send the packet */
-    silc_server_packet_send_real(server, sock, TRUE);
-    silc_free(id);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
-                 "original sender of this packet"));
-  silc_free(id);
-}
-
-/* Internal routine to actually create the channel packet and send it
-   to network. This is common function in channel message sending. If
-   `channel_message' is TRUE this encrypts the message as it is strictly
-   a channel message. If FALSE normal encryption process is used. */
-
-static void
-silc_server_packet_send_to_channel_real(SilcServer server,
-                                       SilcSocketConnection sock,
-                                       SilcPacketContext *packet,
-                                       SilcCipher cipher,
-                                       SilcHmac hmac,
-                                       unsigned char *data,
-                                       unsigned int data_len,
-                                       int channel_message,
-                                       int force_send)
-{
-  packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packet->src_id_len + packet->dst_id_len;
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packet->src_id_len + 
-                          packet->dst_id_len,
-                          packet->padlen,
-                          data_len);
-
-  packet->buffer = sock->outbuf;
-
-  /* Put the data to buffer, assemble and encrypt the packet. The packet
-     is encrypted with normal session key shared with the client. */
-  silc_buffer_put(sock->outbuf, data, data_len);
-  silc_packet_assemble(packet);
-  if (channel_message)
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                       packet->src_id_len + packet->dst_id_len +
-                       packet->padlen);
-  else
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-    
-  SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, force_send);
-}
-
-/* This routine is used by the server to send packets to channel. The 
-   packet sent with this function is distributed to all clients on
-   the channel. Usually this is used to send notify messages to the
-   channel, things like notify about new user joining to the channel. */
-
-void silc_server_packet_send_to_channel(SilcServer server,
-                                       SilcChannelEntry channel,
-                                       SilcPacketType type,
-                                       unsigned char *data,
-                                       unsigned int data_len,
-                                       int force_send)
-{
-  SilcSocketConnection sock = NULL;
-  SilcPacketContext packetdata;
-  SilcClientEntry client = NULL;
-  SilcServerEntry *routed = NULL;
-  SilcChannelClientEntry chl;
-  SilcIDListData idata;
-  unsigned int routed_count = 0;
-
-  /* This doesn't send channel message packets */
-  if (type == SILC_PACKET_CHANNEL_MESSAGE)
-    return;
-  
-  SILC_LOG_DEBUG(("Sending packet to channel"));
-
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = type;
-  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packetdata.src_id_len = SILC_ID_SERVER_LEN;
-  packetdata.src_id_type = SILC_ID_SERVER;
-  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
-  packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.rng = server->rng;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
-  /* If there are global users in the channel we will send the message
-     first to our router for further routing. */
-  if (server->server_type == SILC_SERVER && !server->standalone &&
-      channel->global_users) {
-    SilcServerEntry router;
-
-    /* Get data used in packet header encryption, keys and stuff. */
-    router = server->router;
-    sock = (SilcSocketConnection)router->connection;
-    idata = (SilcIDListData)router;
-    
-    SILC_LOG_DEBUG(("Sending channel message to router for routing"));
-
-    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                           idata->send_key, idata->hmac, 
-                                           data, data_len, FALSE, force_send);
-  }
-
-  /* Send the message to clients on the channel's client list. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    client = chl->client;
-
-    /* If client has router set it is not locally connected client and
-       we will route the message to the router set in the client. */
-    if (client && client->router && server->server_type == SILC_ROUTER) {
-      int k;
-
-      /* Check if we have sent the packet to this route already */
-      for (k = 0; k < routed_count; k++)
-       if (routed[k] == client->router)
-         break;
-      if (k < routed_count)
-       continue;
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->router->connection;
-      idata = (SilcIDListData)client->router;
-
-      /* Send the packet */
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
-                                             data, data_len, FALSE, 
-                                             force_send);
-
-      /* We want to make sure that the packet is routed to same router
-        only once. Mark this route as sent route. */
-      k = routed_count;
-      routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
-      routed[k] = client->router;
-      routed_count++;
-
-      continue;
-    }
-
-    /* Send to locally connected client */
-    if (client) {
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->connection;
-      idata = (SilcIDListData)client;
-
-      /* Send the packet */
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
-                                             data, data_len, FALSE, 
-                                             force_send);
-    }
-  }
-
-  if (routed_count)
-    silc_free(routed);
-  silc_free(packetdata.src_id);
-  silc_free(packetdata.dst_id);
-}
-
-/* This routine is explicitly used to relay messages to some channel.
-   Packets sent with this function we have received earlier and are
-   totally encrypted. This just sends the packet to all clients on
-   the channel. If the sender of the packet is someone on the channel 
-   the message will not be sent to that client. The SILC Packet header
-   is encrypted with the session key shared between us and the client.
-   MAC is also computed before encrypting the header. Rest of the
-   packet will be untouched. */
-
-void silc_server_packet_relay_to_channel(SilcServer server,
-                                        SilcSocketConnection sender_sock,
-                                        SilcChannelEntry channel,
-                                        void *sender, 
-                                        SilcIdType sender_type,
-                                        unsigned char *data,
-                                        unsigned int data_len,
-                                        int force_send)
-{
-  int found = FALSE;
-  SilcSocketConnection sock = NULL;
-  SilcPacketContext packetdata;
-  SilcClientEntry client = NULL;
-  SilcServerEntry *routed = NULL;
-  SilcChannelClientEntry chl;
-  unsigned int routed_count = 0;
-  SilcIDListData idata;
-
-  SILC_LOG_DEBUG(("Relaying packet to channel"));
-
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
-  packetdata.src_id = silc_id_id2str(sender, sender_type);
-  packetdata.src_id_len = silc_id_get_len(sender_type);
-  packetdata.src_id_type = sender_type;
-  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
-  packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.rng = server->rng;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* If there are global users in the channel we will send the message
-     first to our router for further routing. */
-  if (server->server_type == SILC_SERVER && !server->standalone &&
-      channel->global_users) {
-    SilcServerEntry router;
-
-    router = server->router;
-
-    /* Check that the sender is not our router. */
-    if (sender_sock != (SilcSocketConnection)router->connection) {
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)router->connection;
-      idata = (SilcIDListData)router;
-
-      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
-
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
-                                             data, data_len, TRUE, 
-                                             force_send);
-    }
-  }
-
-  /* Send the message to clients on the channel's client list. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    client = chl->client;
-
-    if (client) {
-
-      /* If sender is one on the channel do not send it the packet. */
-      if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
-       found = TRUE;
-       continue;
-      }
-
-      /* If the client has set router it means that it is not locally
-        connected client and we will route the packet further. */
-      if (server->server_type == SILC_ROUTER && client->router) {
-       int k;
-
-       /* Sender maybe server as well so we want to make sure that
-          we won't send the message to the server it came from. */
-       if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
-         found = TRUE;
-         continue;
-       }
-
-       /* Check if we have sent the packet to this route already */
-       for (k = 0; k < routed_count; k++)
-         if (routed[k] == client->router)
-           break;
-       if (k < routed_count)
-         continue;
-       
-       /* Get data used in packet header encryption, keys and stuff. */
-       sock = (SilcSocketConnection)client->router->connection;
-       idata = (SilcIDListData)client->router;
-
-       /* Send the packet */
-       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
-                                               data, data_len, TRUE, 
-                                               force_send);
-       
-       /* We want to make sure that the packet is routed to same router
-          only once. Mark this route as sent route. */
-       k = routed_count;
-       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
-       routed[k] = client->router;
-       routed_count++;
-       
-       continue;
-      }
-
-      /* XXX Check client's mode on the channel. */
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->connection;
-      idata = (SilcIDListData)client;
-
-      SILC_LOG_DEBUG(("Sending packet to client %s", 
-                     sock->hostname ? sock->hostname : sock->ip));
-
-      /* Send the packet */
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
-                                             data, data_len, TRUE, 
-                                             force_send);
-    }
-  }
-
-  silc_free(packetdata.src_id);
-  silc_free(packetdata.dst_id);
-}
-
-/* This function is used to send packets strictly to all local clients
-   on a particular channel.  This is used for example to distribute new
-   channel key to all our locally connected clients on the channel. 
-   The packets are always encrypted with the session key shared between
-   the client, this means these are not _to the channel_ but _to the client_
-   on the channel. */
-
-void silc_server_packet_send_local_channel(SilcServer server,
-                                          SilcChannelEntry channel,
-                                          SilcPacketType type,
-                                          SilcPacketFlags flags,
-                                          unsigned char *data,
-                                          unsigned int data_len,
-                                          int force_send)
-{
-  SilcClientEntry client;
-  SilcChannelClientEntry chl;
-  SilcSocketConnection sock = NULL;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Send the message to clients on the channel's client list. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    client = chl->client;
-
-    if (client) {
-      sock = (SilcSocketConnection)client->connection;
-
-      /* Send the packet to the client */
-      silc_server_packet_send_dest(server, sock, type, flags, client->id,
-                                  SILC_ID_CLIENT, data, data_len,
-                                  force_send);
-    }
-  }
-}
-
-/* Relays received command reply packet to the correct destination. The
-   destination must be one of our locally connected client or the packet
-   will be ignored. This is called when server has forwarded one of
-   client's command request to router and router has now replied to the 
-   command. */
-
-void silc_server_packet_relay_command_reply(SilcServer server,
-                                           SilcSocketConnection sock,
-                                           SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcClientEntry client;
-  SilcClientID *id;
-  SilcSocketConnection dst_sock;
-  SilcIDListData idata;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Source must be server or router */
-  if (packet->src_id_type != SILC_ID_SERVER &&
-      sock->type != SILC_SOCKET_TYPE_ROUTER)
-    return;
-
-  /* Destination must be client */
-  if (packet->dst_id_type != SILC_ID_CLIENT)
-    return;
-
-  /* Execute command reply locally for the command */
-  silc_server_command_reply_process(server, sock, buffer);
-
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
-
-  /* Destination must be one of ours */
-  client = silc_idlist_find_client_by_id(server->local_list, id);
-  if (!client) {
-    SILC_LOG_ERROR(("Cannot relay command reply to unknown client"));
-    silc_free(id);
-    return;
-  }
-
-  /* Relay the packet to the client */
-
-  dst_sock = (SilcSocketConnection)client->connection;
-  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                  + packet->dst_id_len + packet->padlen);
-
-  silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-  silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-
-  idata = (SilcIDListData)client;
-
-  /* Encrypt packet */
-  silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, 
-                     buffer->len);
-    
-  /* Send the packet */
-  silc_server_packet_send_real(server, dst_sock, TRUE);
-
-  silc_free(id);
-}
-
 /* Closes connection to socket connection */
 
 void silc_server_close_connection(SilcServer server,
@@ -2285,7 +1662,7 @@ void silc_server_remove_from_channels(SilcServer server,
         channel globally from SILC network, in this case we will
         notify that this client has left the channel. */
       if (channel->global_users)
-       silc_server_send_notify_to_channel(server, channel,
+       silc_server_send_notify_to_channel(server, channel, TRUE,
                                           SILC_NOTIFY_TYPE_SIGNOFF, 1,
                                           clidp->data, clidp->len);
       
@@ -2299,7 +1676,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* Send notify to channel about client leaving SILC and thus
        the entire channel. */
-    silc_server_send_notify_to_channel(server, channel,
+    silc_server_send_notify_to_channel(server, channel, TRUE,
                                       SILC_NOTIFY_TYPE_SIGNOFF, 1,
                                       clidp->data, clidp->len);
     silc_buffer_free(chidp);
@@ -2346,7 +1723,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
       /* 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_server_send_notify_to_channel(server, channel, TRUE,
                                           SILC_NOTIFY_TYPE_LEAVE, 1,
                                           clidp->data, clidp->len);
       
@@ -2361,7 +1738,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
 
     /* Send notify to channel about client leaving the channel */
     if (notify)
-      silc_server_send_notify_to_channel(server, channel,
+      silc_server_send_notify_to_channel(server, channel, TRUE,
                                         SILC_NOTIFY_TYPE_LEAVE, 1,
                                         clidp->data, clidp->len);
     break;
@@ -2406,712 +1783,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
                                "Connection timeout");
 }
 
-/* Internal routine used to send (relay, route) private messages to some
-   destination. If the private message key does not exist then the message
-   is re-encrypted, otherwise we just pass it along. */
-
-static void 
-silc_server_private_message_send_internal(SilcServer server,
-                                         SilcSocketConnection dst_sock,
-                                         SilcCipher cipher,
-                                         SilcHmac hmac,
-                                         SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-
-  /* Send and re-encrypt if private messge key does not exist */
-  if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
-
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                    + packet->dst_id_len + packet->padlen);
-    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    
-    /* Re-encrypt packet */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
-    
-    /* Send the packet */
-    silc_server_packet_send_real(server, dst_sock, FALSE);
-
-  } else {
-    /* Key exist so just send it */
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                    + packet->dst_id_len + packet->padlen);
-    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    silc_server_packet_send_real(server, dst_sock, FALSE);
-  }
-}
-
-/* Received private message. This resolves the destination of the message 
-   and sends the packet. This is used by both server and router.  If the
-   destination is our locally connected client this sends the packet to
-   the client. This may also send the message for further routing if
-   the destination is not in our server (or router). */
-
-void silc_server_private_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
-{
-  SilcClientID *id;
-  SilcServerEntry router;
-  SilcSocketConnection dst_sock;
-  SilcClientEntry client;
-  SilcIDListData idata;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (!packet->dst_id) {
-    SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped"));
-    goto err;
-  }
-
-  /* Decode destination Client ID */
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
-  if (!id) {
-    SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
-    goto err;
-  }
-
-  /* If the destination belongs to our server we don't have to route
-     the message anywhere but to send it to the local destination. */
-  client = silc_idlist_find_client_by_id(server->local_list, id);
-  if (client) {
-    /* It exists, now deliver the message to the destination */
-    dst_sock = (SilcSocketConnection)client->connection;
-
-    /* If we are router and the client has router then the client is in
-       our cell but not directly connected to us. */
-    if (server->server_type == SILC_ROUTER && client->router) {
-      /* We are of course in this case the client's router thus the real
-        "router" of the client is the server who owns the client. Thus
-        we will send the packet to that server. */
-      router = (SilcServerEntry)dst_sock->user_data;
-      idata = (SilcIDListData)router;
-      //      assert(client->router == server->id_entry);
-
-      silc_server_private_message_send_internal(server, dst_sock,
-                                               idata->send_key,
-                                               idata->hmac,
-                                               packet);
-      return;
-    }
-
-    /* Seems that client really is directly connected to us */
-    idata = (SilcIDListData)client;
-    silc_server_private_message_send_internal(server, dst_sock, 
-                                             idata->send_key,
-                                             idata->hmac, packet);
-    return;
-  }
-
-  /* Destination belongs to someone not in this server. If we are normal
-     server our action is to send the packet to our router. */
-  if (server->server_type == SILC_SERVER && !server->standalone) {
-    router = server->router;
-
-    /* Send to primary route */
-    if (router) {
-      dst_sock = (SilcSocketConnection)router->connection;
-      idata = (SilcIDListData)router;
-      silc_server_private_message_send_internal(server, dst_sock, 
-                                               idata->send_key,
-                                               idata->hmac, packet);
-    }
-    return;
-  }
-
-  /* We are router and we will perform route lookup for the destination 
-     and send the message to fastest route. */
-  if (server->server_type == SILC_ROUTER && !server->standalone) {
-    dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT);
-    router = (SilcServerEntry)dst_sock->user_data;
-    idata = (SilcIDListData)router;
-
-    /* Get fastest route and send packet. */
-    if (router)
-      silc_server_private_message_send_internal(server, dst_sock, 
-                                               idata->send_key,
-                                               idata->hmac, packet);
-    return;
-  }
-
- err:
-  silc_server_send_error(server, sock, 
-                        "No such nickname: Private message not sent");
-}
-
-/* Process received channel message. The message can be originated from
-   client or server. */
-
-void silc_server_channel_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
-{
-  SilcChannelEntry channel = NULL;
-  SilcChannelClientEntry chl;
-  SilcChannelID *id = NULL;
-  void *sender = NULL;
-
-  SILC_LOG_DEBUG(("Processing channel message"));
-
-  /* Sanity checks */
-  if (packet->dst_id_type != SILC_ID_CHANNEL) {
-    SILC_LOG_ERROR(("Received bad message for channel, dropped"));
-    SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
-    goto out;
-  }
-
-  /* Find channel entry */
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
-  channel = silc_idlist_find_channel_by_id(server->local_list, id);
-  if (!channel) {
-    SILC_LOG_DEBUG(("Could not find channel"));
-    goto out;
-  }
-
-  /* See that this client is on the channel. If the message is coming
-     from router we won't do the check as the message is from client that
-     we don't know about. Also, if the original sender is not client
-     (as it can be server as well) we don't do the check. */
-  sender = silc_id_str2id(packet->src_id, packet->src_id_type);
-  if (sock->type != SILC_SOCKET_TYPE_ROUTER && 
-      packet->src_id_type == SILC_ID_CLIENT) {
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
-       break;
-    }
-    if (chl == SILC_LIST_END)
-      goto out;
-  }
-
-  /* Distribute the packet to our local clients. This will send the
-     packet for further routing as well, if needed. */
-  silc_server_packet_relay_to_channel(server, sock, channel, sender,
-                                     packet->src_id_type,
-                                     packet->buffer->data,
-                                     packet->buffer->len, FALSE);
-
- out:
-  if (sender)
-    silc_free(sender);
-  if (id)
-    silc_free(id);
-}
-
-/* Received channel key packet. We distribute the key to all of our locally
-   connected clients on the channel. */
-/* XXX Router must accept this packet and distribute the key to all its
-   server that has clients on the channel */
-
-void silc_server_channel_key(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcChannelKeyPayload payload = NULL;
-  SilcChannelID *id = NULL;
-  SilcChannelEntry channel;
-  SilcChannelClientEntry chl;
-  unsigned char *tmp;
-  unsigned int tmp_len;
-  char *cipher;
-
-  if (packet->src_id_type != SILC_ID_SERVER &&
-      sock->type != SILC_SOCKET_TYPE_ROUTER)
-    goto out;
-
-  /* Decode channel key payload */
-  payload = silc_channel_key_payload_parse(buffer);
-  if (!payload) {
-    SILC_LOG_ERROR(("Bad channel key payload, dropped"));
-    goto out;
-  }
-
-  /* Get channel ID */
-  tmp = silc_channel_key_get_id(payload, &tmp_len);
-  id = silc_id_payload_parse_id(tmp, tmp_len);
-  if (!id)
-    goto out;
-
-  /* Get the channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, id);
-  if (!channel) {
-    SILC_LOG_ERROR(("Received key for non-existent channel"));
-    goto out;
-  }
-
-  /* Save the key for us as well */
-  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;
-  if (!silc_cipher_alloc(cipher, &channel->channel_key))
-    goto out;
-
-  /* Distribute the key to all clients on the channel */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    silc_server_packet_send(server, chl->client->connection,
-                           SILC_PACKET_CHANNEL_KEY, 0,
-                           buffer->data, buffer->len, TRUE);
-  }
-
-  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, 
-                                       tmp, tmp_len);
- out:
-  if (id)
-    silc_free(id);
-  if (payload)
-    silc_channel_key_payload_free(payload);
-}
-
-/* Sends current motd to client */
-
-void silc_server_send_motd(SilcServer server,
-                          SilcSocketConnection sock)
-{
-  char *motd;
-  int motd_len;
-
-  if (server->config && server->config->motd && 
-      server->config->motd->motd_file) {
-
-    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
-    if (!motd)
-      return;
-
-    silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
-                           motd, motd_len);
-    silc_free(motd);
-  }
-}
-
-/* Sends error message. Error messages may or may not have any 
-   implications. */
-
-void silc_server_send_error(SilcServer server,
-                           SilcSocketConnection sock,
-                           const char *fmt, ...)
-{
-  va_list ap;
-  unsigned char buf[4096];
-
-  memset(buf, 0, sizeof(buf));
-  va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
-  va_end(ap);
-
-  silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, 
-                         buf, strlen(buf), FALSE);
-}
-
-/* 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, ...)
-{
-  va_list ap;
-  SilcBuffer packet;
-
-  va_start(ap, argc);
-
-  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);
-}
-
-/* Sends notify message destined to specific entity. */
-
-void silc_server_send_notify_dest(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 void *dest_id,
-                                 SilcIdType dest_id_type,
-                                 SilcNotifyType type,
-                                 unsigned int argc, ...)
-{
-  va_list ap;
-  SilcBuffer packet;
-
-  va_start(ap, argc);
-
-  packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, 
-                              dest_id, dest_id_type,
-                              packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
-}
-
-/* Sends notify message to a channel. The notify message sent is 
-   distributed to all clients on the channel. */
-
-void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcChannelEntry channel,
-                                       SilcNotifyType type,
-                                       unsigned int argc, ...)
-{
-  va_list ap;
-  SilcBuffer packet;
-
-  va_start(ap, argc);
-
-  packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send_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). */
+/* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
+   function may be used only by router. In real SILC network all channels
+   are created by routers thus this function is never used by normal
+   server. */
 
-void silc_server_send_notify_on_channels(SilcServer server,
-                                        SilcClientEntry client,
-                                        SilcNotifyType type,
-                                        unsigned int argc, ...)
-{
-  int 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, chl2;
-  SilcIDListData idata;
-  SilcBuffer packet;
-  unsigned char *data;
-  unsigned int data_len;
-  int force_send = FALSE;
-  va_list ap;
-
-  if (!silc_list_count(client->channels))
-    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;
-
-  silc_list_start(client->channels);
-  while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
-    channel = chl->channel;
-
-    /* Send the message to all clients on the channel's client list. */
-    silc_list_start(channel->user_list);
-    while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-      c = chl2->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;
-       idata = (SilcIDListData)c->router;
-       
-       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,
-                                               idata->send_key, idata->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;
-       idata = (SilcIDListData)c;
-       
-       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,
-                                               idata->send_key, idata->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. 
-   If the argument `broadcast' is TRUE then the packet is sent as
-   broadcast packet. */
-
-void silc_server_send_new_id(SilcServer server,
-                            SilcSocketConnection sock,
-                            int broadcast,
-                            void *id, SilcIdType id_type, 
-                            unsigned int id_len)
-{
-  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, 
-                         idp->data, idp->len, FALSE);
-  silc_buffer_free(idp);
-}
-
-/* Sends Replace ID payload to remote end. This is used to replace old
-   ID with new ID sent in the packet.  This is called for example when
-   user changes nickname and we create new ID for the user.  If the 
-   argument `broadcast' is TRUE then the packet is sent as
-   broadcast packet. */
-/* XXX It would be expected that the new id is same type as the old
-   ID. :) */
-
-void silc_server_send_replace_id(SilcServer server,
-                                SilcSocketConnection sock,
-                                int broadcast,
-                                void *old_id, SilcIdType old_id_type,
-                                unsigned int old_id_len,
-                                void *new_id, SilcIdType new_id_type,
-                                unsigned int new_id_len)
-{
-  SilcBuffer packet;
-  unsigned char *oid;
-  unsigned char *nid;
-
-  oid = silc_id_id2str(old_id, old_id_type);
-  if (!oid)
-    return;
-
-  nid = silc_id_id2str(new_id, new_id_type);
-  if (!nid)
-    return;
-
-  packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(old_id_type),
-                    SILC_STR_UI_SHORT(old_id_len),
-                    SILC_STR_UI_XNSTRING(oid, old_id_len),
-                    SILC_STR_UI_SHORT(new_id_type),
-                    SILC_STR_UI_SHORT(new_id_len),
-                    SILC_STR_UI_XNSTRING(nid, new_id_len),
-                    SILC_STR_END);
-
-  silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID, 
-                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
-                         packet->data, packet->len, FALSE);
-  silc_free(oid);
-  silc_free(nid);
-  silc_buffer_free(packet);
-}
-
-/* This function is used to send Remove Channel User payload. This may sent
-   by server but is usually used only by router to notify other routers that
-   user has left a channel. Normal server sends this packet to its router
-   to notify that the router should not hold a record about this client
-   on a channel anymore. Router distributes it further to other routers. */
-
-void silc_server_send_remove_channel_user(SilcServer server,
-                                         SilcSocketConnection sock,
-                                         int broadcast,
-                                         void *client_id, void *channel_id)
-{
-  SilcBuffer packet;
-  unsigned char *clid, *chid;
-
-  clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
-  if (!clid)
-    return;
-
-  chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
-  if (!chid)
-    return;
-
-  packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
-                    SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
-                    SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
-                    SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN),
-                    SILC_STR_END);
-
-  silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER, 
-                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
-                         packet->data, packet->len, FALSE);
-  silc_free(clid);
-  silc_free(chid);
-  silc_buffer_free(packet);
-}
-
-/* Received packet to replace a ID. This checks that the requested ID
-   exists and replaces it with the new one. */
-
-void silc_server_replace_id(SilcServer server,
-                           SilcSocketConnection sock,
-                           SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  unsigned char *old_id = NULL, *new_id = NULL;
-  SilcIdType old_id_type, new_id_type;
-  unsigned short old_id_len, new_id_len;
-  void *id = NULL, *id2 = NULL;
-
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
-      packet->src_id_type == SILC_ID_CLIENT)
-    return;
-
-  SILC_LOG_DEBUG(("Replacing ID"));
-
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_SHORT(&old_id_type),
-                      SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len),
-                      SILC_STR_UI_SHORT(&new_id_type),
-                      SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len),
-                      SILC_STR_END);
-
-  if (old_id_type != new_id_type)
-    goto out;
-
-  if (old_id_len != silc_id_get_len(old_id_type) ||
-      new_id_len != silc_id_get_len(new_id_type))
-    goto out;
-
-  id = silc_id_str2id(old_id, old_id_type);
-  if (!id)
-    goto out;
-
-  id2 = silc_id_str2id(new_id, new_id_type);
-  if (!id2)
-    goto out;
-
-  /* If we are router and this packet is not already broadcast packet
-     we will broadcast it. The sending socket really cannot be router or
-     the router is buggy. If this packet is coming from router then it must
-     have the broadcast flag set already and we won't do anything. */
-  if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
-      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
-    SILC_LOG_DEBUG(("Broadcasting received Replace ID packet"));
-    silc_server_packet_send(server, server->router->connection, packet->type,
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                           buffer->data, buffer->len, FALSE);
-  }
-
-  /* Replace the old ID */
-  switch(old_id_type) {
-  case SILC_ID_CLIENT:
-    if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL)
-      if (server->server_type == SILC_ROUTER)
-       silc_idlist_replace_client_id(server->global_list, id, id2);
-    break;
-
-  case SILC_ID_SERVER:
-    if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL)
-      if (server->server_type == SILC_ROUTER)
-       silc_idlist_replace_server_id(server->global_list, id, id2);
-    break;
-
-  case SILC_ID_CHANNEL:
-    /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be
-       re-generated. */
-    silc_free(id2);
-    break;
-
-  default:
-    silc_free(id2);
-    break;
-  }
-
- out:
-  if (id)
-    silc_free(id);
-  if (old_id)
-    silc_free(old_id);
-  if (new_id)
-    silc_free(new_id);
-}
-
-/* Creates new channel. */
-
-SilcChannelEntry silc_server_new_channel(SilcServer server, 
-                                        SilcServerID *router_id,
-                                        char *cipher, char *channel_name)
+SilcChannelEntry silc_server_create_new_channel(SilcServer server, 
+                                               SilcServerID *router_id,
+                                               char *cipher, 
+                                               char *channel_name)
 {
   int i, key_len;
   SilcChannelID *channel_id;
@@ -3152,377 +1832,9 @@ SilcChannelEntry silc_server_new_channel(SilcServer server,
   /* Notify other routers about the new channel. We send the packet
      to our primary route. */
   if (server->standalone == FALSE) {
-    silc_server_send_new_id(server, server->router->connection,
-                           server->server_type == SILC_SERVER ? FALSE : TRUE,
-                           entry->id, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
+    silc_server_send_new_channel(server, server->router->connection, TRUE, 
+                                channel_name, entry->id, SILC_ID_CHANNEL_LEN);
   }
 
   return entry;
 }
-
-/* Create new client. This processes incoming NEW_CLIENT packet and creates
-   Client ID for the client. Client becomes registered after calling this
-   functions. */
-
-SilcClientEntry silc_server_new_client(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcClientEntry client;
-  SilcIDCacheEntry cache;
-  SilcClientID *client_id;
-  SilcBuffer reply;
-  SilcIDListData idata;
-  char *username = NULL, *realname = NULL, *id_string;
-
-  SILC_LOG_DEBUG(("Creating new client"));
-
-  if (sock->type != SILC_SOCKET_TYPE_CLIENT)
-    return NULL;
-
-  /* Take client entry */
-  client = (SilcClientEntry)sock->user_data;
-  idata = (SilcIDListData)client;
-
-  /* Fetch the old client cache entry so that we can update it. */
-  if (!silc_idcache_find_by_context(server->local_list->clients,
-                                   sock->user_data, &cache)) {
-    SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
-    return NULL;
-  }
-
-  /* Parse incoming packet */
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI16_STRING_ALLOC(&username),
-                      SILC_STR_UI16_STRING_ALLOC(&realname),
-                      SILC_STR_END);
-
-  /* Create Client ID */
-  silc_id_create_client_id(server->id, server->rng, server->md5hash,
-                          username, &client_id);
-
-  /* Update client entry */
-  idata->registered = TRUE;
-  client->nickname = strdup(username);
-  client->username = username;
-  client->userinfo = realname;
-  client->id = client_id;
-
-  /* Update the cache entry */
-  cache->id = (void *)client_id;
-  cache->type = SILC_ID_CLIENT;
-  cache->data = username;
-  silc_idcache_sort_by_data(server->local_list->clients);
-
-  /* Notify our router about new client on the SILC network */
-  if (!server->standalone)
-    silc_server_send_new_id(server, (SilcSocketConnection) 
-                           server->router->connection, 
-                           server->server_type == SILC_ROUTER ? TRUE : FALSE,
-                           client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
-  
-  /* Send the new client ID to the client. */
-  id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
-  reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
-  silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
-  silc_buffer_format(reply,
-                    SILC_STR_UI_SHORT(SILC_ID_CLIENT),
-                    SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
-                    SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
-                    SILC_STR_END);
-  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0, 
-                         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,
-                         ("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",
-                          idata->send_key->cipher->name,
-                          idata->send_key->cipher->key_len));
-  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                         ("Your current nickname is %s",
-                          client->nickname));
-
-  /* Send motd */
-  silc_server_send_motd(server, sock);
-
-  return client;
-}
-
-/* Create new server. This processes incoming NEW_SERVER packet and
-   saves the received Server ID. The server is our locally connected
-   server thus we save all the information and save it to local list. 
-   This funtion can be used by both normal server and router server.
-   If normal server uses this it means that its router has connected
-   to the server. If router uses this it means that one of the cell's
-   servers is connected to the router. */
-
-SilcServerEntry silc_server_new_server(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcServerEntry new_server;
-  SilcIDCacheEntry cache;
-  SilcServerID *server_id;
-  SilcIDListData idata;
-  unsigned char *server_name, *id_string;
-  unsigned short id_len;
-
-  SILC_LOG_DEBUG(("Creating new server"));
-
-  if (sock->type != SILC_SOCKET_TYPE_SERVER &&
-      sock->type != SILC_SOCKET_TYPE_ROUTER)
-    return NULL;
-
-  /* Take server entry */
-  new_server = (SilcServerEntry)sock->user_data;
-  idata = (SilcIDListData)new_server;
-
-  /* Fetch the old server cache entry so that we can update it. */
-  if (!silc_idcache_find_by_context(server->local_list->servers,
-                                   sock->user_data, &cache)) {
-    SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
-    return NULL;
-  }
-
-  /* Parse the incoming packet */
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI16_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);
-  silc_free(id_string);
-
-  /* Update client entry */
-  idata->registered = TRUE;
-  new_server->server_name = server_name;
-  new_server->id = server_id;
-
-  /* Update the cache entry */
-  cache->id = (void *)server_id;
-  cache->type = SILC_ID_SERVER;
-  cache->data = server_name;
-  silc_idcache_sort_by_data(server->local_list->servers);
-
-  /* Distribute the information about new server in the SILC network
-     to our router. If we are normal server we won't send anything
-     since this connection must be our router connection. */
-  if (server->server_type == SILC_ROUTER && !server->standalone &&
-      server->router->connection != sock)
-    silc_server_send_new_id(server, server->router->connection,
-                           TRUE, new_server->id, SILC_ID_SERVER, 
-                           SILC_ID_SERVER_LEN);
-
-  return new_server;
-}
-
-/* Processes incoming New ID Payload. New ID Payload is used to distribute
-   information about newly registered clients, servers and created 
-   channels. */
-
-void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
-                       SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcIDList id_list;
-  SilcServerEntry tmpserver, router;
-  SilcSocketConnection router_sock;
-  SilcIDPayload idp;
-  SilcIdType id_type;
-  void *id, *tmpid;
-
-  SILC_LOG_DEBUG(("Processing new ID"));
-
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
-      server->server_type == SILC_SERVER ||
-      packet->src_id_type != SILC_ID_SERVER)
-    return;
-
-  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_payload_get_id(idp);
-  if (!id)
-    goto out;
-
-  /* If the sender of this packet is server and we are router we need to
-     broadcast this packet to other routers in the network. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
-      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
-    SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
-    silc_server_packet_send(server, server->router->connection,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           buffer->data, buffer->len, FALSE);
-  }
-
-  /* If the packet is originated from the one who sent it to us we know
-     that the ID belongs to our cell, unless the sender was router. */
-  tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
-  tmpserver = (SilcServerEntry)sock->user_data;
-
-  if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
-      sock->type == SILC_SOCKET_TYPE_SERVER) {
-    id_list = server->local_list;
-    router_sock = sock;
-    router = sock->user_data;
-    /*    router = server->id_entry; */
-  } else {
-    id_list = server->global_list;
-    router_sock = (SilcSocketConnection)server->router->connection;
-    router = server->router;
-  }
-
-  silc_free(tmpid);
-
-  switch(id_type) {
-  case SILC_ID_CLIENT:
-    {
-      SilcClientEntry idlist;
-
-      SILC_LOG_DEBUG(("New client id(%s) from [%s] %s",
-                     silc_id_render(id, SILC_ID_CLIENT),
-                     sock->type == SILC_SOCKET_TYPE_SERVER ?
-                     "Server" : "Router", sock->hostname));
-
-      /* Add the client to our local list. We are router and we keep
-        cell specific local database of all clients in the cell. */
-      idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL,
-                                     id, router, router_sock);
-    }
-    break;
-
-  case SILC_ID_SERVER:
-    {
-      SilcServerEntry idlist;
-
-      SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
-                     silc_id_render(id, SILC_ID_SERVER),
-                     sock->type == SILC_SOCKET_TYPE_SERVER ?
-                     "Server" : "Router", sock->hostname));
-
-      /* Add the server to our local list. We are router and we keep
-        cell specific local database of all servers in the cell. */
-      idlist = silc_idlist_add_server(id_list, NULL, 0, id, router, 
-                                     router_sock);
-    }
-    break;
-
-  case SILC_ID_CHANNEL:
-    SILC_LOG_DEBUG(("New channel id(%s) from [%s] %s",
-                   silc_id_render(id, SILC_ID_CHANNEL),
-                   sock->type == SILC_SOCKET_TYPE_SERVER ?
-                   "Server" : "Router", sock->hostname));
-
-    /* Add the channel to our local list. We are router and we keep
-       cell specific local database of all channels in the cell. */
-    silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL);
-    break;
-
-  default:
-    break;
-  }
-
- out:
-  silc_id_payload_free(idp);
-}
-
-/* Received packet to remove a user from a channel. Routers notify other
-   routers that user has left a channel. Client must not send this packet. 
-   Normal server may send this packet but ignores if it receives one. */
-
-void silc_server_remove_channel_user(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  unsigned char *tmp1 = NULL, *tmp2 = NULL;
-  SilcClientID *client_id = NULL;
-  SilcChannelID *channel_id = NULL;
-  SilcChannelEntry channel;
-  SilcClientEntry client;
-
-  SILC_LOG_DEBUG(("Removing user from channel"));
-
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
-      server->server_type == SILC_SERVER)
-    return;
-
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI16_STRING_ALLOC(&tmp1),
-                      SILC_STR_UI16_STRING_ALLOC(&tmp2),
-                      SILC_STR_END);
-
-  if (!tmp1 || !tmp2)
-    goto out;
-
-  client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT);
-  channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL);
-  if (!client_id || !channel_id)
-    goto out;
-
-  /* If we are router and this packet is not already broadcast packet
-     we will broadcast it. The sending socket really cannot be router or
-     the router is buggy. If this packet is coming from router then it must
-     have the broadcast flag set already and we won't do anything. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
-      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
-    SILC_LOG_DEBUG(("Broadcasting received Remove Channel User packet"));
-    silc_server_packet_send(server, server->router->connection, packet->type,
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                           buffer->data, buffer->len, FALSE);
-  }
-
-  /* XXX routers should check server->global_list as well */
-  /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
-  if (!channel)
-    goto out;
-  
-  /* XXX routers should check server->global_list as well */
-  /* Get client entry */
-  client = silc_idlist_find_client_by_id(server->local_list, client_id);
-  if (!client)
-    goto out;
-
-  /* Remove from channel */
-  silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
-
- out:
-  if (tmp1)
-    silc_free(tmp1);
-  if (tmp2)
-    silc_free(tmp2);
-  if (client_id)
-    silc_free(client_id);
-  if (channel_id)
-    silc_free(channel_id);
-}
index f6dd8e398f0bf0a89a727a10c7170421f860f4b9..7df7c010e6fc15be36fe90ec36fc5aa7cfec4173 100644 (file)
@@ -83,53 +83,6 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context);
 void silc_server_packet_parse_type(SilcServer server, 
                                   SilcSocketConnection sock,
                                   SilcPacketContext *packet);
-void silc_server_packet_send(SilcServer server,
-                            SilcSocketConnection sock, 
-                            SilcPacketType type, 
-                            SilcPacketFlags flags,
-                            unsigned char *data, 
-                            unsigned int data_len,
-                            int force_send);
-void silc_server_packet_send_dest(SilcServer server,
-                                 SilcSocketConnection sock, 
-                                 SilcPacketType type, 
-                                 SilcPacketFlags flags,
-                                 void *dst_id,
-                                 SilcIdType dst_id_type,
-                                 unsigned char *data, 
-                                 unsigned int data_len,
-                                 int force_send);
-void silc_server_packet_forward(SilcServer server,
-                               SilcSocketConnection sock,
-                               unsigned char *data, unsigned int data_len,
-                               int force_send);
-void silc_server_packet_broadcast(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketContext *packet);
-void silc_server_packet_send_to_channel(SilcServer server,
-                                       SilcChannelEntry channel,
-                                       SilcPacketType type,
-                                       unsigned char *data,
-                                       unsigned int data_len,
-                                       int force_send);
-void silc_server_packet_relay_to_channel(SilcServer server,
-                                        SilcSocketConnection sender_sock,
-                                        SilcChannelEntry channel,
-                                        void *sender, 
-                                        SilcIdType sender_type,
-                                        unsigned char *data,
-                                        unsigned int data_len,
-                                        int force_send);
-void silc_server_packet_send_local_channel(SilcServer server,
-                                          SilcChannelEntry channel,
-                                          SilcPacketType type,
-                                          SilcPacketFlags flags,
-                                          unsigned char *data,
-                                          unsigned int data_len,
-                                          int force_send);
-void silc_server_packet_relay_command_reply(SilcServer server,
-                                           SilcSocketConnection sock,
-                                           SilcPacketContext *packet);
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock);
 void silc_server_free_sock_user_data(SilcServer server, 
@@ -147,70 +100,9 @@ int silc_server_client_on_channel(SilcClientEntry client,
 void silc_server_disconnect_remote(SilcServer server,
                                   SilcSocketConnection sock,
                                   const char *fmt, ...);
-void silc_server_private_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet);
-void silc_server_channel_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet);
-void silc_server_channel_key(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet);
-void silc_server_send_motd(SilcServer server,
-                          SilcSocketConnection sock);
-void silc_server_send_error(SilcServer server,
-                           SilcSocketConnection sock,
-                           const char *fmt, ...);
-void silc_server_send_notify(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcNotifyType type,
-                            unsigned int argc, ...);
-void silc_server_send_notify_dest(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 void *dest_id,
-                                 SilcIdType dest_id_type,
-                                 SilcNotifyType type,
-                                 unsigned int argc, ...);
-void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcChannelEntry channel,
-                                       SilcNotifyType type,
-                                       unsigned int argc, ...);
-void silc_server_send_notify_on_channels(SilcServer server,
-                                        SilcClientEntry client,
-                                        SilcNotifyType type,
-                                        unsigned int argc, ...);
-void silc_server_send_new_id(SilcServer server,
-                            SilcSocketConnection sock,
-                            int broadcast,
-                            void *id, SilcIdType id_type, 
-                            unsigned int id_len);
-void silc_server_send_replace_id(SilcServer server,
-                                SilcSocketConnection sock,
-                                int broadcast,
-                                void *old_id, SilcIdType old_id_type,
-                                unsigned int old_id_len,
-                                void *new_id, SilcIdType new_id_type,
-                                unsigned int new_id_len);
-void silc_server_send_remove_channel_user(SilcServer server,
-                                         SilcSocketConnection sock,
-                                         int broadcast,
-                                         void *client_id, void *channel_id);
-void silc_server_replace_id(SilcServer server,
-                           SilcSocketConnection sock,
-                           SilcPacketContext *packet);
-SilcChannelEntry silc_server_new_channel(SilcServer server, 
-                                        SilcServerID *router_id,
-                                        char *cipher, char *channel_name);
-SilcClientEntry silc_server_new_client(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet);
-SilcServerEntry silc_server_new_server(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet);
-void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
-                       SilcPacketContext *packet);
-void silc_server_remove_channel_user(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcPacketContext *packet);
+SilcChannelEntry silc_server_create_new_channel(SilcServer server, 
+                                               SilcServerID *router_id,
+                                               char *cipher, 
+                                               char *channel_name);
 
 #endif