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:
 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...
 
    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.
  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
 ================================
 
 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
 ========================
 
 
 
 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 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.
 
        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; }
 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 = {
 );
 
 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.
 
 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
 
 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;
 static void event_topic(SILC_SERVER_REC *server, va_list va)
 {
   SILC_CHANNEL_REC *chanrec;
+  void *entry;
   SilcClientEntry client;
   SilcClientEntry client;
+  SilcServerEntry server_entry;
   SilcChannelEntry channel;
   char *topic;
   char userhost[256];
   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);
 
   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);
   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);
   }
 
     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");
 
                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;
     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: 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)
 
 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;
   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,
   /* 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;
 
   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;
       server->server_type == SILC_SERVER && !cmd->pending && 
       !server->standalone) {
     SilcBuffer tmpbuf;
@@ -860,20 +867,11 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
     goto out;
   }
 
     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;
 
   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 */
   /* 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 *servers_count,
                                   SilcChannelEntry **channels,
                                   uint32 *channels_count,
-                                  uint32 *count)
+                                  uint32 *count,
+                                  bool *names)
 {
   SilcServer server = cmd->server;
   unsigned char *tmp;
 {
   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. */
   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);
 
     /* 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;
   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;
       server->server_type == SILC_SERVER && !cmd->pending && 
       !server->standalone) {
     SilcBuffer tmpbuf;
@@ -1860,17 +1869,6 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
     goto out;
   }
 
     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, 
   /* 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 ?
     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 */
                                        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));
                                       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,
                                             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;
 {
   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];
   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"));
 
 
   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) {
   /* 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))) {
     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.
    */
   /*
    * 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. */
      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);
                                     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);
       /* 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);
   }
 
   silc_buffer_free(reply);
@@ -3179,14 +3229,15 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
 {
   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;
 
   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);
 
   /* 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;
   }
 
     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);
   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, 
 
   /* 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,
 
   /* 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);
 
 
   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;
   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);
 
   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 */
       }
 
       /* Save the passphrase */
-      channel->passphrase = strdup(tmp);
+      passphrase = channel->passphrase = strdup(tmp);
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
     }
   } 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;
 
   /* 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,
   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,
                                     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)
 
   /* 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,
                                  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,
 
   /* 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) {
 
   /* 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, 
                                       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;
     }
 
       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, 
 
     /* 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));
     }
 
       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:
     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);
       }
                                     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);
     }
 
     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,
        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
       }
 
       /* 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
    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,
 
 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) {
     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, 
       
       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,
                                   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];
 {
   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,
 
   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,
                               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
   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,
    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);
 }
 
   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. */
    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,
                                       SilcSocketConnection sock,
                                       bool broadcast,
                                       SilcChannelEntry channel,
-                                      SilcClientID *client_id,
+                                      void *id, SilcIdType id_type,
                                       char *topic)
 {
   SilcBuffer idp;
 
                                       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);
 }
 
   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,
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
-                                       unsigned char route_notify,
+                                       bool route_notify,
                                        SilcNotifyType type,
                                        uint32 argc, ...)
 {
                                        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,
                                            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);
 }
   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,
                                   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,
 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,
                                       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,
                                       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,
 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,
                                        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'
 /* 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,
 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;
                                             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)) {
 
   /* 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_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))
        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;
                                  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,
 
   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,
 
   /* 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);
 
   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);
   }
 
     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'. */
 }
 
 /* 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_users,
                                       SilcBuffer **channel_users_modes,
                                       uint32 *channel_users_modes_c,
+                                      SilcBuffer **channel_topics,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time)
 {
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time)
 {
@@ -3397,6 +3446,7 @@ void silc_server_announce_get_channels(SilcServer server,
          silc_buffer_pull(*channels, len);
        }
 
          silc_buffer_pull(*channels, len);
        }
 
+       /* Channel user modes */
        *channel_users_modes = silc_realloc(*channel_users_modes,
                                            sizeof(**channel_users_modes) * 
                                            (i + 1));
        *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_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))
        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 channels = NULL, channel_users = NULL;
   SilcBuffer *channel_users_modes = NULL;
+  SilcBuffer *channel_topics = NULL;
   uint32 channel_users_modes_c = 0;
   SilcChannelID **channel_ids = 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,
                                    &channels, &channel_users,
                                    &channel_users_modes,
                                    &channel_users_modes_c,
+                                   &channel_topics,
                                    &channel_ids, creation_time);
 
   /* Get channels and channel users in global list */
                                    &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,
                                      &channels, &channel_users,
                                      &channel_users_modes,
                                      &channel_users_modes_c,
+                                     &channel_topics,
                                      &channel_ids, creation_time);
 
   if (channels) {
                                      &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_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
 }
 
 /* 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);
                                              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,
 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_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,
                                       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 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
 
         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
         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.
 
             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.
 
 
             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
         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
       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
 
 
 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.
 
       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
 
       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
       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
 
 
 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);
   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;
 
   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;
 
     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 */
       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);
 
     /* 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. */
     /* 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:
     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)));
 
     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);
 
     /* 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)));
 
     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);
 
     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(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),
   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_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;
     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;
     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;
   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);
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -1001,6 +1003,11 @@ SILC_CLIENT_CMD_FUNC(join)
     goto out;
   }
 
     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)) {
   /* 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;
 
   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);
   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;
 
   /* Notify application */
   COMMAND;
@@ -1520,11 +1546,11 @@ SILC_CLIENT_CMD_FUNC(cumode)
       if (add) {
        if (cmd->argc == 5) {
          if (!strcasecmp(cmd->argv[4], "-pubkey")) {
       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]);
          } else {
            auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
                                            cmd->argv[4], cmd->argv_lens[4]);