updates.
[silc.git] / lib / silcclient / client_notify.c
index 82a0654fa9158a125f53a06b4ad0de17a673a8a1..ddc70e7bdcbd5e87aebf251ab7645bd88a9c5788 100644 (file)
 #include "clientlibincludes.h"
 #include "client_internal.h"
 
+typedef struct {
+  SilcPacketContext *packet;
+  void *context;
+  SilcSocketConnection sock;
+} *SilcClientNotifyResolve;
+
 /* Called when notify is received and some async operation (such as command)
    is required before processing the notify message. This calls again the
    silc_client_notify_by_server and reprocesses the original notify packet. */
 
 static void silc_client_notify_by_server_pending(void *context, void *context2)
 {
-  SilcPacketContext *p = (SilcPacketContext *)context;
-  silc_client_notify_by_server(p->context, p->sock, p);
-  silc_socket_free(p->sock);
+  SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+  SilcClientCommandReplyContext reply = 
+    (SilcClientCommandReplyContext)context2;
+
+  if (reply) {
+    SilcCommandStatus status;
+    unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
+    SILC_GET16_MSB(status, tmp);
+    if (status != SILC_STATUS_OK) {
+      silc_socket_free(res->sock);
+      return;
+    }
+  }
+
+  silc_client_notify_by_server(res->context, res->sock, res->packet);
+  silc_socket_free(res->sock);
 }
 
 /* Destructor for the pending command callback */
 
 static void silc_client_notify_by_server_destructor(void *context)
 {
-  silc_packet_context_free((SilcPacketContext *)context);
+  SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+  silc_packet_context_free(res->packet);
+  silc_free(res);
 }
 
 /* Resolve client information from server by Client ID. */
@@ -50,17 +71,18 @@ static void silc_client_notify_by_server_resolve(SilcClient client,
                                                 SilcPacketContext *packet,
                                                 SilcClientID *client_id)
 {
-  SilcPacketContext *p = silc_packet_context_dup(packet);
+  SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
   SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
 
-  p->context = (void *)client;
-  p->sock = silc_socket_dup(conn->sock);
+  res->packet = silc_packet_context_dup(packet);
+  res->context = client;
+  res->sock = silc_socket_dup(conn->sock);
 
   silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
                           1, 3, idp->data, idp->len);
   silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
                              silc_client_notify_by_server_destructor,
-                             silc_client_notify_by_server_pending, p);
+                             silc_client_notify_by_server_pending, res);
   silc_buffer_free(idp);
 }
 
