updates. New data types.
[silc.git] / apps / silcd / packet_send.c
index 3b72d89a77679f52819af78be81954aa71f7651d..a88eedbeac363bf0ce46ab0694529d98d77cb539 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2001 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ void silc_server_packet_send(SilcServer server,
                             SilcPacketType type, 
                             SilcPacketFlags flags,
                             unsigned char *data, 
-                            unsigned int data_len,
+                            uint32 data_len,
                             int force_send)
 {
   void *dst_id = NULL;
@@ -107,7 +107,7 @@ void silc_server_packet_send_dest(SilcServer server,
                                  void *dst_id,
                                  SilcIdType dst_id_type,
                                  unsigned char *data, 
-                                 unsigned int data_len,
+                                 uint32 data_len,
                                  int force_send)
 {
   SilcPacketContext packetdata;
@@ -115,7 +115,7 @@ void silc_server_packet_send_dest(SilcServer server,
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
   unsigned char *dst_id_data = NULL;
-  unsigned int dst_id_len = 0;
+  uint32 dst_id_len = 0;
 
   SILC_LOG_DEBUG(("Sending packet, type %d", type));
 
@@ -139,7 +139,6 @@ void silc_server_packet_send_dest(SilcServer server,
   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, 
@@ -180,36 +179,81 @@ void silc_server_packet_send_dest(SilcServer server,
     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)
+/* 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. 
+   The source and destination information is sent as argument for this
+   function. */
+
+void silc_server_packet_send_srcdest(SilcServer server,
+                                    SilcSocketConnection sock, 
+                                    SilcPacketType type, 
+                                    SilcPacketFlags flags,
+                                    void *src_id,
+                                    SilcIdType src_id_type,
+                                    void *dst_id,
+                                    SilcIdType dst_id_type,
+                                    unsigned char *data, 
+                                    uint32 data_len,
+                                    int force_send)
 {
+  SilcPacketContext packetdata;
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  unsigned char *dst_id_data = NULL;
+  uint32 dst_id_len = 0;
+  unsigned char *src_id_data = NULL;
+  uint32 src_id_len = 0;
 
-  SILC_LOG_DEBUG(("Forwarding packet"));
+  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);
+  }
+
+  if (src_id) {
+    src_id_data = silc_id_id2str(src_id, src_id_type);
+    src_id_len = silc_id_get_len(src_id_type);
+  }
+
+  /* Set the packet context pointers */
+  packetdata.type = type;
+  packetdata.flags = flags;
+  packetdata.src_id = src_id_data;
+  packetdata.src_id_len = src_id_len;
+  packetdata.src_id_type = src_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);
+
   /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 0, 0, data_len);
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packetdata.src_id_len + 
+                          packetdata.dst_id_len,
+                          packetdata.padlen,
+                          data_len);
+
+  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+  packetdata.buffer = sock->outbuf;
 
   /* 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;
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
 
   if (idata) {
     cipher = idata->send_key;
@@ -219,11 +263,16 @@ void silc_server_packet_forward(SilcServer server,
   /* Encrypt the packet */
   silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Forwarded packet, len %d", 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);
 }
 
 /* Broadcast received packet to our primary route. This function is used
@@ -243,7 +292,7 @@ void silc_server_packet_broadcast(SilcServer server,
 
   /* 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);
+  id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
   if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
     idata = (SilcIDListData)sock->user_data;
 
@@ -267,6 +316,33 @@ void silc_server_packet_broadcast(SilcServer server,
   silc_free(id);
 }
 
+/* Routes received packet to `sock'. This is used to route the packets that
+   router receives but are not destined to it. */
+
+void silc_server_packet_route(SilcServer server,
+                             SilcSocketConnection sock,
+                             SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Routing received packet"));
+
+  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(("Routed 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);
+}
+
 /* 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
@@ -279,7 +355,7 @@ silc_server_packet_send_to_channel_real(SilcServer server,
                                        SilcCipher cipher,
                                        SilcHmac hmac,
                                        unsigned char *data,
-                                       unsigned int data_len,
+                                       uint32 data_len,
                                        int channel_message,
                                        int force_send)
 {
@@ -319,14 +395,17 @@ silc_server_packet_send_to_channel_real(SilcServer server,
    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. */
+   be routed anywhere (for router locally means cell wide). If `sender'
+   is provided then the packet is not sent to that connection since it
+   originally came from it. */
 
 void silc_server_packet_send_to_channel(SilcServer server,
+                                       SilcSocketConnection sender,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
                                        unsigned char route,
                                        unsigned char *data,
-                                       unsigned int data_len,
+                                       uint32 data_len,
                                        int force_send)
 {
   SilcSocketConnection sock = NULL;
@@ -335,7 +414,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
   SilcIDListData idata;
-  unsigned int routed_count = 0;
+  uint32 routed_count = 0;
 
   /* This doesn't send channel message packets */
   if (type == SILC_PACKET_CHANNEL_MESSAGE)
@@ -352,7 +431,6 @@ void silc_server_packet_send_to_channel(SilcServer 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);
@@ -368,11 +446,14 @@ void silc_server_packet_send_to_channel(SilcServer server,
     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);
+    if (sock != sender) {
+      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. */
@@ -381,9 +462,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
     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) {
+       we will route the message to the router set in the client. Though,
+       send locally connected server in all cases. */
+    if (server->server_type == SILC_ROUTER && client && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
       int k;
 
       /* Check if we have sent the packet to this route already */
@@ -397,6 +479,9 @@ void silc_server_packet_send_to_channel(SilcServer server,
       sock = (SilcSocketConnection)client->router->connection;
       idata = (SilcIDListData)client->router;
 
+      if (sender && sock == sender)
+       continue;
+
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, idata->hmac, 
@@ -413,6 +498,9 @@ void silc_server_packet_send_to_channel(SilcServer server,
       continue;
     }
 
+    if (client && client->router)
+      continue;
+
     /* Send to locally connected client */
     if (client) {
 
@@ -420,6 +508,9 @@ void silc_server_packet_send_to_channel(SilcServer server,
       sock = (SilcSocketConnection)client->connection;
       idata = (SilcIDListData)client;
 
+      if (sender && sock == sender)
+       continue;
+
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, idata->hmac, 
@@ -449,7 +540,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                         void *sender, 
                                         SilcIdType sender_type,
                                         unsigned char *data,
-                                        unsigned int data_len,
+                                        uint32 data_len,
                                         int force_send)
 {
   int found = FALSE;
@@ -458,7 +549,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
-  unsigned int routed_count = 0;
+  uint32 routed_count = 0;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Relaying packet to channel"));
@@ -472,7 +563,6 @@ void silc_server_packet_relay_to_channel(SilcServer 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.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
                                          packetdata.src_id_len +
                                          packetdata.dst_id_len));
@@ -537,12 +627,13 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        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);
-       
+       if (sender_sock && sock == sender_sock)
+         continue;
+
+       SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)", 
+                       silc_id_render(client->id, SILC_ID_CLIENT),
+                       sock->hostname, sock->ip));
+
        /* We want to make sure that the packet is routed to same router
           only once. Mark this route as sent route. */
        k = routed_count;
@@ -550,17 +641,72 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        routed[k] = client->router;
        routed_count++;
        
+       /* If the remote connection is router then we'll decrypt the
+          channel message and re-encrypt it with the session key shared
+          between us and the remote router. This is done because the
+          channel keys are cell specific and we have different channel
+          key than the remote router has. */
+       if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+
+         /* If private key mode is not set then decrypt the packet
+            and re-encrypt it */
+         if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+           unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
+           memcpy(tmp, data, data_len);
+
+           /* Decrypt the channel message (we don't check the MAC) */
+           if (!silc_channel_message_payload_decrypt(tmp, data_len, 
+                                                     channel->channel_key,
+                                                     NULL)) {
+             memset(tmp, 0, data_len);
+             silc_free(tmp);
+             continue;
+           }
+
+           /* Now re-encrypt and send it to the router */
+           silc_server_packet_send_srcdest(server, sock, 
+                                           SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                           sender, sender_type,
+                                           channel->id, SILC_ID_CHANNEL,
+                                           tmp, data_len, force_send);
+           
+           /* Free the copy of the channel message */
+           memset(tmp, 0, data_len);
+           silc_free(tmp);
+         } else {
+           /* Private key mode is set, we don't have the channel key, so
+              just re-encrypt the entire packet and send it to the router. */
+           silc_server_packet_send_srcdest(server, sock, 
+                                           SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                           sender, sender_type,
+                                           channel->id, SILC_ID_CHANNEL,
+                                           data, data_len, force_send);
+         }
+         continue;
+       }
+  
+       /* Send the packet (to normal server) */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               idata->send_key, idata->hmac, 
+                                               data, data_len, TRUE, 
+                                               force_send);
+
        continue;
       }
 
-      /* XXX Check client's mode on the channel. */
+      if (client && client->router)
+       continue;
 
       /* 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));
+      if (sender_sock && sock == sender_sock)
+       continue;
+
+      SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)", 
+                     silc_id_render(client->id, SILC_ID_CLIENT),
+                     sock->hostname, sock->ip));
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
@@ -586,10 +732,9 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcPacketType type,
                                           SilcPacketFlags flags,
                                           unsigned char *data,
-                                          unsigned int data_len,
+                                          uint32 data_len,
                                           int force_send)
 {
-  SilcClientEntry client;
   SilcChannelClientEntry chl;
   SilcSocketConnection sock = NULL;
 
@@ -598,13 +743,11 @@ void silc_server_packet_send_local_channel(SilcServer server,
   /* 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;
+    if (chl->client && !chl->client->router) {
+      sock = (SilcSocketConnection)chl->client->connection;
 
       /* Send the packet to the client */
-      silc_server_packet_send_dest(server, sock, type, flags, client->id,
+      silc_server_packet_send_dest(server, sock, type, flags, chl->client->id,
                                   SILC_ID_CLIENT, data, data_len,
                                   force_send);
     }
@@ -625,7 +768,7 @@ void silc_server_send_private_message(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer;
 
-  /* Send and re-encrypt if private messge key does not exist */
+  /* Re-encrypt and send 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 
@@ -640,11 +783,17 @@ void silc_server_send_private_message(SilcServer server,
     silc_server_packet_send_real(server, dst_sock, FALSE);
 
   } else {
-    /* Key exist so just send it */
+    /* Key exist so encrypt just header and 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);
+
+    /* Encrypt header */
+    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, 
+                       SILC_PACKET_HEADER_LEN + packet->src_id_len + 
+                       packet->dst_id_len + packet->padlen);
+
     silc_server_packet_send_real(server, dst_sock, FALSE);
   }
 }
@@ -655,7 +804,7 @@ void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock)
 {
   char *motd;
-  int motd_len;
+  uint32 motd_len;
 
   if (server->config && server->config->motd && 
       server->config->motd->motd_file) {
@@ -664,7 +813,7 @@ void silc_server_send_motd(SilcServer server,
     if (!motd)
       return;
 
-    silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+    silc_server_send_notify(server, sock, FALSE, SILC_NOTIFY_TYPE_MOTD, 1,
                            motd, motd_len);
     silc_free(motd);
   }
@@ -696,8 +845,9 @@ void silc_server_send_error(SilcServer server,
 
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
+                            int broadcast,
                             SilcNotifyType type,
-                            unsigned int argc, ...)
+                            uint32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -710,14 +860,339 @@ void silc_server_send_notify(SilcServer server,
   silc_buffer_free(packet);
 }
 
+/* Sends notify message and gets the arguments from the `args' Argument
+   Payloads. */
+
+void silc_server_send_notify_args(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 int broadcast,
+                                 SilcNotifyType type,
+                                 uint32 argc,
+                                 SilcBuffer args)
+{
+  SilcBuffer packet;
+
+  packet = silc_notify_payload_encode_args(type, argc, args);
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+}
+
+/* Send CHANNEL_CHANGE notify type. This tells the receiver to replace the
+   `old_id' with the `new_id'. */
+
+void silc_server_send_notify_channel_change(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           int broadcast,
+                                           SilcChannelID *old_id,
+                                           SilcChannelID *new_id,
+                                           uint32 id_len)
+{
+  SilcBuffer idp1, idp2;
+
+  idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CHANNEL);
+  idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CHANNEL);
+
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_CHANNEL_CHANGE,
+                         2, idp1->data, idp1->len, idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
+}
+
+/* Send NICK_CHANGE notify type. This tells the receiver to replace the
+   `old_id' with the `new_id'. */
+
+void silc_server_send_notify_nick_change(SilcServer server,
+                                        SilcSocketConnection sock,
+                                        int broadcast,
+                                        SilcClientID *old_id,
+                                        SilcClientID *new_id,
+                                        uint32 id_len)
+{
+  SilcBuffer idp1, idp2;
+
+  idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CLIENT);
+
+  silc_server_send_notify(server, sock, broadcast, 
+                         SILC_NOTIFY_TYPE_NICK_CHANGE,
+                         2, idp1->data, idp1->len, idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
+}
+
+/* Sends JOIN notify type. This tells that new client by `client_id' ID
+   has joined to the `channel'. */
+
+void silc_server_send_notify_join(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 int broadcast,
+                                 SilcChannelEntry channel,
+                                 SilcClientID *client_id,
+                                 uint32 client_id_len)
+{
+  SilcBuffer idp1, idp2;
+
+  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+  silc_server_send_notify(server, sock, broadcast, SILC_NOTIFY_TYPE_JOIN,
+                         2, idp1->data, idp1->len,
+                         idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
+}
+
+/* Sends LEAVE notify type. This tells that `client_id' has left the
+   `channel'. The Notify packet is always destined to the channel. */
+
+void silc_server_send_notify_leave(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  int broadcast,
+                                  SilcChannelEntry channel,
+                                  SilcClientID *client_id,
+                                  uint32 client_id_len)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_LEAVE,
+                              1, idp->data, idp->len);
+  silc_buffer_free(idp);
+}
+
+/* Sends CMODE_CHANGE notify type. This tells that `client_id' changed the
+   `channel' mode to `mode. The Notify packet is always destined to
+   the channel. */
+
+void silc_server_send_notify_cmode(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  int broadcast,
+                                  SilcChannelEntry channel,
+                                  uint32 mode_mask,
+                                  void *id, SilcIdType id_type,
+                                  uint32 id_len,
+                                  char *cipher, char *hmac)
+{
+  SilcBuffer idp;
+  unsigned char mode[4];
+
+  idp = silc_id_payload_encode((void *)id, id_type);
+  SILC_PUT32_MSB(mode_mask, mode);
+
+  silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
+                              4, idp->data, idp->len,
+                              mode, 4,
+                              cipher, cipher ? strlen(cipher) : 0,
+                              hmac, hmac ? strlen(hmac) : 0);
+  silc_buffer_free(idp);
+}
+
+/* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
+   `target' client's mode on `channel'. The Notify packet is always
+   destined to the channel. */
+
+void silc_server_send_notify_cumode(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   uint32 mode_mask,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   SilcClientID *target,
+                                   uint32 target_len)
+{
+  SilcBuffer idp1, idp2;
+  unsigned char mode[4];
+
+  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
+  SILC_PUT32_MSB(mode_mask, mode);
+
+  silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+                              SILC_ID_CHANNEL, 
+                              SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3, 
+                              idp1->data, idp1->len,
+                              mode, 4,
+                              idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
+}
+
+/* Sends SIGNOFF notify type. This tells that `client_id' client has
+   left SILC network. This function is used only between server and router
+   traffic. This is not used to send the notify to the channel for
+   client. The `message may be NULL. */
+
+void silc_server_send_notify_signoff(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    int broadcast,
+                                    SilcClientID *client_id,
+                                    uint32 client_id_len,
+                                    char *message)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_SIGNOFF,
+                         message ? 2 : 1, idp->data, idp->len,
+                         message, message ? strlen(message): 0);
+  silc_buffer_free(idp);
+}
+
+/* Sends TOPIC_SET notify type. This tells that `client_id' changed
+   the `channel's topic to `topic'. The Notify packet is always destined
+   to the channel. This function is used to send the topic set notifies
+   between routers. */
+
+void silc_server_send_notify_topic_set(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      int broadcast,
+                                      SilcChannelEntry channel,
+                                      SilcClientID *client_id,
+                                      uint32 client_id_len,
+                                      char *topic)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
+                         topic ? 2 : 1, 
+                         idp->data, idp->len, 
+                         topic, topic ? strlen(topic) : 0);
+  silc_buffer_free(idp);
+}
+
+/* Send KICKED notify type. This tells that the `client_id' on `channel'
+   was kicked off the channel.  The `comment' may indicate the reason
+   for the kicking. This function is used only between server and router
+   traffic. */
+
+void silc_server_send_notify_kicked(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   char *comment)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED,
+                              comment ? 2 : 1, idp->data, idp->len,
+                              comment, comment ? strlen(comment) : 0);
+  silc_buffer_free(idp);
+}
+
+/* Send KILLED notify type. This tells that the `client_id' client was
+   killed from the network.  The `comment' may indicate the reason
+   for the killing. */
+
+void silc_server_send_notify_killed(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   char *comment)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
+                              SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
+                              comment ? 2 : 1, idp->data, idp->len,
+                              comment, comment ? strlen(comment) : 0);
+  silc_buffer_free(idp);
+}
+
+/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
+   user mode in the SILC Network was changed. This function is used to
+   send the packet between routers as broadcast packet. */
+
+void silc_server_send_notify_umode(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  int broadcast,
+                                  SilcClientID *client_id,
+                                  uint32 client_id_len,
+                                  uint32 mode_mask)
+{
+  SilcBuffer idp;
+  unsigned char mode[4];
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  SILC_PUT32_MSB(mode_mask, mode);
+
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_UMODE_CHANGE, 2,
+                         idp->data, idp->len, 
+                         mode, 4);
+  silc_buffer_free(idp);
+}
+
+/* Sends BAN notify type. This tells that ban has been either `add'ed
+   or `del'eted on the `channel. This function is used to send the packet
+   between routers as broadcast packet. */
+
+void silc_server_send_notify_ban(SilcServer server,
+                                SilcSocketConnection sock,
+                                int broadcast,
+                                SilcChannelEntry channel,
+                                char *add, char *del)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_BAN, 3,
+                         idp->data, idp->len,
+                         add, add ? strlen(add) : 0,
+                         del, del ? strlen(del) : 0);
+  silc_buffer_free(idp);
+}
+
+/* Sends INVITE notify type. This tells that invite has been either `add'ed
+   or `del'eted on the `channel.  The sender of the invite is the `client_id'.
+   This function is used to send the packet between routers as broadcast
+   packet. */
+
+void silc_server_send_notify_invite(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   SilcClientID *client_id,
+                                   uint32 client_id_len,
+                                   char *add, char *del)
+{
+  SilcBuffer idp, idp2;
+
+  idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+  idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify(server, sock, broadcast,
+                         SILC_NOTIFY_TYPE_INVITE, 5,
+                         idp->data, idp->len,
+                         channel->channel_name, strlen(channel->channel_name),
+                         idp2->data, idp2->len,
+                         add, add ? strlen(add) : 0,
+                         del, del ? strlen(del) : 0);
+  silc_buffer_free(idp);
+  silc_buffer_free(idp2);
+}
+
 /* Sends notify message destined to specific entity. */
 
 void silc_server_send_notify_dest(SilcServer server,
                                  SilcSocketConnection sock,
+                                 int broadcast,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
-                                 unsigned int argc, ...)
+                                 uint32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -732,15 +1207,18 @@ void silc_server_send_notify_dest(SilcServer server,
 }
 
 /* Sends notify message to a channel. The notify message sent is 
-   distributed to all clients on the channel. If `router_notify' is TRUE
+   distributed to all clients on the channel. If `route_notify' is TRUE
    then the notify may be routed to primary route or to some other routers.
-   If FALSE it is assured that the notify is sent only locally. */
+   If FALSE it is assured that the notify is sent only locally. If `sender'
+   is provided then the packet is not sent to that connection since it
+   originally came from it. */
 
 void silc_server_send_notify_to_channel(SilcServer server,
+                                       SilcSocketConnection sender,
                                        SilcChannelEntry channel,
                                        unsigned char route_notify,
                                        SilcNotifyType type,
-                                       unsigned int argc, ...)
+                                       uint32 argc, ...)
 {
   va_list ap;
   SilcBuffer packet;
@@ -748,37 +1226,39 @@ void silc_server_send_notify_to_channel(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send_to_channel(server, channel, 
+  silc_server_packet_send_to_channel(server, sender, 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
+/* Send notify message to all channels 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). */
+   local servers if we are router). If `sender' is provided the packet is
+   not sent to that client at all. */
 
 void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry sender,
                                         SilcClientEntry client,
                                         SilcNotifyType type,
