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.10 2000/07/19 07:06:33 priikone
26 * Revision 1.9 2000/07/12 05:56:32 priikone
27 * Major rewrite of ID Cache system. Support added for the new
30 * Revision 1.8 2000/07/10 05:39:11 priikone
31 * Added INFO and VERSION commands. Minor changes to SERVER command
32 * to show current servers when giving without arguments.
34 * Revision 1.7 2000/07/07 06:54:44 priikone
35 * Fixed channel joining bug, do not allow joining twice on the
38 * Revision 1.6 2000/07/06 07:14:36 priikone
39 * Fixes to NAMES command handling.
40 * Fixes when leaving from channel.
42 * Revision 1.5 2000/07/05 06:12:05 priikone
43 * Global cosmetic changes.
45 * Revision 1.4 2000/07/04 08:28:03 priikone
46 * Added INVITE, PING and NAMES command.
48 * Revision 1.3 2000/07/03 05:49:49 priikone
49 * Implemented LEAVE command. Minor bug fixes.
51 * Revision 1.2 2000/06/27 19:38:40 priikone
52 * Added missing goto flag.
54 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
55 * Imported from internal CVS/Added Log headers.
60 #include "clientincludes.h"
62 /* Client command list. */
63 SilcClientCommand silc_command_list[] =
65 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
66 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
67 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
68 SILC_CF_LAG | SILC_CF_REG, 3),
69 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
70 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
71 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
72 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
73 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
74 SILC_CLIENT_CMD(kill, KILL, "KILL",
75 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
76 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
77 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
78 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
79 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
80 SILC_CLIENT_CMD(oper, OPER, "OPER",
81 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
82 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
83 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
84 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
85 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
86 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
87 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
88 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
89 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
90 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
91 SILC_CLIENT_CMD(die, DIE, "DIE",
92 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
93 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
94 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
95 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
96 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
99 * Local. Client specific commands
101 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
102 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
103 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
104 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
105 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
106 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
111 #define SILC_NOT_CONNECTED(x) \
112 silc_say((x), "You are not connected to a server, use /SERVER to connect");
114 /* List of pending commands. */
115 SilcClientCommandPending *silc_command_pending = NULL;
117 /* Add new pending command to the list of pending commands. Currently
118 pending commands are executed from command replies, thus we can
119 execute any command after receiving some specific command reply.
121 The argument `reply_cmd' is the command reply from where the callback
122 function is to be called, thus, it IS NOT the command to be executed.
124 XXX: If needed in the future this support may be extended for
125 commands as well, when any command could be executed after executing
126 some specific command. */
128 void silc_client_command_pending(SilcCommand reply_cmd,
129 SilcClientCommandCallback callback,
132 SilcClientCommandPending *reply, *r;
134 reply = silc_calloc(1, sizeof(*reply));
135 reply->reply_cmd = reply_cmd;
136 reply->context = context;
137 reply->callback = callback;
139 if (silc_command_pending == NULL) {
140 silc_command_pending = reply;
144 for (r = silc_command_pending; r; r = r->next) {
145 if (r->next == NULL) {
152 /* Deletes pending command by reply command type. */
154 void silc_client_command_pending_del(SilcCommand reply_cmd)
156 SilcClientCommandPending *r, *tmp;
158 if (silc_command_pending) {
159 if (silc_command_pending->reply_cmd == reply_cmd) {
160 silc_free(silc_command_pending);
161 silc_command_pending = NULL;
165 for (r = silc_command_pending; r; r = r->next) {
166 if (r->next && r->next->reply_cmd == reply_cmd) {
168 r->next = r->next->next;
176 /* Free command context and its internals */
178 static void silc_client_command_free(SilcClientCommandContext cmd)
183 for (i = 0; i < cmd->argc; i++)
184 silc_free(cmd->argv[i]);
189 /* Command WHOIS. This command is used to query information about
192 SILC_CLIENT_CMD_FUNC(whois)
194 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
197 if (cmd->argc < 2 || cmd->argc > 3) {
198 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
202 if (!cmd->client->current_win->sock) {
203 SILC_NOT_CONNECTED(cmd->client);
207 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
208 cmd->argc - 1, ++cmd->argv,
209 ++cmd->argv_lens, ++cmd->argv_types);
210 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
211 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
212 buffer->data, buffer->len, TRUE);
213 silc_buffer_free(buffer);
219 silc_client_command_free(cmd);
222 SILC_CLIENT_CMD_FUNC(whowas)
226 /* Command IDENTIFY. This command is used to query information about
227 specific user, especially ID's. */
229 SILC_CLIENT_CMD_FUNC(identify)
231 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
234 if (cmd->argc < 2 || cmd->argc > 3) {
235 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
239 if (!cmd->client->current_win->sock) {
240 SILC_NOT_CONNECTED(cmd->client);
244 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
245 cmd->argc - 1, ++cmd->argv,
246 ++cmd->argv_lens, ++cmd->argv_types);
247 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
248 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
249 buffer->data, buffer->len, TRUE);
250 silc_buffer_free(buffer);
256 silc_client_command_free(cmd);
259 /* Command NICK. Shows current nickname/sets new nickname on current
262 SILC_CLIENT_CMD_FUNC(nick)
264 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
265 SilcClientWindow win = NULL;
269 SILC_NOT_CONNECTED(cmd->client);
273 /* Show current nickname */
276 silc_say(cmd->client, "Your nickname is %s on server %s",
277 win->nickname, win->remote_host);
279 silc_say(cmd->client, "Your nickname is %s", win->nickname);
284 win = (SilcClientWindow)cmd->sock->user_data;
286 /* Set new nickname */
287 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
288 cmd->argc - 1, ++cmd->argv,
289 ++cmd->argv_lens, ++cmd->argv_types);
290 silc_client_packet_send(cmd->client, cmd->sock,
291 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
292 buffer->data, buffer->len, TRUE);
293 silc_buffer_free(buffer);
298 silc_free(win->nickname);
299 win->nickname = strdup(cmd->argv[1]);
302 silc_client_command_free(cmd);
305 /* Command SERVER. Connects to remote SILC server. This is local command. */
307 SILC_CLIENT_CMD_FUNC(server)
309 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
310 SilcClient client = cmd->client;
311 int i = 0, len, port;
315 /* Show current servers */
317 if (!cmd->client->current_win->sock) {
318 silc_say(cmd->client, "You are not connected to any server");
319 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
323 silc_say(client, "Current server: %s on %d %s",
324 client->current_win->remote_host,
325 client->current_win->remote_port,
326 client->windows[i]->remote_info ?
327 client->windows[i]->remote_info : "");
329 silc_say(client, "Server list:");
330 for (i = 0; i < client->windows_count; i++) {
331 silc_say(client, " [%d] %s on %d %s", i + 1,
332 client->windows[i]->remote_host,
333 client->windows[i]->remote_port,
334 client->windows[i]->remote_info ?
335 client->windows[i]->remote_info : "");
341 /* See if port is included and then extract it */
342 if (strchr(cmd->argv[1], ':')) {
343 len = strcspn(cmd->argv[1], ":");
344 hostname = silc_calloc(len + 1, sizeof(char));
345 memcpy(hostname, cmd->argv[1], len);
346 port = atoi(cmd->argv[1] + 1 + len);
348 hostname = cmd->argv[1];
352 /* Connect asynchronously to not to block user interface */
353 silc_client_connect_to_server(cmd->client, port, hostname);
356 silc_client_command_free(cmd);
359 SILC_CLIENT_CMD_FUNC(list)
363 SILC_CLIENT_CMD_FUNC(topic)
367 /* Command INVITE. Invites specific client to join a channel. */
369 SILC_CLIENT_CMD_FUNC(invite)
371 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
372 SilcClient client = cmd->client;
373 SilcClientWindow win = NULL;
374 SilcClientEntry client_entry;
375 SilcChannelEntry channel_entry;
377 unsigned int num = 0;
378 char *nickname = NULL, *server = NULL;
379 unsigned char *client_id, *channel_id;
381 if (cmd->argc != 3) {
382 silc_say(cmd->client, "Usage: /INVITE <nickname>[@<server>] <channel>");
386 if (!cmd->client->current_win->sock) {
387 SILC_NOT_CONNECTED(cmd->client);
391 win = (SilcClientWindow)cmd->sock->user_data;
393 /* Parse the typed nickname. */
394 if (!silc_client_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
395 silc_say(cmd->client, "Bad nickname");
399 /* Find client entry */
400 client_entry = silc_idlist_get_client(client, win, nickname, server, num);
402 /* Client entry not found, it was requested thus mark this to be
404 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
405 silc_client_command_invite, context);
409 client_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
411 /* Find channel entry */
412 channel_entry = silc_idlist_get_channel(client, win, cmd->argv[2]);
413 if (!channel_entry) {
414 silc_say(cmd->client, "You are not on that channel");
415 silc_free(client_id);
419 channel_id = silc_id_id2str(channel_entry->id, SILC_ID_CHANNEL);
421 buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
422 1, client_id, SILC_ID_CLIENT_LEN,
423 2, channel_id, SILC_ID_CHANNEL_LEN);
424 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
425 0, NULL, NULL, buffer->data, buffer->len, TRUE);
426 silc_buffer_free(buffer);
428 silc_say(cmd->client, "Inviting %s to channel %s", cmd->argv[1],
432 silc_client_command_free(cmd);
435 /* Command QUIT. Closes connection with current server. */
437 SILC_CLIENT_CMD_FUNC(quit)
439 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
442 if (!cmd->client->current_win->sock) {
443 SILC_NOT_CONNECTED(cmd->client);
447 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
448 ++cmd->argv, ++cmd->argv_lens,
450 silc_client_packet_send(cmd->client, cmd->sock, SILC_PACKET_COMMAND, NULL,
451 0, NULL, NULL, buffer->data, buffer->len, TRUE);
452 silc_buffer_free(buffer);
457 /* Close connection */
458 silc_client_close_connection(cmd->client, cmd->sock);
459 cmd->client->screen->bottom_line->connection = NULL;
460 silc_screen_print_bottom_line(cmd->client->screen, 0);
463 silc_client_command_free(cmd);
466 SILC_CLIENT_CMD_FUNC(kill)
470 /* Command INFO. Request information about specific server. If specific
471 server is not provided the current server is used. */
473 SILC_CLIENT_CMD_FUNC(info)
475 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
476 SilcClientWindow win = NULL;
481 SILC_NOT_CONNECTED(cmd->client);
485 win = (SilcClientWindow)cmd->sock->user_data;
488 name = strdup(win->remote_host);
490 name = strdup(cmd->argv[1]);
492 /* Send the command */
493 buffer = silc_command_encode_payload_va(SILC_COMMAND_INFO, 1,
494 1, name, strlen(name));
495 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
496 0, NULL, NULL, buffer->data, buffer->len, TRUE);
497 silc_buffer_free(buffer);
500 silc_client_command_free(cmd);
503 SILC_CLIENT_CMD_FUNC(connect)
507 /* Command PING. Sends ping to server. This is used to test the
508 communication channel. */
510 SILC_CLIENT_CMD_FUNC(ping)
512 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
513 SilcClientWindow win = NULL;
520 SILC_NOT_CONNECTED(cmd->client);
524 win = (SilcClientWindow)cmd->sock->user_data;
526 if (cmd->argc == 1 || !strcmp(cmd->argv[1], win->remote_host))
527 name = strdup(win->remote_host);
529 id = silc_id_str2id(win->remote_id_data, SILC_ID_SERVER);
531 /* Send the command */
532 buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 1,
533 1, win->remote_id_data,
535 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
536 0, NULL, NULL, buffer->data, buffer->len, TRUE);
537 silc_buffer_free(buffer);
539 /* Start counting time */
540 for (i = 0; i < win->ping_count; i++) {
541 if (win->ping[i].dest_id == NULL) {
542 win->ping[i].start_time = time(NULL);
543 win->ping[i].dest_id = id;
544 win->ping[i].dest_name = name;
549 if (i >= win->ping_count) {
551 win->ping = silc_realloc(win->ping, sizeof(*win->ping) * (i + 1));
552 win->ping[i].start_time = time(NULL);
553 win->ping[i].dest_id = id;
554 win->ping[i].dest_name = name;
559 silc_client_command_free(cmd);
562 SILC_CLIENT_CMD_FUNC(oper)
566 SILC_CLIENT_CMD_FUNC(trace)
570 SILC_CLIENT_CMD_FUNC(notice)
574 /* Command JOIN. Joins to a channel. */
576 SILC_CLIENT_CMD_FUNC(join)
578 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
579 SilcClientWindow win = NULL;
580 SilcIDCacheEntry id_cache = NULL;
584 /* Show channels currently joined to */
585 if (!cmd->client->current_win->sock) {
586 silc_say(cmd->client, "No current channel for this window");
587 SILC_NOT_CONNECTED(cmd->client);
595 if (!cmd->client->current_win->sock) {
596 SILC_NOT_CONNECTED(cmd->client);
600 win = (SilcClientWindow)cmd->sock->user_data;
602 /* See if we have joined to the requested channel already */
603 if (silc_idcache_find_by_data_one(win->channel_cache, cmd->argv[1],
605 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
606 win->current_channel = (SilcChannelEntry)id_cache->context;
607 cmd->client->screen->bottom_line->channel = cmd->argv[1];
608 silc_screen_print_bottom_line(cmd->client->screen, 0);
612 /* Send JOIN command to the server */
613 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
614 cmd->argc - 1, ++cmd->argv,
615 ++cmd->argv_lens, ++cmd->argv_types);
616 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
617 0, NULL, NULL, buffer->data, buffer->len, TRUE);
618 silc_buffer_free(buffer);
624 silc_client_command_free(cmd);
627 SILC_CLIENT_CMD_FUNC(motd)
631 SILC_CLIENT_CMD_FUNC(umode)
635 SILC_CLIENT_CMD_FUNC(cmode)
639 SILC_CLIENT_CMD_FUNC(kick)
643 SILC_CLIENT_CMD_FUNC(restart)
647 SILC_CLIENT_CMD_FUNC(close)
651 SILC_CLIENT_CMD_FUNC(die)
655 SILC_CLIENT_CMD_FUNC(silcoper)
659 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
661 SILC_CLIENT_CMD_FUNC(leave)
663 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
664 SilcClientWindow win = NULL;
665 SilcIDCacheEntry id_cache = NULL;
666 SilcChannelEntry channel;
668 unsigned char *id_string;
671 if (cmd->argc != 2) {
672 silc_say(cmd->client, "Usage: /LEAVE <channel>");
676 if (!cmd->client->current_win->sock) {
677 SILC_NOT_CONNECTED(cmd->client);
681 win = (SilcClientWindow)cmd->sock->user_data;
683 if (cmd->argv[1][0] == '*') {
684 if (!win->current_channel) {
685 silc_say(cmd->client, "You are not on any chanenl");
688 name = win->current_channel->channel_name;
693 if (!win->current_channel) {
694 silc_say(cmd->client, "You are not on that channel");
698 /* Get the Channel ID of the channel */
699 if (!silc_idcache_find_by_data_one(win->channel_cache, name, &id_cache)) {
700 silc_say(cmd->client, "You are not on that channel");
704 channel = (SilcChannelEntry)id_cache->context;
706 /* Send LEAVE command to the server */
707 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
708 buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1,
709 1, id_string, SILC_ID_CHANNEL_LEN);
710 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
711 0, NULL, NULL, buffer->data, buffer->len, TRUE);
712 silc_buffer_free(buffer);
714 /* We won't talk anymore on this channel */
715 silc_say(cmd->client, "You have left channel %s", name);
717 if (!strncmp(win->current_channel->channel_name, name, strlen(name))) {
718 cmd->client->screen->bottom_line->channel = NULL;
719 silc_screen_print_bottom_line(cmd->client->screen, 0);
720 win->current_channel = NULL;
723 silc_idcache_del_by_id(win->channel_cache, SILC_ID_CHANNEL, channel->id);
724 silc_free(channel->channel_name);
725 silc_free(channel->id);
726 silc_free(channel->key);
727 silc_cipher_free(channel->channel_key);
729 silc_free(id_string);
732 silc_client_command_free(cmd);
735 /* Command NAMES. Requests the names of the clients joined on requested
738 SILC_CLIENT_CMD_FUNC(names)
740 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
741 SilcClientWindow win = NULL;
742 SilcIDCacheEntry id_cache = NULL;
745 unsigned char *id_string;
747 if (cmd->argc != 2) {
748 silc_say(cmd->client, "Usage: /NAMES <channel>");
752 if (!cmd->client->current_win->sock) {
753 SILC_NOT_CONNECTED(cmd->client);
757 win = (SilcClientWindow)cmd->sock->user_data;
759 if (cmd->argv[1][0] == '*')
760 name = win->current_channel->channel_name;
764 /* Get the Channel ID of the channel */
765 if (!silc_idcache_find_by_data_one(win->channel_cache, name, &id_cache)) {
766 /* XXX should resolve the channel ID; LIST command */
767 silc_say(cmd->client, "You are not on that channel", name);
771 /* Send NAMES command to the server */
772 id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
773 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
774 1, id_string, SILC_ID_CHANNEL_LEN);
775 silc_client_packet_send(cmd->client, win->sock, SILC_PACKET_COMMAND, NULL,
776 0, NULL, NULL, buffer->data, buffer->len, TRUE);
777 silc_buffer_free(buffer);
778 silc_free(id_string);
780 /* Register dummy pending command that will tell the reply command
781 that user called this command. Server may send reply to this command
782 even if user did not send this command thus we want to handle things
783 differently when user sent the command. This is dummy and won't be
785 /* XXX this is kludge and should be removed after pending command reply
786 support is added. Currently only commands may be pending not command
788 silc_client_command_pending(SILC_COMMAND_NAMES,
789 silc_client_command_names, NULL);
792 silc_client_command_free(cmd);
799 /* HELP command. This is local command and shows help on SILC */
801 SILC_CLIENT_CMD_FUNC(help)
806 /* CLEAR command. This is local command and clears current output window */
808 SILC_CLIENT_CMD_FUNC(clear)
810 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
811 SilcClient client = cmd->client;
813 assert(client->current_win != NULL);
814 wclear((WINDOW *)client->current_win->screen);
815 wrefresh((WINDOW *)client->current_win->screen);
817 silc_client_command_free(cmd);
820 /* VERSION command. This is local command and shows version of the client */
822 SILC_CLIENT_CMD_FUNC(version)
824 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
825 SilcClient client = cmd->client;
826 extern char *silc_version;
827 extern char *silc_name;
828 extern char *silc_fullname;
830 silc_say(client, "%s (%s) version %s", silc_name, silc_fullname,
833 silc_client_command_free(cmd);
836 /* Command MSG. Sends private message to user or list of users. Note that
837 private messages are not really commands, they are message packets,
838 however, on user interface it is convenient to show them as commands
839 as that is the common way of sending private messages (like in IRC). */
840 /* XXX supports only one destination */
842 SILC_CLIENT_CMD_FUNC(msg)
844 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
845 SilcClientWindow win = NULL;
846 SilcClient client = cmd->client;
847 SilcClientEntry client_entry = NULL;
848 unsigned int num = 0;
849 char *nickname = NULL, *server = NULL;
852 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
856 if (!cmd->client->current_win->sock) {
857 SILC_NOT_CONNECTED(cmd->client);
861 win = (SilcClientWindow)cmd->sock->user_data;
863 /* Parse the typed nickname. */
864 if (!silc_client_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
865 silc_say(cmd->client, "Bad nickname");
869 /* Find client entry */
870 client_entry = silc_idlist_get_client(client, win, nickname, server, num);
872 /* Client entry not found, it was requested thus mark this to be
874 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
875 silc_client_command_msg, context);
879 /* Display the message for our eyes. */
880 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
882 /* Send the private message */
883 silc_client_packet_send_private_message(client, cmd->sock, client_entry,
884 cmd->argv[2], cmd->argv_lens[2],
888 silc_client_command_free(cmd);
891 /* Local command AWAY. Client replies with away message to whomever sends
892 private message to the client if the away message is set. If this is
893 given without arguments the away message is removed. */
895 SILC_CLIENT_CMD_FUNC(away)
897 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
898 SilcClientWindow win = NULL;
899 SilcClient client = cmd->client;
901 if (!cmd->client->current_win->sock) {
902 SILC_NOT_CONNECTED(cmd->client);
906 win = (SilcClientWindow)cmd->sock->user_data;
908 if (cmd->argc == 1) {
910 silc_free(win->away->away);
911 silc_free(win->away);
914 silc_say(client, "Away message removed");
919 silc_free(win->away->away);
921 win->away = silc_calloc(1, sizeof(*win->away));
923 win->away->away = strdup(cmd->argv[1]);
925 silc_say(client, "Away message set: %s", win->away->away);
929 silc_client_command_free(cmd);