updates.
[silc.git] / apps / silcd / command.c
index 94d172e427b3c4994606f50ccab3d6866c3cb60b..188c04cac8c0421383229208c4436e3085dd7706 100644 (file)
@@ -161,6 +161,7 @@ void silc_server_command_process(SilcServer server,
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
     silc_buffer_free(packet->buffer);
     silc_packet_context_free(packet);
+    silc_socket_free(ctx->sock);
     silc_free(ctx);
     return;
   }
@@ -1284,13 +1285,12 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Send notify about nickname change to our router. We send the new
      ID and ask to replace it with the old one. If we are router the
-     packet is broadcasted. */
+     packet is broadcasted. Send NICK_CHANGE notify. */
   if (!server->standalone)
-    silc_server_send_replace_id(server, server->router->connection, 
-                               server->server_type == SILC_SERVER ? 
-                               FALSE : TRUE, client->id,
-                               SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
-                               new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+    silc_server_send_notify_nick_change(server, server->router->connection, 
+                                       server->server_type == SILC_SERVER ? 
+                                       FALSE : TRUE, client->id,
+                                       new_id, SILC_ID_CLIENT_LEN);
 
   /* Remove old cache entry */
   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
@@ -1317,7 +1317,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
-  /* Send NICK_CHANGE notify */
+  /* Send NICK_CHANGE notify to the client's channels */
   silc_server_send_notify_on_channels(server, client, 
                                      SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
                                      oidp->data, oidp->len, 
@@ -1401,15 +1401,15 @@ SILC_SERVER_CMD_FUNC(topic)
 
     /* See whether has rights to change topic */
     silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-      if (chl->client == client) {
-       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-         goto out;
-       } else {
-         break;
-       }
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+      if (chl->client == client)
+       break;
+
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+      if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
       }
     }
 
@@ -1418,6 +1418,13 @@ SILC_SERVER_CMD_FUNC(topic)
       silc_free(channel->topic);
     channel->topic = strdup(tmp);
 
+    /* Send TOPIC_SET notify type to the network */
+    if (!server->standalone)
+      silc_server_send_notify_topic_set(server, server->router->connection,
+                                       server->server_type == SILC_ROUTER ?
+                                       TRUE : FALSE, channel, client->id,
+                                       SILC_ID_CLIENT_LEN, channel->topic);
+
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
     /* Send notify about topic change to all clients on the channel */
@@ -1551,7 +1558,8 @@ SILC_SERVER_CMD_FUNC(invite)
   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
 
   /* Send notify to the client that is invited to the channel */
-  silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
+  silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
+                              SILC_ID_CLIENT,
                               SILC_NOTIFY_TYPE_INVITE, 2, 
                               sidp->data, sidp->len, tmp, len);
 
@@ -1565,20 +1573,30 @@ SILC_SERVER_CMD_FUNC(invite)
   silc_server_command_free(cmd);
 }
 
+typedef struct {
+  SilcServer server;
+  SilcSocketConnection sock;
+  char *signoff;
+} *QuitInternal;
+
 /* Quits connection to client. This gets called if client won't
    close the connection even when it has issued QUIT command. */
 
 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
 {
-  SilcServer server = (SilcServer)context;
-  SilcSocketConnection sock = server->sockets[fd];
+  QuitInternal q = (QuitInternal)context;
 
   /* Free all client specific data, such as client entry and entires
      on channels this client may be on. */
-  silc_server_free_sock_user_data(server, sock);
+  silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
+                              q->signoff);
+  q->sock->user_data = NULL;
 
   /* Close the connection on our side */
-  silc_server_close_connection(server, sock);
+  silc_server_close_connection(q->server, q->sock);
+
+  silc_free(q->signoff);
+  silc_free(q);
 }
 
 /* Quits SILC session. This is the normal way to disconnect client. */
@@ -1588,13 +1606,26 @@ SILC_SERVER_CMD_FUNC(quit)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcSocketConnection sock = cmd->sock;
+  QuitInternal q;
+  unsigned char *tmp = NULL;
+  unsigned int len = 0;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
+
+  /* Get destination ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  if (len > 128)
+    tmp = NULL;
+
+  q = silc_calloc(1, sizeof(*q));
+  q->server = server;
+  q->sock = sock;
+  q->signoff = tmp ? strdup(tmp) : NULL;
 
   /* We quit the connection with little timeout */
   silc_task_register(server->timeout_queue, sock->sock,
-                    silc_server_command_quit_cb, server,
-                    0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+                    silc_server_command_quit_cb, (void *)q,
+                    0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   silc_server_command_free(cmd);
 }
