updates.
authorPekka Riikonen <priikone@silcnet.org>
Thu, 22 Mar 2001 09:13:48 +0000 (09:13 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 22 Mar 2001 09:13:48 +0000 (09:13 +0000)
16 files changed:
CHANGES
README
TODO
apps/silc/client_ops.c
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/testi2.conf
doc/draft-riikonen-silc-spec-01.nroff
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silccore/silcnotify.h

diff --git a/CHANGES b/CHANGES
index dc17654a9c4adb3a23da35c18805d41493119246..3fd8b63d824fd392be6c9d9763f7f660a3e00726 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,28 @@
+Wed Mar 21 15:27:58 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed MOTD command in the server to work in router environment.
+
+       * Fixed the MOTD command in the client library to support
+         the server argument in the command.
+
+       * Added `nickname_len' argument to the silc_idlist_add_client
+         in the server, as the `nickname' argument may be binary data
+         (it may be hash).
+
+       * Added silc_idlist_get_channels to return all channels from
+         the ID list.
+
+       * Implemented LIST command to the server.  Affected file is
+         silcd/command.c.
+
+       * Implemented the LIST command to the client library and on the
+         user interface.
+
+       * Added [<user count>] argument to the LIST command reply.
+         With private channels the user count is not shown.
+
+       * Updated TODO and README.
+
 Tue Mar 20 21:05:57 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * The client entry's data.registered must be TRUE even with
diff --git a/README b/README
index 97e58a3786ea4d2d544d8339acf752e6c712347f..ac9e349f63e609888cacb77ff73bffef11620f88 100644 (file)
--- a/README
+++ b/README
@@ -43,10 +43,8 @@ To run SILC server
        ./silcd -f <config file>
 
 
-Working Commands
-================
-
-Following commands has been, at least partly, implemented:
+SILC Commands
+=============
 
 
        /SERVER [<server>[:<port>]]
@@ -92,7 +90,7 @@ Following commands has been, at least partly, implemented:
                                Add client to/remove client from ban list
                I <username!nickname@server>    
                                Add client to/remove client from invite list
-               c <cipher>[:<keylen>]
+               c <cipher>
                                Set/unset channel's cipher
 
                Multiple modes can be set/unset at once if the modes does not
@@ -120,6 +118,14 @@ Following commands has been, at least partly, implemented:
 
        /UMODE  +|-<modes>
 
+               Sets/unsets user mode.  Currently none of the modes can
+               be set by the user so this command can be merely used to
+               unset some mode.  Following user modes are available:
+
+               a       Unset all modes
+               s       Unset server operator privileges
+               r       Unset router operator privileges
+
        /MSG    <nickname> <message>
 
                Sends private message to remote client.  Support for
@@ -201,6 +207,17 @@ Following commands has been, at least partly, implemented:
                Shutdowns the server.  You must be server operator to be
                able to do this.
 
+       /MOTD   [<server>]
+
+               Display the MOTD of the server.  If server is not specified
+               the current server is used.
+
+       /LIST   [<channel>]
+
+               Lists all channels in the current server, or the channel
+               specified.  If the channel cannot be found then all
+               channels are listed.
+
 
 Features
 ========
diff --git a/TODO b/TODO
index 482f0055fa4b403dc6607b0071b9dedaf9423b32..b8bb37f6b7eb7a1b5500c3ea63bb85c5ec625e14 100644 (file)
--- a/TODO
+++ b/TODO
@@ -102,13 +102,8 @@ TODO In SILC Server
 
  o TODO in command.c and in command_reply.c:
 
-       o LIST is not implemented
        o RESTART is not implemented
        o INVITE is probably not working correctly
-       o PING works only with local server.  It must work with any
-         server in the network, implement the sending to other servers.
-       o MOTD works only with local server.  It must work with any
-         server in the network, implement the sending to other servers.
        o JOIN does not check the invite and ban lists
        o CMODE should be rewritten as it uses a lot duplicated code.
          Some of the modes may still not be implemented or is implemented
@@ -119,7 +114,7 @@ TODO In SILC Server
          it is not called but in server, I think, it must be called.
          When implementing this check that all commands handle the
          situation correctly when it is called as pending command
-         (it should most likely the that cmd->pending == TRUE/FALSE).
+         (it should most likely check that cmd->pending == TRUE/FALSE).
 
  o Packet processing can be made faster. All packet function in the
    packet_receive.c has same prototypes.  Instead of calling those from
index 0a9eb74d8435126b3a32fa59ab9a720f845e5007..690584b8be44206118dded0b790e8772637b9478 100644 (file)
@@ -599,6 +599,55 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
       }
       break;
 
