updates.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 2 Dec 2001 19:05:27 +0000 (19:05 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 2 Dec 2001 19:05:27 +0000 (19:05 +0000)
17 files changed:
CHANGES
TODO
apps/irssi/config
apps/irssi/docs/help/in/join.in
apps/irssi/src/silc/core/silc-channels.c
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/command.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/server.c
apps/silcd/server.h
doc/draft-riikonen-silc-commands-03.nroff
doc/draft-riikonen-silc-pp-05.nroff
lib/silcclient/client.c
lib/silcclient/client_notify.c
lib/silcclient/command.c

diff --git a/CHANGES b/CHANGES
index 88a533cf149eb42d052030fba6d31f9de096ee3d..bb563c34e2123bf2f80e78b8769f9569bc929c57 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,36 @@
+Sun Dec  2 13:48:46 EET 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Distribute to the channel passphrase in CMODE_CHANGE notify.
+         Updated specs and implemented it.  Affected file silcd/command.c,
+         silcd/packet_send.c and silcd/packet_receive.c.
+
+       * Implemented the <founder auth> payload handling in the JOIN
+         command.  If provided all conditions for channel joining
+         except requirement to provide correct passphrase can be 
+         overrided by the channel founder.  Updated the protocol specs.
+         Affected file silcd/command.c.
+
+         Added support for founder auth in JOIN command in client
+         library.  Fixed the parsing of the JOIN command now to support
+         all options as they should be.  The affected file is
+         lib/silcclient/command.c.
+
+       * Optimized the WHOIS and IDENTIFY commands to send the request
+         to router only if it includes nicknames or other names.  If
+         they include only IDs then check the local cache first before
+         routing.  Affected file is silcd/command.c.
+
+       * Added channels topic announcements.  Affected file is
+         silcd/packet_receive.c and silcd/server.c.
+
+       * Fixed the silc_server_send_notify_topic_set to really destine
+         the packet to channel.  Affected file silcd/packet_send.c.
+
+       * Fixed a crash in CHANNEL_CHANGE notify handling in the client
+         library.  Affected file lib/silcclient/client_notify.c.
+
+       * Added UMODE announcements.  Affected file silcd/server.c.
+
 Sat Dec  1 12:52:39 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Memory leak fixes in:
diff --git a/TODO b/TODO
index 00e588d83f157dab93afd359fccdec21cfc4a7df..d080e0cac1d8426f06505625013b1f5704c6b1d5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -13,11 +13,6 @@ TODO/bugs in Irssi SILC client
    that the user has.  And a local command to dump the contents of the
    public key to the screen.  Something like LISTKEYS, SHOWKEY...
 
- o The JOIN command's HELP is generated from Irssi IRCs JOIN help and
-   the syntax is not same in SILC.  This must be fixed.  Most likely
-   we must forget the Irssi's JOIN command and mimic it to get our
-   required syntax for it too.
-
  o We should get rid of the clientconfig.[ch] in Irssi SILC and move the
    cipher, hash, hmac and pkcs configuration to the Irssi SILC's config
    file.
@@ -35,48 +30,14 @@ TODO/bugs in Irssi SILC client
 TODO/bugs In SILC Client Library
 ================================
 
- o JOIN command's argument handling is buggy.  See the XXX in the code.
+ o N/A
 
 
 TODO/bugs In SILC Server
 ========================
 
- o XXXXXXXXX cannot join +a channel from other servers
-
- o Implement the <founder auth> and founder privileges gaining to
-   the JOIN command.  This will bypass invite-only mode as well for
-   the client who got the founder mode during JOIN.
-
- o Optimize the WHOIS and IDENTIFY commands to check if the request
-   includes an ID or multiple IDs, then they are checked from local cache
-   first, and not sent directly to router.  This is because if they
-   are found in the local cache there's no need to send them to the
-   router.  Only if some ID is not found, or an found entry is 
-   incomplete it can be queried from the router.  This way these
-   commands become faster, and for example JOIN command becomes a lot
-   faster since the server ends up resolving the same information only
-   once, as opposed to resolve it everytime JOIN command is issued, like
-   it does now.
-
-   The same thing can be done with WHOWAS command as well.
-
-   It is important to send these requests to router only if they can be
-   expanded to many results (as when doing WHOIS for nickname).  If
-   they are explicit (like requesting by ID) the local cache MUST be
-   searched before sending it to router.
-
- o Announcements are incomplete: channel topics are not announced,
-   user modes (UMODE) are not announced.
-
- o Change the server to connect to another server from low ports (706)
-   and not from high ports.  Currently we cannot do incoming connection
-   checking by remote port because the port is not fixed.
-
  o Backup router related issues
 
-       o After backup resume protocol the TOPIC_SET was not handled
-         correctly by all (unknown Channel ID).
-
        o Channel user mode changes are notified unnecessarely when
          switching to backup router on router crash.
 
index d611d4bdf0985f95688eb608d8406f463142ac16..f6276469d201a0cfbdc11b1b9306d0ee8fbc014b 100644 (file)
@@ -1,5 +1,8 @@
 servers = (
   { address = "silc.silcnet.org"; chatnet = SILCNet; port = 706; }
+  { address = "silc.ytti.fi"; chatnet = SILCNet; port = 706; }
+  { address = "silc.peelo.com"; chatnet = SILCNet; port = 706; }
+  { address = "silc.silcnet.org"; chatnet = SILCNet; port = 707; }
 );
 
 chatnets = {
index 424362afd7e601603d37132e2be7a9a633329d91..bd95134542b70bd610b752ff9ca680a07b0dd1c1 100644 (file)
@@ -4,9 +4,21 @@
 Joins a specified channel. Channel names usually begin with #-sign,
 but note that the #-sign is not mandatory in channel names.
 
+If -cipher is provided and the channel does not exist the cipher to
+secure the channel messages on the channel will be set to <cipher>.  If
+the -hmac is provided and the channel does not exist the hmac to
+secure the channel messages on the channel will be set to <hmac>.
+
+If -founder is provided, and the channel's mode includes founder mode
+it is possible to gain channel founder privileges at the same time
+joining the channel.  If the channel has user limit, active bans,
+or is invite-only channel the founder can override these conditions
+and join the channel.  Only the client who set the founder mode on the
+channel is able to use -founder option.
+
 JOIN is aliased to J by default.
 
 Description
 
-See also: LEAVE, WINDOW CLOSE
+See also: LEAVE, WINDOW CLOSE, CMODE, CUMODE
 
index 25d6b6a4e122e12375c9c3a312414d9a4a5831fc..5e52a6bbe861439e36576db8a9f574259a9bfa77 100644 (file)
@@ -242,17 +242,19 @@ static void event_signoff(SILC_SERVER_REC *server, va_list va)
 static void event_topic(SILC_SERVER_REC *server, va_list va)
 {
   SILC_CHANNEL_REC *chanrec;
+  void *entry;
   SilcClientEntry client;
+  SilcServerEntry server_entry;
   SilcChannelEntry channel;
   char *topic;
   char userhost[256];
+  SilcIdType idtype;
 
-  client = va_arg(va, SilcClientEntry);
+  idtype = va_arg(va, int);
+  entry = va_arg(va, void *);
   topic = va_arg(va, char *);
   channel = va_arg(va, SilcChannelEntry);
 
-  silc_server_free_ftp(server, client);
-
   chanrec = silc_channel_find_entry(server, channel);
   if (chanrec != NULL) {
     g_free_not_null(chanrec->topic);
@@ -260,11 +262,23 @@ static void event_topic(SILC_SERVER_REC *server, va_list va)
     signal_emit("channel topic changed", 1, chanrec);
   }
 
-  memset(userhost, 0, sizeof(userhost));
-  snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
-          client->username, client->hostname);
-  signal_emit("message topic", 5, server, channel->channel_name,
-             topic, client->nickname, userhost);
+  if (idtype == SILC_ID_CLIENT) {
+    client = (SilcClientEntry)entry;
+    memset(userhost, 0, sizeof(userhost));
+    snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+            client->username, client->hostname);
+    signal_emit("message topic", 5, server, channel->channel_name,
+               topic, client->nickname, userhost);
+  } else if (idtype == SILC_ID_SERVER) {
+    server_entry = (SilcServerEntry)entry;
+    signal_emit("message topic", 5, server, channel->channel_name,
+               topic, server_entry->server_name, 
+               server_entry->server_name);
+  } else {
+    channel = (SilcChannelEntry)entry;
+    signal_emit("message topic", 5, server, channel->channel_name,
+               topic, channel->channel_name, channel->channel_name);
+  }
 }
 
 /*
@@ -459,6 +473,8 @@ static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
                clients[i]->username ? userhost : "", 
                "server signoff");
 
+    silc_server_free_ftp(server, clients[i]);
+
     nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
     for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
       CHANNEL_REC *channel = tmp->data;
index f9f5854f20f26d002658adeba1c513fc947f534d..8e476fa19f5da47cb1c1ff4469869fbac1957b8d 100644 (file)
@@ -312,6 +312,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: FILE RECEIVE [<nickname>] */
 /* SYNTAX: FILE CLOSE [<nickname>] */
 /* SYNTAX: FILE */
