#define NOTIFY conn->client->internal->ops->notify
+/* Notify processing context */
+typedef struct {
+ SilcPacket packet;
+ SilcNotifyPayload payload;
+ SilcFSMThread fsm;
+ SilcChannelEntry channel;
+} *SilcClientNotify;
+
/************************ Static utility functions **************************/
/* Entry resolving callback. This will continue processing the notify. */
SilcDList entries,
void *context)
{
+ SilcClientNotify notify = context;
+
/* If no entries found, just finish the notify processing, a silent error */
if (!entries)
- silc_fsm_next(context, silc_client_notify_processed);
+ silc_fsm_next(notify->fsm, silc_client_notify_processed);
+
+ if (notify->channel) {
+ notify->channel->internal.resolve_cmd_ident = 0;
+ silc_client_unref_channel(client, conn, notify->channel);
+ }
/* Continue processing the notify */
- SILC_FSM_CALL_CONTINUE_SYNC(context);
+ SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
+}
+
+/* Continue notify processing after it was suspended while waiting for
+ channel information being resolved. */
+
+static SilcBool silc_client_notify_wait_continue(SilcClient client,
+ SilcClientConnection conn,
+ SilcCommand command,
+ SilcStatus status,
+ SilcStatus error,
+ void *context,
+ va_list ap)
+{
+ SilcClientNotify notify = context;
+
+ /* Continue after last command reply received */
+ if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
+ status == SILC_STATUS_LIST_END)
+ SILC_FSM_CALL_CONTINUE(notify->fsm);
+
+ return TRUE;
}
/********************************* Notify ***********************************/
SILC_FSM_STATE(silc_client_notify)
{
SilcPacket packet = state_context;
+ SilcClientNotify notify;
SilcNotifyPayload payload;
payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
return SILC_FSM_FINISH;
}
+ notify = silc_calloc(1, sizeof(*notify));
+ if (!notify) {
+ silc_notify_payload_free(payload);
+ silc_packet_free(packet);
+ return SILC_FSM_FINISH;
+ }
+
/* Save notify payload to packet context during processing */
- packet->next = (void *)payload;
+ notify->packet = packet;
+ notify->payload = payload;
+ notify->fsm = fsm;
+ silc_fsm_set_state_context(fsm, notify);
/* Process the notify */
switch (silc_notify_get_type(payload)) {
/** Unknown notify */
silc_notify_payload_free(payload);
silc_packet_free(packet);
+ silc_free(notify);
return SILC_FSM_FINISH;
break;
}
SILC_FSM_STATE(silc_client_notify_processed)
{
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcPacket packet = notify->packet;
+ SilcNotifyPayload payload = notify->payload;
+
silc_notify_payload_free(payload);
silc_packet_free(packet);
+ silc_free(notify);
return SILC_FSM_FINISH;
}
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry;
/* Get the channel entry */
channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get sender Client ID */
if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
goto out;
if (!client_entry || !client_entry->nickname[0]) {
/** Resolve client */
silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_client_by_id_resolve(
client, conn, &id.u.client_id, NULL,
silc_client_notify_resolved,
fsm));
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry;
if (!channel)
goto out;
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get Client ID */
if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
goto out;
!client_entry->username[0]) {
/** Resolve client */
silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_client_by_id_resolve(
client, conn, &id.u.client_id, NULL,
silc_client_notify_resolved,
fsm));
silc_client_nickname_format(client, conn, client_entry);
/* Join the client to channel */
- silc_client_add_to_channel(channel, client_entry, 0);
+ if (!silc_client_add_to_channel(channel, client_entry, 0))
+ goto out;
/* Notify application. */
NOTIFY(client, conn, type, client_entry, channel);
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
+ SilcPacket packet = notify->packet;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL;
if (!channel)
goto out;
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get Client ID */
if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
goto out;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
+ SilcPacket packet = notify->packet;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL;
if (!channel)
goto out;
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get ID */
if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
goto out;
if (!client_entry || !client_entry->nickname[0]) {
/** Resolve client */
silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_client_by_id_resolve(
client, conn, &id.u.client_id, NULL,
silc_client_notify_resolved,
fsm));
server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
if (!server) {
/** Resolve server */
- SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_server_by_id_resolve(
client, conn, &id.u.server_id,
silc_client_notify_resolved,
fsm));
&id.u.channel_id);
if (!channel_entry) {
/** Resolve channel */
- SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_channel_by_id_resolve(
client, conn, &id.u.channel_id,
silc_client_notify_resolved,
fsm));
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
+ SilcPacket packet = notify->packet;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL;
if (!channel)
goto out;
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get the mode */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
if (!tmp)
if (!client_entry || !client_entry->nickname[0]) {
/** Resolve client */
silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_client_by_id_resolve(
client, conn, &id.u.client_id, NULL,
silc_client_notify_resolved,
fsm));
server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
if (!server) {
/** Resolve server */
- SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_server_by_id_resolve(
client, conn, &id.u.server_id,
silc_client_notify_resolved,
fsm));
&id.u.channel_id);
if (!channel_entry) {
/** Resolve channel */
- SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_channel_by_id_resolve(
client, conn, &id.u.channel_id,
silc_client_notify_resolved,
fsm));
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
+ SilcPacket packet = notify->packet;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL, client_entry2 = NULL;
if (!channel)
goto out;
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get the mode */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
if (!tmp)
if (!client_entry || !client_entry->nickname[0]) {
/** Resolve client */
silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_client_by_id_resolve(
client, conn, &id.u.client_id, NULL,
silc_client_notify_resolved,
fsm));
server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
if (!server) {
/** Resolve server */
- SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_server_by_id_resolve(
client, conn, &id.u.server_id,
silc_client_notify_resolved,
fsm));
&id.u.channel_id);
if (!channel_entry) {
/** Resolve channel */
- SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_channel_by_id_resolve(
client, conn, &id.u.channel_id,
silc_client_notify_resolved,
fsm));
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
unsigned char *tmp;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcChannelEntry channel = NULL;
if (!channel)
goto out;
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get the new ID */
if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
goto out;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
+ SilcPacket packet = notify->packet;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry, client_entry2;
SILC_LOG_DEBUG(("Notify: KICKED"));
+ /* Get channel entry */
+ if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
+ &id.u.channel_id, sizeof(id.u.channel_id)))
+ goto out;
+ channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ if (!channel)
+ goto out;
+
+ /* If channel is being resolved handle notify after resolving */
+ if (channel->internal.resolve_cmd_ident) {
+ silc_client_unref_channel(client, conn, channel);
+ SILC_FSM_CALL(silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ channel->internal.resolve_cmd_ident,
+ silc_client_notify_wait_continue,
+ fsm));
+ /* NOT REACHED */
+ }
+
/* Get Client ID */
if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
goto out;
if (!client_entry)
goto out;
- /* Get channel entry */
- if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id)))
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
-
/* Get kicker's Client ID */
if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
goto out;
/** 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(
+ notify->channel = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_client_by_id_resolve(
client, conn, &id.u.client_id, NULL,
silc_client_notify_resolved,
fsm));
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL, client_entry2 = NULL;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry;
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+ SilcClientNotify notify = state_context;
+ SilcNotifyPayload payload = notify->payload;
SilcNotifyType type = silc_notify_get_type(payload);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry = NULL;
- SilcNotifyType notify = 0;
+ SilcNotifyType ntype = 0;
SilcBool del_client = FALSE;
unsigned char *pk, *tmp;
SilcUInt32 mode, pk_len, tmp_len;
if (tmp && tmp_len != 2)
goto out;
if (tmp)
- SILC_GET16_MSB(notify, tmp);
+ SILC_GET16_MSB(ntype, tmp);
/* Get nickname */
tmp = silc_argument_get_arg_type(args, 2, NULL);
}
/* Notify application. */
- NOTIFY(client, conn, type, client_entry, tmp, mode, notify,
+ NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
client_entry->public_key);
client_entry->mode = mode;
/* If nickname was changed, remove the client entry unless the
client is on some channel */
/* XXX, why do we need to remove the client entry?? */
- if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
+ if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
!silc_hash_table_count(client_entry->channels))
del_client = TRUE;
- else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
- notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
- notify == SILC_NOTIFY_TYPE_KILLED)
+ else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
+ ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
+ ntype == SILC_NOTIFY_TYPE_KILLED)
del_client = TRUE;
if (del_client)