More client library rewrites (added rekey)
[silc.git] / lib / silcclient / client_notify.c
index 9087ba35f22c8f754887ea8f5a7b78b5719dccad..068b22d5926560c9dc9c9389a27f3e85eb96c8d1 100644 (file)
@@ -238,6 +238,8 @@ SILC_FSM_STATE(silc_client_notify_none)
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
 
+  SILC_LOG_DEBUG(("Notify: NONE"));
+
   /* Notify application */
   NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
 
@@ -285,7 +287,7 @@ SILC_FSM_STATE(silc_client_notify_invite)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -303,7 +305,7 @@ SILC_FSM_STATE(silc_client_notify_invite)
                  silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -353,7 +355,7 @@ SILC_FSM_STATE(silc_client_notify_join)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -372,7 +374,7 @@ SILC_FSM_STATE(silc_client_notify_join)
                  silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -380,7 +382,7 @@ SILC_FSM_STATE(silc_client_notify_join)
     silc_client_nickname_format(client, conn, client_entry);
 
   /* Join the client to channel */
-  if (!silc_client_add_to_channel(channel, client_entry, 0))
+  if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0))
     goto out;
 
   /* Notify application. */
@@ -410,7 +412,6 @@ SILC_FSM_STATE(silc_client_notify_leave)
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
   SilcChannelEntry channel = NULL;
-  SilcChannelUser chu;
   SilcID id;
 
   SILC_LOG_DEBUG(("Notify: LEAVE"));
@@ -430,7 +431,7 @@ SILC_FSM_STATE(silc_client_notify_leave)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -444,30 +445,7 @@ SILC_FSM_STATE(silc_client_notify_leave)
     goto out;
 
   /* Remove client from channel */
-  chu = silc_client_on_channel(channel, client_entry);
-  if (chu) {
-    silc_hash_table_del(client_entry->channels, channel);
-    silc_hash_table_del(channel->user_list, client_entry);
-    silc_free(chu);
-  }
-
-#if 0 /* Kind of useless, server will return error if client keeps using
-        non-existing client, and the entry is removed then. */
-  /* Some client implementations actually quit network by first doing
-     LEAVE and then immediately SIGNOFF.  We'll check for this by doing
-     check for the client after 5 - 34 seconds.  If it is not valid after
-     that we'll remove the client from cache. */
-  if (!silc_hash_table_count(client_entry->channels)) {
-    SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
-    res->context = client;
-    res->sock = silc_socket_dup(conn->sock);
-    res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
-    silc_schedule_task_add(client->schedule, conn->sock->sock,
-                          silc_client_notify_check_client, res,
-                          (5 + (silc_rng_get_rn16(client->rng) % 29)),
-                          0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-  }
-#endif
+  silc_client_remove_from_channel(client, conn, channel, client_entry);
 
   /* Notify application. */
   NOTIFY(client, conn, type, client_entry, channel);
@@ -517,17 +495,10 @@ SILC_FSM_STATE(silc_client_notify_signoff)
   /* Notify application */
   NOTIFY(client, conn, type, client_entry, tmp);
 
-  /* Remove from all channels */
+  /* Delete client */
   silc_client_remove_from_channels(client, conn, client_entry);
-
-#if 0
-  /* Remove from cache */
-  silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
-#endif
-
-  /* Free data */
+  silc_client_del_client(client, conn, client_entry);
   silc_client_unref_client(client, conn, client_entry);
-  silc_client_del_client_entry(client, conn, client_entry);
 
  out:
   /** Notify processed */
@@ -573,7 +544,7 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -597,7 +568,7 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
                    silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry;
@@ -611,7 +582,7 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
                    silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -626,7 +597,7 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
                    silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -667,7 +638,7 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
   SilcClientEntry client_entry = NULL;
   unsigned char *tmp, *nick, oldnick[128 + 1];
   SilcUInt32 tmp_len;
-  SilcID id;
+  SilcID id, id2;
 
   SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
 
@@ -680,6 +651,15 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
       SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
     goto out;
 
+  /* Get new Client ID */
+  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
+    goto out;
+
+  /* Ignore my ID */
+  if (conn->local_id &&
+      SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
+    goto out;
+
   /* Find old Client entry */
   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
   if (!client_entry || !client_entry->nickname[0]) {
@@ -688,14 +668,10 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
-  /* Get new Client ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
-    goto out;
-
   /* Take the new nickname */
   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
   if (!tmp)
@@ -704,12 +680,14 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
   /* Check whether nickname changed at all.  It is possible that nick
      change notify is received but nickname didn't change, only the
      ID changes.  If Client ID hash match, nickname didn't change. */
-  if (SILC_ID_COMPARE_HASH(&client_entry->id, &id.u.client_id) &&
+  if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
       silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
     /* Nickname didn't change.  Update only Client ID.  We don't notify
        application because nickname didn't change. */
-    silc_idcache_update(conn->internal->client_cache, client_entry,
-                       &client_entry->id, &id.u.client_id, NULL, NULL, FALSE);
+    silc_mutex_lock(conn->internal->lock);
+    silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
+                                  &id2.u.client_id, NULL, FALSE);
+    silc_mutex_unlock(conn->internal->lock);
     goto out;
   }
 
@@ -719,12 +697,14 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
     goto out;
 
   /* Update nickname */
-  if (!silc_idcache_update(conn->internal->client_cache, client_entry,
-                          NULL, NULL, client_entry->nickname_normalized,
-                          nick, TRUE)) {
+  silc_mutex_lock(conn->internal->lock);
+  if (!silc_idcache_update_by_context(conn->internal->client_cache,
+                                     client_entry, NULL, nick, TRUE)) {
     silc_free(nick);
+    silc_mutex_unlock(conn->internal->lock);
     goto out;
   }
+  silc_mutex_unlock(conn->internal->lock);
   memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
   memcpy(client_entry->nickname, tmp, tmp_len);
   client_entry->nickname_normalized = nick;
@@ -781,7 +761,7 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -806,7 +786,7 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
                    silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry;
@@ -820,7 +800,7 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
                    silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -835,7 +815,7 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
                    silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -957,7 +937,23 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
+    /* NOT REACHED */
+  }
+
+  /* Get target Client ID */
+  if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
+    goto out;
+
+  /* Find target Client entry */
+  client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
+  if (!client_entry2 || !client_entry2->nickname[0]) {
+    /** Resolve client */
+    silc_client_unref_client(client, conn, client_entry2);
+    SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+                                        client, conn, &id2.u.client_id, NULL,
+                                        silc_client_notify_resolved,
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -982,7 +978,7 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
                    silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry;
@@ -996,7 +992,7 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
                    silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -1011,29 +1007,12 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
                    silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
   }
 
-  /* Get target Client ID */
-  if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
-    goto out;
-
-  /* Find target Client entry */
-  client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
-  if (!client_entry2 || !client_entry2->nickname[0]) {
-    /** Resolve client */
-    silc_client_unref_client(client, conn, client_entry);
-    silc_client_unref_client(client, conn, client_entry2);
-    SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
-                                        client, conn, &id2.u.client_id, NULL,
-                                        silc_client_notify_resolved,
-                                        fsm));
-    /* NOT REACHED */
-  }
-
   /* Save the mode */
   chu = silc_client_on_channel(channel, client_entry2);
   if (chu)
