X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand.c;h=5257bf450ef6f306f11eec2a37932d7a4c117b89;hb=487b9263317ab859b530cdda115984a970ca04eb;hp=b449b1150ed9da09d1d1eccd113d1f948bf63754;hpb=017dec75a98209fbef49eb496c2269b0c49e736d;p=silc.git diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index b449b115..5257bf45 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -349,6 +349,36 @@ SILC_CLIENT_CMD_FUNC(identify) silc_client_command_free(cmd); } +/* Pending callbcak that will be called after the NICK command was + replied by the server. This sets the nickname if there were no + errors. */ + +SILC_CLIENT_CMD_FUNC(nick_change) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientConnection conn = cmd->conn; + SilcClientCommandReplyContext reply = + (SilcClientCommandReplyContext)context2; + SilcCommandStatus status; + + SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL)); + if (status == SILC_STATUS_OK) { + /* Set the nickname */ + if (conn->nickname) + silc_free(conn->nickname); + conn->nickname = strdup(cmd->argv[1]); + conn->local_entry->nickname = conn->nickname; + silc_idcache_del_by_context(conn->client_cache, conn->local_entry); + silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]), + conn->local_entry->id, conn->local_entry, FALSE); + COMMAND; + } else { + COMMAND_ERROR; + } + + silc_client_command_free(cmd); +} + /* Command NICK. Shows current nickname/sets new nickname on current window. */ @@ -389,24 +419,29 @@ SILC_CLIENT_CMD_FUNC(nick) goto out; } - /* Set new nickname */ - buffer = silc_command_payload_encode(SILC_COMMAND_NICK, - cmd->argc - 1, ++cmd->argv, - ++cmd->argv_lens, ++cmd->argv_types, + if (cmd->argv_lens[1] > 128) + cmd->argv_lens[1] = 128; + + /* Send the NICK command */ + buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1, + &cmd->argv[1], + &cmd->argv_lens[1], + &cmd->argv_types[1], ++cmd->conn->cmd_ident); silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); - cmd->argv--; - cmd->argv_lens--; - cmd->argv_types--; - if (conn->nickname) - silc_free(conn->nickname); - conn->nickname = strdup(cmd->argv[1]); - /* Notify application */ - COMMAND; + /* Register pending callback that will actually set the new nickname + if there were no errors returned by the server. */ + silc_client_command_pending(conn, SILC_COMMAND_NICK, + cmd->conn->cmd_ident, + silc_client_command_destructor, + silc_client_command_nick_change, + silc_client_command_dup(cmd)); + cmd->pending = TRUE; + return; out: silc_client_command_free(cmd); @@ -600,12 +635,11 @@ SILC_CLIENT_CMD_FUNC(invite) client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[2], TRUE); if (!client_entry) { - silc_free(nickname); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); /* Client entry not found, it was requested thus mark this to be pending command. */ @@ -705,6 +739,9 @@ SILC_CLIENT_CMD_FUNC(quit) q->client = cmd->client; q->conn = cmd->conn; + /* Sleep for a while */ + sleep(2); + /* We quit the connection with little timeout */ silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock, silc_client_command_quit_cb, (void *)q, @@ -717,6 +754,56 @@ SILC_CLIENT_CMD_FUNC(quit) silc_client_command_free(cmd); } +/* Timeout callback to remove the killed client from cache */ + +SILC_TASK_CALLBACK(silc_client_command_kill_remove_later) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClient client = cmd->client; + SilcClientConnection conn = cmd->conn; + SilcClientEntry target; + char *nickname = NULL; + + /* Parse the typed nickname. */ + if (client->params->nickname_parse) + client->params->nickname_parse(cmd->argv[1], &nickname); + else + nickname = strdup(cmd->argv[1]); + + /* Get the target client */ + target = silc_idlist_get_client(cmd->client, conn, nickname, + cmd->argv[1], FALSE); + if (target) { + silc_client_remove_from_channels(client, conn, target); + silc_client_del_client(client, conn, target); + } + + silc_free(nickname); + silc_client_command_free(cmd); +} + +/* Kill command's pending command callback to actually remove the killed + client from our local cache. */ + +SILC_CLIENT_CMD_FUNC(kill_remove) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientCommandReplyContext reply = + (SilcClientCommandReplyContext)context2; + SilcCommandStatus status; + + SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL)); + if (status == SILC_STATUS_OK) { + /* Remove with timeout */ + silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock, + silc_client_command_kill_remove_later, context, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + return; + } + + silc_client_command_free(cmd); +} + /* Command KILL. Router operator can use this command to remove an client fromthe SILC Network. */ @@ -752,13 +839,13 @@ SILC_CLIENT_CMD_FUNC(kill) target = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[1], TRUE); if (!target) { - silc_free(nickname); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); + /* Client entry not found, it was requested thus mark this to be pending command. */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, @@ -773,10 +860,12 @@ SILC_CLIENT_CMD_FUNC(kill) /* Send the KILL command to the server */ idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT); if (cmd->argc == 2) - buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, + ++conn->cmd_ident, 1, 1, idp->data, idp->len); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2, + buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, + ++conn->cmd_ident, 2, 1, idp->data, idp->len, 2, cmd->argv[2], strlen(cmd->argv[2])); @@ -788,6 +877,12 @@ SILC_CLIENT_CMD_FUNC(kill) /* Notify application */ COMMAND; + /* Register a pending callback that will actually remove the killed + client from our cache. */ + silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident, + NULL, silc_client_command_kill_remove, + silc_client_command_dup(cmd)); + out: silc_free(nickname); silc_client_command_free(cmd); @@ -872,7 +967,6 @@ SILC_CLIENT_CMD_FUNC(ping) conn->ping[i].start_time = time(NULL); conn->ping[i].dest_id = id; conn->ping[i].dest_name = strdup(conn->remote_host); - conn->ping_count++; break; } } @@ -909,11 +1003,17 @@ SILC_CLIENT_CMD_FUNC(join) /* See if we have joined to the requested channel already */ if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1], - &id_cache)) - goto out; + &id_cache)) { + SilcChannelEntry channel = (SilcChannelEntry)id_cache->context; + if (channel->on_channel) + goto out; + } idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT); + if (cmd->argv_lens[1] > 256) + cmd->argv_lens[1] = 256; + /* Send JOIN command to the server */ if (cmd->argc == 2) buffer = @@ -1370,13 +1470,13 @@ SILC_CLIENT_CMD_FUNC(cumode) client_entry = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[3], TRUE); if (!client_entry) { - silc_free(nickname); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); + /* Client entry not found, it was requested thus mark this to be pending command. */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, @@ -1389,6 +1489,7 @@ SILC_CLIENT_CMD_FUNC(cumode) } /* Get the current mode */ + silc_list_start(channel->clients); while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { if (chu->client == client_entry) { mode = chu->mode; @@ -1453,7 +1554,8 @@ SILC_CLIENT_CMD_FUNC(cumode) /* Send the command packet. We support sending only one mode at once that requires an argument. */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4, + buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, + auth ? 4 : 3, 1, chidp->data, chidp->len, 2, modebuf, 4, 3, clidp->data, clidp->len, @@ -1955,6 +2057,7 @@ SILC_CLIENT_CMD_FUNC(leave) } channel = (SilcChannelEntry)id_cache->context; + channel->on_channel = FALSE; /* Send LEAVE command to the server */ idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL); @@ -2053,6 +2156,23 @@ SILC_CLIENT_CMD_FUNC(getkey) goto out; } + if (cmd->pending) { + SilcClientCommandReplyContext reply = + (SilcClientCommandReplyContext)context2; + SilcCommandStatus status; + unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL); + SILC_GET16_MSB(status, tmp); + + if (status == SILC_STATUS_ERR_NO_SUCH_NICK || + status == SILC_STATUS_ERR_NO_SUCH_SERVER) { + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "%s", + silc_client_command_status_message(status)); + COMMAND_ERROR; + goto out; + } + } + /* Parse the typed nickname. */ if (client->params->nickname_parse) client->params->nickname_parse(cmd->argv[1], &nickname); @@ -2067,6 +2187,11 @@ SILC_CLIENT_CMD_FUNC(getkey) server_entry = silc_client_get_server(client, conn, cmd->argv[1]); if (!server_entry) { + if (cmd->pending) { + COMMAND_ERROR; + goto out; + } + /* No. what ever user wants we don't have it, so resolve it. We will try to resolve both client and server, one of them is bound to be wrong. */ @@ -2079,13 +2204,12 @@ SILC_CLIENT_CMD_FUNC(getkey) silc_client_command_getkey, silc_client_command_dup(cmd)); - /* This sends the INFO command to resolve the server. */ - silc_client_send_command(client, conn, SILC_COMMAND_INFO, + /* This sends the IDENTIFY command to resolve the server. */ + silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY, ++conn->cmd_ident, 1, - 1, cmd->argv[1], cmd->argv_lens[1]); + 2, cmd->argv[1], cmd->argv_lens[1]); silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - silc_client_command_destructor, + conn->cmd_ident, NULL, silc_client_command_getkey, silc_client_command_dup(cmd));