+    case SILC_COMMAND_LIST:
+      {
+       char *topic, *name;
+       unsigned int usercount;
+       unsigned char buf[256], tmp[16];
+       int i, len;
+
+       if (!success)
+         return;
+
+       (void)va_arg(vp, SilcChannelEntry);
+       name = va_arg(vp, char *);
+       topic = va_arg(vp, char *);
+       usercount = va_arg(vp, unsigned int);
+
+       if (status == SILC_STATUS_LIST_START ||
+           status == SILC_STATUS_OK)
+         silc_say(client, conn, 
+         "  Channel                                  Users     Topic");
+
+       memset(buf, 0, sizeof(buf));
+       strncat(buf, "  ", 2);
+       len = strlen(name);
+       strncat(buf, name, len > 40 ? 40 : len);
+       if (len < 40)
+         for (i = 0; i < 40 - len; i++)
+           strcat(buf, " ");
+       strcat(buf, " ");
+
+       memset(tmp, 0, sizeof(tmp));
+       if (usercount) {
+         snprintf(tmp, sizeof(tmp), "%d", usercount);
+         strcat(buf, tmp);
+       }
+       len = strlen(tmp);
+       if (len < 10)
+         for (i = 0; i < 10 - len; i++)
+           strcat(buf, " ");
+       strcat(buf, " ");
+
+       if (topic) {
+         len = strlen(topic);
+         strncat(buf, topic, len);
+       }
+
+       silc_say(client, conn, "%s", buf);
+      }
+      break;
+
     case SILC_COMMAND_UMODE:
       {
        unsigned int mode;
index 7fac79e7df278489113a555cb6e0244953bb7da6..f92e8a39b30e6a646b2ee114a40dcde7781b8378 100644 (file)
@@ -561,7 +561,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     if (count && i - 1 == count)
       break;
 
-    if (clients_count > 2)
+    if (i >= 1)
       status = SILC_STATUS_LIST_ITEM;
 
     if (clients_count > 1 && i == clients_count - 1)
@@ -1363,7 +1363,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     if (count && i - 1 == count)
       break;
 
-    if (clients_count > 2)
+    if (i >= 1)
       status = SILC_STATUS_LIST_ITEM;
 
     if (clients_count > 1 && i == clients_count - 1)
@@ -1793,8 +1793,179 @@ SILC_SERVER_CMD_FUNC(nick)
   silc_server_command_free(cmd);
 }
 