@@ -1121,7 +1100,7 @@ SILC_FSM_STATE(silc_client_notify_channel_change)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -1158,7 +1137,6 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry, client_entry2;
   SilcChannelEntry channel = NULL;
-  SilcChannelUser chu;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   SilcID id;
@@ -1180,7 +1158,7 @@ SILC_FSM_STATE(silc_client_notify_kicked)
                                      conn, SILC_COMMAND_NONE,
                                      channel->internal.resolve_cmd_ident,
                                      silc_client_notify_wait_continue,
-                                     fsm));
+                                     notify));
     /* NOT REACHED */
   }
 
@@ -1208,7 +1186,7 @@ SILC_FSM_STATE(silc_client_notify_kicked)
                  silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -1216,14 +1194,8 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
 
   /* Remove kicked client from channel */
-  if (client_entry != conn->local_entry) {
-    chu = silc_client_on_channel(channel, client_entry);
-    if (chu) {
-      silc_hash_table_del(client_entry->channels, channel);
-      silc_hash_table_del(channel->user_list, client_entry);
-      silc_free(chu);
-    }
-  }
+  if (client_entry != conn->local_entry)
+    silc_client_remove_from_channel(client, conn, channel, client_entry);
 
   /* Notify application. */
   NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
@@ -1232,6 +1204,7 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   if (client_entry == conn->local_entry) {
     if (conn->current_channel == channel)
       conn->current_channel = NULL;
+    silc_client_empty_channel(client, conn, channel);
     silc_client_del_channel(client, conn, channel);
   }
 
@@ -1294,7 +1267,7 @@ SILC_FSM_STATE(silc_client_notify_killed)
       SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry2;
@@ -1306,7 +1279,7 @@ SILC_FSM_STATE(silc_client_notify_killed)
       SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -1319,7 +1292,7 @@ SILC_FSM_STATE(silc_client_notify_killed)
       SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -1329,8 +1302,10 @@ SILC_FSM_STATE(silc_client_notify_killed)
   NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
 
   /* Delete the killed client */
-  if (client_entry != conn->local_entry)
+  if (client_entry != conn->local_entry) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
+  }
 
  out:
   silc_client_unref_client(client, conn, client_entry);
@@ -1363,7 +1338,7 @@ SILC_FSM_STATE(silc_client_notify_server_signoff)
   SilcID id;
   int i;
 
-  SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+  SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
 
   clients = silc_dlist_init();
   if (!clients)
@@ -1386,8 +1361,10 @@ SILC_FSM_STATE(silc_client_notify_server_signoff)
 
   /* Delete the clients */
   silc_dlist_start(clients);
-  while ((client_entry = silc_dlist_get(clients)))
+  while ((client_entry = silc_dlist_get(clients))) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
+  }
 
  out:
   /** Notify processed */
@@ -1428,6 +1405,7 @@ SILC_FSM_STATE(silc_client_notify_error)
       goto out;
     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
     if (client_entry) {
+      silc_client_remove_from_channels(client, conn, client_entry);
       silc_client_del_client(client, conn, client_entry);
       silc_client_unref_client(client, conn, client_entry);
     }
@@ -1476,7 +1454,7 @@ SILC_FSM_STATE(silc_client_notify_watch)
     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -1538,8 +1516,10 @@ SILC_FSM_STATE(silc_client_notify_watch)
           ntype == SILC_NOTIFY_TYPE_KILLED)
     del_client = TRUE;
 
-  if (del_client)
+  if (del_client) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
+  }
 
   if (public_key)
     silc_pkcs_public_key_free(public_key);