@@ -89,7 +111,9 @@ void silc_client_notify_by_server(SilcClient client,
   unsigned char *tmp;
   uint32 tmp_len, mode;
 
-  payload = silc_notify_payload_parse(buffer);
+  SILC_LOG_DEBUG(("Start"));
+
+  payload = silc_notify_payload_parse(buffer->data, buffer->len);
   if (!payload)
     goto out;
 
@@ -111,6 +135,8 @@ void silc_client_notify_by_server(SilcClient client,
      * for the application.
      */
     
+    SILC_LOG_DEBUG(("Notify: INVITE"));
+
     /* Get Channel ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -157,6 +183,8 @@ void silc_client_notify_by_server(SilcClient client,
      * cache them for later use.
      */
 
+    SILC_LOG_DEBUG(("Notify: JOIN"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -175,8 +203,16 @@ void silc_client_notify_by_server(SilcClient client,
 
     /* If nickname or username hasn't been resolved, do so */
     if (!client_entry->nickname || !client_entry->username) {
+      if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+       client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+       goto out;
+      }
+      client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
       goto out;
+    } else {
+      if (client_entry != conn->local_entry)
+       silc_client_nickname_format(client, conn, client_entry);
     }
 
     /* Get Channel ID */
@@ -214,6 +250,8 @@ void silc_client_notify_by_server(SilcClient client,
      * we'll keep it in the cache in case we'll need it later.
      */
     
+    SILC_LOG_DEBUG(("Notify: LEAVE"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -261,6 +299,8 @@ void silc_client_notify_by_server(SilcClient client,
      * Someone left SILC. We'll remove it from all channels and from cache.
      */
 
+    SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -291,7 +331,7 @@ void silc_client_notify_by_server(SilcClient client,
     client->ops->notify(client, conn, type, client_entry, tmp);
 
     /* Free data */
-    silc_client_del_client_entry(client, client_entry);
+    silc_client_del_client_entry(client, conn, client_entry);
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -299,6 +339,8 @@ void silc_client_notify_by_server(SilcClient client,
      * Someone set the topic on a channel.
      */
 
+    SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -344,6 +386,8 @@ void silc_client_notify_by_server(SilcClient client,
      * application.
      */
 
+    SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
+
     /* Get old Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -379,6 +423,9 @@ void silc_client_notify_by_server(SilcClient client,
     if (!client_entry2) {
       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
       goto out;
+    } else {
+      if (client_entry2 != conn->local_entry)
+       silc_client_nickname_format(client, conn, client_entry2);
     }
 
     /* Remove the old from cache */
@@ -392,7 +439,7 @@ void silc_client_notify_by_server(SilcClient client,
     client->ops->notify(client, conn, type, client_entry, client_entry2);
 
     /* Free data */
-    silc_client_del_client_entry(client, client_entry);
+    silc_client_del_client_entry(client, conn, client_entry);
     break;
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
@@ -400,12 +447,14 @@ void silc_client_notify_by_server(SilcClient client,
      * Someone changed a channel mode
      */
 
+    SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
 
-    idp = silc_id_payload_parse_data(tmp, tmp_len);
+    idp = silc_id_payload_parse(tmp, tmp_len);
     if (!idp)
       goto out;
 
@@ -478,10 +527,11 @@ void silc_client_notify_by_server(SilcClient client,
       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
        goto out;
 
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), 
+                    channel->key, channel->key_len / 8,
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
 
@@ -499,6 +549,8 @@ void silc_client_notify_by_server(SilcClient client,
      * Someone changed user's mode on a channel
      */
 
+    SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -570,6 +622,8 @@ void silc_client_notify_by_server(SilcClient client,
      * Received Message of the day
      */
 
+    SILC_LOG_DEBUG(("Notify: MOTD"));
+
     /* Get motd */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -585,6 +639,8 @@ void silc_client_notify_by_server(SilcClient client,
      * ID to the one provided here.
      */
 
+    SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
+
     /* Get the old ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -631,6 +687,8 @@ void silc_client_notify_by_server(SilcClient client,
      * A client (maybe me) was kicked from a channel
      */
 
+    SILC_LOG_DEBUG(("Notify: KICKED"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -651,18 +709,38 @@ void silc_client_notify_by_server(SilcClient client,
     if (!channel_id)
       goto out;
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                &id_cache))
+                                    &id_cache))
       break;
 
     channel = (SilcChannelEntry)id_cache->context;
 
+    /* Get the kicker */
+    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
+
+    /* Find kicker's client entry and if not found resolve it */
+    client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
+    if (!client_entry2) {
+      silc_client_notify_by_server_resolve(client, conn, packet, client_id);
+      goto out;
+    } else {
+      if (client_entry2 != conn->local_entry)
+       silc_client_nickname_format(client, conn, client_entry2);
+    }
+
     /* Get comment */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
 
     /* 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, client_entry, tmp, 
+                       client_entry2, channel);
 
     /* If I was kicked from channel, remove the channel */
     if (client_entry == conn->local_entry) {
@@ -682,6 +760,8 @@ void silc_client_notify_by_server(SilcClient client,
      * A client (maybe me) was killed from the network.
      */
 
+    SILC_LOG_DEBUG(("Notify: KILLED"));
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -720,6 +800,8 @@ void silc_client_notify_by_server(SilcClient client,
       uint32 clients_count = 0;
       int i;
 
+      SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
        /* Get Client ID */
        tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);