+/* Sends the LIST command reply */
+
+static void
+silc_server_command_list_send_reply(SilcServerCommandContext cmd,
+                                   SilcChannelEntry *lch, 
+                                   unsigned int lch_count,
+                                   SilcChannelEntry *gch,
+                                   unsigned int gch_count)
+{
+  int i;
+  SilcBuffer packet, idp;
+  SilcChannelEntry entry;
+  SilcCommandStatus status;
+  unsigned short ident = silc_command_get_ident(cmd->payload);
+  char *topic;
+  unsigned char usercount[4];
+  unsigned int users;
+
+  for (i = 0; i < lch_count; i++)
+    if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+      lch[i] = NULL;
+  for (i = 0; i < gch_count; i++)
+    if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+      gch[i] = NULL;
+
+  status = SILC_STATUS_OK;
+  if ((lch_count + gch_count) > 1)
+    status = SILC_STATUS_LIST_START;
+
+  /* Local list */
+  for (i = 0; i < lch_count; i++) {
+    entry = lch[i];
+
+    if (!entry)
+      continue;
+
+    if (i >= 1)
+      status = SILC_STATUS_LIST_ITEM;
+
+    if (i == lch_count - 1 && gch_count)
+      break;
+    if (lch_count > 1 && i == lch_count - 1)
+      status = SILC_STATUS_LIST_END;
+
+    idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+    if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+      topic = "*private*";
+      memset(usercount, 0, sizeof(usercount));
+    } else {
+      topic = entry->topic;
+      users = silc_list_count(entry->user_list);
+      SILC_PUT32_MSB(users, usercount);
+    }
+
+    /* Send the reply */
+    if (topic)
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                            status, ident, 4, 
+                                            2, idp->data, idp->len,
+                                            3, entry->channel_name, 
+                                            strlen(entry->channel_name),
+                                            4, topic, strlen(topic),
+                                            5, usercount, 4);
+    else
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                            status, ident, 3, 
+                                            2, idp->data, idp->len,
+                                            3, entry->channel_name, 
+                                            strlen(entry->channel_name),
+                                            5, usercount, 4);
+    silc_server_packet_send(cmd->server, cmd->sock, 
+                           SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
+                           packet->len, FALSE);
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
+  }
+
+  status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
+
+  /* Global list */
+  for (i = 0; i < gch_count; i++) {
+    entry = gch[i];
+
+    if (!entry)
+      continue;
+
+    if (i >= 1)
+      status = SILC_STATUS_LIST_ITEM;
+
+    if (gch_count > 1 && i == lch_count - 1)
+      status = SILC_STATUS_LIST_END;
+
+    idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+    if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+      topic = "*private*";
+      memset(usercount, 0, sizeof(usercount));
+    } else {
+      topic = entry->topic;
+      users = silc_list_count(entry->user_list);
+      SILC_PUT32_MSB(users, usercount);
+    }
+
+    /* Send the reply */
+    if (topic)
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                            status, ident, 4, 
+                                            2, idp->data, idp->len,
+                                            3, entry->channel_name, 
+                                            strlen(entry->channel_name),
+                                            4, topic, strlen(topic),
+                                            5, usercount, 4);
+    else
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                            status, ident, 3, 
+                                            2, idp->data, idp->len,
+                                            3, entry->channel_name, 
+                                            strlen(entry->channel_name),
+                                            5, usercount, 4);
+    silc_server_packet_send(cmd->server, cmd->sock, 
+                           SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
+                           packet->len, FALSE);
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
+  }
+}
+
+/* Server side of LIST command. This lists the channel of the requested
+   server. Secret channels are not listed. */
+
 SILC_SERVER_CMD_FUNC(list)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcChannelID *channel_id = NULL;
+  unsigned char *tmp;
+  unsigned int tmp_len;
+  SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
+  unsigned int lch_count = 0, gch_count = 0;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (tmp) {
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel_id) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
+      goto out;
+    }
+  }
+
+  /* Get the channels from local list */
+  lchannels = silc_idlist_get_channels(server->local_list, channel_id,
+                                      &lch_count);
+  
+  /* Get the channels from global list if we are router */
+  if (server->server_type == SILC_ROUTER) 
+    gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+                                        &gch_count);
+
+  /* Send the reply */
+  silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
+                                     gchannels, gch_count);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 /* Server side of TOPIC command. Sets topic for channel and/or returns
@@ -2756,30 +2927,135 @@ SILC_SERVER_CMD_FUNC(motd)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  char *motd;
+  SilcBuffer packet, idp;
+  char *motd, *dest_server;
   int motd_len;
+  unsigned short ident = silc_command_get_ident(cmd->payload);
   
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
 
-  /* XXX show currently only our motd */
+  /* Get server name */
+  dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  if (!dest_server) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+                                         SILC_STATUS_ERR_NO_SUCH_SERVER);
+    goto out;
+  }
 
-  if (server->config && server->config->motd && 
-      server->config->motd->motd_file) {
+  if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+    /* Send our MOTD */
 
-    /* Send motd */
-    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
-    if (!motd)
+    idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+
+    if (server->config && server->config->motd && 
+       server->config->motd->motd_file) {
+      /* Send motd */
+      motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+      if (!motd)
+       goto out;
+      
+      motd[motd_len] = 0;
+      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+                                                   SILC_STATUS_OK, ident, 2,
+                                                   2, idp, idp->len,
+                                                   3, motd, motd_len);
       goto out;
+    } else {
+      /* No motd */
+      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+                                                   SILC_STATUS_OK, ident, 1,
+                                                   2, idp, idp->len);
+    }
 
