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.4 2000/07/04 08:28:03 priikone
24 * Added INVITE, PING and NAMES command.
26 * Revision 1.3 2000/07/03 05:49:49 priikone
27 * Implemented LEAVE command. Minor bug fixes.
29 * Revision 1.2 2000/06/27 19:38:40 priikone
30 * Added missing goto flag.
32 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
33 * Importet from internal CVS/Added Log headers.
38 #include "clientincludes.h"
40 /* Client command list. */
41 SilcClientCommand silc_command_list[] =
43 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
44 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
45 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
46 SILC_CF_LAG | SILC_CF_REG, 3),
47 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
48 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
49 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
50 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
51 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
52 SILC_CLIENT_CMD(kill, KILL, "KILL",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
54 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
55 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
56 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
57 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
58 SILC_CLIENT_CMD(oper, OPER, "OPER",
59 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
60 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
61 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
62 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
63 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
64 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
65 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
66 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
67 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
68 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
69 SILC_CLIENT_CMD(die, DIE, "DIE",
70 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
71 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
72 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
73 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
74 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
77 * Local. client specific commands
79 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
80 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
81 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
82 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
83 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
84 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
89 #define SILC_NOT_CONNECTED(x) \
90 silc_say((x), "You are not connected to a server, use /SERVER to connect");
92 /* List of pending commands. */
93 SilcClientCommandPending *silc_command_pending = NULL;
95 /* Add new pending command to the list of pending commands. Currently
96 pending commands are executed from command replies, thus we can
97 execute any command after receiving some specific command reply.
99 The argument `reply_cmd' is the command reply from where the callback
100 function is to be called, thus, it IS NOT the command to be executed.
102 XXX: If needed in the future this support may be extended for
103 commands as well, when any command could be executed after executing
104 some specific command. */
106 void silc_client_command_pending(SilcCommand reply_cmd,
107 SilcClientCommandCallback callback,
110 SilcClientCommandPending *reply, *r;
112 reply = silc_calloc(1, sizeof(*reply));
113 reply->reply_cmd = reply_cmd;
114 reply->context = context;
115 reply->callback = callback;
117 if (silc_command_pending == NULL) {
118 silc_command_pending = reply;
122 for (r = silc_command_pending; r; r = r->next) {
123 if (r->next == NULL) {
130 /* Deletes pending command by reply command type. */
132 void silc_client_command_pending_del(SilcCommand reply_cmd)
134 SilcClientCommandPending *r, *tmp;
136 if (silc_command_pending) {
137 if (silc_command_pending->reply_cmd == reply_cmd) {
138 silc_free(silc_command_pending);
139 silc_command_pending = NULL;
143 for (r = silc_command_pending; r; r = r->next) {
144 if (r->next && r->next->reply_cmd == reply_cmd) {
146 r->next = r->next->next;
154 /* Free command context and its internals */
156 static void silc_client_command_free(SilcClientCommandContext cmd)
161 for (i = 0; i < cmd->argc; i++)
162 silc_free(cmd->argv[i]);
167 /* Command WHOIS. This command is used to query information about
170 SILC_CLIENT_CMD_FUNC(whois)
172 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
175 if (cmd->argc < 2 || cmd->argc > 3) {
176 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
180 if (!cmd->client->current_win->sock) {
181 SILC_NOT_CONNECTED(cmd->client);
185 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
186 cmd->argc - 1, ++cmd->argv,
187 ++cmd->argv_lens, ++cmd->argv_types);
188 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
189 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
190 buffer->data, buffer->len, TRUE);
191 silc_buffer_free(buffer);
197 silc_client_command_free(cmd);
200 SILC_CLIENT_CMD_FUNC(whowas)
204 /* Command IDENTIFY. This command is used to query information about
205 specific user, especially ID's. */
207 SILC_CLIENT_CMD_FUNC(identify)
209 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
212 if (cmd->argc < 2 || cmd->argc > 3) {
213 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
217 if (!cmd->client->current_win->sock) {
218 SILC_NOT_CONNECTED(cmd->client);
222 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
223 cmd->argc - 1, ++cmd->argv,
224 ++cmd->argv_lens, ++cmd->argv_types);
225 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
226 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
227 buffer->data, buffer->len, TRUE);
228 silc_buffer_free(buffer);
234 silc_client_command_free(cmd);
237 /* Command NICK. Shows current nickname/sets new nickname on current
240 SILC_CLIENT_CMD_FUNC(nick)
242 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
243 SilcClientWindow win = NULL;
247 SILC_NOT_CONNECTED(cmd->client);
251 /* Show current nickname */
254 silc_say(cmd->client, "Your nickname is %s on server %s",
255 win->nickname, win->remote_host);
257 silc_say(cmd->client, "Your nickname is %s", win->nickname);
262 win = (SilcClientWindow)cmd->sock->user_data;
264 /* Set new nickname */
265 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
266 cmd->argc - 1, ++cmd->argv,
267 ++cmd->argv_lens, ++cmd->argv_types);
268 silc_client_packet_send(cmd->client, cmd->sock,
269 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
270 buffer->data, buffer->len, TRUE);
271 silc_buffer_free(buffer);
276 silc_free(win->nickname);
277 win->nickname = strdup(cmd->argv[1]);
280 silc_client_command_free(cmd);
283 /* Command SERVER. Connects to remote SILC server. This is local command. */
285 SILC_CLIENT_CMD_FUNC(server)
287 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
292 /* Show current servers */
293 if (!cmd->client->current_win->sock) {
294 silc_say(cmd->client, "You are not connected to any server");
295 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
302 /* See if port is included and then extract it */
303 if (strchr(cmd->argv[1], ':')) {
304 len = strcspn(cmd->argv[1], ":");
305 hostname = silc_calloc(len + 1, sizeof(char));
306 memcpy(hostname, cmd->argv[1], len);
307 port = atoi(cmd->argv[1] + 1 + len);
309 hostname = cmd->argv[1];
313 /* Connect asynchronously to not to block user interface */
314 silc_client_connect_to_server(cmd->client, port, hostname);
317 silc_client_command_free(cmd);
320 SILC_CLIENT_CMD_FUNC(list)
324 SILC_CLIENT_CMD_FUNC(topic)
328 /* Command INVITE. Invites specific client to join a channel. */
330 SILC_CLIENT_CMD_FUNC(invite)
332 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
333 SilcClientWindow win = NULL;
335 SilcIDCache *id_cache;
336 unsigned char *client_id, *channel_id;
338 #define CIDC(x) win->client_id_cache[(x) - 32], \
339 win->client_id_cache_count[(x) - 32]
340 #define CHIDC(x) win->channel_id_cache[(x) - 32], \
341 win->channel_id_cache_count[(x) - 32]
343 if (cmd->argc != 3) {
344 silc_say(cmd->client, "Usage: /INVITE <nickname>[@<server>] <channel>");
348 if (!cmd->client->current_win->sock) {
349 SILC_NOT_CONNECTED(cmd->client);
353 win = (SilcClientWindow)cmd->sock->user_data;
355 /* Get client ID of the client to be invited. If we don't have it
356 we will request it and cache it. This same command will be called
357 again after we have received the reply (ie. pending). */
358 if (!silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
360 SilcClientCommandContext ctx;
363 ctx = silc_calloc(1, sizeof(*ctx));
364 ctx->client = cmd->client;
365 ctx->sock = cmd->sock;
366 memset(ident, 0, sizeof(ident));
367 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
368 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
369 &ctx->argv_types, &ctx->argc, 2);
370 silc_client_command_identify(ctx);
371 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
372 silc_client_command_invite, context);
376 client_id = silc_id_id2str(id_cache->id, SILC_ID_CLIENT);
378 /* Get Channel ID of the channel. */
379 if (!silc_idcache_find_by_data(CHIDC(cmd->argv[2][0]), cmd->argv[2],
381 silc_say(cmd->client, "You are not on that channel");
382 silc_free(client_id);
386 channel_id = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
388 buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
389 client_id, SILC_ID_CLIENT_LEN,
390 channel_id, SILC_ID_CHANNEL_LEN);
391 silc_client_packet_send(cmd->client, cmd->sock,
392 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
393 buffer->data, buffer->len, TRUE);
394 silc_buffer_free(buffer);
396 silc_say(cmd->client, "Inviting %s to channel %s", cmd->argv[1],
400 silc_client_command_free(cmd);
405 /* Command QUIT. Closes connection with current server. */
407 SILC_CLIENT_CMD_FUNC(quit)
409 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
412 if (!cmd->client->current_win->sock) {
413 SILC_NOT_CONNECTED(cmd->client);
417 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
418 ++cmd->argv, ++cmd->argv_lens,
420 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
421 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
422 buffer->data, buffer->len, TRUE);
423 silc_buffer_free(buffer);
428 /* Close connection */
429 silc_client_close_connection(cmd->client, cmd->sock);
430 cmd->client->screen->bottom_line->connection = NULL;
431 silc_screen_print_bottom_line(cmd->client->screen, 0);
434 silc_client_command_free(cmd);
437 SILC_CLIENT_CMD_FUNC(kill)
441 SILC_CLIENT_CMD_FUNC(info)
445 SILC_CLIENT_CMD_FUNC(connect)
449 /* Command PING. Sends ping to server. This is used to test the
450 communication channel. */
452 SILC_CLIENT_CMD_FUNC(ping)
454 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
455 SilcClientWindow win = NULL;
462 SILC_NOT_CONNECTED(cmd->client);
466 win = (SilcClientWindow)cmd->sock->user_data;
468 if (cmd->argc == 1 || !strcmp(cmd->argv[1], win->remote_host))
469 name = strdup(win->remote_host);
471 id = silc_id_str2id(win->remote_id_data, SILC_ID_SERVER);
473 /* Send the command */
474 buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 1,
477 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
478 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
479 buffer->data, buffer->len, TRUE);
480 silc_buffer_free(buffer);
482 /* Start counting time */
483 for (i = 0; i < win->ping_count; i++) {
484 if (win->ping[i].dest_id == NULL) {
485 win->ping[i].start_time = time(NULL);
486 win->ping[i].dest_id = id;
487 win->ping[i].dest_name = name;
492 if (i >= win->ping_count) {
494 win->ping = silc_realloc(win->ping, sizeof(*win->ping) * (i + 1));
495 win->ping[i].start_time = time(NULL);
496 win->ping[i].dest_id = id;
497 win->ping[i].dest_name = name;
502 silc_client_command_free(cmd);
505 SILC_CLIENT_CMD_FUNC(oper)
509 SILC_CLIENT_CMD_FUNC(trace)
513 SILC_CLIENT_CMD_FUNC(notice)
517 /* Command JOIN. Joins to a channel. */
519 SILC_CLIENT_CMD_FUNC(join)
521 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
522 SilcClientWindow win = NULL;
523 SilcIDCache *id_cache = NULL;
526 #define CIDC(x) win->channel_id_cache[(x) - 32]
527 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
530 /* Show channels currently joined to */
531 if (!cmd->client->current_win->sock) {
532 silc_say(cmd->client, "No current channel for this window");
533 SILC_NOT_CONNECTED(cmd->client);
541 if (!cmd->client->current_win->sock) {
542 SILC_NOT_CONNECTED(cmd->client);
546 win = (SilcClientWindow)cmd->sock->user_data;
548 /* See if we have joined to the requested channel already */
549 silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]),
550 cmd->argv[1], &id_cache);
553 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
554 win->current_channel = (SilcChannelEntry)id_cache->context;
555 cmd->client->screen->bottom_line->channel = cmd->argv[1];
556 silc_screen_print_bottom_line(cmd->client->screen, 0);
560 /* Send JOIN command to the server */
561 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
562 cmd->argc - 1, ++cmd->argv,
563 ++cmd->argv_lens, ++cmd->argv_types);
564 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
565 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
566 buffer->data, buffer->len, TRUE);
567 silc_buffer_free(buffer);
573 silc_client_command_free(cmd);
578 SILC_CLIENT_CMD_FUNC(motd)
582 SILC_CLIENT_CMD_FUNC(umode)
586 SILC_CLIENT_CMD_FUNC(cmode)
590 SILC_CLIENT_CMD_FUNC(kick)
594 SILC_CLIENT_CMD_FUNC(restart)
598 SILC_CLIENT_CMD_FUNC(close)
602 SILC_CLIENT_CMD_FUNC(die)
606 SILC_CLIENT_CMD_FUNC(silcoper)
610 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
612 SILC_CLIENT_CMD_FUNC(leave)
614 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
615 SilcClientWindow win = NULL;
616 SilcIDCache *id_cache = NULL;
618 unsigned char *id_string;
621 #define CIDC(x) win->channel_id_cache[(x) - 32]
622 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
624 if (cmd->argc != 2) {
625 silc_say(cmd->client, "Usage: /LEAVE <channel>");
629 if (!cmd->client->current_win->sock) {
630 SILC_NOT_CONNECTED(cmd->client);
634 win = (SilcClientWindow)cmd->sock->user_data;
636 if (cmd->argv[1][0] == '*')
637 name = win->current_channel->channel_name;
641 if (!win->current_channel) {
642 silc_say(cmd->client, "You are not on that channel", name);
646 /* Get the Channel ID of the channel */
647 silc_idcache_find_by_data(CIDC(name[0]), CIDCC(name[0]), name, &id_cache);
649 silc_say(cmd->client, "You are not on that channel", name);
653 /* Send LEAVE command to the server */
654 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
655 buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1,
656 id_string, SILC_ID_CHANNEL_LEN);
657 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
658 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
659 buffer->data, buffer->len, TRUE);
660 silc_buffer_free(buffer);
662 /* We won't talk anymore on this channel */
663 silc_say(cmd->client, "You have left channel %s", name);
664 cmd->client->screen->bottom_line->channel = NULL;
665 silc_screen_print_bottom_line(cmd->client->screen, 0);
667 silc_idcache_del_by_id(CIDC(name[0]), CIDCC(name[0]),
668 SILC_ID_CHANNEL, win->current_channel->id);
669 silc_free(win->current_channel->channel_name);
670 silc_free(win->current_channel->id);
671 silc_free(win->current_channel->key);
672 silc_cipher_free(win->current_channel->channel_key);
673 silc_free(win->current_channel);
674 win->current_channel = NULL;
675 silc_free(id_string);
678 silc_client_command_free(cmd);
683 /* Command NAMES. Requests the names of the clients joined on requested
686 SILC_CLIENT_CMD_FUNC(names)
688 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
689 SilcClientWindow win = NULL;
690 SilcIDCache *id_cache = NULL;
693 unsigned char *id_string;
695 #define CIDC(x) win->channel_id_cache[(x) - 32]
696 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
698 if (cmd->argc != 2) {
699 silc_say(cmd->client, "Usage: /NAMES <channel>");
703 if (!cmd->client->current_win->sock) {
704 SILC_NOT_CONNECTED(cmd->client);
708 win = (SilcClientWindow)cmd->sock->user_data;
710 if (cmd->argv[1][0] == '*')
711 name = win->current_channel->channel_name;
715 /* Get the Channel ID of the channel */
716 silc_idcache_find_by_data(CIDC(name[0]), CIDCC(name[0]), name, &id_cache);
718 /* XXX should resolve the channel ID; LIST command */
719 silc_say(cmd->client, "You are not on that channel", name);
723 /* Send NAMES command to the server */
724 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
725 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
726 id_string, SILC_ID_CHANNEL_LEN);
727 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
728 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
729 buffer->data, buffer->len, TRUE);
730 silc_buffer_free(buffer);
731 silc_free(id_string);
734 silc_client_command_free(cmd);
743 /* HELP command. This is local command and shows help on SILC */
745 SILC_CLIENT_CMD_FUNC(help)
750 /* CLEAR command. This is local command and clears current output window */
752 SILC_CLIENT_CMD_FUNC(clear)
754 SilcClient client = (SilcClient)context;
756 assert(client->current_win != NULL);
757 wclear((WINDOW *)client->current_win->screen);
758 wrefresh((WINDOW *)client->current_win->screen);
761 /* VERSION command. This is local command and shows version of the client */
763 SILC_CLIENT_CMD_FUNC(version)
768 /* Command MSG. Sends private message to user or list of users. */
769 /* XXX supports only one destination */
771 SILC_CLIENT_CMD_FUNC(msg)
773 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
774 SilcClientWindow win = NULL;
775 SilcClient client = cmd->client;
776 SilcIDCache *id_cache;
778 #define CIDC(x) win->client_id_cache[(x) - 32], \
779 win->client_id_cache_count[(x) - 32]
782 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
786 if (!cmd->client->current_win->sock) {
787 SILC_NOT_CONNECTED(cmd->client);
791 win = (SilcClientWindow)cmd->sock->user_data;
793 /* Find ID from cache */
794 if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
795 &id_cache) == FALSE) {
796 SilcClientCommandContext ctx;
799 SILC_LOG_DEBUG(("Requesting Client ID from server"));
801 /* No ID found. Do query from the server. The query is done by
802 sending simple IDENTIFY command to the server. */
803 ctx = silc_calloc(1, sizeof(*ctx));
804 ctx->client = client;
805 ctx->sock = cmd->sock;
806 memset(ident, 0, sizeof(ident));
807 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
808 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
809 &ctx->argv_types, &ctx->argc, 2);
810 silc_client_command_identify(ctx);
812 /* Mark this command to be pending command and to be executed after
813 we have received the IDENTIFY reply from server. */
814 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
815 silc_client_command_msg, context);
819 /* Display the message for our eyes. */
820 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
822 /* Send the private message */
823 silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
824 cmd->argv[2], cmd->argv_lens[2],
828 silc_client_command_free(cmd);
832 SILC_CLIENT_CMD_FUNC(away)