updates
[silc.git] / lib / silcclient / command_reply.c
index 5ed0a3b1fe9935d3003ecd6ece3c66927e179ce0..d901385b48325eb34016e8b2304ecafacb40cc6f 100644 (file)
@@ -241,12 +241,31 @@ silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
     silc_parse_nickname(nickname, &client_entry->nickname, 
                        &client_entry->server, &client_entry->num);
     client_entry->username = strdup(username);
+    if (realname)
+      client_entry->realname = strdup(realname);
     
     /* Add client to cache */
     silc_idcache_add(conn->client_cache, client_entry->nickname,
                     SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
   } else {
     client_entry = (SilcClientEntry)id_cache->context;
+    if (client_entry->nickname)
+      silc_free(client_entry->nickname);
+    if (client_entry->server)
+      silc_free(client_entry->server);
+    if (client_entry->username)
+      silc_free(client_entry->username);
+    if (client_entry->realname)
+      silc_free(client_entry->realname);
+
+    silc_parse_nickname(nickname, &client_entry->nickname, 
+                       &client_entry->server, &client_entry->num);
+    client_entry->username = strdup(username);
+    if (realname)
+      client_entry->realname = strdup(realname);
+
+    id_cache->data = client_entry->nickname;
+
     silc_free(client_id);
   }
 