-    motd[motd_len] = 0;
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
-                                        SILC_STATUS_OK,
-                                        2, motd, motd_len);
-    goto out;
+    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                           packet->data, packet->len, FALSE);
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
   } else {
-    /* No motd */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
-                                         SILC_STATUS_OK);
+    SilcServerEntry entry;
+
+    /* Check whether we have this server cached */
+    entry = silc_idlist_find_server_by_name(server->global_list,
+                                           dest_server, NULL);
+    if (!entry) {
+      entry = silc_idlist_find_server_by_name(server->local_list,
+                                             dest_server, NULL);
+    }
+
+    if (server->server_type == SILC_ROUTER && !cmd->pending && 
+       entry && !entry->motd) {
+      /* Send to the server */
+      SilcBuffer tmpbuf;
+      unsigned short old_ident;
+
+      old_ident = silc_command_get_ident(cmd->payload);
+      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+      silc_server_packet_send(server, entry->connection,
+                             SILC_PACKET_COMMAND, cmd->packet->flags,
+                             tmpbuf->data, tmpbuf->len, TRUE);
+
+      /* Reprocess this packet after received reply from router */
+      silc_server_command_pending(server, SILC_COMMAND_MOTD, 
+                                 silc_command_get_ident(cmd->payload),
+                                 silc_server_command_destructor,
+                                 silc_server_command_motd,
+                                 silc_server_command_dup(cmd));
+      cmd->pending = TRUE;
+      silc_command_set_ident(cmd->payload, old_ident);
+      silc_buffer_free(tmpbuf);
+      return;
+    }
+
+    if (!entry && !cmd->pending && !server->standalone) {
+      /* Send to the primary router */
+      SilcBuffer tmpbuf;
+      unsigned short old_ident;
+
+      old_ident = silc_command_get_ident(cmd->payload);
+      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+      silc_server_packet_send(server, server->router->connection,
+                             SILC_PACKET_COMMAND, cmd->packet->flags,
+                             tmpbuf->data, tmpbuf->len, TRUE);
+
+      /* Reprocess this packet after received reply from router */
+      silc_server_command_pending(server, SILC_COMMAND_MOTD, 
+                                 silc_command_get_ident(cmd->payload),
+                                 silc_server_command_destructor,
+                                 silc_server_command_motd,
+                                 silc_server_command_dup(cmd));
+      cmd->pending = TRUE;
+      silc_command_set_ident(cmd->payload, old_ident);
+      silc_buffer_free(tmpbuf);
+      return;
+    }
+
+    if (!entry) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
+      goto out;
+    }
+
+    idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+
+    if (entry->motd)
+      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+                                                   SILC_STATUS_OK, ident, 2,
+                                                   2, idp, idp->len,
+                                                   3, entry->motd,
+                                                   strlen(entry->motd));
+    else
+      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+                                                   SILC_STATUS_OK, ident, 1,
+                                                   2, idp, idp->len);
+
+    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                           packet->data, packet->len, FALSE);
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
   }
 
  out:
index 6dac16d1e42fcd9631905543a695b16748883915..b693e2f3711bf1c6eb110b614f5dc8945afe1680 100644 (file)
@@ -54,6 +54,7 @@ SilcServerCommandReply silc_command_reply_list[] =
   SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
   SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
   SILC_SERVER_CMD_REPLY(info, INFO),
+  SILC_SERVER_CMD_REPLY(motd, MOTD),
   SILC_SERVER_CMD_REPLY(join, JOIN),
   SILC_SERVER_CMD_REPLY(users, USERS),
 
@@ -187,7 +188,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
        global. */
-    client = silc_idlist_add_client(server->global_list, nick,
+    client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
                                    strdup(username), 
                                    strdup(realname), client_id, 
                                    cmd->sock->user_data, NULL);
@@ -314,9 +315,8 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
        global. */
-    client = silc_idlist_add_client(server->global_list, nick,
-                                   strdup(username), 
-                                   strdup(realname), 
+    client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
+                                   strdup(username), strdup(realname), 
                                    silc_id_dup(client_id, SILC_ID_CLIENT), 
                                    cmd->sock->user_data, NULL);
     if (!client)
@@ -435,7 +435,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
        global. */
