5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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.
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
25 /* Client command list. */
26 SilcClientCommand silc_command_list[] =
28 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
30 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
31 SILC_CF_LAG | SILC_CF_REG, 3),
32 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
34 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
36 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
37 SILC_CLIENT_CMD(kill, KILL, "KILL",
38 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
39 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
40 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
41 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
42 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
43 SILC_CLIENT_CMD(oper, OPER, "OPER",
44 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
46 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
48 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
49 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
50 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
51 SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
52 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
54 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
56 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
58 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
60 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2),
62 { NULL, 0, NULL, 0, 0 },
65 #define SILC_NOT_CONNECTED(x, c) \
66 x->ops->say((x), (c), \
67 "You are not connected to a server, use /SERVER to connect");
69 /* Command operation that is called at the end of all commands.
71 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
72 cmd, TRUE, cmd->command->cmd)
74 /* Error to application. Usage: COMMAND_ERROR; */
75 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
76 cmd, FALSE, cmd->command->cmd)
78 /* Generic function to send any command. The arguments must be sent already
79 encoded into correct form and in correct order. */
81 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
82 SilcCommand command, uint16 ident,
90 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
91 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
92 NULL, 0, NULL, NULL, packet->data,
94 silc_buffer_free(packet);
97 /* Finds and returns a pointer to the command list. Return NULL if the
98 command is not found. */
100 SilcClientCommand *silc_client_command_find(const char *name)
102 SilcClientCommand *cmd;
104 for (cmd = silc_command_list; cmd->name; cmd++) {
105 if (!strcmp(cmd->name, name))
112 /* Add new pending command to be executed when reply to a command has been
113 received. The `reply_cmd' is the command that will call the `callback'
114 with `context' when reply has been received. If `ident is non-zero
115 the `callback' will be executed when received reply with command
116 identifier `ident'. */
118 void silc_client_command_pending(SilcClientConnection conn,
119 SilcCommand reply_cmd,
121 SilcClientPendingDestructor destructor,
122 SilcCommandCb callback,
125 SilcClientCommandPending *reply;
127 reply = silc_calloc(1, sizeof(*reply));
128 reply->reply_cmd = reply_cmd;
129 reply->ident = ident;
130 reply->context = context;
131 reply->callback = callback;
132 reply->destructor = destructor;
133 silc_dlist_add(conn->pending_commands, reply);
136 /* Deletes pending command by reply command type. */
138 void silc_client_command_pending_del(SilcClientConnection conn,
139 SilcCommand reply_cmd,
142 SilcClientCommandPending *r;
144 silc_dlist_start(conn->pending_commands);
145 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
146 if (r->reply_cmd == reply_cmd && r->ident == ident) {
147 silc_dlist_del(conn->pending_commands, r);
153 /* Checks for pending commands and marks callbacks to be called from
154 the command reply function. Returns TRUE if there were pending command. */
156 int silc_client_command_pending_check(SilcClientConnection conn,
157 SilcClientCommandReplyContext ctx,
161 SilcClientCommandPending *r;
163 silc_dlist_start(conn->pending_commands);
164 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
165 if (r->reply_cmd == command && r->ident == ident) {
166 ctx->context = r->context;
167 ctx->callback = r->callback;
168 ctx->destructor = r->destructor;
177 /* Allocate Command Context */
179 SilcClientCommandContext silc_client_command_alloc()
181 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
186 /* Free command context and its internals */
188 void silc_client_command_free(SilcClientCommandContext ctx)
191 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
193 if (ctx->users < 1) {
196 for (i = 0; i < ctx->argc; i++)
197 silc_free(ctx->argv[i]);
202 /* Duplicate Command Context by adding reference counter. The context won't
203 be free'd untill it hits zero. */
205 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
208 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
213 /* Pending command destructor. */
215 static void silc_client_command_destructor(void *context)
217 silc_client_command_free((SilcClientCommandContext)context);
220 /* silc_client_get_client completion callback */
221 void silc_client_command_completion(SilcClient client,
222 SilcClientConnection conn,
223 SilcClientEntry clients,
224 uint32 clients_count,
230 /* Command WHOIS. This command is used to query information about
233 SILC_CLIENT_CMD_FUNC(whois)
235 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
236 SilcClientConnection conn = cmd->conn;
240 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
245 if (cmd->argc < 2 || cmd->argc > 3) {
246 cmd->client->ops->say(cmd->client, conn,
247 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
252 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
253 cmd->argc - 1, ++cmd->argv,
254 ++cmd->argv_lens, ++cmd->argv_types,
256 silc_client_packet_send(cmd->client, cmd->conn->sock,
257 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
258 buffer->data, buffer->len, TRUE);
259 silc_buffer_free(buffer);
264 /* Notify application */
268 silc_client_command_free(cmd);
271 /* Command WHOWAS. This command is used to query history information about
272 specific user that used to exist in the network. */
274 SILC_CLIENT_CMD_FUNC(whowas)
276 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
277 SilcClientConnection conn = cmd->conn;
281 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
286 if (cmd->argc < 2 || cmd->argc > 3) {
287 cmd->client->ops->say(cmd->client, conn,
288 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
293 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
294 cmd->argc - 1, ++cmd->argv,
295 ++cmd->argv_lens, ++cmd->argv_types,
297 silc_client_packet_send(cmd->client, cmd->conn->sock,
298 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
299 buffer->data, buffer->len, TRUE);
300 silc_buffer_free(buffer);
305 /* Notify application */
309 silc_client_command_free(cmd);
312 /* Command IDENTIFY. This command is used to query information about
313 specific user, especially ID's. */
315 SILC_CLIENT_CMD_FUNC(identify)
317 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
318 SilcClientConnection conn = cmd->conn;
322 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
327 if (cmd->argc < 2 || cmd->argc > 3) {
328 cmd->client->ops->say(cmd->client, conn,
329 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
334 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
335 cmd->argc - 1, ++cmd->argv,
336 ++cmd->argv_lens, ++cmd->argv_types,
338 silc_client_packet_send(cmd->client, cmd->conn->sock,
339 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
340 buffer->data, buffer->len, TRUE);
341 silc_buffer_free(buffer);
346 /* Notify application */
350 silc_client_command_free(cmd);
353 /* Command NICK. Shows current nickname/sets new nickname on current
356 SILC_CLIENT_CMD_FUNC(nick)
358 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
359 SilcClientConnection conn = cmd->conn;
363 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
368 if (!strcmp(conn->nickname, cmd->argv[1]))
371 /* Show current nickname */
374 cmd->client->ops->say(cmd->client, conn,
375 "Your nickname is %s on server %s",
376 conn->nickname, conn->remote_host);
378 cmd->client->ops->say(cmd->client, conn,
379 "Your nickname is %s", conn->nickname);
382 /* XXX Notify application */
387 /* Set new nickname */
388 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
389 cmd->argc - 1, ++cmd->argv,
390 ++cmd->argv_lens, ++cmd->argv_types,
391 ++cmd->conn->cmd_ident);
392 silc_client_packet_send(cmd->client, cmd->conn->sock,
393 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
394 buffer->data, buffer->len, TRUE);
395 silc_buffer_free(buffer);
400 silc_free(conn->nickname);
401 conn->nickname = strdup(cmd->argv[1]);
403 /* Notify application */
407 silc_client_command_free(cmd);
410 /* Command LIST. Lists channels on the current server. */
412 SILC_CLIENT_CMD_FUNC(list)
414 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
415 SilcClientConnection conn = cmd->conn;
416 SilcIDCacheEntry id_cache = NULL;
417 SilcChannelEntry channel;
418 SilcBuffer buffer, idp = NULL;
422 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
427 if (cmd->argc == 2) {
430 /* Get the Channel ID of the channel */
431 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
432 channel = (SilcChannelEntry)id_cache->context;
433 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
438 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
439 ++conn->cmd_ident, 0);
441 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
442 ++conn->cmd_ident, 1,
443 1, idp->data, idp->len);
445 silc_client_packet_send(cmd->client, cmd->conn->sock,
446 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
447 buffer->data, buffer->len, TRUE);
448 silc_buffer_free(buffer);
450 silc_buffer_free(idp);
452 /* Notify application */
456 silc_client_command_free(cmd);
459 /* Command TOPIC. Sets/shows topic on a channel. */
461 SILC_CLIENT_CMD_FUNC(topic)
463 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
464 SilcClientConnection conn = cmd->conn;
465 SilcIDCacheEntry id_cache = NULL;
466 SilcChannelEntry channel;
467 SilcBuffer buffer, idp;
471 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
476 if (cmd->argc < 2 || cmd->argc > 3) {
477 cmd->client->ops->say(cmd->client, conn,
478 "Usage: /TOPIC <channel> [<topic>]");
483 if (cmd->argv[1][0] == '*') {
484 if (!conn->current_channel) {
485 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
489 name = conn->current_channel->channel_name;
494 if (!conn->current_channel) {
495 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
500 /* Get the Channel ID of the channel */
501 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
502 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
507 channel = (SilcChannelEntry)id_cache->context;
509 /* Send TOPIC command to the server */
510 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
512 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
513 ++conn->cmd_ident, 2,
514 1, idp->data, idp->len,
516 strlen(cmd->argv[2]));
518 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
519 ++conn->cmd_ident, 1,
520 1, idp->data, idp->len);
521 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
522 0, NULL, NULL, buffer->data, buffer->len, TRUE);
523 silc_buffer_free(buffer);
524 silc_buffer_free(idp);
526 /* Notify application */
530 silc_client_command_free(cmd);
533 /* Command INVITE. Invites specific client to join a channel. This is
534 also used to mange the invite list of the channel. */
536 SILC_CLIENT_CMD_FUNC(invite)
538 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
539 SilcClient client = cmd->client;
540 SilcClientConnection conn = cmd->conn;
541 SilcClientEntry client_entry = NULL;
542 SilcChannelEntry channel;
543 SilcBuffer buffer, clidp, chidp;
544 uint32 num = 0, type = 0;
545 char *nickname = NULL, *server = NULL, *name;
549 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
555 cmd->client->ops->say(cmd->client, conn,
556 "Usage: /INVITE <channel> [<nickname>[@server>]"
557 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
562 if (cmd->argv[1][0] == '*') {
563 if (!conn->current_channel) {
564 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
569 channel = conn->current_channel;
573 channel = silc_client_get_channel(cmd->client, conn, name);
575 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
581 /* Parse the typed nickname. */
582 if (cmd->argc == 3) {
583 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
584 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
585 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
590 /* Find client entry */
591 client_entry = silc_idlist_get_client(client, conn, nickname,
604 /* Client entry not found, it was requested thus mark this to be
606 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
608 silc_client_command_destructor,
609 silc_client_command_invite,
610 silc_client_command_dup(cmd));
615 cmd->client->ops->say(cmd->client, conn,
616 "Inviting %s to channel %s", cmd->argv[2],
617 channel->channel_name);
619 invite = cmd->argv[2];
621 if (cmd->argv[2][0] == '+')
628 /* Send the command */
629 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
631 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
632 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
633 ++conn->cmd_ident, 3,
634 1, chidp->data, chidp->len,
635 2, clidp->data, clidp->len,
636 type, invite, invite ?
638 silc_buffer_free(clidp);
640 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
641 ++conn->cmd_ident, 2,
642 1, chidp->data, chidp->len,
643 type, invite, invite ?
647 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
648 0, NULL, NULL, buffer->data, buffer->len, TRUE);
649 silc_buffer_free(buffer);
650 silc_buffer_free(chidp);
652 /* Notify application */
660 silc_client_command_free(cmd);
665 SilcClientConnection conn;
668 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
670 QuitInternal q = (QuitInternal)context;
672 /* Close connection */
673 q->client->ops->disconnect(q->client, q->conn);
674 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
679 /* Command QUIT. Closes connection with current server. */
681 SILC_CLIENT_CMD_FUNC(quit)
683 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
688 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
694 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
695 &cmd->argv[1], &cmd->argv_lens[1],
696 &cmd->argv_types[1], 0);
698 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
699 NULL, NULL, NULL, 0);
700 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
702 buffer->data, buffer->len, TRUE);
703 silc_buffer_free(buffer);
705 q = silc_calloc(1, sizeof(*q));
706 q->client = cmd->client;
709 /* We quit the connection with little timeout */
710 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
711 silc_client_command_quit_cb, (void *)q,
712 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
714 /* Notify application */
718 silc_client_command_free(cmd);
721 /* Command KILL. Router operator can use this command to remove an client
722 fromthe SILC Network. */
724 SILC_CLIENT_CMD_FUNC(kill)
726 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
727 SilcClientConnection conn = cmd->conn;
728 SilcBuffer buffer, idp;
729 SilcClientEntry target;
731 char *nickname = NULL, *server = NULL;
734 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
740 cmd->client->ops->say(cmd->client, conn,
741 "Usage: /KILL <nickname> [<comment>]");
746 /* Parse the typed nickname. */
747 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
748 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
753 /* Get the target client */
754 target = silc_idlist_get_client(cmd->client, conn, nickname,
766 /* Client entry not found, it was requested thus mark this to be
768 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
770 silc_client_command_destructor,
771 silc_client_command_kill,
772 silc_client_command_dup(cmd));
777 /* Send the KILL command to the server */
778 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
780 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
781 1, idp->data, idp->len);
783 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
784 1, idp->data, idp->len,
786 strlen(cmd->argv[2]));
787 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
788 0, NULL, NULL, buffer->data, buffer->len, TRUE);
789 silc_buffer_free(buffer);
790 silc_buffer_free(idp);
792 /* Notify application */
800 silc_client_command_free(cmd);
803 /* Command INFO. Request information about specific server. If specific
804 server is not provided the current server is used. */
806 SILC_CLIENT_CMD_FUNC(info)
808 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
809 SilcClientConnection conn = cmd->conn;
814 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
820 name = strdup(cmd->argv[1]);
822 /* Send the command */
824 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
825 1, name, strlen(name));
827 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
828 NULL, NULL, NULL, 0);
829 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
830 0, NULL, NULL, buffer->data, buffer->len, TRUE);
831 silc_buffer_free(buffer);
835 /* Notify application */
839 silc_client_command_free(cmd);
842 /* Command PING. Sends ping to server. This is used to test the
843 communication channel. */
845 SILC_CLIENT_CMD_FUNC(ping)
847 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
848 SilcClientConnection conn = cmd->conn;
855 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
860 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
861 name = strdup(conn->remote_host);
863 /* Send the command */
864 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
865 1, conn->remote_id_data,
866 silc_id_get_len(conn->remote_id,
868 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
869 0, NULL, NULL, buffer->data, buffer->len, TRUE);
870 silc_buffer_free(buffer);
872 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
875 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
880 /* Start counting time */
881 for (i = 0; i < conn->ping_count; i++) {
882 if (conn->ping[i].dest_id == NULL) {
883 conn->ping[i].start_time = time(NULL);
884 conn->ping[i].dest_id = id;
885 conn->ping[i].dest_name = name;
890 if (i >= conn->ping_count) {
891 i = conn->ping_count;
892 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
893 conn->ping[i].start_time = time(NULL);
894 conn->ping[i].dest_id = id;
895 conn->ping[i].dest_name = name;
899 /* Notify application */
903 silc_client_command_free(cmd);
906 SILC_CLIENT_CMD_FUNC(notice)
910 /* Command JOIN. Joins to a channel. */
912 SILC_CLIENT_CMD_FUNC(join)
914 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
915 SilcClientConnection conn = cmd->conn;
916 SilcIDCacheEntry id_cache = NULL;
917 SilcBuffer buffer, idp;
920 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
926 /* Show channels currently joined to */
931 /* See if we have joined to the requested channel already */
932 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
935 cmd->client->ops->say(cmd->client, conn,
936 "You are talking to channel %s", cmd->argv[1]);
937 conn->current_channel = (SilcChannelEntry)id_cache->context;
938 cmd->client->screen->bottom_line->channel = cmd->argv[1];
939 silc_screen_print_bottom_line(cmd->client->screen, 0);
944 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
946 /* Send JOIN command to the server */
949 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
950 1, cmd->argv[1], cmd->argv_lens[1],
951 2, idp->data, idp->len);
952 else if (cmd->argc == 3)
955 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
956 1, cmd->argv[1], cmd->argv_lens[1],
957 2, idp->data, idp->len,
958 3, cmd->argv[2], cmd->argv_lens[2]);
961 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
962 1, cmd->argv[1], cmd->argv_lens[1],
963 2, idp->data, idp->len,
964 3, cmd->argv[2], cmd->argv_lens[2],
965 4, cmd->argv[3], cmd->argv_lens[3]);
967 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
968 0, NULL, NULL, buffer->data, buffer->len, TRUE);
969 silc_buffer_free(buffer);
970 silc_buffer_free(idp);
972 /* Notify application */
976 silc_client_command_free(cmd);
979 /* MOTD command. Requests motd from server. */
981 SILC_CLIENT_CMD_FUNC(motd)
983 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
984 SilcClientConnection conn = cmd->conn;
988 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
993 if (cmd->argc < 1 || cmd->argc > 2) {
994 cmd->client->ops->say(cmd->client, conn,
995 "Usage: /MOTD [<server>]");
1000 /* Send TOPIC command to the server */
1002 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1003 1, conn->remote_host,
1004 strlen(conn->remote_host));
1006 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1009 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1010 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1011 silc_buffer_free(buffer);
1013 /* Notify application */
1017 silc_client_command_free(cmd);
1020 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1021 modes as client cannot set itself server/router operator privileges. */
1023 SILC_CLIENT_CMD_FUNC(umode)
1025 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1026 SilcClientConnection conn = cmd->conn;
1027 SilcBuffer buffer, idp;
1028 unsigned char *cp, modebuf[4];
1029 uint32 mode, add, len;
1033 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1038 if (cmd->argc < 2) {
1039 cmd->client->ops->say(cmd->client, conn,
1040 "Usage: /UMODE +|-<modes>");
1045 mode = conn->local_entry->mode;
1047 /* Are we adding or removing mode */
1048 if (cmd->argv[1][0] == '-')
1054 cp = cmd->argv[1] + 1;
1056 for (i = 0; i < len; i++) {
1061 mode |= SILC_UMODE_SERVER_OPERATOR;
1062 mode |= SILC_UMODE_ROUTER_OPERATOR;
1064 mode = SILC_UMODE_NONE;
1069 mode |= SILC_UMODE_SERVER_OPERATOR;
1071 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1075 mode |= SILC_UMODE_ROUTER_OPERATOR;
1077 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1081 mode |= SILC_UMODE_GONE;
1083 mode &= ~SILC_UMODE_GONE;
1092 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1093 SILC_PUT32_MSB(mode, modebuf);
1095 /* Send the command packet. We support sending only one mode at once
1096 that requires an argument. */
1098 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1099 1, idp->data, idp->len,
1100 2, modebuf, sizeof(modebuf));
1101 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1102 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1103 silc_buffer_free(buffer);
1104 silc_buffer_free(idp);
1106 /* Notify application */
1110 silc_client_command_free(cmd);
1113 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1114 can be set several at once. Those modes that require argument must be set
1115 separately (unless set with modes that does not require arguments). */
1117 SILC_CLIENT_CMD_FUNC(cmode)
1119 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1120 SilcClientConnection conn = cmd->conn;
1121 SilcChannelEntry channel;
1122 SilcBuffer buffer, chidp, auth = NULL;
1123 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1124 uint32 mode, add, type, len, arg_len = 0;
1128 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1133 if (cmd->argc < 3) {
1134 cmd->client->ops->say(cmd->client, conn,
1135 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1140 if (cmd->argv[1][0] == '*') {
1141 if (!conn->current_channel) {
1142 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1147 channel = conn->current_channel;
1149 name = cmd->argv[1];
1151 channel = silc_client_get_channel(cmd->client, conn, name);
1153 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1159 mode = channel->mode;
1161 /* Are we adding or removing mode */
1162 if (cmd->argv[2][0] == '-')
1167 /* Argument type to be sent to server */
1171 cp = cmd->argv[2] + 1;
1173 for (i = 0; i < len; i++) {
1177 mode |= SILC_CHANNEL_MODE_PRIVATE;
1179 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1183 mode |= SILC_CHANNEL_MODE_SECRET;
1185 mode &= ~SILC_CHANNEL_MODE_SECRET;
1189 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1191 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1195 mode |= SILC_CHANNEL_MODE_INVITE;
1197 mode &= ~SILC_CHANNEL_MODE_INVITE;
1201 mode |= SILC_CHANNEL_MODE_TOPIC;
1203 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1208 mode |= SILC_CHANNEL_MODE_ULIMIT;
1210 ll = atoi(cmd->argv[3]);
1211 SILC_PUT32_MSB(ll, tmp);
1215 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1220 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1223 arg_len = cmd->argv_lens[3];
1225 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1230 mode |= SILC_CHANNEL_MODE_CIPHER;
1233 arg_len = cmd->argv_lens[3];
1235 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1240 mode |= SILC_CHANNEL_MODE_HMAC;
1243 arg_len = cmd->argv_lens[3];
1245 mode &= ~SILC_CHANNEL_MODE_HMAC;
1250 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1253 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1254 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1255 cmd->client->private_key,
1260 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1261 cmd->argv[3], cmd->argv_lens[3]);
1265 arg_len = auth->len;
1267 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1277 if (type && cmd->argc < 3) {
1282 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1283 SILC_PUT32_MSB(mode, modebuf);
1285 /* Send the command packet. We support sending only one mode at once
1286 that requires an argument. */
1289 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1290 1, chidp->data, chidp->len,
1291 2, modebuf, sizeof(modebuf),
1292 type, arg, arg_len);
1295 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1296 1, chidp->data, chidp->len,
1297 2, modebuf, sizeof(modebuf));
1300 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1301 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1302 silc_buffer_free(buffer);
1303 silc_buffer_free(chidp);
1305 silc_buffer_free(auth);
1307 /* Notify application */
1311 silc_client_command_free(cmd);
1314 /* CUMODE command. Changes client's mode on a channel. */
1316 SILC_CLIENT_CMD_FUNC(cumode)
1318 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1319 SilcClientConnection conn = cmd->conn;
1320 SilcChannelEntry channel;
1321 SilcChannelUser chu;
1322 SilcClientEntry client_entry;
1323 SilcBuffer buffer, clidp, chidp, auth = NULL;
1324 unsigned char *name, *cp, modebuf[4];
1325 uint32 mode = 0, add, len;
1326 char *nickname = NULL, *server = NULL;
1331 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1336 if (cmd->argc < 4) {
1337 cmd->client->ops->say(cmd->client, conn,
1338 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1343 if (cmd->argv[1][0] == '*') {
1344 if (!conn->current_channel) {
1345 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1350 channel = conn->current_channel;
1352 name = cmd->argv[1];
1354 channel = silc_client_get_channel(cmd->client, conn, name);
1356 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1362 /* Parse the typed nickname. */
1363 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1364 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1369 /* Find client entry */
1370 client_entry = silc_idlist_get_client(cmd->client, conn,
1371 nickname, server, num, TRUE);
1372 if (!client_entry) {
1378 /* Client entry not found, it was requested thus mark this to be
1380 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1382 silc_client_command_destructor,
1383 silc_client_command_cumode,
1384 silc_client_command_dup(cmd));
1389 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1390 if (chu->client == client_entry) {
1396 /* Are we adding or removing mode */
1397 if (cmd->argv[2][0] == '-')
1403 cp = cmd->argv[2] + 1;
1405 for (i = 0; i < len; i++) {
1409 mode |= SILC_CHANNEL_UMODE_CHANFO;
1410 mode |= SILC_CHANNEL_UMODE_CHANOP;
1412 mode = SILC_CHANNEL_UMODE_NONE;
1417 if (cmd->argc == 5) {
1418 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1419 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1420 cmd->client->private_key,
1425 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1426 cmd->argv[4], cmd->argv_lens[4]);
1429 mode |= SILC_CHANNEL_UMODE_CHANFO;
1431 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1436 mode |= SILC_CHANNEL_UMODE_CHANOP;
1438 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1447 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1448 SILC_PUT32_MSB(mode, modebuf);
1449 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1451 /* Send the command packet. We support sending only one mode at once
1452 that requires an argument. */
1453 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1454 1, chidp->data, chidp->len,
1456 3, clidp->data, clidp->len,
1457 4, auth ? auth->data : NULL,
1458 auth ? auth->len : 0);
1460 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1461 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1462 silc_buffer_free(buffer);
1463 silc_buffer_free(chidp);
1464 silc_buffer_free(clidp);
1466 silc_buffer_free(auth);
1468 /* Notify application */
1473 silc_free(nickname);
1476 silc_client_command_free(cmd);
1479 /* KICK command. Kicks a client out of channel. */
1481 SILC_CLIENT_CMD_FUNC(kick)
1483 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1484 SilcClientConnection conn = cmd->conn;
1485 SilcIDCacheEntry id_cache = NULL;
1486 SilcChannelEntry channel;
1487 SilcBuffer buffer, idp, idp2;
1488 SilcClientEntry target;
1491 char *nickname = NULL, *server = NULL;
1494 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1499 if (cmd->argc < 3) {
1500 cmd->client->ops->say(cmd->client, conn,
1501 "Usage: /KICK <channel> <nickname> [<comment>]");
1506 if (cmd->argv[1][0] == '*') {
1507 if (!conn->current_channel) {
1508 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1512 name = conn->current_channel->channel_name;
1514 name = cmd->argv[1];
1517 if (!conn->current_channel) {
1518 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1523 /* Get the Channel ID of the channel */
1524 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1525 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1530 channel = (SilcChannelEntry)id_cache->context;
1532 /* Parse the typed nickname. */
1533 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1534 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1539 /* Get the target client */
1540 target = silc_idlist_get_client(cmd->client, conn, nickname,
1541 server, num, FALSE);
1543 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1549 /* Send KICK command to the server */
1550 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1551 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1553 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1554 1, idp->data, idp->len,
1555 2, idp2->data, idp2->len);
1557 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1558 1, idp->data, idp->len,
1559 2, idp2->data, idp2->len,
1561 strlen(cmd->argv[3]));
1562 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1563 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1564 silc_buffer_free(buffer);
1565 silc_buffer_free(idp);
1566 silc_buffer_free(idp2);
1568 /* Notify application */
1573 silc_free(nickname);
1576 silc_client_command_free(cmd);
1579 /* OPER command. Used to obtain server operator privileges. */
1581 SILC_CLIENT_CMD_FUNC(oper)
1583 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1584 SilcClientConnection conn = cmd->conn;
1586 unsigned char *auth_data;
1590 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1595 if (cmd->argc < 2) {
1596 cmd->client->ops->say(cmd->client, conn,
1597 "Usage: /OPER <username> [<public key>]");
1602 if (cmd->argc == 3) {
1603 /* XXX Get public key */
1608 /* Get passphrase */
1610 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1616 /* Encode the authentication payload */
1617 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1618 auth_data, strlen(auth_data));
1621 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1623 strlen(cmd->argv[1]),
1624 2, auth->data, auth->len);
1625 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1626 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1628 silc_buffer_free(buffer);
1629 silc_buffer_free(auth);
1630 memset(auth_data, 0, strlen(auth_data));
1631 silc_free(auth_data);
1633 /* Notify application */
1637 silc_client_command_free(cmd);
1640 /* SILCOPER command. Used to obtain router operator privileges. */
1642 SILC_CLIENT_CMD_FUNC(silcoper)
1644 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1645 SilcClientConnection conn = cmd->conn;
1647 unsigned char *auth_data;
1651 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1656 if (cmd->argc < 2) {
1657 cmd->client->ops->say(cmd->client, conn,
1658 "Usage: /SILCOPER <username> [<public key>]");
1663 if (cmd->argc == 3) {
1664 /* XXX Get public key */
1669 /* Get passphrase */
1671 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1677 /* Encode the authentication payload */
1678 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1679 auth_data, strlen(auth_data));
1682 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1684 strlen(cmd->argv[1]),
1685 2, auth->data, auth->len);
1686 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1687 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1689 silc_buffer_free(buffer);
1690 silc_buffer_free(auth);
1691 memset(auth_data, 0, strlen(auth_data));
1692 silc_free(auth_data);
1694 /* Notify application */
1698 silc_client_command_free(cmd);
1701 /* CONNECT command. Connects the server to another server. */
1703 SILC_CLIENT_CMD_FUNC(connect)
1705 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1706 SilcClientConnection conn = cmd->conn;
1708 unsigned char port[4];
1712 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1717 if (cmd->argc < 2) {
1718 cmd->client->ops->say(cmd->client, conn,
1719 "Usage: /CONNECT <server> [<port>]");
1724 if (cmd->argc == 3) {
1725 tmp = atoi(cmd->argv[2]);
1726 SILC_PUT32_MSB(tmp, port);
1730 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1732 strlen(cmd->argv[1]),
1735 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1737 strlen(cmd->argv[1]));
1738 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1739 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1740 silc_buffer_free(buffer);
1742 /* Notify application */
1746 silc_client_command_free(cmd);
1749 /* Command BAN. This is used to manage the ban list of the channel. */
1751 SILC_CLIENT_CMD_FUNC(ban)
1753 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1754 SilcClientConnection conn = cmd->conn;
1755 SilcChannelEntry channel;
1756 SilcBuffer buffer, chidp;
1758 char *name, *ban = NULL;
1761 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1766 if (cmd->argc < 2) {
1767 cmd->client->ops->say(cmd->client, conn,
1768 "Usage: /BAN <channel> "
1769 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1774 if (cmd->argv[1][0] == '*') {
1775 if (!conn->current_channel) {
1776 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1781 channel = conn->current_channel;
1783 name = cmd->argv[1];
1785 channel = silc_client_get_channel(cmd->client, conn, name);
1787 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1793 if (cmd->argc == 3) {
1794 if (cmd->argv[2][0] == '+')
1803 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1805 /* Send the command */
1807 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1808 1, chidp->data, chidp->len,
1809 type, ban, strlen(ban));
1811 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1812 1, chidp->data, chidp->len);
1814 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1815 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1816 silc_buffer_free(buffer);
1817 silc_buffer_free(chidp);
1819 /* Notify application */
1823 silc_client_command_free(cmd);
1826 /* CLOSE command. Close server connection to the remote server */
1828 SILC_CLIENT_CMD_FUNC(close)
1830 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1831 SilcClientConnection conn = cmd->conn;
1833 unsigned char port[4];
1837 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1842 if (cmd->argc < 2) {
1843 cmd->client->ops->say(cmd->client, conn,
1844 "Usage: /CLOSE <server> [<port>]");
1849 if (cmd->argc == 3) {
1850 tmp = atoi(cmd->argv[2]);
1851 SILC_PUT32_MSB(tmp, port);
1855 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1857 strlen(cmd->argv[1]),
1860 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1862 strlen(cmd->argv[1]));
1863 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1864 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1865 silc_buffer_free(buffer);
1867 /* Notify application */
1871 silc_client_command_free(cmd);
1874 /* SHUTDOWN command. Shutdowns the server. */
1876 SILC_CLIENT_CMD_FUNC(shutdown)
1878 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1881 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1886 /* Send the command */
1887 silc_client_send_command(cmd->client, cmd->conn,
1888 SILC_COMMAND_SHUTDOWN, 0, 0);
1890 /* Notify application */
1894 silc_client_command_free(cmd);
1897 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1899 SILC_CLIENT_CMD_FUNC(leave)
1901 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1902 SilcClientConnection conn = cmd->conn;
1903 SilcIDCacheEntry id_cache = NULL;
1904 SilcChannelEntry channel;
1905 SilcBuffer buffer, idp;
1909 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1914 if (cmd->argc != 2) {
1915 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1920 if (cmd->argv[1][0] == '*') {
1921 if (!conn->current_channel) {
1922 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1926 name = conn->current_channel->channel_name;
1928 name = cmd->argv[1];
1931 if (!conn->current_channel) {
1932 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1937 /* Get the Channel ID of the channel */
1938 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1939 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1944 channel = (SilcChannelEntry)id_cache->context;
1946 /* Send LEAVE command to the server */
1947 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1948 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1949 1, idp->data, idp->len);
1950 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1951 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1952 silc_buffer_free(buffer);
1953 silc_buffer_free(idp);
1955 /* Notify application */
1958 conn->current_channel = NULL;
1960 silc_idcache_del_by_id(conn->channel_cache, channel->id);
1961 silc_free(channel->channel_name);
1962 silc_free(channel->id);
1963 silc_free(channel->key);
1964 silc_cipher_free(channel->channel_key);
1968 silc_client_command_free(cmd);
1971 /* Command USERS. Requests the USERS of the clients joined on requested
1974 SILC_CLIENT_CMD_FUNC(users)
1976 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1977 SilcClientConnection conn = cmd->conn;
1978 SilcIDCacheEntry id_cache = NULL;
1979 SilcChannelEntry channel;
1980 SilcBuffer buffer, idp;
1984 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1989 if (cmd->argc != 2) {
1990 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1995 if (cmd->argv[1][0] == '*') {
1996 if (!conn->current_channel) {
1997 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2001 name = conn->current_channel->channel_name;
2003 name = cmd->argv[1];
2006 if (!conn->current_channel) {
2007 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2012 /* Get the Channel ID of the channel */
2013 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2014 /* XXX should resolve the channel ID; LIST command */
2015 cmd->client->ops->say(cmd->client, conn,
2016 "You are not on that channel", name);
2021 channel = (SilcChannelEntry)id_cache->context;
2023 if (!cmd->pending) {
2024 /* Send USERS command to the server */
2025 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2026 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2027 ++conn->cmd_ident, 1,
2028 1, idp->data, idp->len);
2029 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2030 NULL, 0, NULL, NULL, buffer->data,
2032 silc_buffer_free(buffer);
2033 silc_buffer_free(idp);
2035 /* Register pending callback which will recall this command callback with
2036 same context and reprocesses the command. When reprocessing we actually
2037 display the information on the screen. */
2038 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2039 silc_client_command_destructor,
2040 silc_client_command_users,
2041 silc_client_command_dup(cmd));
2042 cmd->pending = TRUE;
2046 /* Notify application */
2050 silc_client_command_free(cmd);
2053 /* Command GETKEY. Used to fetch remote client's public key. */
2055 SILC_CLIENT_CMD_FUNC(getkey)
2057 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2058 SilcClientConnection conn = cmd->conn;
2059 SilcClient client = cmd->client;
2060 SilcClientEntry client_entry = NULL;
2062 char *nickname = NULL, *server = NULL;
2063 SilcBuffer idp, buffer;
2066 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2071 if (cmd->argc < 2) {
2072 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2077 /* Parse the typed nickname. */
2078 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2079 client->ops->say(client, conn, "Bad nickname");
2084 /* Find client entry */
2085 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2087 if (!client_entry) {
2088 /* Client entry not found, it was requested thus mark this to be
2090 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2092 silc_client_command_destructor,
2093 silc_client_command_getkey,
2094 silc_client_command_dup(cmd));
2099 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2100 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2101 1, idp->data, idp->len);
2102 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2103 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2104 silc_buffer_free(buffer);
2105 silc_buffer_free(idp);
2107 /* Notify application */
2111 silc_client_command_free(cmd);