@@ -254,8 +273,8 @@ silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
     cmd->client->ops->say(cmd->client, conn, "%s", buf);
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, client_entry, nickname, 
-                username, realname, NULL, NULL));
+  COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
+                NULL, NULL));
 }
 
 /* Received reply for WHOIS command. This maybe called several times
@@ -335,6 +354,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify)
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcClientEntry client_entry;
+  SilcIDCacheEntry id_cache = NULL;
   SilcCommandStatus status;
   unsigned char *tmp;
 
@@ -368,23 +388,47 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify)
     unsigned char *id_data;
     char *nickname;
     char *username;
+    SilcClientID *client_id;
 
     id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+    if (!id_data)
+      goto out;
+    client_id = silc_id_payload_parse_id(id_data, len);
+
     nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
     username = silc_argument_get_arg_type(cmd->args, 4, NULL);
 
-    /* Allocate client entry */
-    client_entry = silc_calloc(1, sizeof(*client_entry));
-    client_entry->id = silc_id_payload_parse_id(id_data, len);
-    if (nickname)
+    if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+                                    SILC_ID_CLIENT, &id_cache)) {
+      client_entry = silc_calloc(1, sizeof(*client_entry));
+      client_entry->id = client_id;
       silc_parse_nickname(nickname, &client_entry->nickname, 
                          &client_entry->server, &client_entry->num);
-    if (username)
-      client_entry->username = strdup(username);
+      if (username)
+       client_entry->username = strdup(username);
+    
+      /* Add client to cache */
+      silc_idcache_add(conn->client_cache, client_entry->nickname,
+                      SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
+    } else {
+      client_entry = (SilcClientEntry)id_cache->context;
+      if (client_entry->nickname)
+       silc_free(client_entry->nickname);
+      if (client_entry->server)
+       silc_free(client_entry->server);
+      if (username && client_entry->username)
+       silc_free(client_entry->username);
 
-    /* Save received Client ID to ID cache */
-    silc_idcache_add(conn->client_cache, client_entry->nickname,
-                    SILC_ID_CLIENT, client_entry->id, client_entry, TRUE);
+      silc_parse_nickname(nickname, &client_entry->nickname, 
+                         &client_entry->server, &client_entry->num);
+
+      if (username)
+       client_entry->username = strdup(username);
+
+      id_cache->data = client_entry->nickname;
+
+      silc_free(client_id);
+    }
   }
 
   if (status == SILC_STATUS_LIST_START) {
@@ -916,6 +960,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   SilcCommandStatus status;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
+  SilcChannelUser chu;
   SilcChannelID *channel_id = NULL;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
@@ -988,41 +1033,21 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
   
   channel = (SilcChannelEntry)id_cache->context;
 
-  /* If there is pending command we know that user has called this command
-     and we will handle the name list differently. */
-  if (cmd->callback) {
-    /* We will resolve all the necessary information about the people
-       on the channel. Only after that will we display the user list. */
-    for (i = 0; i < len1; i++) {
-      /* XXX */
-
+  /* Remove commas from list */
+  for (i = 0; i < len1; i++)
+    if (name_list[i] == ',') {
+      name_list[i] = ' ';
+      list_count++;
     }
-    silc_client_command_pending_del(SILC_COMMAND_NAMES);
-  } else {
-    /* there is no pending callback it means that this command reply
-       has been received without calling the command, ie. server has sent
-       the reply without getting the command from us first. This happens
-       with SILC servers that sends NAMES reply after joining to a channel. */
-
-    /* Remove commas from list */
-    for (i = 0; i < len1; i++)
-      if (name_list[i] == ',') {
-       name_list[i] = ' ';
-       list_count++;
-      }
-    list_count++;
-  }
+  list_count++;
 
-  /* Remove old client list from channel, if exists */
-  if (channel->clients) {
-    silc_free(channel->clients);
-    channel->clients = NULL;
-    channel->clients_count = 0;
+  /* Remove old client list from channel. */
+  silc_list_start(channel->clients);
+  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+    silc_list_del(channel->clients, chu);
+    silc_free(chu);
   }
 
-  /* Allocate room for clients in the channel */
-  channel->clients = silc_calloc(list_count, sizeof(*channel->clients));
-
   /* Cache the received name list, client ID's and modes. This cache expires
      whenever server sends notify message to channel. It means two things;
      some user has joined or leaved the channel. */
@@ -1063,24 +1088,25 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
       id_cache = NULL;
     }
 
-    channel->clients[channel->clients_count].client = client;
-    channel->clients[channel->clients_count].mode = mode;
-    channel->clients_count++;
+    chu = silc_calloc(1, sizeof(*chu));
+    chu->client = client;
+    chu->mode = mode;
+    silc_list_add(channel->clients, chu);
 
     name_list += nick_len + 1;
   }
 
   name_list = cp;
   for (i = 0; i < list_count; i++) {
-    int c;
+    int c = 0;
     int nick_len = strcspn(name_list, " ");
     char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
     memcpy(nickname, name_list, nick_len);
 
-    for (c = 0, k = 0; k < channel->clients_count; k++) {
-      if (channel->clients[k].client && 
-         !strncmp(channel->clients[k].client->nickname, 
-                  nickname, strlen(channel->clients[k].client->nickname))) {
+    silc_list_start(channel->clients);
+    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+      if (!strncmp(chu->client->nickname, nickname, 
+                  strlen(chu->client->nickname))) {
        char t[8];
        
        if (!c) {
@@ -1089,43 +1115,106 @@ SILC_CLIENT_CMD_REPLY_FUNC(names)
        }
        
        memset(t, 0, sizeof(t));
-       channel->clients[k].client->nickname = 
-         silc_calloc(strlen(nickname) + 8, sizeof(*channel->clients[k].
-                                                  client->nickname));
-       strncat(channel->clients[k].client->nickname, nickname, 
-               strlen(nickname));
-       snprintf(t, sizeof(t), " [%d]", c++);
-       strncat(channel->clients[k].client->nickname, t, strlen(t));
+       chu->client->nickname = silc_calloc(strlen(nickname) + 8, 1);
+       snprintf(t, sizeof(t), "[%d]", c++);
+       strncat(chu->client->nickname, t, strlen(t));
+       strncat(chu->client->nickname, nickname, strlen(nickname));
       }
     }
 
     silc_free(nickname);
   }
 
-  name_list = NULL;
-  len1 = 0;
-  for (k = 0; k < channel->clients_count; k++) {
-    char *n = channel->clients[k].client->nickname;
-    len2 = strlen(n);
-    len1 += len2;
-    name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 1));
-    memcpy(name_list + (len1 - len2), n, len2);
-    name_list[len1] = 0;
+  /* XXX hmm... actually it is applications business to display this
+     information. We should just pass (as we do) the data to application and
+     let it to parse it and display it the way it wants. */
+  if (cmd->callback) {
+    cmd->client->ops->say(cmd->client, conn, "Users on %s", 
+                         channel->channel_name);
     
-    if (k == channel->clients_count - 1)
-      break;
-    memcpy(name_list + len1, " ", 1);
-    len1++;
+    silc_list_start(channel->clients);
+    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+      SilcClientEntry e = chu->client;
+      char *m, tmp[80], line[80];
+
+      memset(line, 0, sizeof(line));
+      memset(tmp, 0, sizeof(tmp));
+      m = silc_client_chumode_char(chu->mode);
+
+      strcat(line, " ");
+      strcat(line, e->nickname);
+      strcat(line, e->server ? "@" : "");
+
+      len1 = 0;
+      if (e->server)
+       len1 = strlen(e->server);
+      strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
+
+      len1 = strlen(line);
+      if (len1 >= 30) {
+       memset(&line[29], 0, len1 - 29);
+      } else {
+       for (i = 0; i < 30 - len1 - 1; i++)
+         strcat(line, " ");
+      }
+
+      strcat(line, "  H");
+      strcat(tmp, m ? m : "");
+      strcat(line, tmp);
+
+      if (strlen(tmp) < 5)
+       for (i = 0; i < 5 - strlen(tmp); i++)
+         strcat(line, " ");
+
+      strcat(line, e->username ? e->username : "");
+
+      cmd->client->ops->say(cmd->client, conn, "%s", line);
+
+      if (m)
+       silc_free(m);
+    }
+
+  } else {
+    name_list = NULL;
+    len1 = 0;
+    k = 0;
+
+    silc_list_start(channel->clients);
+    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+      char *m, *n = chu->client->nickname;
+      len2 = strlen(n);
+      len1 += len2;
+
+      name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
+
+      m = silc_client_chumode_char(chu->mode);
+      if (m) {
+       memcpy(name_list + (len1 - len2), m, strlen(m));
+       len1 += strlen(m);
+       silc_free(m);
+      }
+
+      memcpy(name_list + (len1 - len2), n, len2);
+      name_list[len1] = 0;
+      
+      if (k == silc_list_count(channel->clients) - 1)
+       break;
+      memcpy(name_list + len1, " ", 1);
+      len1++;
+      k++;
+    }
+
+    cmd->client->ops->say(cmd->client, conn, "Users on %s: %s",
+                         channel->channel_name, name_list);
+    silc_free(name_list);
   }
 
-  cmd->client->ops->say(cmd->client, conn,
-                       "Users on %s: %s", channel->channel_name, name_list);
+  name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
 
   /* Notify application */
   COMMAND_REPLY((ARGS, channel, name_list, client_id_list->head,
                 client_mode_list->head));
 
-  silc_free(name_list);
   silc_buffer_free(client_id_list);
   silc_buffer_free(client_mode_list);