-    client = silc_idlist_add_client(server->global_list, nick,
+    client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
                                    username ? strdup(username) : NULL, NULL,
                                    client_id, cmd->sock->user_data, NULL);
     client->data.registered = TRUE;
@@ -524,7 +524,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   if (!server_id)
     goto out;
 
-  /* Get the info string */
+  /* Get the name */
   name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
   if (tmp_len > 256)
     goto out;
@@ -560,6 +560,53 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   silc_server_command_reply_free(cmd);
 }
 
+/* Received reply fro MOTD command. */
+
+SILC_SERVER_CMD_REPLY_FUNC(motd)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcServer server = cmd->server;
+  SilcCommandStatus status;
+  SilcServerEntry entry;
+  SilcServerID *server_id;
+  unsigned int tmp_len;
+  unsigned char *tmp;
+
+  COMMAND_CHECK_STATUS;
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!tmp)
+    goto out;
+  server_id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!server_id)
+    goto out;
+
+  entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL);
+  if (!entry) {
+    entry = silc_idlist_find_server_by_id(server->global_list, server_id, 
+                                         NULL);
+    if (!entry)
+      goto out;
+  }
+
+  /* Get the motd */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  if (tmp_len > 256)
+    tmp = NULL;
+
+  entry->motd = tmp;
+
+  /* Execute any pending commands */
+  SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
+
+  entry->motd = NULL;
+
+ out:
+  SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
+  silc_server_command_reply_free(cmd);
+}
+
 /* Received reply for forwarded JOIN command. Router has created or joined
    the client to the channel. We save some channel information locally
    for future use. */
index 0726f108224dd8d074f87b99f1eb66500dedb14d..397c825f52c8901143640fdf7d4ac34e3597e5f1 100644 (file)
@@ -65,6 +65,7 @@ SILC_SERVER_CMD_REPLY_FUNC(whois);
 SILC_SERVER_CMD_REPLY_FUNC(whowas);
 SILC_SERVER_CMD_REPLY_FUNC(identify);
 SILC_SERVER_CMD_REPLY_FUNC(info);
+SILC_SERVER_CMD_REPLY_FUNC(motd);
 SILC_SERVER_CMD_REPLY_FUNC(join);
 SILC_SERVER_CMD_REPLY_FUNC(users);
 
index 6d0b9030b97e512f721cf46963cd516f3df19c3d..b5c17daf5627dd5b9e79f2063538d4085b01a66c 100644 (file)
@@ -287,7 +287,8 @@ void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
 
 SilcClientEntry
 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, 
-                      char *username, char *userinfo, SilcClientID *id, 
+                      unsigned int nickname_len, char *username, 
+                      char *userinfo, SilcClientID *id, 
                       SilcServerEntry router, void *connection)
 {
   SilcClientEntry client;
@@ -304,8 +305,7 @@ silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
   silc_list_init(client->channels, struct SilcChannelClientEntryStruct, 
                 client_list);
 
-  if (!silc_idcache_add(id_list->clients, nickname, 
-                       nickname ? strlen(nickname) : 0,
+  if (!silc_idcache_add(id_list->clients, nickname,  nickname_len,
                        SILC_ID_CLIENT, (void *)client->id, 
                        (void *)client, TRUE, FALSE)) {
     silc_free(client);
@@ -382,6 +382,10 @@ silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
 
 /* Returns all clients matching requested nickname. Number of clients is
    returned to `clients_count'. Caller must free the returned table. */
+/* XXX This actually checks the data, which can be hash of the nickname
+   but is not if the client is local client. Global client on global
+   list may have hash.  Thus, this is not fully reliable function.
+   Instead this should probably check the hash from the lists client ID's. */
 
 SilcClientEntry *
 silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
@@ -775,5 +779,42 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
   channel->id = new_id;
   id_cache->id = (void *)new_id;
 
+  SILC_LOG_DEBUG(("Replaced"));
+
   return channel;
 }
+
+/* Returns channels from the ID list. If the `channel_id' is NULL then
+   all channels are returned. */
+
+SilcChannelEntry *
+silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
+                        unsigned int *channels_count)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry *channels;
+  int i;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!silc_idcache_find_by_id(id_list->channels, channel_id ? channel_id :
+                              SILC_ID_CACHE_ANY, SILC_ID_CHANNEL, &list))
+    return NULL;
+
+  channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
+
+  i = 0;
+  silc_idcache_list_first(list, &id_cache);
+  channels[i++] = (SilcChannelEntry)id_cache->context;
+
+  while (silc_idcache_list_next(list, &id_cache))
+    channels[i++] = (SilcChannelEntry)id_cache->context;
+  
+  silc_idcache_list_free(list);
+  
+  if (channels_count)
+    *channels_count = i;
+
+  return channels;
+}
index 59d6282d5ce798f6b249e55c4923b09808da34d2..efca0dbf03cfd73ceee9a94840e641f6baba405d 100644 (file)
@@ -107,6 +107,12 @@ typedef struct {
        the server SILC will ever need. These are also the informations
        that is broadcasted between servers and routers in the SILC network.
 
+   char *server_info
+   char *motd
+
+       Server info (from INFO command) saved temporarily and motd (from
+       MOTD command) saved temporarily.
+
    SilcServerEntry router
 
        This is a pointer back to the server list. This is the router server 
@@ -134,6 +140,7 @@ struct SilcServerEntryStruct {
   int server_type;
   SilcServerID *id;
   char *server_info;
+  char *motd;
 
   /* Pointer to the router */
   SilcServerEntry router;
@@ -489,7 +496,8 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
 void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry);
 SilcClientEntry
 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, 
-                      char *username, char *userinfo, SilcClientID *id, 
+                      unsigned int nickname_len, char *username, 
+                      char *userinfo, SilcClientID *id, 
                       SilcServerEntry router, void *connection);
 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry);
 SilcClientEntry *