+/* SYNTAX: JOIN <channel> [<passphrase>] [-cipher <cipher>] [-hmac <hmac>] [-founder <-pubkey|passwd>] */
 
 void silc_command_exec(SILC_SERVER_REC *server,
                       const char *command, const char *args)
@@ -331,7 +332,7 @@ void silc_command_exec(SILC_SERVER_REC *server,
   g_free(tmpcmd);
   if (cmd == NULL)
     return;
-
+  
   /* Now parse all arguments */
   data = g_strconcat(command, " ", args, NULL);
   silc_parse_command_line(data, &argv, &argv_lens,
index 5316ee9965259e988237db8958ceb041aedd87e9..d523172c351657c9b1a68729f589a4197e0fe98d 100644 (file)
@@ -825,11 +825,18 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   int i, ret = 0;
   bool check_global = FALSE;
 
-  /* Protocol dictates that we must always send the received WHOIS request
-     to our router if we are normal server, so let's do it now unless we
-     are standalone. We will not send any replies to the client until we
-     have received reply from the router. */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+  /* Parse the whois request */
+  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
+                                      &nick, &server_name, &count,
+                                      SILC_COMMAND_WHOIS))
+    return 0;
+
+  /* Send the WHOIS request to the router only if it included nickname.
+     Since nicknames can be expanded into many clients we need to send it
+     to router.  If the WHOIS included only client ID's we will check them
+     first locally since we just might have them. */
+  if (nick && !client_id_count &&
+      cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
       server->server_type == SILC_SERVER && !cmd->pending && 
       !server->standalone) {
     SilcBuffer tmpbuf;
@@ -860,20 +867,11 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
     goto out;
   }
 
-  /* We are ready to process the command request. Let's search for the
-     requested client and send reply to the requesting client. */
-
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     check_global = TRUE;
   else if (server->server_type != SILC_SERVER)
     check_global = TRUE;
 
