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.9 2000/07/12 05:56:32 priikone
24 * Major rewrite of ID Cache system. Support added for the new
27 * Revision 1.8 2000/07/10 05:39:11 priikone
28 * Added INFO and VERSION commands. Minor changes to SERVER command
29 * to show current servers when giving without arguments.
31 * Revision 1.7 2000/07/07 06:54:44 priikone
32 * Fixed channel joining bug, do not allow joining twice on the
35 * Revision 1.6 2000/07/06 07:14:36 priikone
36 * Fixes to NAMES command handling.
37 * Fixes when leaving from channel.
39 * Revision 1.5 2000/07/05 06:12:05 priikone
40 * Global cosmetic changes.
42 * Revision 1.4 2000/07/04 08:28:03 priikone
43 * Added INVITE, PING and NAMES command.
45 * Revision 1.3 2000/07/03 05:49:49 priikone
46 * Implemented LEAVE command. Minor bug fixes.
48 * Revision 1.2 2000/06/27 19:38:40 priikone
49 * Added missing goto flag.
51 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
52 * Imported from internal CVS/Added Log headers.
57 #include "clientincludes.h"
59 /* Client command list. */
60 SilcClientCommand silc_command_list[] =
62 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
63 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
64 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
65 SILC_CF_LAG | SILC_CF_REG, 3),
66 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
67 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
68 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
69 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
70 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
71 SILC_CLIENT_CMD(kill, KILL, "KILL",
72 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
73 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
74 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
75 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
76 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
77 SILC_CLIENT_CMD(oper, OPER, "OPER",
78 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
79 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
80 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
81 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
82 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
83 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
84 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
85 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
86 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
87 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
88 SILC_CLIENT_CMD(die, DIE, "DIE",
89 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
90 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
91 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
92 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
93 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
96 * Local. Client specific commands
98 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
99 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
100 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
101 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
102 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
103 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
108 #define SILC_NOT_CONNECTED(x) \
109 silc_say((x), "You are not connected to a server, use /SERVER to connect");
111 /* List of pending commands. */
112 SilcClientCommandPending *silc_command_pending = NULL;
114 /* Add new pending command to the list of pending commands. Currently
115 pending commands are executed from command replies, thus we can
116 execute any command after receiving some specific command reply.
118 The argument `reply_cmd' is the command reply from where the callback
119 function is to be called, thus, it IS NOT the command to be executed.
121 XXX: If needed in the future this support may be extended for
122 commands as well, when any command could be executed after executing
123 some specific command. */
125 void silc_client_command_pending(SilcCommand reply_cmd,
126 SilcClientCommandCallback callback,
129 SilcClientCommandPending *reply, *r;
131 reply = silc_calloc(1, sizeof(*reply));
132 reply->reply_cmd = reply_cmd;
133 reply->context = context;
134 reply->callback = callback;
136 if (silc_command_pending == NULL) {
137 silc_command_pending = reply;
141 for (r = silc_command_pending; r; r = r->next) {
142 if (r->next == NULL) {
149 /* Deletes pending command by reply command type. */
151 void silc_client_command_pending_del(SilcCommand reply_cmd)
153 SilcClientCommandPending *r, *tmp;
155 if (silc_command_pending) {
156 if (silc_command_pending->reply_cmd == reply_cmd) {
157 silc_free(silc_command_pending);
158 silc_command_pending = NULL;
162 for (r = silc_command_pending; r; r = r->next) {
163 if (r->next && r->next->reply_cmd == reply_cmd) {
165 r->next = r->next->next;
173 /* Free command context and its internals */
175 static void silc_client_command_free(SilcClientCommandContext cmd)
180 for (i = 0; i < cmd->argc; i++)
181 silc_free(cmd->argv[i]);
186 /* Command WHOIS. This command is used to query information about
189 SILC_CLIENT_CMD_FUNC(whois)
191 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
194 if (cmd->argc < 2 || cmd->argc > 3) {
195 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
199 if (!cmd->client->current_win->sock) {
200 SILC_NOT_CONNECTED(cmd->client);
204 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
205 cmd->argc - 1, ++cmd->argv,
206 ++cmd->argv_lens, ++cmd->argv_types);
207 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
208 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
209 buffer->data, buffer->len, TRUE);
210 silc_buffer_free(buffer);
216 silc_client_command_free(cmd);
219 SILC_CLIENT_CMD_FUNC(whowas)
223 /* Command IDENTIFY. This command is used to query information about
224 specific user, especially ID's. */
226 SILC_CLIENT_CMD_FUNC(identify)
228 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
231 if (cmd->argc < 2 || cmd->argc > 3) {
232 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
236 if (!cmd->client->current_win->sock) {
237 SILC_NOT_CONNECTED(cmd->client);
241 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
242 cmd->argc - 1, ++cmd->argv,
243 ++cmd->argv_lens, ++cmd->argv_types);
244 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
245 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
246 buffer->data, buffer->len, TRUE);
247 silc_buffer_free(buffer);
253 silc_client_command_free(cmd);
256 /* Command NICK. Shows current nickname/sets new nickname on current
259 SILC_CLIENT_CMD_FUNC(nick)
261 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
262 SilcClientWindow win = NULL;
266 SILC_NOT_CONNECTED(cmd->client);
270 /* Show current nickname */
273 silc_say(cmd->client, "Your nickname is %s on server %s",
274 win->nickname, win->remote_host);
276 silc_say(cmd->client, "Your nickname is %s", win->nickname);
281 win = (SilcClientWindow)cmd->sock->user_data;
283 /* Set new nickname */
284 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
285 cmd->argc - 1, ++cmd->argv,
286 ++cmd->argv_lens, ++cmd->argv_types);
287 silc_client_packet_send(cmd->client, cmd->sock,
288 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
289 buffer->data, buffer->len, TRUE);
290 silc_buffer_free(buffer);
295 silc_free(win->nickname);
296 win->nickname = strdup(cmd->argv[1]);
299 silc_client_command_free(cmd);
302 /* Command SERVER. Connects to remote SILC server. This is local command. */
304 SILC_CLIENT_CMD_FUNC(server)
306 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
307 SilcClient client = cmd->client;
308 int i = 0, len, port;
312 /* Show current servers */
314 if (!cmd->client->current_win->sock) {
315 silc_say(cmd->client, "You are not connected to any server");
316 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
320 silc_say(client, "Current server: %s on %d %s",
321 client->current_win->remote_host,
322 client->current_win->remote_port,
323 client->windows[i]->remote_info ?
324 client->windows[i]->remote_info : "");
326 silc_say(client, "Server list:");
327 for (i = 0; i < client->windows_count; i++) {
328 silc_say(client, " [%d] %s on %d %s", i + 1,
329 client->windows[i]->remote_host,
330 client->windows[i]->remote_port,
331 client->windows[i]->remote_info ?
332 client->windows[i]->remote_info : "");
338 /* See if port is included and then extract it */
339 if (strchr(cmd->argv[1], ':')) {
340 len = strcspn(cmd->argv[1], ":");
341 hostname = silc_calloc(len + 1, sizeof(char));
342 memcpy(hostname, cmd->argv[1], len);
343 port = atoi(cmd->argv[1] + 1 + len);
345 hostname = cmd->argv[1];
349 /* Connect asynchronously to not to block user interface */
350 silc_client_connect_to_server(cmd->client, port, hostname);
353 silc_client_command_free(cmd);
356 SILC_CLIENT_CMD_FUNC(list)
360 SILC_CLIENT_CMD_FUNC(topic)
364 /* Command INVITE. Invites specific client to join a channel. */
366 SILC_CLIENT_CMD_FUNC(invite)
368 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
369 SilcClient client = cmd->client;
370 SilcClientWindow win = NULL;
371 SilcClientEntry client_entry;
372 SilcChannelEntry channel_entry;
374 unsigned int num = 0;
375 char *nickname = NULL, *server = NULL;
376 unsigned char *client_id, *channel_id;
378 if (cmd->argc != 3) {
379 silc_say(cmd->client, "Usage: /INVITE <nickname>[@<server>] <channel>");
383 if (!cmd->client->current_win->sock) {
384 SILC_NOT_CONNECTED(cmd->client);
388 win = (SilcClientWindow)cmd->sock->user_data;
390 /* Parse the typed nickname. */
391 if (!silc_client_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
392 silc_say(cmd->client, "Bad nickname");
396 /* Find client entry */
397 client_entry = silc_idlist_get_client(client, win, nickname, server, num);
399 /* Client entry not found, it was requested thus mark this to be
401 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
402 silc_client_command_invite, context);
406 client_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
408 /* Find channel entry */
409 channel_entry = silc_idlist_get_channel(client, win, cmd->argv[2]);
410 if (!channel_entry) {
411 silc_say(cmd->client, "You are not on that channel");
412 silc_free(client_id);
416 channel_id = silc_id_id2str(channel_entry->id, SILC_ID_CHANNEL);
418 buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
419 1, client_id, SILC_ID_CLIENT_LEN,
420 2, channel_id, SILC_ID_CHANNEL_LEN);
421 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
422 0, NULL, NULL, buffer->data, buffer->len, TRUE);
423 silc_buffer_free(buffer);
425 silc_say(cmd->client, "Inviting %s to channel %s", cmd->argv[1],
429 silc_client_command_free(cmd);
432 /* Command QUIT. Closes connection with current server. */
434 SILC_CLIENT_CMD_FUNC(quit)
436 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
439 if (!cmd->client->current_win->sock) {
440 SILC_NOT_CONNECTED(cmd->client);
444 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
445 ++cmd->argv, ++cmd->argv_lens,
447 silc_client_packet_send(cmd->client, cmd->sock, SILC_PACKET_COMMAND, NULL,
448 0, NULL, NULL, buffer->data, buffer->len, TRUE);
449 silc_buffer_free(buffer);
454 /* Close connection */
455 silc_client_close_connection(cmd->client, cmd->sock);
456 cmd->client->screen->bottom_line->connection = NULL;
457 silc_screen_print_bottom_line(cmd->client->screen, 0);
460 silc_client_command_free(cmd);
463 SILC_CLIENT_CMD_FUNC(kill)
467 /* Command INFO. Request information about specific server. If specific
468 server is not provided the current server is used. */
470 SILC_CLIENT_CMD_FUNC(info)
472 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
473 SilcClientWindow win = NULL;
478 SILC_NOT_CONNECTED(cmd->client);
482 win = (SilcClientWindow)cmd->sock->user_data;
485 name = strdup(win->remote_host);
487 name = strdup(cmd->argv[1]);
489 /* Send the command */
490 buffer = silc_command_encode_payload_va(SILC_COMMAND_INFO, 1,
491 1, name, strlen(name));
492 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
493 0, NULL, NULL, buffer->data, buffer->len, TRUE);
494 silc_buffer_free(buffer);
497 silc_client_command_free(cmd);
500 SILC_CLIENT_CMD_FUNC(connect)
504 /* Command PING. Sends ping to server. This is used to test the
505 communication channel. */
507 SILC_CLIENT_CMD_FUNC(ping)
509 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
510 SilcClientWindow win = NULL;
517 SILC_NOT_CONNECTED(cmd->client);
521 win = (SilcClientWindow)cmd->sock->user_data;
523 if (cmd->argc == 1 || !strcmp(cmd->argv[1], win->remote_host))
524 name = strdup(win->remote_host);
526 id = silc_id_str2id(win->remote_id_data, SILC_ID_SERVER);
528 /* Send the command */
529 buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 1,
530 1, win->remote_id_data,
532 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
533 0, NULL, NULL, buffer->data, buffer->len, TRUE);
534 silc_buffer_free(buffer);
536 /* Start counting time */
537 for (i = 0; i < win->ping_count; i++) {
538 if (win->ping[i].dest_id == NULL) {
539 win->ping[i].start_time = time(NULL);
540 win->ping[i].dest_id = id;
541 win->ping[i].dest_name = name;
546 if (i >= win->ping_count) {
548 win->ping = silc_realloc(win->ping, sizeof(*win->ping) * (i + 1));
549 win->ping[i].start_time = time(NULL);
550 win->ping[i].dest_id = id;
551 win->ping[i].dest_name = name;
556 silc_client_command_free(cmd);
559 SILC_CLIENT_CMD_FUNC(oper)
563 SILC_CLIENT_CMD_FUNC(trace)
567 SILC_CLIENT_CMD_FUNC(notice)
571 /* Command JOIN. Joins to a channel. */
573 SILC_CLIENT_CMD_FUNC(join)
575 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
576 SilcClientWindow win = NULL;
577 SilcIDCacheEntry id_cache = NULL;
581 /* Show channels currently joined to */
582 if (!cmd->client->current_win->sock) {
583 silc_say(cmd->client, "No current channel for this window");
584 SILC_NOT_CONNECTED(cmd->client);
592 if (!cmd->client->current_win->sock) {
593 SILC_NOT_CONNECTED(cmd->client);
597 win = (SilcClientWindow)cmd->sock->user_data;
599 /* See if we have joined to the requested channel already */
600 if (silc_idcache_find_by_data_one(win->channel_cache, cmd->argv[1],
602 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
603 win->current_channel = (SilcChannelEntry)id_cache->context;
604 cmd->client->screen->bottom_line->channel = cmd->argv[1];
605 silc_screen_print_bottom_line(cmd->client->screen, 0);
609 /* Send JOIN command to the server */
610 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
611 cmd->argc - 1, ++cmd->argv,
612 ++cmd->argv_lens, ++cmd->argv_types);
613 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
614 0, NULL, NULL, buffer->data, buffer->len, TRUE);
615 silc_buffer_free(buffer);
621 silc_client_command_free(cmd);
624 SILC_CLIENT_CMD_FUNC(motd)
628 SILC_CLIENT_CMD_FUNC(umode)
632 SILC_CLIENT_CMD_FUNC(cmode)
636 SILC_CLIENT_CMD_FUNC(kick)
640 SILC_CLIENT_CMD_FUNC(restart)
644 SILC_CLIENT_CMD_FUNC(close)
648 SILC_CLIENT_CMD_FUNC(die)
652 SILC_CLIENT_CMD_FUNC(silcoper)
656 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
658 SILC_CLIENT_CMD_FUNC(leave)
660 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
661 SilcClientWindow win = NULL;
662 SilcIDCacheEntry id_cache = NULL;
663 SilcChannelEntry channel;
665 unsigned char *id_string;
668 if (cmd->argc != 2) {
669 silc_say(cmd->client, "Usage: /LEAVE <channel>");
673 if (!cmd->client->current_win->sock) {
674 SILC_NOT_CONNECTED(cmd->client);
678 win = (SilcClientWindow)cmd->sock->user_data;
680 if (cmd->argv[1][0] == '*') {
681 if (!win->current_channel) {
682 silc_say(cmd->client, "You are not on any chanenl");
685 name = win->current_channel->channel_name;
690 if (!win->current_channel) {
691 silc_say(cmd->client, "You are not on that channel");
695 /* Get the Channel ID of the channel */
696 if (!silc_idcache_find_by_data_one(win->channel_cache, name, &id_cache)) {
697 silc_say(cmd->client, "You are not on that channel");
701 channel = (SilcChannelEntry)id_cache->context;
703 /* Send LEAVE command to the server */
704 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
705 buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1,
706 1, id_string, SILC_ID_CHANNEL_LEN);
707 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
708 0, NULL, NULL, buffer->data, buffer->len, TRUE);
709 silc_buffer_free(buffer);
711 /* We won't talk anymore on this channel */
712 silc_say(cmd->client, "You have left channel %s", name);
714 if (!strncmp(win->current_channel->channel_name, name, strlen(name))) {
715 cmd->client->screen->bottom_line->channel = NULL;
716 silc_screen_print_bottom_line(cmd->client->screen, 0);
717 win->current_channel = NULL;
720 silc_idcache_del_by_id(win->channel_cache, SILC_ID_CHANNEL, channel->id);
721 silc_free(channel->channel_name);
722 silc_free(channel->id);
723 silc_free(channel->key);
724 silc_cipher_free(channel->channel_key);
726 silc_free(id_string);
729 silc_client_command_free(cmd);
732 /* Command NAMES. Requests the names of the clients joined on requested
735 SILC_CLIENT_CMD_FUNC(names)
737 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
738 SilcClientWindow win = NULL;
739 SilcIDCacheEntry id_cache = NULL;
742 unsigned char *id_string;
744 if (cmd->argc != 2) {
745 silc_say(cmd->client, "Usage: /NAMES <channel>");
749 if (!cmd->client->current_win->sock) {
750 SILC_NOT_CONNECTED(cmd->client);
754 win = (SilcClientWindow)cmd->sock->user_data;
756 if (cmd->argv[1][0] == '*')
757 name = win->current_channel->channel_name;
761 /* Get the Channel ID of the channel */
762 if (!silc_idcache_find_by_data_one(win->channel_cache, name, &id_cache)) {
763 /* XXX should resolve the channel ID; LIST command */
764 silc_say(cmd->client, "You are not on that channel", name);
768 /* Send NAMES command to the server */
769 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
770 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
771 1, id_string, SILC_ID_CHANNEL_LEN);
772 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
773 0, NULL, NULL, buffer->data, buffer->len, TRUE);
774 silc_buffer_free(buffer);
775 silc_free(id_string);
777 /* Register dummy pending command that will tell the reply command
778 that user called this command. Server may send reply to this command
779 even if user did not send this command thus we want to handle things
780 differently when user sent the command. This is dummy and won't be
782 /* XXX this is kludge and should be removed after pending command reply
783 support is added. Currently only commands may be pending not command
785 silc_client_command_pending(SILC_COMMAND_NAMES,
786 silc_client_command_names, NULL);
789 silc_client_command_free(cmd);
796 /* HELP command. This is local command and shows help on SILC */
798 SILC_CLIENT_CMD_FUNC(help)
803 /* CLEAR command. This is local command and clears current output window */
805 SILC_CLIENT_CMD_FUNC(clear)
807 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
808 SilcClient client = cmd->client;
810 assert(client->current_win != NULL);
811 wclear((WINDOW *)client->current_win->screen);
812 wrefresh((WINDOW *)client->current_win->screen);
814 silc_client_command_free(cmd);
817 /* VERSION command. This is local command and shows version of the client */
819 SILC_CLIENT_CMD_FUNC(version)
821 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
822 SilcClient client = cmd->client;
823 extern char *silc_version;
824 extern char *silc_name;
825 extern char *silc_fullname;
827 silc_say(client, "%s (%s) version %s", silc_name, silc_fullname,
830 silc_client_command_free(cmd);
833 /* Command MSG. Sends private message to user or list of users. */
834 /* XXX supports only one destination */
836 SILC_CLIENT_CMD_FUNC(msg)
838 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
839 SilcClientWindow win = NULL;
840 SilcClient client = cmd->client;
841 SilcClientEntry client_entry = NULL;
842 unsigned int num = 0;
843 char *nickname = NULL, *server = NULL;
846 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
850 if (!cmd->client->current_win->sock) {
851 SILC_NOT_CONNECTED(cmd->client);
855 win = (SilcClientWindow)cmd->sock->user_data;
857 /* Parse the typed nickname. */
858 if (!silc_client_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
859 silc_say(cmd->client, "Bad nickname");
863 /* Find client entry */
864 client_entry = silc_idlist_get_client(client, win, nickname, server, num);
866 /* Client entry not found, it was requested thus mark this to be
868 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
869 silc_client_command_msg, context);
873 /* Display the message for our eyes. */
874 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
876 /* Send the private message */
877 silc_client_packet_send_private_message(client, cmd->sock, client_entry,
878 cmd->argv[2], cmd->argv_lens[2],
882 silc_client_command_free(cmd);
885 SILC_CLIENT_CMD_FUNC(away)