Improved UTF-8 encoding and decoding, improved toolkit doc,
[silc.git] / apps / silcd / packet_send.c
index 424a27333fc3cdce4bb4ccfcc143a0b730c6ca80..8e947fd70a90b12b56532c24efea6cb24ed5ab22 100644 (file)
@@ -50,8 +50,10 @@ int silc_server_packet_send_real(SilcServer server,
 
   /* Send the packet */
   ret = silc_packet_send(sock, force_send);
-  if (ret != -2)
+  if (ret != -2) {
+    server->stat.packets_sent++;
     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
@@ -154,7 +156,7 @@ void silc_server_packet_send_dest(SilcServer server,
   if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
     return;
 
-  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+  SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
   if (dst_id) {
     dst_id_data = silc_id_id2str(dst_id, dst_id_type);
@@ -171,9 +173,9 @@ void silc_server_packet_send_dest(SilcServer server,
   /* 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_get_len(server->id, server->id_type);
-  packetdata.src_id_type = server->id_type;
+  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+  packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+  packetdata.src_id_type = SILC_ID_SERVER;
   packetdata.dst_id = dst_id_data;
   packetdata.dst_id_len = dst_id_len;
   packetdata.dst_id_type = dst_id_type;
@@ -239,7 +241,7 @@ void silc_server_packet_send_srcdest(SilcServer server,
   SilcUInt32 src_id_len = 0;
   int block_len = 0;
 
-  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+  SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
   /* Get data used in the packet sending, keys and stuff */
   idata = (SilcIDListData)sock->user_data;
@@ -385,8 +387,7 @@ void silc_server_packet_route(SilcServer server,
    clients (for server locally connected, and for router local cell). */
 
 void silc_server_packet_send_clients(SilcServer server,
-                                    SilcClientEntry *clients,
-                                    SilcUInt32 clients_count,
+                                    SilcHashTable clients,
                                     SilcPacketType type, 
                                     SilcPacketFlags flags,
                                     bool route,
@@ -395,18 +396,18 @@ void silc_server_packet_send_clients(SilcServer server,
                                     bool force_send)
 {
   SilcSocketConnection sock = NULL;
+  SilcHashTableList htl;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcUInt32 routed_count = 0;
   bool gone = FALSE;
-  int i, k;
+  int k;
 
   SILC_LOG_DEBUG(("Sending packet to list of clients"));
 
   /* Send to all clients in table */
-  for (i = 0; i < clients_count; i++) {
-    client = clients[i];
-
+  silc_hash_table_list(clients, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void **)&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. Though,
        send locally connected server in all cases. */
@@ -444,11 +445,14 @@ void silc_server_packet_send_clients(SilcServer server,
 
     /* Send to locally connected client */
     sock = (SilcSocketConnection)client->connection;
+    if (!sock)
+      continue;
+
     silc_server_packet_send_dest(server, sock, type, flags,
                                 client->id, SILC_ID_CLIENT,
                                 data, data_len, force_send);
   }
-
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
 }
 
@@ -585,7 +589,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
   /* Send the message to clients on the channel's client list. */
   silc_hash_table_list(channel->user_list, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+  while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
     client = chl->client;
     if (!client)
       continue;
@@ -680,15 +684,16 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
       channel->channel_key) {
     SilcUInt32 mac_len = silc_hmac_len(channel->hmac);
     SilcUInt32 iv_len = silc_cipher_get_block_len(channel->channel_key);
+    unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
 
     if (data_len <= mac_len + iv_len) {
       SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
       return FALSE;
     }
 
-    memcpy(channel->iv, data + (data_len - iv_len), iv_len);
+    memcpy(iv, data + (data_len - iv_len), iv_len);
     silc_channel_message_payload_encrypt(data, data_len - iv_len - mac_len,
-                                        data_len, channel->iv, iv_len,
+                                        data_len, iv, iv_len,
                                         channel->channel_key, channel->hmac);
   }
 
@@ -718,7 +723,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
-  SilcChannelClientEntry chl;
+  SilcChannelClientEntry chl, chl_sender;
   SilcUInt32 routed_count = 0;
   SilcIDListData idata;
   SilcHashTableList htl;
@@ -727,6 +732,9 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
   SILC_LOG_DEBUG(("Relaying packet to channel"));
 
+  if (!silc_server_client_on_channel(sender_entry, channel, &chl_sender))
+    return;
+
   /* This encrypts the packet, if needed. It will be encrypted if
      it came from the router thus it needs to be encrypted with the
      channel key. If the channel key does not exist, then we know we
@@ -779,11 +787,22 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
   /* Send the message to clients on the channel's client list. */
   silc_hash_table_list(channel->user_list, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+  while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
     client = chl->client;
     if (!client || client == sender_entry)
       continue;
 
+    /* Check whether message sending is blocked */
+    if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
+      continue;
+    if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS &&
+       !(chl_sender->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl_sender->mode & SILC_CHANNEL_UMODE_CHANFO))
+      continue;
+    if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS &&
+       sender_entry->mode & SILC_UMODE_ROBOT)
+      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) {
@@ -920,7 +939,7 @@ void silc_server_packet_send_local_channel(SilcServer server,
 
   /* Send the message to clients on the channel's client list. */
   silc_hash_table_list(channel->user_list, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+  while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
     if (chl->client && !chl->client->router) {
       sock = (SilcSocketConnection)chl->client->connection;
 
@@ -1157,27 +1176,33 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcChannelEntry channel,
                                   SilcUInt32 mode_mask,
                                   void *id, SilcIdType id_type,
-                                  char *cipher, char *hmac,
-                                  char *passphrase)
+                                  const char *cipher, const char *hmac,
+                                  const char *passphrase,
+                                  SilcPublicKey founder_key)
 {
   SilcBuffer idp;
-  unsigned char mode[4];
+  unsigned char mode[4], *key = NULL;
+  SilcUInt32 key_len = 0;
 
   idp = silc_id_payload_encode((void *)id, id_type);
   SILC_PUT32_MSB(mode_mask, mode);
+  if (founder_key)
+    key = silc_pkcs_public_key_encode(founder_key, &key_len);
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              5, idp->data, idp->len,
+                              6, idp->data, idp->len,
                               mode, 4,
                               cipher, cipher ? strlen(cipher) : 0,
                               hmac, hmac ? strlen(hmac) : 0,
                               passphrase, passphrase ? 
-                              strlen(passphrase) : 0);
+                              strlen(passphrase) : 0,
+                              key, key_len);
+  silc_free(key);
   silc_buffer_free(idp);
 }
 
-/* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
+/* Sends CUMODE_CHANGE notify type. This tells that `id' changed the
    `target' client's mode on `channel'. The notify packet is always
    destined to the channel. */
 
@@ -1187,21 +1212,27 @@ void silc_server_send_notify_cumode(SilcServer server,
                                    SilcChannelEntry channel,
                                    SilcUInt32 mode_mask,
                                    void *id, SilcIdType id_type,
-                                   SilcClientID *target)
+                                   SilcClientID *target,
+                                   SilcPublicKey founder_key)
 {
   SilcBuffer idp1, idp2;
-  unsigned char mode[4];
+  unsigned char mode[4], *key = NULL;
+  SilcUInt32 key_len = 0;
 
   idp1 = silc_id_payload_encode((void *)id, id_type);
   idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
   SILC_PUT32_MSB(mode_mask, mode);
+  if (founder_key)
+    key = silc_pkcs_public_key_encode(founder_key, &key_len);
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, 
-                              SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3
+                              SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4
                               idp1->data, idp1->len,
                               mode, 4,
-                              idp2->data, idp2->len);
+                              idp2->data, idp2->len,
+                              key, key_len);
+  silc_free(key);
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 }
@@ -1286,14 +1317,14 @@ void silc_server_send_notify_killed(SilcServer server,
                                    SilcSocketConnection sock,
                                    bool broadcast,
                                    SilcClientID *client_id,
-                                   char *comment,
-                                   SilcClientID *killer)
+                                   const char *comment,
+                                   void *killer, SilcIdType killer_type)
 {
   SilcBuffer idp1;
   SilcBuffer idp2;
 
-  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
-  idp2 = silc_id_payload_encode((void *)killer, SILC_ID_CLIENT);
+  idp1 = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode(killer, killer_type);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
                               SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
                               3, idp1->data, idp1->len,
@@ -1374,6 +1405,32 @@ void silc_server_send_notify_invite(SilcServer server,
   silc_buffer_free(idp2);
 }
 
+/* Sends WATCH notify type. This tells that the `client' was watched and
+   its status in the network has changed. */
+
+void silc_server_send_notify_watch(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  SilcClientEntry watcher,
+                                  SilcClientEntry client,
+                                  const char *nickname,
+                                  SilcNotifyType type)
+{
+  SilcBuffer idp;
+  unsigned char mode[4], n[2];
+
+  idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+  SILC_PUT16_MSB(type, n);
+  SILC_PUT32_MSB(client->mode, mode);
+  silc_server_send_notify_dest(server, sock, FALSE, watcher->id,
+                              SILC_ID_CLIENT, SILC_NOTIFY_TYPE_WATCH,
+                              4, idp->data, idp->len,
+                              nickname, nickname ? strlen(nickname) : 0,
+                              mode, sizeof(mode), 
+                              type != SILC_NOTIFY_TYPE_NONE ?
+                              n : NULL, sizeof(n));
+  silc_buffer_free(idp);
+}
+
 /* Sends notify message destined to specific entity. */
 
 void silc_server_send_notify_dest(SilcServer server,
@@ -1474,12 +1531,12 @@ void silc_server_send_notify_on_channels(SilcServer server,
   packetdata.src_id_type = SILC_ID_SERVER;
 
   silc_hash_table_list(client->channels, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+  while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
     channel = chl->channel;
 
     /* Send the message to all clients on the channel's client list. */
     silc_hash_table_list(channel->user_list, &htl2);
-    while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
+    while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
       c = chl2->client;
       
       if (sender && c == sender)
@@ -1594,20 +1651,12 @@ void silc_server_send_new_id(SilcServer server,
 {
   SilcBuffer idp;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Sending new ID"));
 
   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);
-
-  /* Send to backup routers if this is being broadcasted to primary
-     router. */
-  if (server->router && server->router->connection &&
-      sock == server->router->connection && broadcast)
-    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
-                           idp->data, idp->len, FALSE, TRUE);
-
   silc_buffer_free(idp);
 }
 
@@ -1627,7 +1676,7 @@ void silc_server_send_new_channel(SilcServer server,
   unsigned char *cid;
   SilcUInt32 name_len = strlen(channel_name);
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Sending new channel"));
 
   cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
   if (!cid)
@@ -1641,14 +1690,6 @@ void silc_server_send_new_channel(SilcServer server,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
                          packet->data, packet->len, FALSE);
 
-  /* Send to backup routers if this is being broadcasted to primary
-     router. */
-  if (server->server_type == SILC_ROUTER &&
-      server->router && server->router->connection &&
-      sock == server->router->connection && broadcast)
-    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
-                           packet->data, packet->len, FALSE, TRUE);
-
   silc_free(cid);
   silc_buffer_free(packet);
 }
@@ -1719,7 +1760,8 @@ void silc_server_send_command(SilcServer server,
 void silc_server_send_command_reply(SilcServer server, 
                                    SilcSocketConnection sock,
                                    SilcCommand command, 
-                                   SilcCommandStatus status,
+                                   SilcStatus status,
+                                   SilcStatus error,
                                    SilcUInt16 ident,
                                    SilcUInt32 argc, ...)
 {
@@ -1728,8 +1770,8 @@ void silc_server_send_command_reply(SilcServer server,
 
   va_start(ap, argc);
 
-  packet = silc_command_reply_payload_encode_vap(command, status, ident, 
-                                                argc, ap);
+  packet = silc_command_reply_payload_encode_vap(command, status, error,
+                                                ident, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, TRUE);
   silc_buffer_free(packet);
@@ -1744,7 +1786,8 @@ void silc_server_send_dest_command_reply(SilcServer server,
                                         void *dst_id,
                                         SilcIdType dst_id_type,
                                         SilcCommand command, 
-                                        SilcCommandStatus status,
+                                        SilcStatus status,
+                                        SilcStatus error,
                                         SilcUInt16 ident,
                                         SilcUInt32 argc, ...)
 {
@@ -1753,8 +1796,8 @@ void silc_server_send_dest_command_reply(SilcServer server,
 
   va_start(ap, argc);
 
-  packet = silc_command_reply_payload_encode_vap(command, status, ident, 
-                                                argc, ap);
+  packet = silc_command_reply_payload_encode_vap(command, status, error,
+                                                ident, argc, ap);
   silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
                               dst_id, dst_id_type, packet->data, 
                               packet->len, TRUE);