-  /* Parse the whois request */
-  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
-                                      &nick, &server_name, &count,
-                                      SILC_COMMAND_WHOIS))
-    return 0;
-
   /* Get all clients matching that ID or nickname from local list */
   if (client_id_count) {
     /* Check all Client ID's received in the command packet */
@@ -1270,7 +1268,8 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                   uint32 *servers_count,
                                   SilcChannelEntry **channels,
                                   uint32 *channels_count,
-                                  uint32 *count)
+                                  uint32 *count,
+                                  bool *names)
 {
   SilcServer server = cmd->server;
   unsigned char *tmp;
@@ -1291,6 +1290,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
   tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
   if (!tmp) {
     /* No ID, get the names. */
+    *names = TRUE;
 
     /* Try to get nickname@server. */
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
@@ -1824,12 +1824,21 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
   SilcServerEntry *servers = NULL;
   SilcChannelEntry *channels = NULL;
   uint32 clients_count = 0, servers_count = 0, channels_count = 0;
+  bool names;
 
-  /* Protocol dictates that we must always send the received IDENTIFY request
-     to our router if we are normal server, so let's do it now unless we
-     are standalone. We will not send any replies to the client until we
-     have received reply from the router. */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
+  /* Parse the IDENTIFY request */
+  if (!silc_server_command_identify_parse(cmd,
+                                         &clients, &clients_count,
+                                         &servers, &servers_count,
+                                         &channels, &channels_count,
+                                         &count, &names))
+    return 0;
+
+  /* Send the IDENTIFY request to the router only if it included nickname.
+     Since nicknames can be expanded into many clients we need to send it
+     to router.  If the IDENTIFY included only client ID's we will check them
+     first locally since we just might have them. */
+  if (names && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
       server->server_type == SILC_SERVER && !cmd->pending && 
       !server->standalone) {
     SilcBuffer tmpbuf;
@@ -1860,17 +1869,6 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
     goto out;
   }
 
-  /* We are ready to process the command request. Let's search for the
-     requested client and send reply to the requesting client. */
-
-  /* Parse the IDENTIFY request */
-  if (!silc_server_command_identify_parse(cmd,
-                                         &clients, &clients_count,
-                                         &servers, &servers_count,
-                                         &channels, &channels_count,
-                                         &count))
-    return 0;
-
   /* Check that all mandatory fields are present and request those data
      from the server who owns the client if necessary. */
   if (clients && !silc_server_command_identify_check_client(cmd, clients, 
@@ -2287,13 +2285,14 @@ SILC_SERVER_CMD_FUNC(topic)
     if (!server->standalone)
       silc_server_send_notify_topic_set(server, server->router->connection,
                                        server->server_type == SILC_ROUTER ?
-                                       TRUE : FALSE, channel, client->id,
+                                       TRUE : FALSE, channel, 
+                                       client->id, SILC_ID_CLIENT,
                                        channel->topic);
 
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
     /* Send notify about topic change to all clients on the channel */
-    silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+    silc_server_send_notify_to_channel(server, NULL, channel, TRUE, 
                                       SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                       idp->data, idp->len,
                                       channel->topic, strlen(channel->topic));
@@ -2931,7 +2930,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcClientID *client_id,
                                             bool created,
                                             bool create_key,
-                                            uint32 umode)
+                                            uint32 umode,
+                                            const unsigned char *auth,
+                                            uint32 auth_len)
 {
   SilcSocketConnection sock = cmd->sock;
   unsigned char *tmp;
@@ -2942,6 +2943,7 @@ static void silc_server_command_join_channel(SilcServer server,
   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
   uint16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
+  bool founder = FALSE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2971,64 +2973,104 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /*
-   * Check channel modes
+   * Check founder auth payload if provided.  If client can gain founder
+   * privileges it can override various conditions on joining the channel,
+   * and can have directly the founder mode set on the channel.
    */
-
-  memset(check, 0, sizeof(check));
-  memset(check2, 0, sizeof(check2));
-  strncat(check, client->nickname, strlen(client->nickname));
-  strncat(check, "!", 1);
-  strncat(check, client->username, strlen(client->username));
-  if (!strchr(client->username, '@')) {
-    strncat(check, "@", 1);
-    strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+  if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+    SilcIDListData idata = (SilcIDListData)client;
+
+    if (channel->founder_key && idata->public_key &&
+       silc_pkcs_public_key_compare(channel->founder_key, 
+                                    idata->public_key)) {
+      void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
+                        (void *)channel->founder_passwd : 
+                        (void *)channel->founder_key);
+      uint32 auth_data_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+                             channel->founder_passwd_len : 0);
+
+      /* Check whether the client is to become founder */
+      if (silc_auth_verify_data(auth, auth_len, channel->founder_method, 
+                               auth_data, auth_data_len,
+                               idata->hash, client->id, SILC_ID_CLIENT)) {
+       umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+       founder = TRUE;
+      }
+    }
   }
 
-  strncat(check2, client->nickname, strlen(client->nickname));
-  if (!strchr(client->nickname, '@')) {
-    strncat(check2, "@", 1);
-    strncat(check2, server->server_name, strlen(server->server_name));
-  }
-  strncat(check2, "!", 1);
-  strncat(check2, client->username, strlen(client->username));
-  if (!strchr(client->username, '@')) {
-    strncat(check2, "@", 1);
-    strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
-  }
+  /*
+   * Check channel modes
+   */
 
-  /* Check invite list if channel is invite-only channel */
-  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
-    if (!channel->invite_list ||
-       (!silc_string_match(channel->invite_list, check) &&
-        !silc_string_match(channel->invite_list, check2))) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_NOT_INVITED);
-      goto out;
+  if (!umode) {
+    memset(check, 0, sizeof(check));
+    memset(check2, 0, sizeof(check2));
+    strncat(check, client->nickname, strlen(client->nickname));
+    strncat(check, "!", 1);
+    strncat(check, client->username, strlen(client->username));
+    if (!strchr(client->username, '@')) {
+      strncat(check, "@", 1);
+      strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
     }
-  }
 
-  /* Check ban list if it exists. If the client's nickname, server,
-     username and/or hostname is in the ban list the access to the
-     channel is denied. */
-  if (channel->ban_list) {
-    if (!channel->ban_list ||
-        silc_string_match(channel->ban_list, check) ||
-       silc_string_match(channel->ban_list, check2)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                             SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
-      goto out;
+    strncat(check2, client->nickname, strlen(client->nickname));
+    if (!strchr(client->nickname, '@')) {
+      strncat(check2, "@", 1);
+      strncat(check2, server->server_name, strlen(server->server_name));
+    }
+    strncat(check2, "!", 1);
+    strncat(check2, client->username, strlen(client->username));
+    if (!strchr(client->username, '@')) {
+      strncat(check2, "@", 1);
+      strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
+    }
+    
+    /* Check invite list if channel is invite-only channel */
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+      if (!channel->invite_list ||
+         (!silc_string_match(channel->invite_list, check) &&
+          !silc_string_match(channel->invite_list, check2))) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                             SILC_STATUS_ERR_NOT_INVITED);
+       goto out;
+      }
     }
-  }
 
-  /* Get passphrase */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (tmp) {
-    passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
-    memcpy(passphrase, tmp, tmp_len);
+    /* Check ban list if it exists. If the client's nickname, server,
+       username and/or hostname is in the ban list the access to the
+       channel is denied. */
+    if (channel->ban_list) {
+      if (!channel->ban_list ||
+         silc_string_match(channel->ban_list, check) ||
+         silc_string_match(channel->ban_list, check2)) {
+       silc_server_command_send_status_reply(
+                                     cmd, SILC_COMMAND_JOIN,
+                                     SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
+       goto out;
+      }
+    }
+    
+    /* Check user count limit if set. */
+    if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+      if (silc_hash_table_count(channel->user_list) + 1 > 
+         channel->user_limit) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
+       goto out;
+      }
+    }
   }