@@ -1752,11 +1783,9 @@ void silc_server_command_send_users(SilcServer server,
     /* If this function was called from pending command then instead of
        processing the command now, register a pending command callback which
        will process it after we've received the automatic USERS command 
-       reply. */
-    silc_server_command_pending(server, SILC_COMMAND_USERS, 0,
-                               silc_server_command_destructor,
-                               silc_server_command_users,
-                               silc_server_command_dup(cmd));
+       reply which server will send in JOIN. */
+    silc_server_command_pending(server, SILC_COMMAND_USERS, 0, NULL,
+                               silc_server_command_users, cmd);
     cmd->pending = TRUE;
     silc_buffer_free(buffer);
     silc_buffer_free(idp);
@@ -1934,16 +1963,16 @@ static void silc_server_command_join_channel(SilcServer server,
   if (!cmd->pending) {
     /* Send JOIN notify to locally connected clients on the channel */
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                      SILC_NOTIFY_TYPE_JOIN, 1,
-                                      clidp->data, clidp->len);
+                                      SILC_NOTIFY_TYPE_JOIN, 2,
+                                      clidp->data, clidp->len,
+                                      chidp->data, chidp->len);
 
-    /* Send NEW_CHANNEL_USER packet to our primary router */
+    /* Send JOIN notify packet to our primary router */
     if (!server->standalone)
-      silc_server_send_new_channel_user(server, server->router->connection,
-                                       server->server_type == SILC_SERVER ?
-                                       FALSE : TRUE,
-                                       channel->id, SILC_ID_CHANNEL_LEN,
-                                       client->id, SILC_ID_CLIENT_LEN);
+      silc_server_send_notify_join(server, server->router->connection,
+                                  server->server_type == SILC_ROUTER ?
+                                  TRUE : FALSE, channel, client->id,
+                                  SILC_ID_CLIENT_LEN);
   }
 
   /* Send USERS command reply to the joined channel so the user sees who
@@ -2566,11 +2595,17 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Send CMODE_CHANGE notify */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-  silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                     SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
                                     cidp->data, cidp->len, 
                                     tmp_mask, tmp_len);
-  silc_free(cidp);
+
+  /* Set CMODE notify type to network */
+  if (!server->standalone)
+    silc_server_send_notify_cmode(server, server->router->connection,
+                                 server->server_type == SILC_ROUTER ? 
+                                 TRUE : FALSE, channel,
+                                 mode_mask, client->id, SILC_ID_CLIENT_LEN);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -2581,6 +2616,7 @@ SILC_SERVER_CMD_FUNC(cmode)
     
   silc_buffer_free(packet);
   silc_free(channel_id);
+  silc_free(cidp);
 
  out:
   silc_server_command_free(cmd);
@@ -2599,20 +2635,20 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcClientEntry target_client;
   SilcChannelClientEntry chl;
   SilcBuffer packet, idp;
-  unsigned char *tmp_id, *tmp_mask;
-  unsigned int target_mask, sender_mask, tmp_len;
+  unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
+  unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
   int notify = FALSE;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
 
   /* Get Channel ID */
-  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp_id) {
+  tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
+  if (!tmp_ch_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
     goto out;
   }
-  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+  channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len);
   if (!channel_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
@@ -2678,7 +2714,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   target_client = silc_idlist_find_client_by_id(server->local_list, 
                                                client_id, NULL);
   if (!target_client) {
-    /* XXX If target client is not one of mine send to primary route */
+    target_client = silc_idlist_find_client_by_id(server->global_list, 
+                                                 client_id, NULL);
   }
 
   /* Check whether target client is on the channel */
@@ -2739,14 +2776,25 @@ SILC_SERVER_CMD_FUNC(cumode)
     }
   }
 
+  idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
-    idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-    silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
                                       idp->data, idp->len,
-                                      tmp_mask, 4, tmp_id, tmp_len);
-    silc_buffer_free(idp);
+                                      tmp_mask, 4, 
+                                      tmp_id, tmp_len);
+
+    /* Set CUMODE notify type to network */
+    if (!server->standalone)
+      silc_server_send_notify_cumode(server, server->router->connection,
+                                    server->server_type == SILC_ROUTER ? 
+                                    TRUE : FALSE, channel,
+                                    target_mask, client->id, 
+                                    SILC_ID_CLIENT_LEN,
+                                    target_client->id, 
+                                    SILC_ID_CLIENT_LEN);
   }
 
   /* Send command reply to sender */
@@ -2760,6 +2808,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   silc_buffer_free(packet);
   silc_free(channel_id);
   silc_free(client_id);
+  silc_buffer_free(idp);
 
  out:
   silc_server_command_free(cmd);
@@ -2833,12 +2882,12 @@ SILC_SERVER_CMD_FUNC(leave)
   }
 
   /* Notify routers that they should remove this client from their list
-     of clients on the channel. */
+     of clients on the channel. Send LEAVE notify type. */
   if (!server->standalone)
-    silc_server_send_remove_channel_user(server, 
-                                        server->router->connection,
-                                        server->server_type == SILC_ROUTER ?
-                                        TRUE : FALSE, id_entry->id, id);
+    silc_server_send_notify_leave(server, server->router->connection,
+                                 server->server_type == SILC_ROUTER ?
+                                 TRUE : FALSE, channel, id_entry->id,
+                                 SILC_ID_CLIENT_LEN);
 
   /* Remove client from channel */
   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,