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
 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>
 
 
        ./silcd -f <config file>
 
 
-Working Commands
-================
-
-Following commands has been, at least partly, implemented:
+SILC Commands
+=============
 
 
        /SERVER [<server>[:<port>]]
 
 
        /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
                                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
                                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>
 
 
        /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
        /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.
 
                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
 ========
 
 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 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 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
        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 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
 
  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;
 
       }
       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;
     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 (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)
       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 (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)
       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);
 }
 
   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)
 {
 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
 }
 
 /* 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;
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  char *motd;
+  SilcBuffer packet, idp;
+  char *motd, *dest_server;
   int motd_len;
   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;
       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 {
   } 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:
   }
 
  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(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),
 
   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. */
     /* 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);
                                    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. */
     /* 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)
                                    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. */
     /* 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;
                                    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;
 
   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;
   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);
 }
 
   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. */
 /* 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(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);
 
 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, 
 
 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;
                       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);
 
   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);
                        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. */
 
 /* 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,
 
 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;
 
   channel->id = new_id;
   id_cache->id = (void *)new_id;
 
+  SILC_LOG_DEBUG(("Replaced"));
+
   return channel;
 }
   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.
 
        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 
    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;
   int server_type;
   SilcServerID *id;
   char *server_info;
+  char *motd;
 
   /* Pointer to the router */
   SilcServerEntry router;
 
   /* 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, 
 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 *
                       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_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
 
 #endif
index 98fb540b183b323e25e99694e0472c6087d6aac9..16e9fa430f1d5f9ed0106329a393ffcd6bd70d94 100644 (file)
@@ -148,7 +148,7 @@ void silc_server_notify(SilcServer server,
          goto out;
 
        client = 
          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) {
                                 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));
                         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;
 
       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, 
         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);
       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. */
       /* 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) {
                                      silc_id_dup(client_id, SILC_ID_CLIENT), 
                                      sock->user_data, NULL);
       if (!client) {
index 7140f1186bdf256c2edb5f0cf63a43123dbb537a..42ed3eae557fcc11cf459bdcbb77c8bacb6813ad 100644 (file)
@@ -1,23 +1,17 @@
 [Cipher]
 [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
 
 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
 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]
 hmac-md5:md5:16
 
 #[PKCS]
@@ -31,10 +25,10 @@ nobody:nobody
 Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
 
 [ServerInfo]
 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]
 
 [ListenPort]
-212.146.42.253:212.146.42.253:1334
+10.2.1.7:10.2.1.7:1334
 
 [Logging]
 infologfile:silcd2.log:10000
 
 [Logging]
 infologfile:silcd2.log:10000
@@ -53,13 +47,16 @@ errorlogfile:silcd2.log:10000
 :::1336:1
 
 [AdminConnection]
 :::1336:1
 
 [AdminConnection]
-*:priikone:*:passwd:testi
+*:silc:silc:passwd:testi
 
 [ServerConnection]
 
 [ServerConnection]
-212.146.42.253:passwd:priikone:1336:1:1
+10.2.1.7:passwd:priikone:1333:1:1
 
 [RouterConnection]
 
 [RouterConnection]
-212.146.42.253:passwd:priikone:1335:1:1:0
+10.2.1.7:passwd:priikone:1335:1:1:0
 
 [DenyConnection]
 [RedirectClient]
 
 [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
 
 
    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
         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:
 
 
         Reply messages to the command:
 
-        Max Arguments:  4
+        Max Arguments:  5
             Arguments:  (1) <Status Payload>  (2) <Channel ID>
             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
 
         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_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_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
             SILC_STATUS_ERR_NO_SUCH_SERVER
 
 
             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_ID
             SILC_STATUS_ERR_NOT_ON_CHANNEL
             SILC_STATUS_ERR_USER_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
 
 
    8    SILC_COMMAND_QUIT
 
 
    8    SILC_COMMAND_QUIT
@@ -2570,8 +2569,9 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
 
         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.
 
 
         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);
 }
 
   silc_client_command_free(cmd);
 }
 
+/* Command LIST. Lists channels on the current server. */
+
 SILC_CLIENT_CMD_FUNC(list)
 {
 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. */
 }
 
 /* Command TOPIC. Sets/shows topic on a channel. */
@@ -906,17 +951,22 @@ SILC_CLIENT_CMD_FUNC(motd)
     goto out;
   }
 
     goto out;
   }
 
-  if (cmd->argc < 1 || cmd->argc > 1) {
+  if (cmd->argc < 1 || cmd->argc > 2) {
     cmd->client->ops->say(cmd->client, conn,
     cmd->client->ops->say(cmd->client, conn,
-                         "Usage: /MOTD");
+                         "Usage: /MOTD [<server>]");
     COMMAND_ERROR;
     goto out;
   }
 
   /* Send TOPIC command to the 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);
   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);
 }
 
   silc_client_command_reply_free(cmd);
 }
 
+/* Received reply to the LIST command. */
+
 SILC_CLIENT_CMD_REPLY_FUNC(list)
 {
 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. */
 }
 
 /* Received reply to topic command. */
@@ -1042,13 +1081,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd)
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
-  if (argc > 2) {
+  if (argc > 3) {
     COMMAND_REPLY_ERROR;
     goto out;
   }
 
     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;
     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
 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" */
 #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" */