-  
+
   /* Check the channel passphrase if set. */
   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    /* Get passphrase */
+    tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+    if (tmp) {
+      passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+      memcpy(passphrase, tmp, tmp_len);
+    }
+  
     if (!passphrase || !channel->passphrase ||
         memcmp(channel->passphrase, passphrase,
                strlen(channel->passphrase))) {
@@ -3038,16 +3080,6 @@ static void silc_server_command_join_channel(SilcServer server,
     }
   }
 
-  /* Check user count limit if set. */
-  if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
-    if (silc_hash_table_count(channel->user_list) + 1 > 
-       channel->user_limit) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_CHANNEL_IS_FULL);
-      goto out;
-    }
-  }
-
   /*
    * Client is allowed to join to the channel. Make it happen.
    */
@@ -3143,7 +3175,7 @@ static void silc_server_command_join_channel(SilcServer server,
      we'll ignore it (in packet_receive.c) so we must send it here. If
      we are router then this will send it to local clients and local
      servers. */
-  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                     SILC_NOTIFY_TYPE_JOIN, 2,
                                     clidp->data, clidp->len,
                                     chidp->data, chidp->len);
@@ -3159,6 +3191,24 @@ static void silc_server_command_join_channel(SilcServer server,
       /* Distribute the channel key to all backup routers. */
       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
                              keyp->data, keyp->len, FALSE, TRUE);
+
+    /* If client became founder by providing correct founder auth data
+       notify the mode change to the channel. */
+    if (founder) {
+      SILC_PUT32_MSB(chl->mode, mode);
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                        clidp->data, clidp->len,
+                                        mode, 4, clidp->data, clidp->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,
+                                      chl->mode, client->id, SILC_ID_CLIENT,
+                                      client->id);
+    }
   }
 
   silc_buffer_free(reply);
@@ -3179,14 +3229,15 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  uint32 tmp_len;
+  unsigned char *auth;
+  uint32 tmp_len, auth_len;
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   uint32 umode = 0;
   bool created = FALSE, create_key = TRUE;
   SilcClientID *client_id;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -3220,9 +3271,10 @@ SILC_SERVER_CMD_FUNC(join)
     goto out;
   }
 
-  /* Get cipher and hmac name */
+  /* Get cipher, hmac name and auth payload */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
+  auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
 
   /* See if the channel exists */
   channel = silc_idlist_find_channel_by_name(server->local_list, 
@@ -3364,7 +3416,8 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Join to the channel */
   silc_server_command_join_channel(server, cmd, channel, client_id,
-                                  created, create_key, umode);
+                                  created, create_key, umode,
+                                  auth, auth_len);
 
   silc_free(client_id);
 
@@ -3672,7 +3725,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcChannelClientEntry chl;
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
-  char *cipher = NULL, *hmac = NULL;
+  char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
   uint32 mode_mask, tmp_len, tmp_len2;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
@@ -3796,7 +3849,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Save the passphrase */
-      channel->passphrase = strdup(tmp);
+      passphrase = channel->passphrase = strdup(tmp);
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
@@ -4007,14 +4060,16 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Finally, set the mode */
   channel->mode = mode_mask;
 
-  /* Send CMODE_CHANGE notify */
+  /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
                                     cidp->data, cidp->len, 
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
-                                    hmac, hmac ? strlen(hmac) : 0);
+                                    hmac, hmac ? strlen(hmac) : 0,
+                                    passphrase, passphrase ? 
+                                    strlen(passphrase) : 0);
 
   /* Set CMODE notify type to network */
   if (!server->standalone)
@@ -4022,7 +4077,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
                                  mode_mask, client->id, SILC_ID_CLIENT,
-                                 cipher, hmac);
+                                 cipher, hmac, passphrase);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -4255,7 +4310,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
                                       idp->data, idp->len,
                                       tmp_mask, 4, 
index f5cd5d20c3a3c8a13feed1878bce389c8acbbea2..248442d70a427d7b7a745a92202e6cf95f615dc2 100644 (file)
@@ -367,10 +367,8 @@ void silc_server_notify(SilcServer server,
       goto out;
     }
 
-    if (channel->topic)
-      silc_free(channel->topic);
-    channel->topic = silc_calloc(tmp_len + 1, sizeof(*channel->topic));
-    memcpy(channel->topic, tmp, tmp_len);
+    silc_free(channel->topic);
+    channel->topic = strdup(tmp);
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -520,6 +518,13 @@ void silc_server_notify(SilcServer server,
       memset(hash, 0, sizeof(hash));
     }
 
