X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_notify.c;h=2ccb574c1ac8a384d7fd6a36939e8a0c5b097e52;hb=805fddcf6431e784f9f77114782a90c9d12f9cbe;hp=40a66d3ee9006afe9f7cfaffa20cb76c9df09451;hpb=2899e1a5409cea132653cd67d4e33e9313872e95;p=silc.git diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 40a66d3e..2ccb574c 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2007 Pekka Riikonen + Copyright (C) 1997 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ typedef struct { SilcFSMThread fsm; /* Notify FSM thread */ SilcChannelEntry channel; /* Channel entry being resolved */ SilcClientEntry client_entry; /* Client entry being resolved */ + SilcUInt32 resolve_retry; /* Resolving retry counter */ } *SilcClientNotify; /************************ Static utility functions **************************/ @@ -54,8 +55,15 @@ static void silc_client_notify_resolved(SilcClient client, /* If entry is still invalid, resolving failed. Finish notify processing. */ if (notify->client_entry && !notify->client_entry->internal.valid) { - silc_fsm_next(notify->fsm, silc_client_notify_processed); - silc_client_unref_client(client, conn, notify->client_entry); + /* If resolving timedout try it again many times. */ + if (status != SILC_STATUS_ERR_TIMEDOUT || ++notify->resolve_retry > 1000) { + silc_fsm_next(notify->fsm, silc_client_notify_processed); + + /* Unref client only in case of non-timeout error. In case of timeout + occurred, the routine reprocessing the notify is expected not to + create new references of the entry. */ + silc_client_unref_client(client, conn, notify->client_entry); + } } /* If no entries found, just finish the notify processing */ @@ -290,8 +298,14 @@ SILC_FSM_STATE(silc_client_notify_invite) /* Get the channel entry */ channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); - if (!channel) - goto out; + if (!channel) { + /** Resolve channel */ + SILC_FSM_CALL(silc_client_get_channel_by_id_resolve( + client, conn, &id.u.channel_id, + silc_client_notify_resolved, + notify)); + /* NOT REACHED */ + } /* If channel is being resolved handle notify after resolving */ if (channel->internal.resolve_cmd_ident) { @@ -500,7 +514,7 @@ SILC_FSM_STATE(silc_client_notify_signoff) SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; unsigned char *tmp; SilcUInt32 tmp_len; SilcID id; @@ -521,20 +535,19 @@ SILC_FSM_STATE(silc_client_notify_signoff) if (tmp && tmp_len > 128) tmp[128] = '\0'; + if (packet->dst_id_type == SILC_ID_CHANNEL) + if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL, + &id.u.channel_id, sizeof(id.u.channel_id))) + channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); + /* Notify application */ if (client_entry->internal.valid) - NOTIFY(client, conn, type, client_entry, tmp); + NOTIFY(client, conn, type, client_entry, tmp, channel); /* Remove from channel */ - if (packet->dst_id_type == SILC_ID_CHANNEL) { - if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL, - &id.u.channel_id, sizeof(id.u.channel_id))) { - channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); - if (channel) { - silc_client_remove_from_channel(client, conn, channel, client_entry); - silc_client_unref_channel(client, conn, channel); - } - } + if (channel) { + silc_client_remove_from_channel(client, conn, channel, client_entry); + silc_client_unref_channel(client, conn, channel); } /* Delete client */ @@ -688,7 +701,7 @@ SILC_FSM_STATE(silc_client_notify_nick_change) SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; - unsigned char *tmp, oldnick[128 + 1]; + unsigned char *tmp, oldnick[256 + 1]; SilcUInt32 tmp_len; SilcID id, id2; SilcBool valid; @@ -925,13 +938,15 @@ SILC_FSM_STATE(silc_client_notify_cmode_change) if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) channel->user_limit = 0; - /* Save the new mode */ - channel->mode = mode; - /* Get the channel public key that was added or removed */ tmp = silc_argument_get_arg_type(args, 7, &tmp_len); if (tmp) - silc_client_channel_save_public_keys(channel, tmp, tmp_len); + silc_client_channel_save_public_keys(channel, tmp, tmp_len, FALSE); + else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) + silc_client_channel_save_public_keys(channel, NULL, 0, TRUE); + + /* Save the new mode */ + channel->mode = mode; silc_rwlock_unlock(channel->internal.lock); @@ -1410,6 +1425,7 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; + SilcServerEntry server_entry = NULL; SilcDList clients; SilcID id; int i; @@ -1420,6 +1436,13 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) if (!clients) goto out; + /* Get server ID */ + if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) + goto out; + + /* Get server, in case we have it cached */ + server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id); + for (i = 1; i < silc_argument_get_arg_num(args); i++) { /* Get Client ID */ if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL)) @@ -1431,9 +1454,8 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) silc_dlist_add(clients, client_entry); } - /* Notify application. We don't keep server entries so the server - entry is returned as NULL. The client's are returned as list. */ - NOTIFY(client, conn, type, NULL, clients); + /* Notify application. */ + NOTIFY(client, conn, type, server_entry, clients); /* Delete the clients */ silc_dlist_start(clients); @@ -1445,6 +1467,7 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) out: /** Notify processed */ + silc_client_unref_server(client, conn, server_entry); silc_client_list_free(client, conn, clients); silc_fsm_next(fsm, silc_client_notify_processed); return SILC_FSM_CONTINUE; @@ -1481,7 +1504,7 @@ SILC_FSM_STATE(silc_client_notify_error) if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) goto out; client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id); - if (client_entry) { + if (client_entry && client_entry != conn->local_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); @@ -1511,7 +1534,6 @@ SILC_FSM_STATE(silc_client_notify_watch) SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; SilcNotifyType ntype = 0; - SilcBool del_client = FALSE; unsigned char *pk, *tmp; SilcUInt32 mode, pk_len, tmp_len; SilcPublicKey public_key = NULL; @@ -1579,19 +1601,12 @@ SILC_FSM_STATE(silc_client_notify_watch) 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 && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE && - !silc_hash_table_count(client_entry->channels)) - del_client = TRUE; - else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF || - ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || - ntype == SILC_NOTIFY_TYPE_KILLED) - del_client = TRUE; - - if (del_client) { + /* Remove client that left the network. */ + if (ntype == SILC_NOTIFY_TYPE_SIGNOFF || + ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || + ntype == SILC_NOTIFY_TYPE_KILLED) { silc_client_remove_from_channels(client, conn, client_entry); + client_entry->internal.valid = FALSE; silc_client_del_client(client, conn, client_entry); }