-                                        unsigned int argc, ...)
+                                        uint32 argc, ...)
 {
   int k;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry c;
   SilcClientEntry *sent_clients = NULL;
-  unsigned int sent_clients_count = 0;
+  uint32 sent_clients_count = 0;
   SilcServerEntry *routed = NULL;
-  unsigned int routed_count = 0;
+  uint32 routed_count = 0;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl, chl2;
   SilcIDListData idata;
   SilcBuffer packet;
   unsigned char *data;
-  unsigned int data_len;
+  uint32 data_len;
   int force_send = FALSE;
   va_list ap;
 
@@ -798,7 +1278,6 @@ void silc_server_send_notify_on_channels(SilcServer server,
   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) {
@@ -809,6 +1288,9 @@ void silc_server_send_notify_on_channels(SilcServer server,
     while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
       c = chl2->client;
       
+      if (sender && c == sender)
+       continue;
+
       /* Check if we have sent the packet to this client already */
       for (k = 0; k < sent_clients_count; k++)
        if (sent_clients[k] == c)
@@ -856,6 +1338,9 @@ void silc_server_send_notify_on_channels(SilcServer server,
        continue;
       }
 
+      if (c && c->router)
+       continue;
+
       /* Send to locally connected client */
       if (c) {
        
@@ -904,7 +1389,7 @@ void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             int broadcast,
                             void *id, SilcIdType id_type, 
-                            unsigned int id_len)
+                            uint32 id_len)
 {
   SilcBuffer idp;
 
@@ -917,173 +1402,149 @@ void silc_server_send_new_id(SilcServer server,
   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. :) */
+/* 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_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_new_channel(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 int broadcast,
+                                 char *channel_name,
+                                 void *channel_id, 
+                                 uint32 channel_id_len,
+                                 uint32 mode)
 {
   SilcBuffer packet;
-  unsigned char *oid;
-  unsigned char *nid;
+  unsigned char *cid;
+  uint32 name_len = strlen(channel_name);
 
   SILC_LOG_DEBUG(("Start"));
 
-  oid = silc_id_id2str(old_id, old_id_type);
-  if (!oid)
+  cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+  if (!cid)
     return;
 
-  nid = silc_id_id2str(new_id, new_id_type);
-  if (!nid)
-    return;
+  /* Encode the channel payload */
+  packet = silc_channel_payload_encode(channel_name, name_len,
+                                      cid, channel_id_len, mode);
 
-  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, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
                          packet->data, packet->len, FALSE);
-  silc_free(oid);
-  silc_free(nid);
+
+  silc_free(cid);
   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)
+/* Send Channel Key payload to distribute the new channel key. Normal server
+   sends this to router when new client joins to existing channel. Router
+   sends this to the local server who sent the join command in case where
+   the channel did not exist yet. Both normal and router servers uses this
+   also to send this to locally connected clients on the channel. This
+   must not be broadcasted packet. Routers do not send this to each other. 
+   If `sender is provided then the packet is not sent to that connection since
+   it originally came from it. */
+
+void silc_server_send_channel_key(SilcServer server,
+                                 SilcSocketConnection sender,
+                                 SilcChannelEntry channel,
+                                 unsigned char route)
 {
   SilcBuffer packet;
-  unsigned char *clid, *chid;
-
+  unsigned char *chid;
+  uint32 tmp_len;
   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);
+  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);
+  /* Encode channel key packet */
+  tmp_len = strlen(channel->channel_key->cipher->name);
+  packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len,
+                                           channel->channel_key->cipher->name,
+                                           channel->key_len / 8, channel->key);
+  silc_server_packet_send_to_channel(server, sender, channel, 
+                                    SILC_PACKET_CHANNEL_KEY,
+                                     route, packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
+  silc_free(chid);
 }
 