+    /* Get the passphrase */
+    tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+    if (tmp) {
+      silc_free(channel->passphrase);
+      channel->passphrase = strdup(tmp);
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
@@ -800,6 +805,15 @@ void silc_server_notify(SilcServer server,
                                     users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
+
+      /* Re-announce channel's topic */
+      if (channel->topic) {
+       silc_server_send_notify_topic_set(server, sock,
+                                         server->server_type == SILC_ROUTER ?
+                                         TRUE : FALSE, channel, 
+                                         channel->id, SILC_ID_CHANNEL,
+                                         channel->topic);
+      }
     }
 
     silc_free(channel_id);
@@ -2235,7 +2249,8 @@ void silc_server_new_channel(SilcServer server,
        silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                      channel->mode, server->id,
                                      SILC_ID_SERVER,
-                                     channel->cipher, channel->hmac_name);
+                                     channel->cipher, channel->hmac_name,
+                                     channel->passphrase);
       }
 
       /* Create new key for the channel and send it to the server and
index 3c71557c8a3ef9dadcefe29a39e052296205df83..0278ff1c64e1cc2a037bd82b5f877d58e0860d8e 100644 (file)
@@ -525,7 +525,8 @@ silc_server_packet_send_to_channel_real(SilcServer server,
    If `route' is FALSE then the packet is sent only locally and will not
    be routed anywhere (for router locally means cell wide). If `sender'
    is provided then the packet is not sent to that connection since it
-   originally came from it. */
+   originally came from it. If `send_to_clients' is FALSE then the
+   packet is not sent clients, only servers. */
 
 void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
@@ -574,7 +575,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
     idata = (SilcIDListData)router;
     
     if (sock != sender) {
-      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+      SILC_LOG_DEBUG(("Sending packet to router for routing"));
       
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
@@ -1204,7 +1205,8 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcChannelEntry channel,
                                   uint32 mode_mask,
                                   void *id, SilcIdType id_type,
-                                  char *cipher, char *hmac)
+                                  char *cipher, char *hmac,
+                                  char *passphrase)
 {
   SilcBuffer idp;
   unsigned char mode[4];
@@ -1214,15 +1216,17 @@ void silc_server_send_notify_cmode(SilcServer server,
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              4, idp->data, idp->len,
+                              5, idp->data, idp->len,
                               mode, 4,
                               cipher, cipher ? strlen(cipher) : 0,
-                              hmac, hmac ? strlen(hmac) : 0);
+                              hmac, hmac ? strlen(hmac) : 0,
+                              passphrase, passphrase ? 
+                              strlen(passphrase) : 0);
   silc_buffer_free(idp);
 }
 
 /* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
-   `target' client's mode on `channel'. The Notify packet is always
+   `target' client's mode on `channel'. The notify packet is always
    destined to the channel. */
 
 void silc_server_send_notify_cumode(SilcServer server,
@@ -1271,7 +1275,7 @@ void silc_server_send_notify_signoff(SilcServer server,
   silc_buffer_free(idp);
 }
 
-/* Sends TOPIC_SET notify type. This tells that `client_id' changed
+/* Sends TOPIC_SET notify type. This tells that `id' changed
    the `channel's topic to `topic'. The Notify packet is always destined
    to the channel. This function is used to send the topic set notifies
    between routers. */
@@ -1280,17 +1284,18 @@ void silc_server_send_notify_topic_set(SilcServer server,
                                       SilcSocketConnection sock,
                                       bool broadcast,
                                       SilcChannelEntry channel,
-                                      SilcClientID *client_id,
+                                      void *id, SilcIdType id_type,
                                       char *topic)
 {
   SilcBuffer idp;
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
-  silc_server_send_notify(server, sock, broadcast,
-                         SILC_NOTIFY_TYPE_TOPIC_SET,
-                         topic ? 2 : 1, 
-                         idp->data, idp->len, 
-                         topic, topic ? strlen(topic) : 0);
+  idp = silc_id_payload_encode(id, id_type);
+  silc_server_send_notify_dest(server, sock, broadcast,
+                              (void *)channel->id, SILC_ID_CHANNEL,
+                              SILC_NOTIFY_TYPE_TOPIC_SET,
+                              topic ? 2 : 1, 
+                              idp->data, idp->len, 
+                              topic, topic ? strlen(topic) : 0);
   silc_buffer_free(idp);
 }
 
@@ -1441,7 +1446,7 @@ void silc_server_send_notify_dest(SilcServer server,
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
-                                       unsigned char route_notify,
+                                       bool route_notify,
                                        SilcNotifyType type,
                                        uint32 argc, ...)
 {
@@ -1714,7 +1719,8 @@ void silc_server_send_channel_key(SilcServer server,
                                            channel->key_len / 8, channel->key);
   silc_server_packet_send_to_channel(server, sender, channel, 
                                     SILC_PACKET_CHANNEL_KEY,
-                                     route, packet->data, packet->len, FALSE);
+                                     route, packet->data, packet->len, 
+                                    FALSE);
   silc_buffer_free(packet);
   silc_free(chid);
 }
index 893c820f6216c4e6652855b1354b76e566040b65..412799b1a2a43bb0b2f9dc61c12801f318291f59 100644 (file)
@@ -140,7 +140,8 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcChannelEntry channel,
                                   uint32 mode_mask,
                                   void *id, SilcIdType id_type,
