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.11 2000/07/19 09:19:05 priikone
24 * Enhancements to AWAY command.
26 * Revision 1.10 2000/07/19 07:06:33 priikone
29 * Revision 1.9 2000/07/12 05:56:32 priikone
30 * Major rewrite of ID Cache system. Support added for the new
33 * Revision 1.8 2000/07/10 05:39:11 priikone
34 * Added INFO and VERSION commands. Minor changes to SERVER command
35 * to show current servers when giving without arguments.
37 * Revision 1.7 2000/07/07 06:54:44 priikone
38 * Fixed channel joining bug, do not allow joining twice on the
41 * Revision 1.6 2000/07/06 07:14:36 priikone
42 * Fixes to NAMES command handling.
43 * Fixes when leaving from channel.
45 * Revision 1.5 2000/07/05 06:12:05 priikone
46 * Global cosmetic changes.
48 * Revision 1.4 2000/07/04 08:28:03 priikone
49 * Added INVITE, PING and NAMES command.
51 * Revision 1.3 2000/07/03 05:49:49 priikone
52 * Implemented LEAVE command. Minor bug fixes.
54 * Revision 1.2 2000/06/27 19:38:40 priikone
55 * Added missing goto flag.
57 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
58 * Imported from internal CVS/Added Log headers.
63 #include "clientincludes.h"
65 /* Client command list. */
66 SilcClientCommand silc_command_list[] =
68 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
69 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
70 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
71 SILC_CF_LAG | SILC_CF_REG, 3),
72 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
73 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
74 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
75 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
76 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
77 SILC_CLIENT_CMD(kill, KILL, "KILL",
78 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
79 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
80 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
81 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
82 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
83 SILC_CLIENT_CMD(oper, OPER, "OPER",
84 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
85 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
86 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
87 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
88 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
89 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
90 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
91 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
92 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
93 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
94 SILC_CLIENT_CMD(die, DIE, "DIE",
95 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
96 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
97 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
98 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
99 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
102 * Local. Client specific commands
104 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
105 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
106 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
107 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
108 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
109 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
114 #define SILC_NOT_CONNECTED(x) \
115 silc_say((x), "You are not connected to a server, use /SERVER to connect");
117 /* List of pending commands. */
118 SilcClientCommandPending *silc_command_pending = NULL;
120 /* Add new pending command to the list of pending commands. Currently
121 pending commands are executed from command replies, thus we can
122 execute any command after receiving some specific command reply.
124 The argument `reply_cmd' is the command reply from where the callback
125 function is to be called, thus, it IS NOT the command to be executed.
127 XXX: If needed in the future this support may be extended for
128 commands as well, when any command could be executed after executing
129 some specific command. */
131 void silc_client_command_pending(SilcCommand reply_cmd,
132 SilcClientCommandCallback callback,
135 SilcClientCommandPending *reply, *r;
137 reply = silc_calloc(1, sizeof(*reply));
138 reply->reply_cmd = reply_cmd;
139 reply->context = context;
140 reply->callback = callback;
142 if (silc_command_pending == NULL) {
143 silc_command_pending = reply;
147 for (r = silc_command_pending; r; r = r->next) {
148 if (r->next == NULL) {
155 /* Deletes pending command by reply command type. */
157 void silc_client_command_pending_del(SilcCommand reply_cmd)
159 SilcClientCommandPending *r, *tmp;
161 if (silc_command_pending) {
162 if (silc_command_pending->reply_cmd == reply_cmd) {
163 silc_free(silc_command_pending);
164 silc_command_pending = NULL;
168 for (r = silc_command_pending; r; r = r->next) {
169 if (r->next && r->next->reply_cmd == reply_cmd) {
171 r->next = r->next->next;
179 /* Free command context and its internals */
181 static void silc_client_command_free(SilcClientCommandContext cmd)
186 for (i = 0; i < cmd->argc; i++)
187 silc_free(cmd->argv[i]);
192 /* Command WHOIS. This command is used to query information about
195 SILC_CLIENT_CMD_FUNC(whois)
197 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
200 if (cmd->argc < 2 || cmd->argc > 3) {
201 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
205 if (!cmd->client->current_win->sock) {
206 SILC_NOT_CONNECTED(cmd->client);
210 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
211 cmd->argc - 1, ++cmd->argv,
212 ++cmd->argv_lens, ++cmd->argv_types);
213 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
214 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
215 buffer->data, buffer->len, TRUE);
216 silc_buffer_free(buffer);
222 silc_client_command_free(cmd);
225 SILC_CLIENT_CMD_FUNC(whowas)
229 /* Command IDENTIFY. This command is used to query information about
230 specific user, especially ID's. */
232 SILC_CLIENT_CMD_FUNC(identify)
234 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
237 if (cmd->argc < 2 || cmd->argc > 3) {
238 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
242 if (!cmd->client->current_win->sock) {
243 SILC_NOT_CONNECTED(cmd->client);
247 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
248 cmd->argc - 1, ++cmd->argv,
249 ++cmd->argv_lens, ++cmd->argv_types);
250 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
251 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
252 buffer->data, buffer->len, TRUE);
253 silc_buffer_free(buffer);
259 silc_client_command_free(cmd);
262 /* Command NICK. Shows current nickname/sets new nickname on current
265 SILC_CLIENT_CMD_FUNC(nick)
267 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
268 SilcClientWindow win = NULL;
272 SILC_NOT_CONNECTED(cmd->client);
276 /* Show current nickname */
279 silc_say(cmd->client, "Your nickname is %s on server %s",
280 win->nickname, win->remote_host);
282 silc_say(cmd->client, "Your nickname is %s", win->nickname);
287 win = (SilcClientWindow)cmd->sock->user_data;
289 /* Set new nickname */
290 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
291 cmd->argc - 1, ++cmd->argv,
292 ++cmd->argv_lens, ++cmd->argv_types);
293 silc_client_packet_send(cmd->client, cmd->sock,
294 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
295 buffer->data, buffer->len, TRUE);
296 silc_buffer_free(buffer);
301 silc_free(win->nickname);
302 win->nickname = strdup(cmd->argv[1]);
305 silc_client_command_free(cmd);
308 /* Command SERVER. Connects to remote SILC server. This is local command. */
310 SILC_CLIENT_CMD_FUNC(server)
312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
313 SilcClient client = cmd->client;
314 int i = 0, len, port;
318 /* Show current servers */
320 if (!cmd->client->current_win->sock) {
321 silc_say(cmd->client, "You are not connected to any server");
322 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
326 silc_say(client, "Current server: %s on %d %s",
327 client->current_win->remote_host,
328 client->current_win->remote_port,
329 client->windows[i]->remote_info ?
330 client->windows[i]->remote_info : "");
332 silc_say(client, "Server list:");
333 for (i = 0; i < client->windows_count; i++) {
334 silc_say(client, " [%d] %s on %d %s", i + 1,
335 client->windows[i]->remote_host,
336 client->windows[i]->remote_port,
337 client->windows[i]->remote_info ?
338 client->windows[i]->remote_info : "");
344 /* See if port is included and then extract it */
345 if (strchr(cmd->argv[1], ':')) {
346 len = strcspn(cmd->argv[1], ":");
347 hostname = silc_calloc(len + 1, sizeof(char));
348 memcpy(hostname, cmd->argv[1], len);
349 port = atoi(cmd->argv[1] + 1 + len);
351 hostname = cmd->argv[1];
355 /* Connect asynchronously to not to block user interface */
356 silc_client_connect_to_server(cmd->client, port, hostname);
359 silc_client_command_free(cmd);
362 SILC_CLIENT_CMD_FUNC(list)
366 SILC_CLIENT_CMD_FUNC(topic)
370 /* Command INVITE. Invites specific client to join a channel. */
372 SILC_CLIENT_CMD_FUNC(invite)
374 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
375 SilcClient client = cmd->client;
376 SilcClientWindow win = NULL;
377 SilcClientEntry client_entry;
378 SilcChannelEntry channel_entry;
380 unsigned int num = 0;
381 char *nickname = NULL, *server = NULL;
382 unsigned char *client_id, *channel_id;
384 if (cmd->argc != 3) {
385 silc_say(cmd->client, "Usage: /INVITE <nickname>[@<server>] <channel>");
389 if (!cmd->client->current_win->sock) {
390 SILC_NOT_CONNECTED(cmd->client);
394 win = (SilcClientWindow)cmd->sock->user_data;
396 /* Parse the typed nickname. */
397 if (!silc_client_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
398 silc_say(cmd->client, "Bad nickname");
402 /* Find client entry */
403 client_entry = silc_idlist_get_client(client, win, nickname, server, num);
405 /* Client entry not found, it was requested thus mark this to be
407 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
408 silc_client_command_invite, context);
412 client_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
414 /* Find channel entry */
415 channel_entry = silc_idlist_get_channel(client, win, cmd->argv[2]);
416 if (!channel_entry) {
417 silc_say(cmd->client, "You are not on that channel");
418 silc_free(client_id);
422 channel_id = silc_id_id2str(channel_entry->id, SILC_ID_CHANNEL);
424 buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
425 1, client_id, SILC_ID_CLIENT_LEN,
426 2, channel_id, SILC_ID_CHANNEL_LEN);
427 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
428 0, NULL, NULL, buffer->data, buffer->len, TRUE);
429 silc_buffer_free(buffer);
431 silc_say(cmd->client, "Inviting %s to channel %s", cmd->argv[1],
435 silc_client_command_free(cmd);
438 /* Command QUIT. Closes connection with current server. */
440 SILC_CLIENT_CMD_FUNC(quit)
442 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
445 if (!cmd->client->current_win->sock) {
446 SILC_NOT_CONNECTED(cmd->client);
450 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
451 ++cmd->argv, ++cmd->argv_lens,
453 silc_client_packet_send(cmd->client, cmd->sock, SILC_PACKET_COMMAND, NULL,
454 0, NULL, NULL, buffer->data, buffer->len, TRUE);
455 silc_buffer_free(buffer);
460 /* Close connection */
461 silc_client_close_connection(cmd->client, cmd->sock);
462 cmd->client->screen->bottom_line->connection = NULL;
463 silc_screen_print_bottom_line(cmd->client->screen, 0);
466 silc_client_command_free(cmd);
469 SILC_CLIENT_CMD_FUNC(kill)
473 /* Command INFO. Request information about specific server. If specific
474 server is not provided the current server is used. */
476 SILC_CLIENT_CMD_FUNC(info)
478 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
479 SilcClientWindow win = NULL;
484 SILC_NOT_CONNECTED(cmd->client);
488 win = (SilcClientWindow)cmd->sock->user_data;
491 name = strdup(win->remote_host);
493 name = strdup(cmd->argv[1]);
495 /* Send the command */
496 buffer = silc_command_encode_payload_va(SILC_COMMAND_INFO, 1,
497 1, name, strlen(name));
498 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
499 0, NULL, NULL, buffer->data, buffer->len, TRUE);
500 silc_buffer_free(buffer);
503 silc_client_command_free(cmd);
506 SILC_CLIENT_CMD_FUNC(connect)
510 /* Command PING. Sends ping to server. This is used to test the
511 communication channel. */
513 SILC_CLIENT_CMD_FUNC(ping)
515 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
516 SilcClientWindow win = NULL;
523 SILC_NOT_CONNECTED(cmd->client);
527 win = (SilcClientWindow)cmd->sock->user_data;
529 if (cmd->argc == 1 || !strcmp(cmd->argv[1], win->remote_host))
530 name = strdup(win->remote_host);
532 id = silc_id_str2id(win->remote_id_data, SILC_ID_SERVER);
534 /* Send the command */
535 buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 1,
536 1, win->remote_id_data,
538 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
539 0, NULL, NULL, buffer->data, buffer->len, TRUE);
540 silc_buffer_free(buffer);
542 /* Start counting time */
543 for (i = 0; i < win->ping_count; i++) {
544 if (win->ping[i].dest_id == NULL) {
545 win->ping[i].start_time = time(NULL);
546 win->ping[i].dest_id = id;
547 win->ping[i].dest_name = name;
552 if (i >= win->ping_count) {
554 win->ping = silc_realloc(win->ping, sizeof(*win->ping) * (i + 1));
555 win->ping[i].start_time = time(NULL);
556 win->ping[i].dest_id = id;
557 win->ping[i].dest_name = name;
562 silc_client_command_free(cmd);
565 SILC_CLIENT_CMD_FUNC(oper)
569 SILC_CLIENT_CMD_FUNC(trace)
573 SILC_CLIENT_CMD_FUNC(notice)
577 /* Command JOIN. Joins to a channel. */
579 SILC_CLIENT_CMD_FUNC(join)
581 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
582 SilcClientWindow win = NULL;
583 SilcIDCacheEntry id_cache = NULL;
587 /* Show channels currently joined to */
588 if (!cmd->client->current_win->sock) {
589 silc_say(cmd->client, "No current channel for this window");
590 SILC_NOT_CONNECTED(cmd->client);
598 if (!cmd->client->current_win->sock) {
599 SILC_NOT_CONNECTED(cmd->client);
603 win = (SilcClientWindow)cmd->sock->user_data;
605 /* See if we have joined to the requested channel already */
606 if (silc_idcache_find_by_data_one(win->channel_cache, cmd->argv[1],
608 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
609 win->current_channel = (SilcChannelEntry)id_cache->context;
610 cmd->client->screen->bottom_line->channel = cmd->argv[1];
611 silc_screen_print_bottom_line(cmd->client->screen, 0);
615 /* Send JOIN command to the server */
616 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
617 cmd->argc - 1, ++cmd->argv,
618 ++cmd->argv_lens, ++cmd->argv_types);
619 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
620 0, NULL, NULL, buffer->data, buffer->len, TRUE);
621 silc_buffer_free(buffer);
627 silc_client_command_free(cmd);
630 SILC_CLIENT_CMD_FUNC(motd)
634 SILC_CLIENT_CMD_FUNC(umode)
638 SILC_CLIENT_CMD_FUNC(cmode)
642 SILC_CLIENT_CMD_FUNC(kick)
646 SILC_CLIENT_CMD_FUNC(restart)
650 SILC_CLIENT_CMD_FUNC(close)
654 SILC_CLIENT_CMD_FUNC(die)
658 SILC_CLIENT_CMD_FUNC(silcoper)
662 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
664 SILC_CLIENT_CMD_FUNC(leave)
666 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
667 SilcClientWindow win = NULL;
668 SilcIDCacheEntry id_cache = NULL;
669 SilcChannelEntry channel;
671 unsigned char *id_string;
674 if (cmd->argc != 2) {
675 silc_say(cmd->client, "Usage: /LEAVE <channel>");
679 if (!cmd->client->current_win->sock) {
680 SILC_NOT_CONNECTED(cmd->client);
684 win = (SilcClientWindow)cmd->sock->user_data;
686 if (cmd->argv[1][0] == '*') {
687 if (!win->current_channel) {
688 silc_say(cmd->client, "You are not on any chanenl");
691 name = win->current_channel->channel_name;
696 if (!win->current_channel) {
697 silc_say(cmd->client, "You are not on that channel");
701 /* Get the Channel ID of the channel */
702 if (!silc_idcache_find_by_data_one(win->channel_cache, name, &id_cache)) {
703 silc_say(cmd->client, "You are not on that channel");
707 channel = (SilcChannelEntry)id_cache->context;
709 /* Send LEAVE command to the server */
710 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
711 buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1,
712 1, id_string, SILC_ID_CHANNEL_LEN);
713 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
714 0, NULL, NULL, buffer->data, buffer->len, TRUE);
715 silc_buffer_free(buffer);
717 /* We won't talk anymore on this channel */
718 silc_say(cmd->client, "You have left channel %s", name);
720 if (!strncmp(win->current_channel->channel_name, name, strlen(name))) {
721 cmd->client->screen->bottom_line->channel = NULL;
722 silc_screen_print_bottom_line(cmd->client->screen, 0);
723 win->current_channel = NULL;
726 silc_idcache_del_by_id(win->channel_cache, SILC_ID_CHANNEL, channel->id);
727 silc_free(channel->channel_name);
728 silc_free(channel->id);
729 silc_free(channel->key);
730 silc_cipher_free(channel->channel_key);
732 silc_free(id_string);
735 silc_client_command_free(cmd);
738 /* Command NAMES. Requests the names of the clients joined on requested
741 SILC_CLIENT_CMD_FUNC(names)
743 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
744 SilcClientWindow win = NULL;
745 SilcIDCacheEntry id_cache = NULL;
748 unsigned char *id_string;
750 if (cmd->argc != 2) {
751 silc_say(cmd->client, "Usage: /NAMES <channel>");
755 if (!cmd->client->current_win->sock) {
756 SILC_NOT_CONNECTED(cmd->client);
760 win = (SilcClientWindow)cmd->sock->user_data;
762 if (cmd->argv[1][0] == '*')
763 name = win->current_channel->channel_name;
767 /* Get the Channel ID of the channel */
768 if (!silc_idcache_find_by_data_one(win->channel_cache, name, &id_cache)) {
769 /* XXX should resolve the channel ID; LIST command */
770 silc_say(cmd->client, "You are not on that channel", name);
774 /* Send NAMES command to the server */
775 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
776 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
777 1, id_string, SILC_ID_CHANNEL_LEN);
778 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
779 0, NULL, NULL, buffer->data, buffer->len, TRUE);
780 silc_buffer_free(buffer);
781 silc_free(id_string);
783 /* Register dummy pending command that will tell the reply command
784 that user called this command. Server may send reply to this command
785 even if user did not send this command thus we want to handle things
786 differently when user sent the command. This is dummy and won't be
788 /* XXX this is kludge and should be removed after pending command reply
789 support is added. Currently only commands may be pending not command
791 silc_client_command_pending(SILC_COMMAND_NAMES,
792 silc_client_command_names, NULL);
795 silc_client_command_free(cmd);
802 /* HELP command. This is local command and shows help on SILC */
804 SILC_CLIENT_CMD_FUNC(help)
809 /* CLEAR command. This is local command and clears current output window */
811 SILC_CLIENT_CMD_FUNC(clear)
813 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
814 SilcClient client = cmd->client;
816 assert(client->current_win != NULL);
817 wclear((WINDOW *)client->current_win->screen);
818 wrefresh((WINDOW *)client->current_win->screen);
820 silc_client_command_free(cmd);
823 /* VERSION command. This is local command and shows version of the client */
825 SILC_CLIENT_CMD_FUNC(version)
827 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
828 SilcClient client = cmd->client;
829 extern char *silc_version;
830 extern char *silc_name;
831 extern char *silc_fullname;
833 silc_say(client, "%s (%s) version %s", silc_name, silc_fullname,
836 silc_client_command_free(cmd);
839 /* Command MSG. Sends private message to user or list of users. Note that
840 private messages are not really commands, they are message packets,
841 however, on user interface it is convenient to show them as commands
842 as that is the common way of sending private messages (like in IRC). */
843 /* XXX supports only one destination */
845 SILC_CLIENT_CMD_FUNC(msg)
847 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
848 SilcClientWindow win = NULL;
849 SilcClient client = cmd->client;
850 SilcClientEntry client_entry = NULL;
851 unsigned int num = 0;
852 char *nickname = NULL, *server = NULL;
855 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
859 if (!cmd->client->current_win->sock) {
860 SILC_NOT_CONNECTED(cmd->client);
864 win = (SilcClientWindow)cmd->sock->user_data;
866 /* Parse the typed nickname. */
867 if (!silc_client_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
868 silc_say(cmd->client, "Bad nickname");
872 /* Find client entry */
873 client_entry = silc_idlist_get_client(client, win, nickname, server, num);
875 /* Client entry not found, it was requested thus mark this to be
877 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
878 silc_client_command_msg, context);
882 /* Display the message for our eyes. */
883 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
885 /* Send the private message */
886 silc_client_packet_send_private_message(client, cmd->sock, client_entry,
887 cmd->argv[2], cmd->argv_lens[2],
891 silc_client_command_free(cmd);
894 /* Local command AWAY. Client replies with away message to whomever sends
895 private message to the client if the away message is set. If this is
896 given without arguments the away message is removed. */
898 SILC_CLIENT_CMD_FUNC(away)
900 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
901 SilcClientWindow win = NULL;
902 SilcClient client = cmd->client;
904 if (!cmd->client->current_win->sock) {
905 SILC_NOT_CONNECTED(cmd->client);
909 win = (SilcClientWindow)cmd->sock->user_data;
911 if (cmd->argc == 1) {
913 silc_free(win->away->away);
914 silc_free(win->away);
916 client->screen->bottom_line->away = FALSE;
918 silc_say(client, "Away message removed");
919 silc_screen_print_bottom_line(cmd->client->screen, 0);
924 silc_free(win->away->away);
926 win->away = silc_calloc(1, sizeof(*win->away));
928 client->screen->bottom_line->away = TRUE;
929 win->away->away = strdup(cmd->argv[1]);
931 silc_say(client, "Away message set: %s", win->away->away);
932 silc_screen_print_bottom_line(cmd->client->screen, 0);
936 silc_client_command_free(cmd);