X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand.c;h=781607e3ae676af4807153be70907c11804b9638;hp=f9fc1f805b2e38fcc765ce47f1fd66750f610dda;hb=e5d8d3db6caa344b3d419b884556c21b15e7d123;hpb=7d0ea3fa6be5ed0b3597a9a79f72870d6e2977c7 diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index f9fc1f80..781607e3 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -320,8 +320,6 @@ SILC_CLIENT_CMD_FUNC(identify) } if (cmd->argc < 2 || cmd->argc > 3) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Usage: /IDENTIFY [@] []"); COMMAND_ERROR; goto out; } @@ -551,8 +549,8 @@ SILC_CLIENT_CMD_FUNC(invite) SilcClientEntry client_entry = NULL; SilcChannelEntry channel; SilcBuffer buffer, clidp, chidp; - uint32 num = 0, type = 0; - char *nickname = NULL, *server = NULL, *name; + uint32 type = 0; + char *nickname = NULL, *name; char *invite = NULL; if (!cmd->conn) { @@ -593,26 +591,20 @@ SILC_CLIENT_CMD_FUNC(invite) /* Parse the typed nickname. */ if (cmd->argc == 3) { if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') { - if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Bad nickname"); - COMMAND_ERROR; - goto out; - } - + if (client->params->nickname_parse) + client->params->nickname_parse(cmd->argv[2], &nickname); + else + nickname = strdup(cmd->argv[2]); + /* Find client entry */ client_entry = silc_idlist_get_client(client, conn, nickname, - server, num, TRUE); + cmd->argv[2], TRUE); if (!client_entry) { - if (nickname) - silc_free(nickname); - if (server) - silc_free(server); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); /* Client entry not found, it was requested thus mark this to be pending command. */ @@ -662,10 +654,7 @@ SILC_CLIENT_CMD_FUNC(invite) COMMAND; out: - if (nickname) - silc_free(nickname); - if (server) - silc_free(server); + silc_free(nickname); silc_client_command_free(cmd); } @@ -715,10 +704,13 @@ 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_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock, - silc_client_command_quit_cb, (void *)q, - 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock, + silc_client_command_quit_cb, (void *)q, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); /* Notify application */ COMMAND; @@ -727,17 +719,67 @@ 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. */ SILC_CLIENT_CMD_FUNC(kill) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClient client = cmd->client; SilcClientConnection conn = cmd->conn; SilcBuffer buffer, idp; SilcClientEntry target; - uint32 num = 0; - char *nickname = NULL, *server = NULL; + char *nickname = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -753,26 +795,22 @@ SILC_CLIENT_CMD_FUNC(kill) } /* Parse the typed nickname. */ - if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Bad nickname"); - COMMAND_ERROR; - goto out; - } + 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, - server, num, TRUE); + cmd->argv[1], TRUE); if (!target) { - silc_free(nickname); - if (server) - silc_free(server); - 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, @@ -787,10 +825,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])); @@ -802,11 +842,14 @@ 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: - if (nickname) - silc_free(nickname); - if (server) - silc_free(server); + silc_free(nickname); silc_client_command_free(cmd); } @@ -926,8 +969,11 @@ 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); @@ -1332,6 +1378,7 @@ SILC_CLIENT_CMD_FUNC(cmode) SILC_CLIENT_CMD_FUNC(cumode) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClient client = cmd->client; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; SilcChannelUser chu; @@ -1339,8 +1386,7 @@ SILC_CLIENT_CMD_FUNC(cumode) SilcBuffer buffer, clidp, chidp, auth = NULL; unsigned char *name, *cp, modebuf[4]; uint32 mode = 0, add, len; - char *nickname = NULL, *server = NULL; - uint32 num = 0; + char *nickname = NULL; int i; if (!cmd->conn) { @@ -1378,21 +1424,22 @@ SILC_CLIENT_CMD_FUNC(cumode) } /* Parse the typed nickname. */ - if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname"); - COMMAND_ERROR; - goto out; - } + if (client->params->nickname_parse) + client->params->nickname_parse(cmd->argv[3], &nickname); + else + nickname = strdup(cmd->argv[3]); /* Find client entry */ - client_entry = silc_idlist_get_client(cmd->client, conn, - nickname, server, num, TRUE); + client_entry = silc_idlist_get_client(cmd->client, conn, nickname, + cmd->argv[3], TRUE); if (!client_entry) { 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, @@ -1405,6 +1452,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; @@ -1469,7 +1517,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, @@ -1488,10 +1537,7 @@ SILC_CLIENT_CMD_FUNC(cumode) COMMAND; out: - if (nickname) - silc_free(nickname); - if (server) - silc_free(server); + silc_free(nickname); silc_client_command_free(cmd); } @@ -1500,14 +1546,14 @@ SILC_CLIENT_CMD_FUNC(cumode) SILC_CLIENT_CMD_FUNC(kick) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClient client = cmd->client; SilcClientConnection conn = cmd->conn; SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; SilcBuffer buffer, idp, idp2; SilcClientEntry target; char *name; - uint32 num = 0; - char *nickname = NULL, *server = NULL; + char *nickname = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -1552,16 +1598,14 @@ SILC_CLIENT_CMD_FUNC(kick) channel = (SilcChannelEntry)id_cache->context; /* Parse the typed nickname. */ - if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Bad nickname"); - COMMAND_ERROR; - goto out; - } + if (client->params->nickname_parse) + client->params->nickname_parse(cmd->argv[2], &nickname); + else + nickname = strdup(cmd->argv[2]); /* Get the target client */ target = silc_idlist_get_client(cmd->client, conn, nickname, - server, num, FALSE); + cmd->argv[2], FALSE); if (!target) { cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s", @@ -1593,10 +1637,7 @@ SILC_CLIENT_CMD_FUNC(kick) COMMAND; out: - if (nickname) - silc_free(nickname); - if (server) - silc_free(server); + silc_free(nickname); silc_client_command_free(cmd); } @@ -1607,11 +1648,15 @@ static void silc_client_command_oper_send(unsigned char *data, SilcClientConnection conn = cmd->conn; SilcBuffer buffer, auth; - if (cmd->argc == 3) { - /* Pulic key auth XXX TODO */ - auth = NULL; + if (cmd->argc >= 3) { + /* Encode the public key authentication payload */ + auth = silc_auth_public_key_auth_generate(cmd->client->public_key, + cmd->client->private_key, + conn->hash, + conn->local_id, + SILC_ID_CLIENT); } else { - /* Encode the authentication payload */ + /* Encode the password authentication payload */ auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0, data, data_len); } @@ -1636,8 +1681,6 @@ SILC_CLIENT_CMD_FUNC(oper) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - unsigned char *auth_data; - uint32 auth_data_len = 0; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -1647,17 +1690,12 @@ SILC_CLIENT_CMD_FUNC(oper) if (cmd->argc < 2) { cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Usage: /OPER []"); + "Usage: /OPER [-pubkey]"); COMMAND_ERROR; goto out; } - if (cmd->argc == 3) { - /* XXX Get public key */ - auth_data = NULL; - COMMAND_ERROR; - goto out; - } else { + if (cmd->argc < 3) { /* Get passphrase */ cmd->client->ops->ask_passphrase(cmd->client, conn, silc_client_command_oper_send, @@ -1665,13 +1703,7 @@ SILC_CLIENT_CMD_FUNC(oper) return; } - silc_client_command_oper_send(auth_data, auth_data_len, context); - - memset(auth_data, 0, auth_data_len); - silc_free(auth_data); - - /* Notify application */ - COMMAND; + silc_client_command_oper_send(NULL, 0, context); out: silc_client_command_free(cmd); @@ -1684,11 +1716,15 @@ static void silc_client_command_silcoper_send(unsigned char *data, SilcClientConnection conn = cmd->conn; SilcBuffer buffer, auth; - if (cmd->argc == 3) { - /* Pulic key auth XXX TODO */ - auth = NULL; + if (cmd->argc >= 3) { + /* Encode the public key authentication payload */ + auth = silc_auth_public_key_auth_generate(cmd->client->public_key, + cmd->client->private_key, + conn->hash, + conn->local_id, + SILC_ID_CLIENT); } else { - /* Encode the authentication payload */ + /* Encode the password authentication payload */ auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0, data, data_len); } @@ -1713,8 +1749,6 @@ SILC_CLIENT_CMD_FUNC(silcoper) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - unsigned char *auth_data; - uint32 auth_data_len = 0; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -1724,17 +1758,12 @@ SILC_CLIENT_CMD_FUNC(silcoper) if (cmd->argc < 2) { cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Usage: /SILCOPER []"); + "Usage: /SILCOPER [-pubkey]"); COMMAND_ERROR; goto out; } - if (cmd->argc == 3) { - /* XXX Get public key */ - auth_data = NULL; - COMMAND_ERROR; - goto out; - } else { + if (cmd->argc < 3) { /* Get passphrase */ cmd->client->ops->ask_passphrase(cmd->client, conn, silc_client_command_silcoper_send, @@ -1742,13 +1771,7 @@ SILC_CLIENT_CMD_FUNC(silcoper) return; } - silc_client_command_silcoper_send(auth_data, auth_data_len, context); - - memset(auth_data, 0, auth_data_len); - silc_free(auth_data); - - /* Notify application */ - COMMAND; + silc_client_command_silcoper_send(NULL, 0, context); out: silc_client_command_free(cmd); @@ -1997,6 +2020,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); @@ -2013,12 +2037,7 @@ SILC_CLIENT_CMD_FUNC(leave) if (conn->current_channel == channel) conn->current_channel = NULL; - silc_idcache_del_by_id(conn->channel_cache, channel->id); - silc_free(channel->channel_name); - silc_free(channel->id); - silc_free(channel->key); - silc_cipher_free(channel->channel_key); - silc_free(channel); + silc_client_del_channel(cmd->client, cmd->conn, channel); out: silc_client_command_free(cmd); @@ -2084,8 +2103,7 @@ SILC_CLIENT_CMD_FUNC(getkey) SilcClient client = cmd->client; SilcClientEntry client_entry = NULL; SilcServerEntry server_entry = NULL; - uint32 num = 0; - char *nickname = NULL, *server = NULL; + char *nickname = NULL; SilcBuffer idp, buffer; if (!cmd->conn) { @@ -2101,44 +2119,60 @@ SILC_CLIENT_CMD_FUNC(getkey) goto out; } - /* Parse the typed nickname. */ - if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) { - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname"); - COMMAND_ERROR; - 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); + else + nickname = strdup(cmd->argv[1]); + /* Find client entry */ - client_entry = silc_idlist_get_client(client, conn, nickname, server, num, + client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1], FALSE); if (!client_entry) { /* Check whether user requested server actually */ - server_entry = silc_client_get_server(client, conn, nickname); + server_entry = silc_client_get_server(client, conn, cmd->argv[1]); - if (!server_entry) { + if (!server_entry && !cmd->pending) { /* 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. */ /* This will send the IDENTIFY command */ - silc_idlist_get_client(client, conn, nickname, server, num, TRUE); + silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE); silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, silc_client_command_destructor, 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, nickname, strlen(nickname)); + 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)); cmd->pending = 1; + silc_free(nickname); return; } @@ -2158,5 +2192,6 @@ SILC_CLIENT_CMD_FUNC(getkey) COMMAND; out: + silc_free(nickname); silc_client_command_free(cmd); }