-                                  char *cipher, char *hmac);
+                                  char *cipher, char *hmac,
+                                  char *passphrase);
 void silc_server_send_notify_cumode(SilcServer server,
                                    SilcSocketConnection sock,
                                    bool broadcast,
@@ -157,7 +158,7 @@ void silc_server_send_notify_topic_set(SilcServer server,
                                       SilcSocketConnection sock,
                                       bool broadcast,
                                       SilcChannelEntry channel,
-                                      SilcClientID *client_id,
+                                      void *id, SilcIdType id_type,
                                       char *topic);
 void silc_server_send_notify_kicked(SilcServer server,
                                    SilcSocketConnection sock,
@@ -196,7 +197,7 @@ void silc_server_send_notify_dest(SilcServer server,
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
-                                       unsigned char route_notify,
+                                       bool route_notify,
                                        SilcNotifyType type,
                                        uint32 argc, ...);
 void silc_server_send_notify_on_channels(SilcServer server,
index 22af66f580e2b078d4e77b6723dfbb1293cceaa5..8f58188eb09208c6ad063a129977e3f3be65435c 100644 (file)
@@ -3145,6 +3145,19 @@ static void silc_server_announce_get_servers(SilcServer server,
   }
 }
 
+static SilcBuffer 
+silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
+{
+  va_list ap;
+  SilcBuffer p;
+
+  va_start(ap, argc);
+  p = silc_notify_payload_encode(notify, argc, ap);
+  va_end(ap);
+  return p;
+}
+
 /* This function is used by router to announce existing servers to our
    primary router when we've connected to it. If `creation_time' is non-zero
    then only the servers that has been created after the `creation_time'
@@ -3188,12 +3201,15 @@ void silc_server_announce_servers(SilcServer server, bool global,
 static void silc_server_announce_get_clients(SilcServer server,
                                             SilcIDList id_list,
                                             SilcBuffer *clients,
+                                            SilcBuffer *umodes,
                                             unsigned long creation_time)
 {
   SilcIDCacheList list;
   SilcIDCacheEntry id_cache;
   SilcClientEntry client;
   SilcBuffer idp;
+  SilcBuffer tmp;
+  unsigned char mode[4];
 
   /* Go through all clients in the list */
   if (silc_idcache_get_all(id_list->clients, &list)) {
@@ -3216,6 +3232,20 @@ static void silc_server_announce_get_clients(SilcServer server,
        silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
        silc_buffer_put(*clients, idp->data, idp->len);
        silc_buffer_pull(*clients, idp->len);
+
+       SILC_PUT32_MSB(client->mode, mode);
+       tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+                                                2, idp->data, idp->len,
+                                                mode, 4);
+       *umodes = silc_buffer_realloc(*umodes, 
+                                     (*umodes ? 
+                                      (*umodes)->truelen + tmp->len :  
+                                      tmp->len));
+       silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
+       silc_buffer_put(*umodes, tmp->data, tmp->len);
+       silc_buffer_pull(*umodes, tmp->len);
+       silc_buffer_free(tmp);
+
        silc_buffer_free(idp);
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -3237,17 +3267,18 @@ void silc_server_announce_clients(SilcServer server,
                                  SilcSocketConnection remote)
 {
   SilcBuffer clients = NULL;
+  SilcBuffer umodes = NULL;
 
   SILC_LOG_DEBUG(("Announcing clients"));
 
   /* Get clients in local list */
   silc_server_announce_get_clients(server, server->local_list,
-                                  &clients, creation_time);
+                                  &clients, &umodes, creation_time);
 
   /* As router we announce our global list as well */
   if (server->server_type == SILC_ROUTER)
     silc_server_announce_get_clients(server, server->global_list,
-                                    &clients, creation_time);
+                                    &clients, &umodes, creation_time);
 
   if (clients) {
     silc_buffer_push(clients, clients->data - clients->head);
@@ -3260,19 +3291,36 @@ void silc_server_announce_clients(SilcServer server,
 
     silc_buffer_free(clients);
   }
+
+  if (umodes) {
+    silc_buffer_push(umodes, umodes->data - umodes->head);
+    SILC_LOG_HEXDUMP(("umodes"), umodes->data, umodes->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, remote,
+                           SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                           umodes->data, umodes->len, TRUE);
+
+    silc_buffer_free(umodes);
+  }
 }
 
-static SilcBuffer 
-silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
+/* Returns channel's topic for announcing it */
+
+void silc_server_announce_get_channel_topic(SilcServer server,
+                                           SilcChannelEntry channel,
+                                           SilcBuffer *topic)
 {
-  va_list ap;
-  SilcBuffer p;
+  SilcBuffer chidp;
 
-  va_start(ap, argc);
-  p = silc_notify_payload_encode(notify, argc, ap);
-  va_end(ap);
-  return p;
+  if (channel->topic) {
+    chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+    *topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+                                               chidp->data, chidp->len,
+                                               channel->topic, 
+                                               strlen(channel->topic));
+    silc_buffer_free(chidp);
+  }
 }
 
 /* Returns assembled packets for channel users of the `channel'. */
@@ -3348,6 +3396,7 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcBuffer *channel_users,
                                       SilcBuffer **channel_users_modes,
                                       uint32 *channel_users_modes_c,
+                                      SilcBuffer **channel_topics,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time)
 {
@@ -3397,6 +3446,7 @@ void silc_server_announce_get_channels(SilcServer server,
          silc_buffer_pull(*channels, len);
        }
 
+       /* Channel user modes */
        *channel_users_modes = silc_realloc(*channel_users_modes,
                                            sizeof(**channel_users_modes) * 
                                            (i + 1));
@@ -3408,6 +3458,13 @@ void silc_server_announce_get_channels(SilcServer server,
                                               channel_users,
                                               &(*channel_users_modes)[i]);
        (*channel_ids)[i] = channel->id;
+
+       /* Channel's topic */
+       *channel_topics = silc_realloc(*channel_topics,
+                                      sizeof(**channel_topics) * (i + 1));
+       (*channel_topics)[i] = NULL;
+       silc_server_announce_get_channel_topic(server, channel,
+                                              &(*channel_topics)[i]);
        i++;
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -3434,6 +3491,7 @@ void silc_server_announce_channels(SilcServer server,
 {
   SilcBuffer channels = NULL, channel_users = NULL;
   SilcBuffer *channel_users_modes = NULL;
+  SilcBuffer *channel_topics = NULL;
   uint32 channel_users_modes_c = 0;
   SilcChannelID **channel_ids = NULL;
 
@@ -3444,6 +3502,7 @@ void silc_server_announce_channels(SilcServer server,
                                    &channels, &channel_users,
                                    &channel_users_modes,
                                    &channel_users_modes_c,
+                                   &channel_topics,
                                    &channel_ids, creation_time);
 
   /* Get channels and channel users in global list */
@@ -3452,6 +3511,7 @@ void silc_server_announce_channels(SilcServer server,
                                      &channels, &channel_users,
                                      &channel_users_modes,
                                      &channel_users_modes_c,
+                                     &channel_topics,
                                      &channel_ids, creation_time);
 
   if (channels) {
@@ -3499,8 +3559,32 @@ void silc_server_announce_channels(SilcServer server,
       silc_buffer_free(channel_users_modes[i]);
     }
     silc_free(channel_users_modes);
-    silc_free(channel_ids);
   }
+
+  if (channel_topics) {
+    int i;
+
+    for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_topics[i])
+       continue;
+
+      silc_buffer_push(channel_topics[i], 
+                      channel_topics[i]->data - 
+                      channel_topics[i]->head);
+      SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data, 
+                      channel_topics[i]->len);
+      silc_server_packet_send_dest(server, remote,
+                                  SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                  channel_ids[i], SILC_ID_CHANNEL,
+                                  channel_topics[i]->data, 
+                                  channel_topics[i]->len,
+                                  FALSE);
+      silc_buffer_free(channel_topics[i]);
+    }
+    silc_free(channel_topics);
+  }
+
+  silc_free(channel_ids);
 }
 
 /* Failure timeout callback. If this is called then we will immediately
index 8ea3293b26257cd091c85d04172b65fa594ec84d..6301b58ec0b9be3402be65a6d83310049d06b26c 100644 (file)
@@ -178,6 +178,9 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
                                              SilcChannelEntry channel);
 void silc_server_perform_heartbeat(SilcSocketConnection sock,
                                   void *hb_context);
+void silc_server_announce_get_channel_topic(SilcServer server,
+                                           SilcChannelEntry channel,
+                                           SilcBuffer *topic);
 void silc_server_announce_get_channel_users(SilcServer server,
                                            SilcChannelEntry channel,
                                            SilcBuffer *channel_users,
@@ -188,6 +191,7 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcBuffer *channel_users,
                                       SilcBuffer **channel_users_modes,
                                       uint32 *channel_users_modes_c,
+                                      SilcBuffer **channel_topics,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time);
 void silc_server_announce_servers(SilcServer server, bool global,
index 203c53081b1f56935737bf2a2b49d5a5c76c52a4..64e3d44fedb92f4e06b16e027baa436d8b4a0f58 100644 (file)
@@ -846,10 +846,7 @@ List of all defined commands in SILC follows.
         privileges the same way as the client had given the
         SILC_COMMAND_CUMODE command to gain founder privileges.  The
         client is still able to join the channel even if the founder
-        privileges could not be gained.  If the channel is invite only
-        channel, the client is able to join the channel only if it 
-        was invited to the channel or was able to gain the founder
-        privileges.
+        privileges could not be gained.
 
         The server MUST check whether the user is allowed to join to
         the requested channel.  Various modes set to the channel affect
@@ -857,9 +854,7 @@ List of all defined commands in SILC follows.
         are:
 
             o  The user MUST be invited to the channel if the channel
-               is invite-only channel, or MUST provide correct
-               <founder auth> payload and gain founder privileges, and
-               bypass the invite-only mode.
+               is invite-only channel.
 
             o  The Client ID/nickname/username/host name MUST NOT match
                any active bans.
@@ -869,6 +864,11 @@ List of all defined commands in SILC follows.
 
             o  The user count limit, if set, MUST NOT be reached.
 
+        If the client provided correct <founder auth> payload it can
+        override these conditions, except the condition for the passphrase.
+        The correct passphrase MUST be provided even if <founder auth>
+        payload is provided.
+
         Reply messages to the command:
 
         Max Arguments:  14
index eedbc5673fca6a24bfcbb87b404762166887cb14..23669b93a456d613db741941fe7e8e5155084960 100644 (file)
@@ -1281,9 +1281,10 @@ Also, all ID's sent in arguments are sent inside ID Payload.
       topic was set or changed.
 
       Max Arguments:  2
-          Arguments:  (1) <Client ID>  (2) <topic>
+          Arguments:  (1) <ID Payload>  (2) <topic>
 
-      The <Client ID> is the client which set or changed the <topic>.
+      The <ID Payload> is the ID of the entity who set the topic.  It
+      usually is Client ID but it can be Server ID and Channel ID as well.
 
 
 6     SILC_NOTIFY_TYPE_NICK_CHANGE
@@ -1308,9 +1309,10 @@ Also, all ID's sent in arguments are sent inside ID Payload.
       to the clients which is joined on the channel which mode was
       changed.
 
-      Max Arguments:  4
-          Arguments:  (1) <ID Payload>  (2) <mode mask>
-                      (3) [<cipher>]    (4) <[hmac>]     
+      Max Arguments:  5
+          Arguments:  (1) <ID Payload>    (2) <mode mask>
+                      (3) [<cipher>]      (4) <[hmac>]     
+                      (5) [<passphrase>]
 
       The <ID Payload> is the ID (usually Client ID but it can be
       Server ID as well when the router is enforcing channel mode
@@ -1319,7 +1321,8 @@ Also, all ID's sent in arguments are sent inside ID Payload.
       ignore the <cipher> argument since the SILC_PACKET_CHANNEL_KEY
       packet will force the new channel key change anyway.  The <hmac>
       argument is important since the client is responsible of setting
-      the new HMAC and the hmac key into use.
+      the new HMAC and the hmac key into use.  The <passphrase> is
+      the passphrase of the channel, if it was now set.
 
 
 8     SILC_NOTIFY_TYPE_CUMODE_CHANGE
index 0440478dc2230a3d4f40f3fdc1512fc09407007d..58bcad2b44871972ce3c4b2f288c24d1c959c0aa 100644 (file)
@@ -371,7 +371,7 @@ bool silc_client_start_key_exchange(SilcClient client,
   silc_schedule_task_del_by_fd(client->schedule, fd);
 
   conn->nickname = strdup(client->username);
-  conn->sock->hostname = conn->remote_host;
+  conn->sock->hostname = strdup(conn->remote_host);
   conn->sock->ip = strdup(conn->remote_host);
   conn->sock->port = conn->remote_port;
 
index ddc70e7bdcbd5e87aebf251ab7645bd88a9c5788..d819b97280ac6710b55f1247194fcd4c8cc0ffd0 100644 (file)
@@ -346,15 +346,58 @@ void silc_client_notify_by_server(SilcClient client,
     if (!tmp)
       goto out;
 
-    client_id = silc_id_payload_parse_id(tmp, tmp_len);
-    if (!client_id)
+    idp = silc_id_payload_parse(tmp, tmp_len);
+    if (!idp)
       goto out;
 
     /* Find Client entry */
