X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fcommand_reply.c;h=3c4f490e4c46e4d9c6ead1999520079160318649;hb=a818c5b5411bbc4436d1c5f011236985c96bb787;hp=557a857fa68b953a590912a2365e3412ea8abb55;hpb=a13a1924bf35d6f8d9422a2c60364329fd6511b3;p=silc.git diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 557a857f..3c4f490e 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -57,6 +57,7 @@ SilcServerCommandReply silc_command_reply_list[] = SILC_SERVER_CMD_REPLY(join, JOIN), SILC_SERVER_CMD_REPLY(users, USERS), SILC_SERVER_CMD_REPLY(getkey, GETKEY), + SILC_SERVER_CMD_REPLY(list, LIST), { NULL, 0 }, }; @@ -71,12 +72,12 @@ void silc_server_command_reply_process(SilcServer server, SilcServerCommandReplyContext ctx; SilcCommandPayload payload; SilcCommand command; - uint16 ident; + SilcUInt16 ident; SILC_LOG_DEBUG(("Start")); /* Get command reply payload from packet */ - payload = silc_command_payload_parse(buffer); + payload = silc_command_payload_parse(buffer->data, buffer->len); if (!payload) { /* Silently ignore bad reply packet */ SILC_LOG_DEBUG(("Bad command reply packet")); @@ -93,8 +94,10 @@ void silc_server_command_reply_process(SilcServer server, ident = silc_command_get_ident(ctx->payload); /* Check for pending commands and mark to be exeucted */ - silc_server_command_pending_check(server, ctx, - silc_command_get(ctx->payload), ident); + ctx->callbacks = + silc_server_command_pending_check(server, ctx, + silc_command_get(ctx->payload), + ident, &ctx->callbacks_count); /* Execute command reply */ command = silc_command_get(ctx->payload); @@ -118,6 +121,7 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd) silc_command_payload_free(cmd->payload); if (cmd->sock) silc_socket_free(cmd->sock); /* Decrease the reference counter */ + silc_free(cmd->callbacks); silc_free(cmd); } } @@ -130,11 +134,13 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) SilcServer server = cmd->server; unsigned char *tmp, *id_data; char *nickname, *username, *realname, *servername = NULL; + unsigned char *fingerprint; SilcClientID *client_id; SilcClientEntry client; char global = FALSE; char *nick; - uint32 mode = 0, len, id_len; + SilcUInt32 mode = 0, len, id_len, flen; + int expire = 0; id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); nickname = silc_argument_get_arg_type(cmd->args, 3, &len); @@ -156,31 +162,26 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) if (!client_id) return FALSE; + fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen); + /* Check if we have this client cached already. */ - client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL); + client = silc_idlist_find_client_by_id(server->local_list, client_id, + FALSE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, client_id, - NULL); + FALSE, NULL); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) + if (server->server_type != SILC_SERVER) return FALSE; /* Take hostname out of nick string if it includes it. */ - if (strchr(nickname, '@')) { - int len = strcspn(nickname, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char)); - memcpy(nick, nickname, len); - memcpy(servername, nickname + len + 1, strlen(nickname) - len); - } else { - nick = strdup(nickname); - } + silc_parse_userfqdn(nickname, &nick, &servername); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be @@ -188,11 +189,16 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) client = silc_idlist_add_client(server->global_list, nick, strdup(username), strdup(realname), client_id, - cmd->sock->user_data, NULL); - if (!client) + cmd->sock->user_data, NULL, + time(NULL) + 300); + if (!client) { + SILC_LOG_ERROR(("Could not add new client to the ID Cache")); return FALSE; + } - client->data.registered = TRUE; + client->data.status |= + (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED); + client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; client->mode = mode; client->servername = servername; } else { @@ -201,38 +207,41 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Updating client data")); /* Take hostname out of nick string if it includes it. */ - if (strchr(nickname, '@')) { - int len = strcspn(nickname, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char)); - memcpy(nick, nickname, len); - memcpy(servername, nickname + len + 1, strlen(nickname) - len); - } else { - nick = strdup(nickname); - } + silc_parse_userfqdn(nickname, &nick, &servername); - if (client->nickname) - silc_free(client->nickname); - if (client->username) - silc_free(client->username); - if (client->userinfo) - silc_free(client->userinfo); + /* Remove the old cache entry */ + silc_idcache_del_by_context(global ? server->global_list->clients : + server->local_list->clients, client); + + silc_free(client->nickname); + silc_free(client->username); + silc_free(client->userinfo); + silc_free(client->servername); client->nickname = nick; client->username = strdup(username); client->userinfo = strdup(realname); - client->mode = mode; client->servername = servername; + client->mode = mode; + client->data.status |= SILC_IDLIST_STATUS_RESOLVED; + client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; - /* Remove the old cache entry and create a new one */ - silc_idcache_del_by_context(global ? server->global_list->clients : - server->local_list->clients, client); + /* If client is global and is not on any channel then add that we'll + expire the entry after a while. */ + if (global && !silc_hash_table_count(client->channels) && + server->server_type == SILC_SERVER) + expire = time(NULL) + 300; + + /* Create new cache entry */ silc_idcache_add(global ? server->global_list->clients : server->local_list->clients, nick, client->id, - client, FALSE); + client, expire, NULL); silc_free(client_id); } + if (fingerprint && flen == sizeof(client->data.fingerprint)) + memcpy(client->data.fingerprint, fingerprint, flen); + return TRUE; } @@ -245,6 +254,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) SILC_SERVER_CMD_REPLY_FUNC(whois) { SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; + SilcServer server = cmd->server; SilcCommandStatus status; COMMAND_CHECK_STATUS_LIST; @@ -260,8 +270,31 @@ SILC_SERVER_CMD_REPLY_FUNC(whois) } out: + /* If we received notify for invalid ID we'll remove the ID if we + have it cached. */ + if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID && + cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) { + SilcClientEntry client; + SilcUInt32 tmp_len; + unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (tmp) { + SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len); + if (client_id) { + SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " + "the entry from cache")); + client = silc_idlist_find_client_by_id(server->global_list, + client_id, FALSE, NULL); + if (client) { + silc_server_remove_from_channels(server, NULL, client, TRUE, + NULL, TRUE); + silc_idlist_del_client(server->global_list, client); + } + silc_free(client_id); + } + } + } + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS); silc_server_command_reply_free(cmd); } @@ -271,7 +304,7 @@ static char silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; - uint32 len, id_len; + SilcUInt32 len, id_len; unsigned char *id_data; char *nickname, *username, *realname, *servername = NULL; SilcClientID *client_id; @@ -295,29 +328,21 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) /* Check if we have this client cached already. */ client = silc_idlist_find_client_by_id(server->local_list, client_id, - &cache); + FALSE, &cache); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, - client_id, &cache); + client_id, FALSE, &cache); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) + if (server->server_type != SILC_SERVER) return FALSE; /* Take hostname out of nick string if it includes it. */ - if (strchr(nickname, '@')) { - int len = strcspn(nickname, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char)); - memcpy(nick, nickname, len); - memcpy(servername, nickname + len + 1, strlen(nickname) - len); - } else { - nick = strdup(nickname); - } + silc_parse_userfqdn(nickname, &nick, &servername); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be @@ -325,33 +350,23 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) client = silc_idlist_add_client(server->global_list, nick, strdup(username), strdup(realname), silc_id_dup(client_id, SILC_ID_CLIENT), - cmd->sock->user_data, NULL); - if (!client) + cmd->sock->user_data, NULL, + SILC_ID_CACHE_EXPIRE_DEF); + if (!client) { + SILC_LOG_ERROR(("Could not add new client to the ID Cache")); return FALSE; + } - client->data.registered = FALSE; - client = silc_idlist_find_client_by_id(server->global_list, - client_id, &cache); - cache->expire = SILC_ID_CACHE_EXPIRE_DEF; + client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; client->servername = servername; } else { /* We have the client already, update the data */ /* Take hostname out of nick string if it includes it. */ - if (strchr(nickname, '@')) { - int len = strcspn(nickname, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char)); - memcpy(nick, nickname, len); - memcpy(servername, nickname + len + 1, strlen(nickname) - len); - } else { - nick = strdup(nickname); - } + silc_parse_userfqdn(nickname, &nick, &servername); - if (client->nickname) - silc_free(client->nickname); - if (client->username) - silc_free(client->username); + silc_free(client->nickname); + silc_free(client->username); client->nickname = nick; client->username = strdup(username); @@ -362,7 +377,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) server->local_list->clients, client); silc_idcache_add(global ? server->global_list->clients : server->local_list->clients, nick, client->id, - client, FALSE); + client, 0, NULL); } silc_free(client_id); @@ -392,7 +407,6 @@ SILC_SERVER_CMD_REPLY_FUNC(whowas) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS); silc_server_command_reply_free(cmd); } @@ -402,7 +416,7 @@ static char silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; - uint32 len, id_len; + SilcUInt32 len, id_len; unsigned char *id_data; char *name, *info; SilcClientID *client_id = NULL; @@ -415,11 +429,12 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) char *nick = NULL; SilcIDPayload idp = NULL; SilcIdType id_type; + int expire = 0; id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); if (!id_data) return FALSE; - idp = silc_id_payload_parse_data(id_data, id_len); + idp = silc_id_payload_parse(id_data, id_len); if (!idp) return FALSE; @@ -437,70 +452,72 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Received client information")); client = silc_idlist_find_client_by_id(server->local_list, - client_id, NULL); + client_id, FALSE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, client_id, - NULL); + FALSE, NULL); global = TRUE; } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) + if (server->server_type != SILC_SERVER) goto error; - - /* Take hostname out of nick string if it includes it. */ - if (name) { - if (strchr(name, '@')) { - int len = strcspn(name, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - memcpy(nick, name, len); - } else { - nick = strdup(name); - } - } + + /* Take nickname */ + if (name) + silc_parse_userfqdn(name, &nick, NULL); /* We don't have that client anywhere, add it. The client is added to global list since server didn't have it in the lists so it must be global. */ client = silc_idlist_add_client(server->global_list, nick, info ? strdup(info) : NULL, NULL, - client_id, cmd->sock->user_data, NULL); - client->data.registered = TRUE; + client_id, cmd->sock->user_data, NULL, + time(NULL) + 300); + if (!client) { + SILC_LOG_ERROR(("Could not add new client to the ID Cache")); + goto error; + } + client->data.status |= SILC_IDLIST_STATUS_REGISTERED; + client->data.status |= SILC_IDLIST_STATUS_RESOLVED; + client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; } else { /* We have the client already, update the data */ SILC_LOG_DEBUG(("Updating client data")); - /* Take hostname out of nick string if it includes it. */ + /* Take nickname */ if (name) { - if (strchr(name, '@')) { - int len = strcspn(name, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - memcpy(nick, name, len); - } else { - nick = strdup(name); - } - } - - if (name && client->nickname) + silc_parse_userfqdn(name, &nick, NULL); + + /* Remove the old cache entry */ + silc_idcache_del_by_context(global ? server->global_list->clients : + server->local_list->clients, client); + silc_free(client->nickname); - - if (nick) client->nickname = nick; + } - if (info && client->username) { + if (info) { silc_free(client->username); client->username = strdup(info); } + + client->data.status |= SILC_IDLIST_STATUS_RESOLVED; + client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; - /* Remove the old cache entry and create a new one */ if (name) { - silc_idcache_del_by_context(global ? server->global_list->clients : - server->local_list->clients, client); + /* If client is global and is not on any channel then add that we'll + expire the entry after a while. */ + if (global && !silc_hash_table_count(client->channels) && + server->server_type == SILC_SERVER) + expire = time(NULL) + 300; + + /* Add new cache entry */ silc_idcache_add(global ? server->global_list->clients : server->local_list->clients, nick, client->id, - client, FALSE); + client, expire, NULL); } silc_free(client_id); @@ -509,6 +526,9 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) break; case SILC_ID_SERVER: + if (!name) + goto error; + server_id = silc_id_payload_get_id(idp); if (!server_id) goto error; @@ -516,14 +536,14 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Received server information")); server_entry = silc_idlist_find_server_by_id(server->local_list, - server_id, NULL); + server_id, FALSE, NULL); if (!server_entry) server_entry = silc_idlist_find_server_by_id(server->global_list, - server_id, NULL); + server_id, FALSE, NULL); if (!server_entry) { /* If router did not find such Server ID in its lists then this must - be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) + be bogus server or some router in the net is buggy. */ + if (server->server_type != SILC_SERVER) goto error; /* We don't have that server anywhere, add it. */ @@ -534,6 +554,9 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) silc_free(server_id); goto error; } + server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED; + server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED; + server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; server_id = NULL; } @@ -541,28 +564,30 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) break; case SILC_ID_CHANNEL: + if (!name) + goto error; + channel_id = silc_id_payload_get_id(idp); if (!channel_id) goto error; SILC_LOG_DEBUG(("Received channel information")); - channel = silc_idlist_find_channel_by_id(server->local_list, - channel_id, NULL); + channel = silc_idlist_find_channel_by_name(server->local_list, + name, NULL); if (!channel) - channel = silc_idlist_find_channel_by_id(server->global_list, channel_id, - NULL); + channel = silc_idlist_find_channel_by_name(server->global_list, + name, NULL); if (!channel) { - /* If router did not find such Server ID in its lists then this must - be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) + /* If router did not find such Channel ID in its lists then this must + be bogus channel or some router in the net is buggy. */ + if (server->server_type != SILC_SERVER) goto error; /* We don't have that server anywhere, add it. */ channel = silc_idlist_add_channel(server->global_list, strdup(name), SILC_CHANNEL_MODE_NONE, channel_id, - server->router->connection, - NULL, NULL); + server->router, NULL, NULL, 0); if (!channel) { silc_free(channel_id); goto error; @@ -590,6 +615,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_SERVER_CMD_REPLY_FUNC(identify) { SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; + SilcServer server = cmd->server; SilcCommandStatus status; COMMAND_CHECK_STATUS_LIST; @@ -605,8 +631,31 @@ SILC_SERVER_CMD_REPLY_FUNC(identify) } out: + /* If we received notify for invalid ID we'll remove the ID if we + have it cached. */ + if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID && + cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) { + SilcClientEntry client; + SilcUInt32 tmp_len; + unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (tmp) { + SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len); + if (client_id) { + SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " + "the entry from cache")); + client = silc_idlist_find_client_by_id(server->global_list, + client_id, FALSE, NULL); + if (client) { + silc_server_remove_from_channels(server, NULL, client, TRUE, + NULL, TRUE); + silc_idlist_del_client(server->global_list, client); + } + silc_free(client_id); + } + } + } + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY); silc_server_command_reply_free(cmd); } @@ -619,7 +668,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info) SilcCommandStatus status; SilcServerEntry entry; SilcServerID *server_id; - uint32 tmp_len; + SilcUInt32 tmp_len; unsigned char *tmp, *name; COMMAND_CHECK_STATUS; @@ -637,10 +686,11 @@ SILC_SERVER_CMD_REPLY_FUNC(info) if (tmp_len > 256) goto out; - entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL); + entry = silc_idlist_find_server_by_id(server->local_list, server_id, + FALSE, NULL); if (!entry) { entry = silc_idlist_find_server_by_id(server->global_list, server_id, - NULL); + FALSE, NULL); if (!entry) { /* Add the server to global list */ server_id = silc_id_dup(server_id, SILC_ID_SERVER); @@ -650,6 +700,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info) silc_free(server_id); goto out; } + entry->data.status |= SILC_IDLIST_STATUS_REGISTERED; } } @@ -662,7 +713,6 @@ SILC_SERVER_CMD_REPLY_FUNC(info) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO); silc_server_command_reply_free(cmd); } @@ -675,7 +725,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) SilcCommandStatus status; SilcServerEntry entry = NULL; SilcServerID *server_id; - uint32 tmp_len; + SilcUInt32 tmp_len; unsigned char *tmp; COMMAND_CHECK_STATUS; @@ -688,10 +738,11 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) if (!server_id) goto out; - entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL); + entry = silc_idlist_find_server_by_id(server->local_list, server_id, + TRUE, NULL); if (!entry) { entry = silc_idlist_find_server_by_id(server->global_list, server_id, - NULL); + TRUE, NULL); if (!entry) goto out; } @@ -705,7 +756,6 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD); silc_server_command_reply_free(cmd); if (entry) @@ -726,10 +776,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join) SilcClientID *client_id = NULL; SilcChannelEntry entry; SilcHmac hmac = NULL; - uint32 id_len, len, list_count; + SilcUInt32 id_len, len, list_count; unsigned char *id_string; char *channel_name, *tmp; - uint32 mode, created; + SilcUInt32 mode, created; SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL; COMMAND_CHECK_STATUS; @@ -774,6 +824,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) silc_buffer_put(keyp, tmp, len); } + /* Parse the Channel ID */ id = silc_id_payload_parse_id(id_string, id_len); if (!id) goto out; @@ -819,60 +870,68 @@ SILC_SERVER_CMD_REPLY_FUNC(join) (created == 0 ? "existing" : "created"), channel_name, silc_id_render(id, SILC_ID_CHANNEL))); + /* If the channel is found from global list we must move it to the + local list. */ + entry = silc_idlist_find_channel_by_name(server->global_list, + channel_name, &cache); + if (entry) { + if (entry->rekey) { + silc_schedule_task_del_by_context(server->schedule, entry->rekey); + SILC_LOG_ERROR(("global_list->channels: entry->rekey != NULL, inform Pekka now!!!")); + } + silc_idlist_del_channel(server->global_list, entry); + } + /* Add the channel to our local list. */ entry = silc_idlist_add_channel(server->local_list, strdup(channel_name), SILC_CHANNEL_MODE_NONE, id, - server->router, NULL, hmac); + server->router, NULL, hmac, 0); if (!entry) { silc_free(id); goto out; } + server->stat.my_channels++; } else { /* The entry exists. */ - if (cache->id) - silc_free(cache->id); - entry->id = id; - cache->id = entry->id; + + /* If ID has changed, then update it to the cache too. */ + if (!SILC_ID_CHANNEL_COMPARE(entry->id, id)) + silc_idlist_replace_channel_id(server->local_list, entry->id, id); + + entry->disabled = FALSE; /* Remove the founder auth data if the mode is not set but we have them in the entry */ if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) { silc_pkcs_public_key_free(entry->founder_key); - if (entry->founder_passwd) { - silc_free(entry->founder_passwd); - entry->founder_passwd = NULL; - } + silc_free(entry->founder_passwd); + entry->founder_passwd = NULL; } } if (entry->hmac_name && hmac) { silc_free(entry->hmac_name); - entry->hmac_name = strdup(hmac->hmac->name); + entry->hmac_name = strdup(silc_hmac_get_name(hmac)); } /* Get the ban list */ tmp = silc_argument_get_arg_type(cmd->args, 8, &len); if (tmp) { - if (entry->ban_list) - silc_free(entry->ban_list); - entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list)); - memcpy(entry->ban_list, tmp, len); + silc_free(entry->ban_list); + entry->ban_list = silc_memdup(tmp, len); } /* Get the invite list */ tmp = silc_argument_get_arg_type(cmd->args, 9, &len); if (tmp) { - if (entry->invite_list) - silc_free(entry->invite_list); - entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list)); - memcpy(entry->invite_list, tmp, len); + silc_free(entry->invite_list); + entry->invite_list = silc_memdup(tmp, len); } /* Get the topic */ tmp = silc_argument_get_arg_type(cmd->args, 10, &len); if (tmp) { - if (entry->topic) - silc_free(entry->topic); + silc_free(entry->topic); entry->topic = strdup(tmp); } @@ -891,10 +950,11 @@ SILC_SERVER_CMD_REPLY_FUNC(join) entry->mode = mode; /* Save channel key */ - if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) - silc_server_save_channel_key(server, keyp, entry); - if (keyp) + if (keyp) { + if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) + silc_server_save_channel_key(server, keyp, entry); silc_buffer_free(keyp); + } /* Save the users to the channel */ silc_server_save_users_on_channel(server, cmd->sock, entry, @@ -903,9 +963,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN); - if (client_id) - silc_free(client_id); + silc_free(client_id); silc_server_command_reply_free(cmd); if (client_id_list) @@ -924,8 +982,8 @@ SILC_SERVER_CMD_REPLY_FUNC(users) SilcBuffer client_id_list; SilcBuffer client_mode_list; unsigned char *tmp; - uint32 tmp_len; - uint32 list_count; + SilcUInt32 tmp_len; + SilcUInt32 list_count; COMMAND_CHECK_STATUS; @@ -946,7 +1004,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users) if (!channel) { SilcBuffer idp; - if (server->server_type == SILC_ROUTER) + if (server->server_type != SILC_SERVER) goto out; idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); @@ -960,7 +1018,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users) USERS command reply callback. */ silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, server->cmd_ident, - NULL, silc_server_command_reply_users, cmd); + silc_server_command_reply_users, cmd); return; } } @@ -999,7 +1057,6 @@ SILC_SERVER_CMD_REPLY_FUNC(users) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS); silc_free(channel_id); silc_server_command_reply_free(cmd); } @@ -1015,8 +1072,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) SilcServerID *server_id = NULL; SilcSKEPKType type; unsigned char *tmp, *pk; - uint32 len; - uint16 pk_len; + SilcUInt32 len; + SilcUInt16 pk_len; SilcIDPayload idp = NULL; SilcIdType id_type; SilcPublicKey public_key = NULL; @@ -1026,7 +1083,7 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) tmp = silc_argument_get_arg_type(cmd->args, 2, &len); if (!tmp) goto out; - idp = silc_id_payload_parse_data(tmp, len); + idp = silc_id_payload_parse(tmp, len); if (!idp) goto out; @@ -1052,10 +1109,10 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) client_id = silc_id_payload_get_id(idp); client = silc_idlist_find_client_by_id(server->local_list, client_id, - NULL); + TRUE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, - client_id, NULL); + client_id, TRUE, NULL); if (!client) goto out; } @@ -1065,10 +1122,10 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) server_id = silc_id_payload_get_id(idp); server_entry = silc_idlist_find_server_by_id(server->local_list, server_id, - NULL); + TRUE, NULL); if (!server_entry) { server_entry = silc_idlist_find_server_by_id(server->global_list, - server_id, NULL); + server_id, TRUE, NULL); if (!server_entry) goto out; } @@ -1079,8 +1136,7 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) } out: - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS); + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY); if (idp) silc_id_payload_free(idp); silc_free(client_id); @@ -1089,3 +1145,80 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) silc_pkcs_public_key_free(public_key); silc_server_command_reply_free(cmd); } + +SILC_SERVER_CMD_REPLY_FUNC(list) +{ + SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; + SilcServer server = cmd->server; + SilcCommandStatus status; + SilcChannelID *channel_id = NULL; + SilcChannelEntry channel; + SilcIDCacheEntry cache; + SilcUInt32 len; + unsigned char *tmp, *name, *topic; + SilcUInt32 usercount = 0; + bool global_list = FALSE; + + COMMAND_CHECK_STATUS_LIST; + + tmp = silc_argument_get_arg_type(cmd->args, 2, &len); + channel_id = silc_id_payload_parse_id(tmp, len); + if (!channel_id) + goto out; + + name = silc_argument_get_arg_type(cmd->args, 3, NULL); + topic = silc_argument_get_arg_type(cmd->args, 4, NULL); + tmp = silc_argument_get_arg_type(cmd->args, 5, NULL); + if (tmp) + SILC_GET32_MSB(usercount, tmp); + + /* Add the channel entry if we do not have it already */ + channel = silc_idlist_find_channel_by_name(server->local_list, + name, &cache); + if (!channel) { + channel = silc_idlist_find_channel_by_name(server->global_list, + name, &cache); + global_list = TRUE; + } + if (!channel) { + /* If router did not find such channel in its lists then this must + be bogus channel or some router in the net is buggy. */ + if (server->server_type != SILC_SERVER) + goto out; + + channel = silc_idlist_add_channel(server->global_list, strdup(name), + SILC_CHANNEL_MODE_NONE, channel_id, + server->router, NULL, NULL, + time(NULL) + 60); + if (!channel) + goto out; + channel_id = NULL; + } else { + /* Found, update expiry */ + if (global_list && server->server_type == SILC_SERVER) + cache->expire = time(NULL) + 60; + } + + channel->user_count = usercount; + + if (topic) { + silc_free(channel->topic); + channel->topic = strdup(topic); + } + + /* Pending callbacks are not executed if this was an list entry */ + if (status != SILC_STATUS_OK && + status != SILC_STATUS_LIST_END) { + silc_server_command_reply_free(cmd); + return; + } + + /* Now purge all old entries from the global list, otherwise we'll might + have non-existent entries for long periods of time in the cache. */ + silc_idcache_purge(server->global_list->channels); + + out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST); + silc_free(channel_id); + silc_server_command_reply_free(cmd); +}