@@ -528,5 +536,8 @@ silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
 SilcChannelEntry
 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
                               SilcChannelID *new_id);
+SilcChannelEntry *
+silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
+                        unsigned int *channels_count);
 
 #endif
index 98fb540b183b323e25e99694e0472c6087d6aac9..16e9fa430f1d5f9ed0106329a393ffcd6bd70d94 100644 (file)
@@ -148,7 +148,7 @@ void silc_server_notify(SilcServer server,
          goto out;
 
        client = 
-         silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
+         silc_idlist_add_client(server->global_list, NULL, 0, NULL, NULL,
                                 silc_id_dup(client_id, SILC_ID_CLIENT), 
                                 sock->user_data, NULL);
        if (!client) {
@@ -1305,8 +1305,9 @@ static void silc_server_new_id_real(SilcServer server,
                         sizeof(unsigned char));
       memcpy(hash, ((SilcClientID *)id)->hash, 
             sizeof(((SilcClientID *)id)->hash));
-      entry = silc_idlist_add_client(id_list, hash, NULL, NULL, id, 
-                                    router, NULL);
+      entry = silc_idlist_add_client(id_list, hash, 
+                                    sizeof(((SilcClientID *)id)->hash),
+                                    NULL, NULL, id, router, NULL);
       entry->nickname = NULL;
       entry->data.registered = TRUE;
 
index 999c24b60a6f6f8a893396354a5cc39280321e0b..6df25f7bc93f276b37709b315996fe84704a7557 100644 (file)
@@ -1184,7 +1184,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         and other information is created after we have received NEW_CLIENT
         packet from client. */
       client = silc_idlist_add_client(server->local_list, 
-                                     NULL, NULL, NULL, NULL, NULL, sock);
+                                     NULL, 0, NULL, NULL, NULL, NULL, sock);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
@@ -3102,7 +3102,8 @@ void silc_server_save_users_on_channel(SilcServer server,
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be 
         global. */
-      client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL, 
+      client = silc_idlist_add_client(server->global_list, NULL, 0, NULL, 
+                                     NULL, 
                                      silc_id_dup(client_id, SILC_ID_CLIENT), 
                                      sock->user_data, NULL);
       if (!client) {
index 7140f1186bdf256c2edb5f0cf63a43123dbb537a..42ed3eae557fcc11cf459bdcbb77c8bacb6813ad 100644 (file)
@@ -1,23 +1,17 @@
 [Cipher]
-aes-256-cbc:../lib/silcsim/modules/aes.sim.so:32:16
-aes-192-cbc:../lib/silcsim/modules/aes.sim.so:24:16
-aes-128-cbc:../lib/silcsim/modules/aes.sim.so:16:16
-twofish-256-cbc:../lib/silcsim/modules/twofish.sim.so:32:16
-twofish-192-cbc:../lib/silcsim/modules/twofish.sim.so:24:16
-twofish-128-cbc:../lib/silcsim/modules/twofish.sim.so:16:16
-mars-256-cbc:../lib/silcsim/modules/mars.sim.so:32:16
-mars-192-cbc:../lib/silcsim/modules/mars.sim.so:24:16
-mars-128-cbc:../lib/silcsim/modules/mars.sim.so:16:16
+rc6:../lib/silcsim/modules/rc6.sim.so:16:16
+twofish:../lib/silcsim/modules/twofish.sim.so:16:16
+mars:../lib/silcsim/modules/mars.sim.so:16:16
 none:../lib/silcsim/modules/none.sim.so:0:0
 
-[Hash]
+[Hash] 
 md5::64:16
 sha1::64:20
 
 [hmac]
 hmac-sha1-96:sha1:12
 hmac-md5-96:md5:12
-hmac-sha1:sha1:20   
+hmac-sha1:sha1:20
 hmac-md5:md5:16
 
 #[PKCS]
@@ -31,10 +25,10 @@ nobody:nobody
 Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
 
 [ServerInfo]
-silc:212.146.42.253:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
 
 [ListenPort]
-212.146.42.253:212.146.42.253:1334
+10.2.1.7:10.2.1.7:1334
 
 [Logging]
 infologfile:silcd2.log:10000
@@ -53,13 +47,16 @@ errorlogfile:silcd2.log:10000
 :::1336:1
 
 [AdminConnection]
-*:priikone:*:passwd:testi
+*:silc:silc:passwd:testi
 
 [ServerConnection]
-212.146.42.253:passwd:priikone:1336:1:1
+10.2.1.7:passwd:priikone:1333:1:1
 
 [RouterConnection]
-212.146.42.253:passwd:priikone:1335:1:1:0
+10.2.1.7:passwd:priikone:1335:1:1:0
 
 [DenyConnection]
 [RedirectClient]
+
+[motd]
+./motd
index 8c238d8c5f79f3a32a52cc490c1f1bf1285cae9e..a80c2eea20d91f3532a529ce829e21b7a01a0dab 100644 (file)
@@ -2182,24 +2182,22 @@ List of all defined commands in SILC follows.
 
    5    SILC_COMMAND_LIST
 
-        Max Arguments:  2
-            Arguments:  (1) [<Channel ID>] [<server>]
+        Max Arguments:  1
+            Arguments:  (1) [<Channel ID>]
 
-        The list command is used to list channels and their topics on
+        The list command is used to list channels and their topics on the
         current server.  If the <Channel ID> parameter is used, only the
         status of that channel is displayed.  Secret channels are not
         listed at all.  Private channels are listed with status indicating
-        that the channel is private.
-
-        If the <server> argument is specified the specified server's
-        channels are listed.  In this case the command must be sent to
-        the server who owns the channel that was requested.
+        that the channel is private.  Router may reply with all channels
+        it knows about.
 
         Reply messages to the command:
 
-        Max Arguments:  4
+        Max Arguments:  5
             Arguments:  (1) <Status Payload>  (2) <Channel ID>
-                        (3) <channel>         (4) <topic>
+                        (3) <channel>         (4) [<topic>]
+                        (5) [<user count>]
 
         This command may reply with several command reply messages to form
         a list of results.  In this case the status payload will include
@@ -2219,8 +2217,8 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_WILDCARDS
             SILC_STATUS_ERR_NOT_REGISTERED
             SILC_STATUS_ERR_TOO_MANY_PARAMS
-            SILC_STATUS_ERR_NO_SUCH_CHANNEL
             SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
             SILC_STATUS_ERR_NO_SUCH_SERVER
 
 
@@ -2296,6 +2294,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CHANNEL_ID
             SILC_STATUS_ERR_NOT_ON_CHANNEL
             SILC_STATUS_ERR_USER_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
 
 
    8    SILC_COMMAND_QUIT
@@ -2570,8 +2569,9 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  2
-            Arguments:  (1) <Status Payload>  (2) [<motd>]
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) [<motd>]
 
         This command replies with the motd message if it exists.
 
index 7c90c184b63da344dbea59b10fc70b8caf4225be..002363fb305077eb4b8410759d1bd845275e2e3b 100644 (file)
@@ -407,8 +407,53 @@ SILC_CLIENT_CMD_FUNC(nick)
   silc_client_command_free(cmd);
 }
 
+/* Command LIST. Lists channels on the current server. */
+
 SILC_CLIENT_CMD_FUNC(list)
 {
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, idp = NULL;
+  char *name;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc == 2) {
+    name = cmd->argv[1];
+
+    /* Get the Channel ID of the channel */
+    if (silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
+      channel = (SilcChannelEntry)id_cache->context;
+      idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+    }
+  }
+
+  if (!idp)
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
+                                           ++conn->cmd_ident, 0);
+  else
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
+                                           ++conn->cmd_ident, 1,
+                                           1, idp->data, idp->len);
+
+  silc_client_packet_send(cmd->client, cmd->conn->sock,
+                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  if (idp)
+    silc_buffer_free(idp);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
 }
 
 /* Command TOPIC. Sets/shows topic on a channel. */