-    client_entry = 
-      silc_client_get_client_by_id(client, conn, client_id);
-    if (!client_entry)
-      goto out;
+    if (silc_id_payload_get_type(idp) == SILC_ID_CLIENT) {
+      client_id = silc_id_payload_parse_id(tmp, tmp_len);
+      if (!client_id) {
+       silc_id_payload_free(idp);
+       goto out;
+      }
+
+      /* Find Client entry */
+      client_entry = 
+       silc_client_get_client_by_id(client, conn, client_id);
+      if (!client_entry)
+       goto out;
+    } else if (silc_id_payload_get_type(idp) == SILC_ID_SERVER) {
+      server_id = silc_id_payload_parse_id(tmp, tmp_len);
+      if (!server_id) {
+       silc_id_payload_free(idp);
+       goto out;
+      }
+      
+      server = silc_client_get_server_by_id(client, conn, server_id);
+      if (!server) {
+       silc_id_payload_free(idp);
+       silc_free(server_id);
+       goto out;
+      }
+      
+      /* Save the pointer to the client_entry pointer */
+      client_entry = (SilcClientEntry)server;
+      silc_free(server_id);
+    } else {
+      channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+      if (!channel_id) {
+       silc_id_payload_free(idp);
+       goto out;
+      }
+      
+      channel = silc_client_get_channel_by_id(client, conn, channel_id);
+      if (!channel) {
+       silc_id_payload_free(idp);
+       silc_free(channel_id);
+       goto out;
+      }
+      
+      /* Save the pointer to the client_entry pointer */
+      client_entry = (SilcClientEntry)channel;
+      silc_free(channel_id);
+    }
 
     /* Get topic */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
