X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand.c;h=85e33fe38217f0fe7b17c6c70a97270b1d3e2aca;hb=52e57c880aba9c5e89f59d962eb9af75670b76e0;hp=ce4a03ea546aba268238bb4abc05c13b12b2243c;hpb=3df964f52d094db8ea9e8981fee73ff2a59e365c;p=silc.git diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index ce4a03ea..85e33fe3 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -119,13 +119,36 @@ static void silc_client_command_resolve_continue(SilcClient client, if (status != SILC_STATUS_OK) silc_fsm_next(&cmd->thread, silc_client_command_continue_error); - if (clients) - silc_dlist_uninit(clients); - /* Continue with the command */ SILC_FSM_CALL_CONTINUE(&cmd->thread); } +/* Dummy command callback. Nothing interesting to do here. Use this when + you just send command but don't care about reply. */ + +SilcBool silc_client_command_called_dummy(SilcClient client, + SilcClientConnection conn, + SilcCommand command, + SilcStatus status, + SilcStatus error, + void *context, + va_list ap) +{ + return FALSE; +} + +/* Dummy resolving callback. Nothing interesting to do here. Use this + when you just resolve entires but don't care about reply. */ + +void silc_client_command_resolve_dummy(SilcClient client, + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) +{ + /* Nothing */ +} + /* Register command to client */ static SilcBool @@ -139,11 +162,17 @@ silc_client_command_register(SilcClient client, SilcClientCommand cmd; cmd = silc_calloc(1, sizeof(*cmd)); + if (!cmd) + return FALSE; cmd->cmd = command; cmd->command = command_func; cmd->reply = command_reply_func; - cmd->name = name ? strdup(name) : NULL; cmd->max_args = max_args; + cmd->name = name ? strdup(name) : NULL; + if (!cmd->name) { + silc_free(cmd); + return FALSE; + } silc_list_add(client->internal->commands, cmd); @@ -191,27 +220,20 @@ static SilcClientCommand silc_client_command_find(SilcClient client, return NULL; } -/* Free command context and its internals */ - -static void silc_client_command_free(SilcClientCommandContext cmd) -{ - int i; - - for (i = 0; i < cmd->argc; i++) - silc_free(cmd->argv[i]); - silc_free(cmd->argv); - silc_free(cmd->argv_lens); - silc_free(cmd->argv_types); - silc_free(cmd); -} - /* Command thread destructor */ static void silc_client_command_destructor(SilcFSMThread thread, void *fsm_context, void *destructor_context) { - silc_client_command_free(fsm_context); + SilcClientCommandContext cmd = fsm_context; + SilcClientConnection conn = cmd->conn; + + /* Removes commands that aren't waiting for reply but are waiting + for something. They may not have been removed yet. */ + silc_list_del(conn->internal->pending_commands, cmd); + + silc_client_command_free(cmd); } /* Add a command pending a command reply. Used internally by the library. */ @@ -262,6 +284,9 @@ static SilcUInt16 silc_client_command_send_vap(SilcClient client, SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command))); + if (conn->internal->disconnected) + return 0; + if (!cmd->cmd_ident) cmd->cmd_ident = silc_client_cmd_ident(conn); @@ -305,6 +330,9 @@ silc_client_command_send_arg_array(SilcClient client, SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command))); + if (conn->internal->disconnected) + return 0; + if (!cmd->cmd_ident) cmd->cmd_ident = silc_client_cmd_ident(conn); @@ -353,6 +381,26 @@ static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn, /****************************** Command API *********************************/ +/* Free command context and its internals */ + +void silc_client_command_free(SilcClientCommandContext cmd) +{ + SilcClientCommandReplyCallback cb; + int i; + + for (i = 0; i < cmd->argc; i++) + silc_free(cmd->argv[i]); + silc_free(cmd->argv); + silc_free(cmd->argv_lens); + silc_free(cmd->argv_types); + + silc_list_start(cmd->reply_callbacks); + while ((cb = silc_list_get(cmd->reply_callbacks))) + silc_free(cb); + + silc_free(cmd); +} + /* Executes a command */ SilcUInt16 silc_client_command_call(SilcClient client, @@ -368,7 +416,7 @@ SilcUInt16 silc_client_command_call(SilcClient client, char *arg; if (!conn) { - client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR, + client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "You are not connected to a server, please connect to server"); return 0; } @@ -410,10 +458,10 @@ SilcUInt16 silc_client_command_call(SilcClient client, argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1)); argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1)); if (!argv || !argv_lens || !argv_types) - return FALSE; + return 0; argv[argc] = silc_memdup(arg, strlen(arg)); if (!argv[argc]) - return FALSE; + return 0; argv_lens[argc] = strlen(arg); argv_types[argc] = argc; argc++; @@ -435,6 +483,8 @@ SilcUInt16 silc_client_command_call(SilcClient client, cmd->cmd_ident = silc_client_cmd_ident(conn); cmd->called = TRUE; cmd->verbose = TRUE; + silc_list_init(cmd->reply_callbacks, + struct SilcClientCommandReplyCallbackStruct, next); /*** Call command */ SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd))); @@ -467,6 +517,8 @@ SilcUInt16 silc_client_command_send(SilcClient client, return 0; cmd->conn = conn; cmd->cmd = command; + silc_list_init(cmd->reply_callbacks, + struct SilcClientCommandReplyCallbackStruct, next); /* Send the command */ va_start(ap, argc); @@ -567,7 +619,7 @@ SilcBool silc_client_command_pending(SilcClientConnection conn, silc_mutex_unlock(conn->internal->lock); - return FALSE; + return TRUE; } /******************************** WHOIS *************************************/ @@ -584,22 +636,29 @@ SILC_FSM_STATE(silc_client_command_whois) unsigned char count[4], *tmp = NULL; SilcBool details = FALSE, nick = FALSE; unsigned char *pubkey = NULL; + char *nickname = NULL; int i; /* Given without arguments fetches client's own information */ if (cmd->argc < 2) { - silc_client_command_send(conn->client, conn, SILC_COMMAND_WHOIS, - NULL, NULL, 1, - 4, silc_buffer_datalen(conn->local_idp)); - goto out; + silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4, + silc_buffer_data(conn->internal->local_idp), + silc_buffer_len(conn->internal->local_idp)); + + /* Notify application */ + COMMAND(SILC_STATUS_OK); + + /** Wait for command reply */ + silc_fsm_next(fsm, silc_client_command_reply_wait); + return SILC_FSM_CONTINUE; } for (i = 1; i < cmd->argc; i++) { if (!strcasecmp(cmd->argv[i], "-details")) { - details = TRUE; + details = TRUE; } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) { - pubkey = cmd->argv[i + 1]; - i++; + pubkey = cmd->argv[i + 1]; + i++; } else { /* We assume that the first parameter is the nickname, if it isn't -details or -pubkey. The last parameter should always be the count */ @@ -638,7 +697,7 @@ SILC_FSM_STATE(silc_client_command_whois) SilcPublicKey pk; if (!silc_pkcs_load_public_key(pubkey, &pk)) { - SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "Could not load public key %s, check the filename", pubkey); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); @@ -668,14 +727,22 @@ SILC_FSM_STATE(silc_client_command_whois) SILC_ATTRIBUTE_USER_PUBLIC_KEY, SILC_ATTRIBUTE_FLAG_VALID, &obj, sizeof(obj)); + silc_free(obj.data); + } + + if (nick) { + silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname); + if (!nickname) + nickname = strdup(cmd->argv[1]); } /* Send command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, - 3, 1, nick ? cmd->argv[1] : NULL, - nick ? cmd->argv_lens[1] : 0, + 3, 1, nick ? nickname : NULL, + nick ? strlen(nickname) : 0, 2, tmp ? tmp : NULL, tmp ? 4 : 0, 3, silc_buffer_datalen(attrs)); + silc_free(nickname); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -765,7 +832,7 @@ SILC_FSM_STATE(silc_client_command_identify) SILC_FSM_STATE(silc_client_command_nick) { - SilcClientCommandContext cmd = fsm_context; + SilcClientCommandContext cmd2, cmd = fsm_context; SilcClientConnection conn = cmd->conn; if (cmd->argc < 2) { @@ -793,6 +860,19 @@ SILC_FSM_STATE(silc_client_command_nick) goto out; } + /* If JOIN command is active, wait for it to finish before sending NICK. + To avoid problems locally with changing IDs while joining, we do this. */ + silc_mutex_lock(conn->internal->lock); + silc_list_start(conn->internal->pending_commands); + while ((cmd2 = silc_list_get(conn->internal->pending_commands))) { + if (cmd2->cmd == SILC_COMMAND_JOIN) { + silc_mutex_unlock(conn->internal->lock); + silc_fsm_next_later(fsm, silc_client_command_nick, 0, 300000); + return SILC_FSM_WAIT; + } + } + silc_mutex_unlock(conn->internal->lock); + if (cmd->argv_lens[1] > 128) cmd->argv_lens[1] = 128; @@ -819,14 +899,15 @@ SILC_FSM_STATE(silc_client_command_list) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - SilcChannelEntry channel; + SilcClient client = conn->client; + SilcChannelEntry channel = NULL; SilcBuffer idp = NULL; if (cmd->argc == 2) { /* Get the Channel ID of the channel */ channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]); if (channel) - idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); } if (!idp) @@ -836,6 +917,7 @@ SILC_FSM_STATE(silc_client_command_list) 1, 1, silc_buffer_datalen(idp)); silc_buffer_free(idp); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -853,9 +935,10 @@ SILC_FSM_STATE(silc_client_command_topic) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; + SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer idp; - char *name; + char *name, tmp[512]; if (cmd->argc < 2 || cmd->argc > 3) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -870,7 +953,15 @@ SILC_FSM_STATE(silc_client_command_topic) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -887,7 +978,7 @@ SILC_FSM_STATE(silc_client_command_topic) goto out; } - idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); /* Send TOPIC command to the server */ if (cmd->argc > 2) @@ -899,6 +990,7 @@ SILC_FSM_STATE(silc_client_command_topic) 1, silc_buffer_datalen(idp)); silc_buffer_free(idp); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -922,10 +1014,10 @@ SILC_FSM_STATE(silc_client_command_invite) SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; SilcClientEntry client_entry = NULL; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcBuffer clidp, chidp, args = NULL; SilcPublicKey pubkey = NULL; - SilcDList clients; + SilcDList clients = NULL; char *nickname = NULL, *name; char *invite = NULL; unsigned char action[1]; @@ -945,6 +1037,7 @@ SILC_FSM_STATE(silc_client_command_invite) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -958,24 +1051,19 @@ SILC_FSM_STATE(silc_client_command_invite) /* Parse the typed nickname. */ if (cmd->argc == 3) { if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') { - if (client->internal->params->nickname_parse) - client->internal->params->nickname_parse(cmd->argv[2], &nickname); - else - nickname = strdup(cmd->argv[2]); + silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname); /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[2]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[2], + FALSE); if (!clients) /* Resolve client information */ SILC_FSM_CALL(silc_client_get_clients( - client, conn, nickname, - cmd->argv[2], + client, conn, nickname, NULL, silc_client_command_resolve_continue, cmd)); client_entry = silc_dlist_get(clients); - silc_dlist_uninit(clients); } else { if (cmd->argv[2][0] == '+') action[0] = 0x00; @@ -1007,7 +1095,7 @@ SILC_FSM_STATE(silc_client_command_invite) } /* Send the command */ - chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); if (client_entry) { clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT); silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4, @@ -1026,6 +1114,8 @@ SILC_FSM_STATE(silc_client_command_invite) silc_buffer_free(chidp); silc_buffer_free(args); silc_free(nickname); + silc_client_list_free(client, conn, clients); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1047,15 +1137,18 @@ SILC_FSM_STATE(silc_client_command_quit_final) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - SilcClient client = conn->client; + + SILC_LOG_DEBUG(("Quitting")); /* Notify application */ COMMAND(SILC_STATUS_OK); - /* Close connection */ - conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, - conn->context); - // silc_client_close_connection(q->client, q->conn->sock->user_data); + /* Signal to close connection */ + conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED; + if (!conn->internal->disconnected) { + conn->internal->disconnected = TRUE; + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); + } return SILC_FSM_FINISH; } @@ -1083,7 +1176,6 @@ SILC_FSM_STATE(silc_client_command_quit) /********************************** KILL ************************************/ - /* Command KILL. Router operator can use this command to remove an client fromthe SILC Network. */ @@ -1105,25 +1197,18 @@ SILC_FSM_STATE(silc_client_command_kill) } /* Parse the typed nickname. */ - if (client->internal->params->nickname_parse) - client->internal->params->nickname_parse(cmd->argv[1], &nickname); - else - nickname = strdup(cmd->argv[1]); - if (!nickname) + if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) return SILC_FSM_FINISH; /* Get the target client */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[1]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE); if (!clients) /* Resolve client information */ - SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, - cmd->argv[1], + SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL, silc_client_command_resolve_continue, cmd)); target = silc_dlist_get(clients); - silc_dlist_uninit(clients); if (cmd->argc >= 3) { if (strcasecmp(cmd->argv[2], "-pubkey")) @@ -1135,7 +1220,7 @@ SILC_FSM_STATE(silc_client_command_kill) auth = silc_auth_public_key_auth_generate(conn->public_key, conn->private_key, conn->client->rng, - client->sha1hash, + conn->internal->sha1hash, &target->id, SILC_ID_CLIENT); } } @@ -1149,6 +1234,7 @@ SILC_FSM_STATE(silc_client_command_kill) silc_buffer_free(idp); silc_buffer_free(auth); silc_free(nickname); + silc_client_list_free(client, conn, clients); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1192,14 +1278,10 @@ SILC_FSM_STATE(silc_client_command_stats) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - if (cmd->argc < 2) { - COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); - return SILC_FSM_FINISH; - } - /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, - 1, silc_buffer_datalen(conn->remote_idp)); + 1, silc_buffer_datalen(conn->internal-> + remote_idp)); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1225,7 +1307,8 @@ SILC_FSM_STATE(silc_client_command_ping) /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, - 1, silc_buffer_datalen(conn->remote_idp)); + 1, silc_buffer_datalen(conn->internal-> + remote_idp)); /* Save ping time */ cmd->context = SILC_64_TO_PTR(silc_time()); @@ -1244,9 +1327,10 @@ SILC_FSM_STATE(silc_client_command_ping) SILC_FSM_STATE(silc_client_command_join) { - SilcClientCommandContext cmd = fsm_context; + SilcClientCommandContext cmd2, cmd = fsm_context; SilcClientConnection conn = cmd->conn; - SilcChannelEntry channel; + SilcClient client = conn->client; + SilcChannelEntry channel = NULL; SilcBuffer auth = NULL, cauth = NULL; char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL; int i, passphrase_len = 0; @@ -1261,6 +1345,19 @@ SILC_FSM_STATE(silc_client_command_join) if (channel && silc_client_on_channel(channel, conn->local_entry)) goto out; + /* If NICK command is active, wait for it to finish before sending JOIN. + To avoid problems locally with changing IDs while joining, we do this. */ + silc_mutex_lock(conn->internal->lock); + silc_list_start(conn->internal->pending_commands); + while ((cmd2 = silc_list_get(conn->internal->pending_commands))) { + if (cmd2->cmd == SILC_COMMAND_NICK) { + silc_mutex_unlock(conn->internal->lock); + silc_fsm_next_later(fsm, silc_client_command_join, 0, 300000); + return SILC_FSM_WAIT; + } + } + silc_mutex_unlock(conn->internal->lock); + if (cmd->argv_lens[1] > 256) cmd->argv_lens[1] = 256; @@ -1275,7 +1372,7 @@ SILC_FSM_STATE(silc_client_command_join) auth = silc_auth_public_key_auth_generate(conn->public_key, conn->private_key, conn->client->rng, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); } else if (!strcasecmp(cmd->argv[i], "-auth")) { @@ -1292,7 +1389,7 @@ SILC_FSM_STATE(silc_client_command_join) } if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass, &pubkey, &privkey)) { - SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "Could not load key pair, check your arguments"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1301,13 +1398,13 @@ SILC_FSM_STATE(silc_client_command_join) } pk = silc_pkcs_public_key_encode(pubkey, &pk_len); - silc_hash_make(conn->client->sha1hash, pk, pk_len, pkhash); + silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash); silc_free(pk); pubdata = silc_rng_get_rn_data(conn->client->rng, 128); memcpy(pubdata, pkhash, 20); cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey, pubdata, 128, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); memset(pubdata, 0, 128); @@ -1331,7 +1428,8 @@ SILC_FSM_STATE(silc_client_command_join) /* Send JOIN command to the server */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7, 1, name, strlen(name), - 2, silc_buffer_datalen(conn->local_idp), + 2, silc_buffer_datalen(conn->internal-> + local_idp), 3, passphrase, passphrase_len, 4, cipher, cipher ? strlen(cipher) : 0, 5, hmac, hmac ? strlen(hmac) : 0, @@ -1343,6 +1441,7 @@ SILC_FSM_STATE(silc_client_command_join) if (passphrase) memset(passphrase, 0, strlen(passphrase)); silc_free(passphrase); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1352,6 +1451,7 @@ SILC_FSM_STATE(silc_client_command_join) return SILC_FSM_CONTINUE; out: + silc_client_unref_channel(client, conn, channel); return SILC_FSM_FINISH; } @@ -1516,7 +1616,8 @@ SILC_FSM_STATE(silc_client_command_umode) /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2, - 1, silc_buffer_datalen(conn->local_idp), + 1, silc_buffer_datalen(conn->internal-> + local_idp), 2, modebuf, sizeof(modebuf)); /* Notify application */ @@ -1538,7 +1639,7 @@ SILC_FSM_STATE(silc_client_command_cmode) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcBuffer chidp, auth = NULL, pk = NULL; unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL; SilcUInt32 mode, add, type, len, arg_len = 0; @@ -1558,6 +1659,7 @@ SILC_FSM_STATE(silc_client_command_cmode) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -1707,7 +1809,7 @@ SILC_FSM_STATE(silc_client_command_cmode) pass = cmd->argv[5]; if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass, &pubkey, &privkey)) { - SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "Could not load key pair, check your arguments"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1717,7 +1819,7 @@ SILC_FSM_STATE(silc_client_command_cmode) pk = silc_public_key_payload_encode(pubkey); auth = silc_auth_public_key_auth_generate(pubkey, privkey, conn->client->rng, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); arg = silc_buffer_data(auth); @@ -1737,15 +1839,19 @@ SILC_FSM_STATE(silc_client_command_cmode) if (cmd->argc == 3) { /* Send empty command to receive the public key list. */ - chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE, NULL, NULL, 1, 1, silc_buffer_datalen(chidp)); silc_buffer_free(chidp); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); - goto out; + + /** Wait for command reply */ + silc_fsm_next(fsm, silc_client_command_reply_wait); + return SILC_FSM_CONTINUE; } if (cmd->argc >= 4) { @@ -1759,7 +1865,7 @@ SILC_FSM_STATE(silc_client_command_cmode) if (cmd->argv[k][0] == '+') chadd = TRUE; if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) { - SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "Could not load public key %s, check the filename", cmd->argv[k]); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); @@ -1791,7 +1897,7 @@ SILC_FSM_STATE(silc_client_command_cmode) } } - chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); SILC_PUT32_MSB(mode, modebuf); /* Send the command. We support sending only one mode at once that @@ -1811,6 +1917,7 @@ SILC_FSM_STATE(silc_client_command_cmode) silc_buffer_free(chidp); silc_buffer_free(auth); silc_buffer_free(pk); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1820,6 +1927,7 @@ SILC_FSM_STATE(silc_client_command_cmode) return SILC_FSM_CONTINUE; out: + silc_client_unref_channel(client, conn, channel); return SILC_FSM_FINISH; } @@ -1832,11 +1940,11 @@ SILC_FSM_STATE(silc_client_command_cumode) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcChannelUser chu; SilcClientEntry client_entry; SilcBuffer clidp, chidp, auth = NULL; - SilcDList clients; + SilcDList clients = NULL; unsigned char *name, *cp, modebuf[4]; SilcUInt32 mode = 0, add, len; char *nickname = NULL; @@ -1856,6 +1964,7 @@ SILC_FSM_STATE(silc_client_command_cumode) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -1867,22 +1976,17 @@ SILC_FSM_STATE(silc_client_command_cumode) } /* Parse the typed nickname. */ - if (client->internal->params->nickname_parse) - client->internal->params->nickname_parse(cmd->argv[3], &nickname); - else - nickname = strdup(cmd->argv[3]); + silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname); /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[3]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[3], FALSE); if (!clients) /* Resolve client information */ - SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3], + SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL, silc_client_command_resolve_continue, cmd)); client_entry = silc_dlist_get(clients); - silc_dlist_uninit(clients); /* Get the current mode */ chu = silc_client_on_channel(channel, client_entry); @@ -1922,7 +2026,7 @@ SILC_FSM_STATE(silc_client_command_cumode) pass = cmd->argv[6]; if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass, &pubkey, &privkey)) { - SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "Could not load key pair, check your arguments"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -1931,7 +2035,7 @@ SILC_FSM_STATE(silc_client_command_cumode) auth = silc_auth_public_key_auth_generate(pubkey, privkey, conn->client->rng, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); mode |= SILC_CHANNEL_UMODE_CHANFO; @@ -1976,7 +2080,7 @@ SILC_FSM_STATE(silc_client_command_cumode) } } - chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); SILC_PUT32_MSB(mode, modebuf); clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT); @@ -1992,11 +2096,20 @@ SILC_FSM_STATE(silc_client_command_cumode) silc_buffer_free(clidp); if (auth) silc_buffer_free(auth); + silc_free(nickname); + silc_client_list_free(client, conn, clients); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); + /** Wait for command reply */ + silc_fsm_next(fsm, silc_client_command_reply_wait); + return SILC_FSM_CONTINUE; + out: + silc_client_unref_channel(client, conn, channel); + silc_client_list_free(client, conn, clients); silc_free(nickname); return SILC_FSM_FINISH; } @@ -2010,12 +2123,11 @@ SILC_FSM_STATE(silc_client_command_kick) SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; SilcClient client = conn->client; - SilcChannelEntry channel; + SilcChannelEntry channel = NULL; SilcBuffer idp, idp2; SilcClientEntry target; - SilcDList clients; - char *name; - char *nickname = NULL; + SilcDList clients = NULL; + char *name, tmp[512]; if (cmd->argc < 3) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2029,7 +2141,15 @@ SILC_FSM_STATE(silc_client_command_kick) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -2046,15 +2166,8 @@ SILC_FSM_STATE(silc_client_command_kick) goto out; } - /* Parse the typed nickname. */ - if (client->internal->params->nickname_parse) - client->internal->params->nickname_parse(cmd->argv[2], &nickname); - else - nickname = strdup(cmd->argv[2]); - /* Get the target client */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[2]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[2], FALSE); if (!clients) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s", cmd->argv[2]); @@ -2062,10 +2175,9 @@ SILC_FSM_STATE(silc_client_command_kick) goto out; } target = silc_dlist_get(clients); - silc_dlist_uninit(clients); /* Send KICK command to the server */ - idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT); if (cmd->argc == 3) silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2, @@ -2079,7 +2191,8 @@ SILC_FSM_STATE(silc_client_command_kick) silc_buffer_free(idp); silc_buffer_free(idp2); - silc_free(nickname); + silc_client_list_free(client, conn, clients); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2089,7 +2202,7 @@ SILC_FSM_STATE(silc_client_command_kick) return SILC_FSM_CONTINUE; out: - silc_free(nickname); + silc_client_unref_channel(client, conn, channel); return SILC_FSM_FINISH; } @@ -2102,7 +2215,7 @@ typedef struct { /* Ask passphrase callback */ -static void silc_client_command_oper_cb(unsigned char *data, +static void silc_client_command_oper_cb(const unsigned char *data, SilcUInt32 data_len, void *context) { SilcClientCommandContext cmd = context; @@ -2173,6 +2286,8 @@ SILC_FSM_STATE(silc_client_command_oper) return SILC_FSM_FINISH; } + silc_fsm_next(fsm, silc_client_command_oper_send); + /* Get passphrase */ if (cmd->argc < 3) { oper = silc_calloc(1, sizeof(*oper)); @@ -2184,7 +2299,6 @@ SILC_FSM_STATE(silc_client_command_oper) silc_client_command_oper_cb, cmd)); } - silc_fsm_next(fsm, silc_client_command_oper_send); return SILC_FSM_CONTINUE; } @@ -2203,6 +2317,8 @@ SILC_FSM_STATE(silc_client_command_silcoper) return SILC_FSM_FINISH; } + silc_fsm_next(fsm, silc_client_command_oper_send); + /* Get passphrase */ if (cmd->argc < 3) { oper = silc_calloc(1, sizeof(*oper)); @@ -2214,7 +2330,6 @@ SILC_FSM_STATE(silc_client_command_silcoper) silc_client_command_oper_cb, cmd)); } - silc_fsm_next(fsm, silc_client_command_oper_send); return SILC_FSM_CONTINUE; } @@ -2226,6 +2341,7 @@ SILC_FSM_STATE(silc_client_command_ban) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; + SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer chidp, args = NULL; char *name, *ban = NULL; @@ -2247,6 +2363,7 @@ SILC_FSM_STATE(silc_client_command_ban) } channel = conn->current_channel; + silc_client_ref_channel(client, conn, channel); } else { name = cmd->argv[1]; @@ -2286,7 +2403,7 @@ SILC_FSM_STATE(silc_client_command_ban) } } - chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3, @@ -2296,6 +2413,7 @@ SILC_FSM_STATE(silc_client_command_ban) silc_buffer_free(chidp); silc_buffer_free(args); + silc_client_unref_channel(client, conn, channel); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2364,7 +2482,7 @@ SILC_FSM_STATE(silc_client_command_watch) SilcBuffer buffer; if (!silc_pkcs_load_public_key(pubkey, &pk)) { - SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, "Could not load public key %s, check the filename", pubkey); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -2381,9 +2499,16 @@ SILC_FSM_STATE(silc_client_command_watch) silc_pkcs_public_key_free(pk); } + /* If watching by nickname, resolve all users with that nickname so that + we get their information immediately. */ + if (type == 2) + silc_client_get_clients(conn->client, conn, cmd->argv[2], NULL, + silc_client_command_resolve_dummy, NULL); + /* Send the commmand */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2, - 1, silc_buffer_datalen(conn->local_idp), + 1, silc_buffer_datalen(conn->internal-> + local_idp), type, pubkey ? args->data : cmd->argv[2], pubkey ? silc_buffer_len(args) : cmd->argv_lens[2]); @@ -2409,9 +2534,10 @@ SILC_FSM_STATE(silc_client_command_leave) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; + SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer idp; - char *name; + char *name, tmp[512]; if (cmd->argc != 2) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2425,7 +2551,15 @@ SILC_FSM_STATE(silc_client_command_leave) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -2437,7 +2571,7 @@ SILC_FSM_STATE(silc_client_command_leave) goto out; } - idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL); /* Send LEAVE command to the server */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, @@ -2451,6 +2585,8 @@ SILC_FSM_STATE(silc_client_command_leave) if (conn->current_channel == channel) conn->current_channel = NULL; + silc_client_unref_channel(client, conn, channel); + /** Wait for command reply */ silc_fsm_next(fsm, silc_client_command_reply_wait); return SILC_FSM_CONTINUE; @@ -2468,7 +2604,7 @@ SILC_FSM_STATE(silc_client_command_users) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - char *name; + char *name, tmp[512]; if (cmd->argc != 2) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2482,7 +2618,15 @@ SILC_FSM_STATE(silc_client_command_users) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (conn->client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -2514,7 +2658,6 @@ SILC_FSM_STATE(silc_client_command_getkey) SilcClientEntry client_entry; SilcServerEntry server_entry; SilcDList clients; - char *nickname = NULL; SilcBuffer idp; if (cmd->argc < 2) { @@ -2524,22 +2667,22 @@ SILC_FSM_STATE(silc_client_command_getkey) return SILC_FSM_FINISH; } - /* Parse the typed nickname. */ - if (client->internal->params->nickname_parse) - client->internal->params->nickname_parse(cmd->argv[1], &nickname); - else - nickname = strdup(cmd->argv[1]); - if (!nickname) - return SILC_FSM_FINISH; - /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[1]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE); if (!clients) { /* Check whether user requested server */ server_entry = silc_client_get_server(client, conn, cmd->argv[1]); if (!server_entry) { + if (cmd->resolved) { + /* Resolving didn't find anything. We should never get here as + errors are handled in the resolving callback. */ + COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK); + COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER); + return SILC_FSM_FINISH; + } + /* No client or server exist with this name, query for both. */ + cmd->resolved = TRUE; SILC_FSM_CALL(silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, silc_client_command_continue, @@ -2548,12 +2691,14 @@ SILC_FSM_STATE(silc_client_command_getkey) strlen(cmd->argv[1]), 2, cmd->argv[1], strlen(cmd->argv[1]))); + /* NOT REACHED */ } - idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER); + idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER); + silc_client_unref_server(client, conn, server_entry); } else { client_entry = silc_dlist_get(clients); idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT); - silc_dlist_uninit(clients); + silc_client_list_free(client, conn, clients); } /* Send the commmand */ @@ -2561,7 +2706,6 @@ SILC_FSM_STATE(silc_client_command_getkey) 1, silc_buffer_datalen(idp)); silc_buffer_free(idp); - silc_free(nickname); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -2690,7 +2834,6 @@ static void silc_client_command_process_whois(SilcClient client, SilcCommandPayload payload, SilcArgumentPayload args) { -#if 0 SilcDList attrs; unsigned char *tmp; SilcUInt32 tmp_len; @@ -2714,18 +2857,25 @@ static void silc_client_command_process_whois(SilcClient client, return; } - /* Send the attributes back */ + /* Send the attributes back in COMMAND_REPLY packet */ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, SILC_STATUS_OK, 0, silc_command_get_ident(payload), - 1, 11, buffer->data, buffer->len); - silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY, - NULL, 0, NULL, NULL, packet->data, - packet->len, TRUE); + 1, 11, buffer->data, + silc_buffer_len(buffer)); + if (!packet) { + silc_buffer_free(buffer); + return; + } + + SILC_LOG_DEBUG(("Sending back requested WHOIS attributes")); + + silc_packet_send(conn->stream, SILC_PACKET_COMMAND_REPLY, 0, + silc_buffer_datalen(packet)); + silc_buffer_free(packet); silc_buffer_free(buffer); -#endif /* 0 */ } /* Client is able to receive some command packets even though they are @@ -2748,10 +2898,8 @@ SILC_FSM_STATE(silc_client_command) payload = silc_command_payload_parse(packet->buffer.data, silc_buffer_len(&packet->buffer)); if (!payload) { - /** Bad command payload */ SILC_LOG_DEBUG(("Bad command packet")); - silc_fsm_next(fsm, silc_client_connection_st_packet); - return SILC_FSM_CONTINUE; + return SILC_FSM_FINISH; } /* Get arguments */ @@ -2763,7 +2911,7 @@ SILC_FSM_STATE(silc_client_command) case SILC_COMMAND_WHOIS: /* Ignore everything if requested by application */ - if (client->internal->params->ignore_requested_attributes) + if (conn->internal->params.ignore_requested_attributes) break; silc_client_command_process_whois(client, conn, payload, args); @@ -2774,8 +2922,5 @@ SILC_FSM_STATE(silc_client_command) } silc_command_payload_free(payload); - - /** Packet processed */ - silc_fsm_next(fsm, silc_client_connection_st_packet); - return SILC_FSM_CONTINUE; + return SILC_FSM_FINISH; }