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.8 2000/07/10 05:39:11 priikone
24 * Added INFO and VERSION commands. Minor changes to SERVER command
25 * to show current servers when giving without arguments.
27 * Revision 1.7 2000/07/07 06:54:44 priikone
28 * Fixed channel joining bug, do not allow joining twice on the
31 * Revision 1.6 2000/07/06 07:14:36 priikone
32 * Fixes to NAMES command handling.
33 * Fixes when leaving from channel.
35 * Revision 1.5 2000/07/05 06:12:05 priikone
36 * Global cosmetic changes.
38 * Revision 1.4 2000/07/04 08:28:03 priikone
39 * Added INVITE, PING and NAMES command.
41 * Revision 1.3 2000/07/03 05:49:49 priikone
42 * Implemented LEAVE command. Minor bug fixes.
44 * Revision 1.2 2000/06/27 19:38:40 priikone
45 * Added missing goto flag.
47 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
48 * Imported from internal CVS/Added Log headers.
53 #include "clientincludes.h"
55 /* Client command list. */
56 SilcClientCommand silc_command_list[] =
58 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
59 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
60 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
61 SILC_CF_LAG | SILC_CF_REG, 3),
62 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
63 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
64 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
65 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
66 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
67 SILC_CLIENT_CMD(kill, KILL, "KILL",
68 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
69 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
70 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
71 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
72 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
73 SILC_CLIENT_CMD(oper, OPER, "OPER",
74 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
75 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
76 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
77 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
78 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
79 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
80 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
81 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
82 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
83 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
84 SILC_CLIENT_CMD(die, DIE, "DIE",
85 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
86 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
87 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
88 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
89 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
92 * Local. Client specific commands
94 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
95 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
96 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
97 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
98 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
99 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
104 #define SILC_NOT_CONNECTED(x) \
105 silc_say((x), "You are not connected to a server, use /SERVER to connect");
107 /* List of pending commands. */
108 SilcClientCommandPending *silc_command_pending = NULL;
110 /* Add new pending command to the list of pending commands. Currently
111 pending commands are executed from command replies, thus we can
112 execute any command after receiving some specific command reply.
114 The argument `reply_cmd' is the command reply from where the callback
115 function is to be called, thus, it IS NOT the command to be executed.
117 XXX: If needed in the future this support may be extended for
118 commands as well, when any command could be executed after executing
119 some specific command. */
121 void silc_client_command_pending(SilcCommand reply_cmd,
122 SilcClientCommandCallback callback,
125 SilcClientCommandPending *reply, *r;
127 reply = silc_calloc(1, sizeof(*reply));
128 reply->reply_cmd = reply_cmd;
129 reply->context = context;
130 reply->callback = callback;
132 if (silc_command_pending == NULL) {
133 silc_command_pending = reply;
137 for (r = silc_command_pending; r; r = r->next) {
138 if (r->next == NULL) {
145 /* Deletes pending command by reply command type. */
147 void silc_client_command_pending_del(SilcCommand reply_cmd)
149 SilcClientCommandPending *r, *tmp;
151 if (silc_command_pending) {
152 if (silc_command_pending->reply_cmd == reply_cmd) {
153 silc_free(silc_command_pending);
154 silc_command_pending = NULL;
158 for (r = silc_command_pending; r; r = r->next) {
159 if (r->next && r->next->reply_cmd == reply_cmd) {
161 r->next = r->next->next;
169 /* Free command context and its internals */
171 static void silc_client_command_free(SilcClientCommandContext cmd)
176 for (i = 0; i < cmd->argc; i++)
177 silc_free(cmd->argv[i]);
182 /* Command WHOIS. This command is used to query information about
185 SILC_CLIENT_CMD_FUNC(whois)
187 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
190 if (cmd->argc < 2 || cmd->argc > 3) {
191 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
195 if (!cmd->client->current_win->sock) {
196 SILC_NOT_CONNECTED(cmd->client);
200 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
201 cmd->argc - 1, ++cmd->argv,
202 ++cmd->argv_lens, ++cmd->argv_types);
203 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
204 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
205 buffer->data, buffer->len, TRUE);
206 silc_buffer_free(buffer);
212 silc_client_command_free(cmd);
215 SILC_CLIENT_CMD_FUNC(whowas)
219 /* Command IDENTIFY. This command is used to query information about
220 specific user, especially ID's. */
222 SILC_CLIENT_CMD_FUNC(identify)
224 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
227 if (cmd->argc < 2 || cmd->argc > 3) {
228 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
232 if (!cmd->client->current_win->sock) {
233 SILC_NOT_CONNECTED(cmd->client);
237 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
238 cmd->argc - 1, ++cmd->argv,
239 ++cmd->argv_lens, ++cmd->argv_types);
240 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
241 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
242 buffer->data, buffer->len, TRUE);
243 silc_buffer_free(buffer);
249 silc_client_command_free(cmd);
252 /* Command NICK. Shows current nickname/sets new nickname on current
255 SILC_CLIENT_CMD_FUNC(nick)
257 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
258 SilcClientWindow win = NULL;
262 SILC_NOT_CONNECTED(cmd->client);
266 /* Show current nickname */
269 silc_say(cmd->client, "Your nickname is %s on server %s",
270 win->nickname, win->remote_host);
272 silc_say(cmd->client, "Your nickname is %s", win->nickname);
277 win = (SilcClientWindow)cmd->sock->user_data;
279 /* Set new nickname */
280 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
281 cmd->argc - 1, ++cmd->argv,
282 ++cmd->argv_lens, ++cmd->argv_types);
283 silc_client_packet_send(cmd->client, cmd->sock,
284 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
285 buffer->data, buffer->len, TRUE);
286 silc_buffer_free(buffer);
291 silc_free(win->nickname);
292 win->nickname = strdup(cmd->argv[1]);
295 silc_client_command_free(cmd);
298 /* Command SERVER. Connects to remote SILC server. This is local command. */
300 SILC_CLIENT_CMD_FUNC(server)
302 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
303 SilcClient client = cmd->client;
304 int i = 0, len, port;
308 /* Show current servers */
310 if (!cmd->client->current_win->sock) {
311 silc_say(cmd->client, "You are not connected to any server");
312 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
316 silc_say(client, "Current server: %s on %d %s",
317 client->current_win->remote_host,
318 client->current_win->remote_port,
319 client->windows[i]->remote_info ?
320 client->windows[i]->remote_info : "");
322 silc_say(client, "Server list:");
323 for (i = 0; i < client->windows_count; i++) {
324 silc_say(client, " [%d] %s on %d %s", i + 1,
325 client->windows[i]->remote_host,
326 client->windows[i]->remote_port,
327 client->windows[i]->remote_info ?
328 client->windows[i]->remote_info : "");
334 /* See if port is included and then extract it */
335 if (strchr(cmd->argv[1], ':')) {
336 len = strcspn(cmd->argv[1], ":");
337 hostname = silc_calloc(len + 1, sizeof(char));
338 memcpy(hostname, cmd->argv[1], len);
339 port = atoi(cmd->argv[1] + 1 + len);
341 hostname = cmd->argv[1];
345 /* Connect asynchronously to not to block user interface */
346 silc_client_connect_to_server(cmd->client, port, hostname);
349 silc_client_command_free(cmd);
352 SILC_CLIENT_CMD_FUNC(list)
356 SILC_CLIENT_CMD_FUNC(topic)
360 /* Command INVITE. Invites specific client to join a channel. */
362 SILC_CLIENT_CMD_FUNC(invite)
364 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
365 SilcClientWindow win = NULL;
367 SilcIDCache *id_cache;
368 unsigned char *client_id, *channel_id;
370 #define CIDC(x) win->client_id_cache[(x) - 32], \
371 win->client_id_cache_count[(x) - 32]
372 #define CHIDC(x) win->channel_id_cache[(x) - 32], \
373 win->channel_id_cache_count[(x) - 32]
375 if (cmd->argc != 3) {
376 silc_say(cmd->client, "Usage: /INVITE <nickname>[@<server>] <channel>");
380 if (!cmd->client->current_win->sock) {
381 SILC_NOT_CONNECTED(cmd->client);
385 win = (SilcClientWindow)cmd->sock->user_data;
387 /* Get client ID of the client to be invited. If we don't have it
388 we will request it and cache it. This same command will be called
389 again after we have received the reply (ie. pending). */
390 if (!silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
392 SilcClientCommandContext ctx;
395 ctx = silc_calloc(1, sizeof(*ctx));
396 ctx->client = cmd->client;
397 ctx->sock = cmd->sock;
398 memset(ident, 0, sizeof(ident));
399 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
400 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
401 &ctx->argv_types, &ctx->argc, 2);
402 silc_client_command_identify(ctx);
403 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
404 silc_client_command_invite, context);
408 client_id = silc_id_id2str(id_cache->id, SILC_ID_CLIENT);
410 /* Get Channel ID of the channel. */
411 if (!silc_idcache_find_by_data(CHIDC(cmd->argv[2][0]), cmd->argv[2],
413 silc_say(cmd->client, "You are not on that channel");
414 silc_free(client_id);
418 channel_id = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
420 buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
421 1, client_id, SILC_ID_CLIENT_LEN,
422 2, channel_id, SILC_ID_CHANNEL_LEN);
423 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
424 0, NULL, NULL, buffer->data, buffer->len, TRUE);
425 silc_buffer_free(buffer);
427 silc_say(cmd->client, "Inviting %s to channel %s", cmd->argv[1],
431 silc_client_command_free(cmd);
436 /* Command QUIT. Closes connection with current server. */
438 SILC_CLIENT_CMD_FUNC(quit)
440 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
443 if (!cmd->client->current_win->sock) {
444 SILC_NOT_CONNECTED(cmd->client);
448 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
449 ++cmd->argv, ++cmd->argv_lens,
451 silc_client_packet_send(cmd->client, cmd->sock, SILC_PACKET_COMMAND, NULL,
452 0, NULL, NULL, buffer->data, buffer->len, TRUE);
453 silc_buffer_free(buffer);
458 /* Close connection */
459 silc_client_close_connection(cmd->client, cmd->sock);
460 cmd->client->screen->bottom_line->connection = NULL;
461 silc_screen_print_bottom_line(cmd->client->screen, 0);
464 silc_client_command_free(cmd);
467 SILC_CLIENT_CMD_FUNC(kill)
471 /* Command INFO. Request information about specific server. If specific
472 server is not provided the current server is used. */
474 SILC_CLIENT_CMD_FUNC(info)
476 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
477 SilcClientWindow win = NULL;
482 SILC_NOT_CONNECTED(cmd->client);
486 win = (SilcClientWindow)cmd->sock->user_data;
489 name = strdup(win->remote_host);
491 name = strdup(cmd->argv[1]);
493 /* Send the command */
494 buffer = silc_command_encode_payload_va(SILC_COMMAND_INFO, 1,
495 1, name, strlen(name));
496 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
497 0, NULL, NULL, buffer->data, buffer->len, TRUE);
498 silc_buffer_free(buffer);
501 silc_client_command_free(cmd);
504 SILC_CLIENT_CMD_FUNC(connect)
508 /* Command PING. Sends ping to server. This is used to test the
509 communication channel. */
511 SILC_CLIENT_CMD_FUNC(ping)
513 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
514 SilcClientWindow win = NULL;
521 SILC_NOT_CONNECTED(cmd->client);
525 win = (SilcClientWindow)cmd->sock->user_data;
527 if (cmd->argc == 1 || !strcmp(cmd->argv[1], win->remote_host))
528 name = strdup(win->remote_host);
530 id = silc_id_str2id(win->remote_id_data, SILC_ID_SERVER);
532 /* Send the command */
533 buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 1,
534 1, win->remote_id_data,
536 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
537 0, NULL, NULL, buffer->data, buffer->len, TRUE);
538 silc_buffer_free(buffer);
540 /* Start counting time */
541 for (i = 0; i < win->ping_count; i++) {
542 if (win->ping[i].dest_id == NULL) {
543 win->ping[i].start_time = time(NULL);
544 win->ping[i].dest_id = id;
545 win->ping[i].dest_name = name;
550 if (i >= win->ping_count) {
552 win->ping = silc_realloc(win->ping, sizeof(*win->ping) * (i + 1));
553 win->ping[i].start_time = time(NULL);
554 win->ping[i].dest_id = id;
555 win->ping[i].dest_name = name;
560 silc_client_command_free(cmd);
563 SILC_CLIENT_CMD_FUNC(oper)
567 SILC_CLIENT_CMD_FUNC(trace)
571 SILC_CLIENT_CMD_FUNC(notice)
575 /* Command JOIN. Joins to a channel. */
577 SILC_CLIENT_CMD_FUNC(join)
579 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
580 SilcClientWindow win = NULL;
581 SilcIDCache *id_cache = NULL;
584 #define CIDC(x) win->channel_id_cache[(x) - 32]
585 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
588 /* Show channels currently joined to */
589 if (!cmd->client->current_win->sock) {
590 silc_say(cmd->client, "No current channel for this window");
591 SILC_NOT_CONNECTED(cmd->client);
599 if (!cmd->client->current_win->sock) {
600 SILC_NOT_CONNECTED(cmd->client);
604 win = (SilcClientWindow)cmd->sock->user_data;
606 /* See if we have joined to the requested channel already */
607 silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]),
608 cmd->argv[1], &id_cache);
611 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
612 win->current_channel = (SilcChannelEntry)id_cache->context;
613 cmd->client->screen->bottom_line->channel = cmd->argv[1];
614 silc_screen_print_bottom_line(cmd->client->screen, 0);
618 /* Send JOIN command to the server */
619 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
620 cmd->argc - 1, ++cmd->argv,
621 ++cmd->argv_lens, ++cmd->argv_types);
622 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
623 0, NULL, NULL, buffer->data, buffer->len, TRUE);
624 silc_buffer_free(buffer);
630 silc_client_command_free(cmd);
635 SILC_CLIENT_CMD_FUNC(motd)
639 SILC_CLIENT_CMD_FUNC(umode)
643 SILC_CLIENT_CMD_FUNC(cmode)
647 SILC_CLIENT_CMD_FUNC(kick)
651 SILC_CLIENT_CMD_FUNC(restart)
655 SILC_CLIENT_CMD_FUNC(close)
659 SILC_CLIENT_CMD_FUNC(die)
663 SILC_CLIENT_CMD_FUNC(silcoper)
667 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
669 SILC_CLIENT_CMD_FUNC(leave)
671 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
672 SilcClientWindow win = NULL;
673 SilcIDCache *id_cache = NULL;
674 SilcChannelEntry channel;
676 unsigned char *id_string;
679 #define CIDC(x) win->channel_id_cache[(x) - 32]
680 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
682 if (cmd->argc != 2) {
683 silc_say(cmd->client, "Usage: /LEAVE <channel>");
687 if (!cmd->client->current_win->sock) {
688 SILC_NOT_CONNECTED(cmd->client);
692 win = (SilcClientWindow)cmd->sock->user_data;
694 if (cmd->argv[1][0] == '*') {
695 if (!win->current_channel) {
696 silc_say(cmd->client, "You are not on any chanenl");
699 name = win->current_channel->channel_name;
704 if (!win->current_channel) {
705 silc_say(cmd->client, "You are not on that channel");
709 /* Get the Channel ID of the channel */
710 silc_idcache_find_by_data(CIDC(name[0]), CIDCC(name[0]), name, &id_cache);
712 silc_say(cmd->client, "You are not on that channel");
716 channel = (SilcChannelEntry)id_cache->context;
718 /* Send LEAVE command to the server */
719 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
720 buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1,
721 1, id_string, SILC_ID_CHANNEL_LEN);
722 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
723 0, NULL, NULL, buffer->data, buffer->len, TRUE);
724 silc_buffer_free(buffer);
726 /* We won't talk anymore on this channel */
727 silc_say(cmd->client, "You have left channel %s", name);
729 if (!strncmp(win->current_channel->channel_name, name, strlen(name))) {
730 cmd->client->screen->bottom_line->channel = NULL;
731 silc_screen_print_bottom_line(cmd->client->screen, 0);
732 win->current_channel = NULL;
735 silc_idcache_del_by_id(CIDC(name[0]), CIDCC(name[0]),
736 SILC_ID_CHANNEL, channel->id);
737 silc_free(channel->channel_name);
738 silc_free(channel->id);
739 silc_free(channel->key);
740 silc_cipher_free(channel->channel_key);
742 silc_free(id_string);
745 silc_client_command_free(cmd);
750 /* Command NAMES. Requests the names of the clients joined on requested
753 SILC_CLIENT_CMD_FUNC(names)
755 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
756 SilcClientWindow win = NULL;
757 SilcIDCache *id_cache = NULL;
760 unsigned char *id_string;
762 #define CIDC(x) win->channel_id_cache[(x) - 32]
763 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
765 if (cmd->argc != 2) {
766 silc_say(cmd->client, "Usage: /NAMES <channel>");
770 if (!cmd->client->current_win->sock) {
771 SILC_NOT_CONNECTED(cmd->client);
775 win = (SilcClientWindow)cmd->sock->user_data;
777 if (cmd->argv[1][0] == '*')
778 name = win->current_channel->channel_name;
782 /* Get the Channel ID of the channel */
783 silc_idcache_find_by_data(CIDC(name[0]), CIDCC(name[0]), name, &id_cache);
785 /* XXX should resolve the channel ID; LIST command */
786 silc_say(cmd->client, "You are not on that channel", name);
790 /* Send NAMES command to the server */
791 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
792 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
793 1, id_string, SILC_ID_CHANNEL_LEN);
794 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
795 0, NULL, NULL, buffer->data, buffer->len, TRUE);
796 silc_buffer_free(buffer);
797 silc_free(id_string);
799 /* Register dummy pending command that will tell the reply command
800 that user called this command. Server may send reply to this command
801 even if user did not send this command thus we want to handle things
802 differently when user sent the command. This is dummy and won't be
804 /* XXX this is kludge and should be removed after pending command reply
805 support is added. Currently only commands may be pending not command
807 silc_client_command_pending(SILC_COMMAND_NAMES, silc_client_command_names,
811 silc_client_command_free(cmd);
820 /* HELP command. This is local command and shows help on SILC */
822 SILC_CLIENT_CMD_FUNC(help)
827 /* CLEAR command. This is local command and clears current output window */
829 SILC_CLIENT_CMD_FUNC(clear)
831 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
832 SilcClient client = cmd->client;
834 assert(client->current_win != NULL);
835 wclear((WINDOW *)client->current_win->screen);
836 wrefresh((WINDOW *)client->current_win->screen);
838 silc_client_command_free(cmd);
841 /* VERSION command. This is local command and shows version of the client */
843 SILC_CLIENT_CMD_FUNC(version)
845 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
846 SilcClient client = cmd->client;
847 extern char *silc_version;
848 extern char *silc_name;
849 extern char *silc_fullname;
851 silc_say(client, "%s (%s) version %s", silc_name, silc_fullname,
854 silc_client_command_free(cmd);
857 /* Command MSG. Sends private message to user or list of users. */
858 /* XXX supports only one destination */
860 SILC_CLIENT_CMD_FUNC(msg)
862 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
863 SilcClientWindow win = NULL;
864 SilcClient client = cmd->client;
865 SilcIDCache *id_cache;
867 #define CIDC(x) win->client_id_cache[(x) - 32], \
868 win->client_id_cache_count[(x) - 32]
871 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
875 if (!cmd->client->current_win->sock) {
876 SILC_NOT_CONNECTED(cmd->client);
880 win = (SilcClientWindow)cmd->sock->user_data;
882 /* Find ID from cache */
883 if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
884 &id_cache) == FALSE) {
885 SilcClientCommandContext ctx;
888 SILC_LOG_DEBUG(("Requesting Client ID from server"));
890 /* No ID found. Do query from the server. The query is done by
891 sending simple IDENTIFY command to the server. */
892 ctx = silc_calloc(1, sizeof(*ctx));
893 ctx->client = client;
894 ctx->sock = cmd->sock;
895 memset(ident, 0, sizeof(ident));
896 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
897 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
898 &ctx->argv_types, &ctx->argc, 2);
899 silc_client_command_identify(ctx);
901 /* Mark this command to be pending command and to be executed after
902 we have received the IDENTIFY reply from server. */
903 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
904 silc_client_command_msg, context);
908 /* Display the message for our eyes. */
909 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
911 /* Send the private message */
912 silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
913 cmd->argv[2], cmd->argv_lens[2],
917 silc_client_command_free(cmd);
921 SILC_CLIENT_CMD_FUNC(away)