5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
23 * Revision 1.5 2000/07/05 06:12:05 priikone
24 * Global cosmetic changes.
26 * Revision 1.4 2000/07/04 08:28:03 priikone
27 * Added INVITE, PING and NAMES command.
29 * Revision 1.3 2000/07/03 05:49:49 priikone
30 * Implemented LEAVE command. Minor bug fixes.
32 * Revision 1.2 2000/06/27 19:38:40 priikone
33 * Added missing goto flag.
35 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
36 * Imported from internal CVS/Added Log headers.
41 #include "clientincludes.h"
43 /* Client command list. */
44 SilcClientCommand silc_command_list[] =
46 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
47 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
48 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
49 SILC_CF_LAG | SILC_CF_REG, 3),
50 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
51 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
52 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
53 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
54 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
55 SILC_CLIENT_CMD(kill, KILL, "KILL",
56 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
57 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
58 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
59 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
60 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
61 SILC_CLIENT_CMD(oper, OPER, "OPER",
62 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
63 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
64 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
65 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
66 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
67 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
68 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
69 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
70 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
71 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
72 SILC_CLIENT_CMD(die, DIE, "DIE",
73 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
74 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
75 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
76 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
77 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
80 * Local. client specific commands
82 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
83 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
84 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
85 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
86 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
87 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
92 #define SILC_NOT_CONNECTED(x) \
93 silc_say((x), "You are not connected to a server, use /SERVER to connect");
95 /* List of pending commands. */
96 SilcClientCommandPending *silc_command_pending = NULL;
98 /* Add new pending command to the list of pending commands. Currently
99 pending commands are executed from command replies, thus we can
100 execute any command after receiving some specific command reply.
102 The argument `reply_cmd' is the command reply from where the callback
103 function is to be called, thus, it IS NOT the command to be executed.
105 XXX: If needed in the future this support may be extended for
106 commands as well, when any command could be executed after executing
107 some specific command. */
109 void silc_client_command_pending(SilcCommand reply_cmd,
110 SilcClientCommandCallback callback,
113 SilcClientCommandPending *reply, *r;
115 reply = silc_calloc(1, sizeof(*reply));
116 reply->reply_cmd = reply_cmd;
117 reply->context = context;
118 reply->callback = callback;
120 if (silc_command_pending == NULL) {
121 silc_command_pending = reply;
125 for (r = silc_command_pending; r; r = r->next) {
126 if (r->next == NULL) {
133 /* Deletes pending command by reply command type. */
135 void silc_client_command_pending_del(SilcCommand reply_cmd)
137 SilcClientCommandPending *r, *tmp;
139 if (silc_command_pending) {
140 if (silc_command_pending->reply_cmd == reply_cmd) {
141 silc_free(silc_command_pending);
142 silc_command_pending = NULL;
146 for (r = silc_command_pending; r; r = r->next) {
147 if (r->next && r->next->reply_cmd == reply_cmd) {
149 r->next = r->next->next;
157 /* Free command context and its internals */
159 static void silc_client_command_free(SilcClientCommandContext cmd)
164 for (i = 0; i < cmd->argc; i++)
165 silc_free(cmd->argv[i]);
170 /* Command WHOIS. This command is used to query information about
173 SILC_CLIENT_CMD_FUNC(whois)
175 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
178 if (cmd->argc < 2 || cmd->argc > 3) {
179 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
183 if (!cmd->client->current_win->sock) {
184 SILC_NOT_CONNECTED(cmd->client);
188 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
189 cmd->argc - 1, ++cmd->argv,
190 ++cmd->argv_lens, ++cmd->argv_types);
191 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
192 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
193 buffer->data, buffer->len, TRUE);
194 silc_buffer_free(buffer);
200 silc_client_command_free(cmd);
203 SILC_CLIENT_CMD_FUNC(whowas)
207 /* Command IDENTIFY. This command is used to query information about
208 specific user, especially ID's. */
210 SILC_CLIENT_CMD_FUNC(identify)
212 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
215 if (cmd->argc < 2 || cmd->argc > 3) {
216 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
220 if (!cmd->client->current_win->sock) {
221 SILC_NOT_CONNECTED(cmd->client);
225 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
226 cmd->argc - 1, ++cmd->argv,
227 ++cmd->argv_lens, ++cmd->argv_types);
228 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
229 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
230 buffer->data, buffer->len, TRUE);
231 silc_buffer_free(buffer);
237 silc_client_command_free(cmd);
240 /* Command NICK. Shows current nickname/sets new nickname on current
243 SILC_CLIENT_CMD_FUNC(nick)
245 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
246 SilcClientWindow win = NULL;
250 SILC_NOT_CONNECTED(cmd->client);
254 /* Show current nickname */
257 silc_say(cmd->client, "Your nickname is %s on server %s",
258 win->nickname, win->remote_host);
260 silc_say(cmd->client, "Your nickname is %s", win->nickname);
265 win = (SilcClientWindow)cmd->sock->user_data;
267 /* Set new nickname */
268 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
269 cmd->argc - 1, ++cmd->argv,
270 ++cmd->argv_lens, ++cmd->argv_types);
271 silc_client_packet_send(cmd->client, cmd->sock,
272 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
273 buffer->data, buffer->len, TRUE);
274 silc_buffer_free(buffer);
279 silc_free(win->nickname);
280 win->nickname = strdup(cmd->argv[1]);
283 silc_client_command_free(cmd);
286 /* Command SERVER. Connects to remote SILC server. This is local command. */
288 SILC_CLIENT_CMD_FUNC(server)
290 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
295 /* Show current servers */
296 if (!cmd->client->current_win->sock) {
297 silc_say(cmd->client, "You are not connected to any server");
298 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
305 /* See if port is included and then extract it */
306 if (strchr(cmd->argv[1], ':')) {
307 len = strcspn(cmd->argv[1], ":");
308 hostname = silc_calloc(len + 1, sizeof(char));
309 memcpy(hostname, cmd->argv[1], len);
310 port = atoi(cmd->argv[1] + 1 + len);
312 hostname = cmd->argv[1];
316 /* Connect asynchronously to not to block user interface */
317 silc_client_connect_to_server(cmd->client, port, hostname);
320 silc_client_command_free(cmd);
323 SILC_CLIENT_CMD_FUNC(list)
327 SILC_CLIENT_CMD_FUNC(topic)
331 /* Command INVITE. Invites specific client to join a channel. */
333 SILC_CLIENT_CMD_FUNC(invite)
335 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
336 SilcClientWindow win = NULL;
338 SilcIDCache *id_cache;
339 unsigned char *client_id, *channel_id;
341 #define CIDC(x) win->client_id_cache[(x) - 32], \
342 win->client_id_cache_count[(x) - 32]
343 #define CHIDC(x) win->channel_id_cache[(x) - 32], \
344 win->channel_id_cache_count[(x) - 32]
346 if (cmd->argc != 3) {
347 silc_say(cmd->client, "Usage: /INVITE <nickname>[@<server>] <channel>");
351 if (!cmd->client->current_win->sock) {
352 SILC_NOT_CONNECTED(cmd->client);
356 win = (SilcClientWindow)cmd->sock->user_data;
358 /* Get client ID of the client to be invited. If we don't have it
359 we will request it and cache it. This same command will be called
360 again after we have received the reply (ie. pending). */
361 if (!silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
363 SilcClientCommandContext ctx;
366 ctx = silc_calloc(1, sizeof(*ctx));
367 ctx->client = cmd->client;
368 ctx->sock = cmd->sock;
369 memset(ident, 0, sizeof(ident));
370 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
371 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
372 &ctx->argv_types, &ctx->argc, 2);
373 silc_client_command_identify(ctx);
374 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
375 silc_client_command_invite, context);
379 client_id = silc_id_id2str(id_cache->id, SILC_ID_CLIENT);
381 /* Get Channel ID of the channel. */
382 if (!silc_idcache_find_by_data(CHIDC(cmd->argv[2][0]), cmd->argv[2],
384 silc_say(cmd->client, "You are not on that channel");
385 silc_free(client_id);
389 channel_id = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
391 buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
392 client_id, SILC_ID_CLIENT_LEN,
393 channel_id, SILC_ID_CHANNEL_LEN);
394 silc_client_packet_send(cmd->client, cmd->sock,
395 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
396 buffer->data, buffer->len, TRUE);
397 silc_buffer_free(buffer);
399 silc_say(cmd->client, "Inviting %s to channel %s", cmd->argv[1],
403 silc_client_command_free(cmd);
408 /* Command QUIT. Closes connection with current server. */
410 SILC_CLIENT_CMD_FUNC(quit)
412 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
415 if (!cmd->client->current_win->sock) {
416 SILC_NOT_CONNECTED(cmd->client);
420 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
421 ++cmd->argv, ++cmd->argv_lens,
423 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
424 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
425 buffer->data, buffer->len, TRUE);
426 silc_buffer_free(buffer);
431 /* Close connection */
432 silc_client_close_connection(cmd->client, cmd->sock);
433 cmd->client->screen->bottom_line->connection = NULL;
434 silc_screen_print_bottom_line(cmd->client->screen, 0);
437 silc_client_command_free(cmd);
440 SILC_CLIENT_CMD_FUNC(kill)
444 SILC_CLIENT_CMD_FUNC(info)
448 SILC_CLIENT_CMD_FUNC(connect)
452 /* Command PING. Sends ping to server. This is used to test the
453 communication channel. */
455 SILC_CLIENT_CMD_FUNC(ping)
457 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
458 SilcClientWindow win = NULL;
465 SILC_NOT_CONNECTED(cmd->client);
469 win = (SilcClientWindow)cmd->sock->user_data;
471 if (cmd->argc == 1 || !strcmp(cmd->argv[1], win->remote_host))
472 name = strdup(win->remote_host);
474 id = silc_id_str2id(win->remote_id_data, SILC_ID_SERVER);
476 /* Send the command */
477 buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 1,
480 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
481 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
482 buffer->data, buffer->len, TRUE);
483 silc_buffer_free(buffer);
485 /* Start counting time */
486 for (i = 0; i < win->ping_count; i++) {
487 if (win->ping[i].dest_id == NULL) {
488 win->ping[i].start_time = time(NULL);
489 win->ping[i].dest_id = id;
490 win->ping[i].dest_name = name;
495 if (i >= win->ping_count) {
497 win->ping = silc_realloc(win->ping, sizeof(*win->ping) * (i + 1));
498 win->ping[i].start_time = time(NULL);
499 win->ping[i].dest_id = id;
500 win->ping[i].dest_name = name;
505 silc_client_command_free(cmd);
508 SILC_CLIENT_CMD_FUNC(oper)
512 SILC_CLIENT_CMD_FUNC(trace)
516 SILC_CLIENT_CMD_FUNC(notice)
520 /* Command JOIN. Joins to a channel. */
522 SILC_CLIENT_CMD_FUNC(join)
524 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
525 SilcClientWindow win = NULL;
526 SilcIDCache *id_cache = NULL;
529 #define CIDC(x) win->channel_id_cache[(x) - 32]
530 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
533 /* Show channels currently joined to */
534 if (!cmd->client->current_win->sock) {
535 silc_say(cmd->client, "No current channel for this window");
536 SILC_NOT_CONNECTED(cmd->client);
544 if (!cmd->client->current_win->sock) {
545 SILC_NOT_CONNECTED(cmd->client);
549 win = (SilcClientWindow)cmd->sock->user_data;
551 /* See if we have joined to the requested channel already */
552 silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]),
553 cmd->argv[1], &id_cache);
556 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
557 win->current_channel = (SilcChannelEntry)id_cache->context;
558 cmd->client->screen->bottom_line->channel = cmd->argv[1];
559 silc_screen_print_bottom_line(cmd->client->screen, 0);
563 /* Send JOIN command to the server */
564 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
565 cmd->argc - 1, ++cmd->argv,
566 ++cmd->argv_lens, ++cmd->argv_types);
567 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
568 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
569 buffer->data, buffer->len, TRUE);
570 silc_buffer_free(buffer);
576 silc_client_command_free(cmd);
581 SILC_CLIENT_CMD_FUNC(motd)
585 SILC_CLIENT_CMD_FUNC(umode)
589 SILC_CLIENT_CMD_FUNC(cmode)
593 SILC_CLIENT_CMD_FUNC(kick)
597 SILC_CLIENT_CMD_FUNC(restart)
601 SILC_CLIENT_CMD_FUNC(close)
605 SILC_CLIENT_CMD_FUNC(die)
609 SILC_CLIENT_CMD_FUNC(silcoper)
613 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
615 SILC_CLIENT_CMD_FUNC(leave)
617 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
618 SilcClientWindow win = NULL;
619 SilcIDCache *id_cache = NULL;
621 unsigned char *id_string;
624 #define CIDC(x) win->channel_id_cache[(x) - 32]
625 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
627 if (cmd->argc != 2) {
628 silc_say(cmd->client, "Usage: /LEAVE <channel>");
632 if (!cmd->client->current_win->sock) {
633 SILC_NOT_CONNECTED(cmd->client);
637 win = (SilcClientWindow)cmd->sock->user_data;
639 if (cmd->argv[1][0] == '*')
640 name = win->current_channel->channel_name;
644 if (!win->current_channel) {
645 silc_say(cmd->client, "You are not on that channel", name);
649 /* Get the Channel ID of the channel */
650 silc_idcache_find_by_data(CIDC(name[0]), CIDCC(name[0]), name, &id_cache);
652 silc_say(cmd->client, "You are not on that channel", name);
656 /* Send LEAVE command to the server */
657 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
658 buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1,
659 id_string, SILC_ID_CHANNEL_LEN);
660 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
661 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
662 buffer->data, buffer->len, TRUE);
663 silc_buffer_free(buffer);
665 /* We won't talk anymore on this channel */
666 silc_say(cmd->client, "You have left channel %s", name);
667 cmd->client->screen->bottom_line->channel = NULL;
668 silc_screen_print_bottom_line(cmd->client->screen, 0);
670 silc_idcache_del_by_id(CIDC(name[0]), CIDCC(name[0]),
671 SILC_ID_CHANNEL, win->current_channel->id);
672 silc_free(win->current_channel->channel_name);
673 silc_free(win->current_channel->id);
674 silc_free(win->current_channel->key);
675 silc_cipher_free(win->current_channel->channel_key);
676 silc_free(win->current_channel);
677 win->current_channel = NULL;
678 silc_free(id_string);
681 silc_client_command_free(cmd);
686 /* Command NAMES. Requests the names of the clients joined on requested
689 SILC_CLIENT_CMD_FUNC(names)
691 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
692 SilcClientWindow win = NULL;
693 SilcIDCache *id_cache = NULL;
696 unsigned char *id_string;
698 #define CIDC(x) win->channel_id_cache[(x) - 32]
699 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
701 if (cmd->argc != 2) {
702 silc_say(cmd->client, "Usage: /NAMES <channel>");
706 if (!cmd->client->current_win->sock) {
707 SILC_NOT_CONNECTED(cmd->client);
711 win = (SilcClientWindow)cmd->sock->user_data;
713 if (cmd->argv[1][0] == '*')
714 name = win->current_channel->channel_name;
718 /* Get the Channel ID of the channel */
719 silc_idcache_find_by_data(CIDC(name[0]), CIDCC(name[0]), name, &id_cache);
721 /* XXX should resolve the channel ID; LIST command */
722 silc_say(cmd->client, "You are not on that channel", name);
726 /* Send NAMES command to the server */
727 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
728 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
729 id_string, SILC_ID_CHANNEL_LEN);
730 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
731 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
732 buffer->data, buffer->len, TRUE);
733 silc_buffer_free(buffer);
734 silc_free(id_string);
737 silc_client_command_free(cmd);
746 /* HELP command. This is local command and shows help on SILC */
748 SILC_CLIENT_CMD_FUNC(help)
753 /* CLEAR command. This is local command and clears current output window */
755 SILC_CLIENT_CMD_FUNC(clear)
757 SilcClient client = (SilcClient)context;
759 assert(client->current_win != NULL);
760 wclear((WINDOW *)client->current_win->screen);
761 wrefresh((WINDOW *)client->current_win->screen);
764 /* VERSION command. This is local command and shows version of the client */
766 SILC_CLIENT_CMD_FUNC(version)
771 /* Command MSG. Sends private message to user or list of users. */
772 /* XXX supports only one destination */
774 SILC_CLIENT_CMD_FUNC(msg)
776 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
777 SilcClientWindow win = NULL;
778 SilcClient client = cmd->client;
779 SilcIDCache *id_cache;
781 #define CIDC(x) win->client_id_cache[(x) - 32], \
782 win->client_id_cache_count[(x) - 32]
785 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
789 if (!cmd->client->current_win->sock) {
790 SILC_NOT_CONNECTED(cmd->client);
794 win = (SilcClientWindow)cmd->sock->user_data;
796 /* Find ID from cache */
797 if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
798 &id_cache) == FALSE) {
799 SilcClientCommandContext ctx;
802 SILC_LOG_DEBUG(("Requesting Client ID from server"));
804 /* No ID found. Do query from the server. The query is done by
805 sending simple IDENTIFY command to the server. */
806 ctx = silc_calloc(1, sizeof(*ctx));
807 ctx->client = client;
808 ctx->sock = cmd->sock;
809 memset(ident, 0, sizeof(ident));
810 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
811 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
812 &ctx->argv_types, &ctx->argc, 2);
813 silc_client_command_identify(ctx);
815 /* Mark this command to be pending command and to be executed after
816 we have received the IDENTIFY reply from server. */
817 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
818 silc_client_command_msg, context);
822 /* Display the message for our eyes. */
823 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
825 /* Send the private message */
826 silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
827 cmd->argv[2], cmd->argv_lens[2],
831 silc_client_command_free(cmd);
835 SILC_CLIENT_CMD_FUNC(away)