-/* 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. */
+/* Generic function to send any command. The arguments must be sent already
+   encoded into correct form in correct order. */
 
-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_command(SilcServer server, 
+                             SilcSocketConnection sock,
+                             SilcCommand command, 
+                             uint32 argc, ...)
 {
   SilcBuffer packet;
-  unsigned char *cid;
-  unsigned int name_len = strlen(channel_name);
-
-  SILC_LOG_DEBUG(("Start"));
+  va_list ap;
 
-  cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
-  if (!cid)
-    return;
+  va_start(ap, argc);
 
-  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);
+  packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+  silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+}
 
-  silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, 
-                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
-                         packet->data, packet->len, FALSE);
+/* Send the heartbeat packet. */
 
-  silc_free(cid);
-  silc_buffer_free(packet);
+void silc_server_send_heartbeat(SilcServer server,
+                               SilcSocketConnection sock)
+{
+  silc_server_packet_send(server, sock, SILC_PACKET_HEARTBEAT, 0,
+                         NULL, 0, FALSE);
 }
 
-/* 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. */
+/* Generic function to relay packet we've received. This is used to relay
+   packets to a client but generally can be used to other purposes as well. */
 
-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)
+void silc_server_relay_packet(SilcServer server,
+                             SilcSocketConnection dst_sock,
+                             SilcCipher cipher,
+                             SilcHmac hmac,
+                             SilcPacketContext *packet,
+                             int force_send)
 {
-  SilcBuffer packet;
-  unsigned char *clid, *chid;
+  silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
 
-  SILC_LOG_DEBUG(("Start"));
+  silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
+  silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
+  
+  /* Re-encrypt packet */
+  silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
+  
+  /* Send the packet */
+  silc_server_packet_send_real(server, dst_sock, force_send);
 
-  clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
-  if (!clid)
-    return;
+  silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
+}
 
-  chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
-  if (!chid)
-    return;
+/* Routine used to send the connection authentication packet. */
+
+void silc_server_send_connection_auth_request(SilcServer server,
+                                             SilcSocketConnection sock,
+                                             uint16 conn_type,
+                                             SilcAuthMethod auth_meth)
+{
+  SilcBuffer packet;
 
-  packet = silc_buffer_alloc(2 + 2 + channel_id_len + client_id_len);
+  packet = silc_buffer_alloc(4);
   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_UI_SHORT(conn_type),
+                    SILC_STR_UI_SHORT(auth_meth),
                     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_server_packet_send(server, sock, SILC_PACKET_CONNECTION_AUTH_REQUEST,
+                         0, packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 }