@@ -375,7 +418,10 @@ void silc_client_notify_by_server(SilcClient client,
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
        sent by server. */
-    client->ops->notify(client, conn, type, client_entry, tmp, channel);
+    client->ops->notify(client, conn, type, silc_id_payload_get_type(idp),
+                       client_entry, tmp, channel);
+
+    silc_id_payload_free(idp);
     break;
 
   case SILC_NOTIFY_TYPE_NICK_CHANGE:
@@ -659,6 +705,9 @@ void silc_client_notify_by_server(SilcClient client,
     SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
                    silc_id_render(channel->id, SILC_ID_CHANNEL)));
 
+    /* Remove the old channel entry */
+    silc_idcache_del_by_context(conn->channel_cache, channel);
+
     /* Free the old ID */
     silc_free(channel->id);
 
@@ -673,8 +722,7 @@ void silc_client_notify_by_server(SilcClient client,
     SILC_LOG_DEBUG(("New Channel ID id(%s)", 
                    silc_id_render(channel->id, SILC_ID_CHANNEL)));
 
-    /* Remove the old cache entry and create a new one */
-    silc_idcache_del_by_context(conn->channel_cache, channel);
+    /* Add the channel entry again to ID cache */
     silc_idcache_add(conn->channel_cache, channel->channel_name, 
                     channel->id, channel, FALSE);
 
index 5257bf450ef6f306f11eec2a37932d7a4c117b89..dd329441f6c94e23cda33ad4ff79b5c8f22ded6f 100644 (file)
@@ -42,7 +42,7 @@ SilcClientCommand silc_command_list[] =
   SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(oper, OPER, "OPER",
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
+  SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 9),
   SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
@@ -364,11 +364,11 @@ SILC_CLIENT_CMD_FUNC(nick_change)
   SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
   if (status == SILC_STATUS_OK) {
     /* Set the nickname */
+    silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
     if (conn->nickname)
       silc_free(conn->nickname);
     conn->nickname = strdup(cmd->argv[1]);
     conn->local_entry->nickname = conn->nickname;
-    silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
     silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]), 
                     conn->local_entry->id, conn->local_entry, FALSE);
     COMMAND;
@@ -993,7 +993,9 @@ SILC_CLIENT_CMD_FUNC(join)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcIDCacheEntry id_cache = NULL;
-  SilcBuffer buffer, idp;
+  SilcBuffer buffer, idp, auth = NULL;
+  char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
+  int i;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1001,6 +1003,11 @@ SILC_CLIENT_CMD_FUNC(join)
     goto out;
   }
 
+  if (cmd->argc < 2) {
+    COMMAND_ERROR;
+    goto out;
+  }
+  
   /* See if we have joined to the requested channel already */
   if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
                                    &id_cache)) {
@@ -1014,31 +1021,50 @@ SILC_CLIENT_CMD_FUNC(join)
   if (cmd->argv_lens[1] > 256)
     cmd->argv_lens[1] = 256;
 
-  /* Send JOIN command to the server */
-  if (cmd->argc == 2)
-    buffer = 
-      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
-                                    1, cmd->argv[1], cmd->argv_lens[1],
-                                    2, idp->data, idp->len);
-  else if (cmd->argc == 3)
-    /* XXX Buggy */
-    buffer = 
-      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
-                                    1, cmd->argv[1], cmd->argv_lens[1],
-                                    2, idp->data, idp->len,
-                                    3, cmd->argv[2], cmd->argv_lens[2]);
-  else
-    buffer = 
-      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
-                                    1, cmd->argv[1], cmd->argv_lens[1],
-                                    2, idp->data, idp->len,
-                                    3, cmd->argv[2], cmd->argv_lens[2],
-                                    4, cmd->argv[3], cmd->argv_lens[3]);
+  name = cmd->argv[1];
+
+  for (i = 2; i < cmd->argc; i++) {
+    if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc >= i + 1) {
+      cipher = cmd->argv[i + 1];
+      i++;
+    } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc >= i + 1) {
+      hmac = cmd->argv[i + 1];
+      i++;
+    } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc >= i + 1) {
+      if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
+       auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                                 cmd->client->private_key,
+                                                 conn->hash,
+                                                 conn->local_id,
+                                                 SILC_ID_CLIENT);
+      } else {
+       auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                       cmd->argv[i + 1], 
+                                       cmd->argv_lens[i + 1]);
+      }
+      i++;
+    } else {
+      passphrase = cmd->argv[i];
+    }
+  }
 
+  /* Send JOIN command to the server */
+  buffer =
+    silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
+                                  1, name, strlen(name),
+                                  2, idp->data, idp->len,
+                                  3, passphrase, 
+                                  passphrase ? strlen(passphrase) : 0,
+                                  4, cipher, cipher ? strlen(cipher) : 0,
+                                  5, hmac, hmac ? strlen(hmac) : 0,
+                                  6, auth ? auth->data : NULL,
+                                  auth ? auth->len : 0);
   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_buffer_free(idp);
+  if (auth)
+    silc_buffer_free(auth);
 
   /* Notify application */
   COMMAND;
@@ -1520,11 +1546,11 @@ SILC_CLIENT_CMD_FUNC(cumode)
       if (add) {
        if (cmd->argc == 5) {
          if (!strcasecmp(cmd->argv[4], "-pubkey")) {
-         auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
-                                                   cmd->client->private_key,
-                                                   conn->hash,
-                                                   conn->local_id,
-                                                   SILC_ID_CLIENT);
+           auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                                     cmd->client->private_key,
+                                                     conn->hash,
+                                                     conn->local_id,
+                                                     SILC_ID_CLIENT);
          } else {
            auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
                                            cmd->argv[4], cmd->argv_lens[4]);