@@ -906,17 +951,22 @@ SILC_CLIENT_CMD_FUNC(motd)
     goto out;
   }
 
-  if (cmd->argc < 1 || cmd->argc > 1) {
+  if (cmd->argc < 1 || cmd->argc > 2) {
     cmd->client->ops->say(cmd->client, conn,
-                         "Usage: /MOTD");
+                         "Usage: /MOTD [<server>]");
     COMMAND_ERROR;
     goto out;
   }
 
   /* Send TOPIC command to the server */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
-                                         2, conn->remote_host, 
-                                         strlen(conn->remote_host));
+  if (cmd->argc == 1)
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
+                                           1, conn->remote_host, 
+                                           strlen(conn->remote_host));
+  else
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
+                                           1, cmd->argv[1], 
+                                           cmd->argv_lens[1]);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
index 91579710086e88fe3a8c73adc2838afe94a3b267..261578cf17a8b19cb0723088875106c39a41cda0 100644 (file)
@@ -592,8 +592,47 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   silc_client_command_reply_free(cmd);
 }
 
+/* Received reply to the LIST command. */
+
 SILC_CLIENT_CMD_REPLY_FUNC(list)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcCommandStatus status;
+  unsigned char *tmp, *name, *topic;
+  unsigned int usercount = 0;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK && 
+      status != SILC_STATUS_LIST_START &&
+      status != SILC_STATUS_LIST_ITEM &&
+      status != SILC_STATUS_LIST_END) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+  topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
+  if (tmp)
+    SILC_GET32_MSB(usercount, tmp);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
+
+  /* Pending callbacks are not executed if this was an list entry */
+  if (status != SILC_STATUS_OK &&
+      status != SILC_STATUS_LIST_END) {
+    silc_client_command_reply_free(cmd);
+    return;
+  }
+
+  /* Execute any pending command callbacks */
+  SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
+
+ out:
+  SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
+  silc_client_command_reply_free(cmd);
 }
 
 /* Received reply to topic command. */
@@ -1042,13 +1081,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd)
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
-  if (argc > 2) {
+  if (argc > 3) {
     COMMAND_REPLY_ERROR;
     goto out;
   }
 
-  if (argc == 2) {
-    motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (argc == 3) {
+    motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!motd) {
       COMMAND_REPLY_ERROR;
       goto out;
index 68faeed35dad44fddebea008c03d04b7d2e89a9c..3b42fbaa368baa9b0fa6275b386e5a1bdad9930f 100644 (file)
@@ -28,8 +28,7 @@ typedef struct SilcNotifyPayloadStruct *SilcNotifyPayload;
 typedef unsigned short SilcNotifyType;
 
 /* SILC notify types. Server may send these notify types to client to
-   notify of some action. Server also sends human readable notify message
-   to the client which client may ignore. */
+   notify of some action. */
 #define SILC_NOTIFY_TYPE_NONE            0 /* no specific type */
 #define SILC_NOTIFY_TYPE_INVITE          1 /* "invites you to channel" */
 #define SILC_NOTIFY_TYPE_JOIN            2 /* "has joined channel" */