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_data_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_data_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, 0, 2,
513 1, idp->data, idp->len,
515 strlen(cmd->argv[2]));
517 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
518 1, idp->data, idp->len,
520 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
521 0, NULL, NULL, buffer->data, buffer->len, TRUE);
522 silc_buffer_free(buffer);
523 silc_buffer_free(idp);
525 /* Notify application */
529 silc_client_command_free(cmd);
532 /* Command INVITE. Invites specific client to join a channel. This is
533 also used to mange the invite list of the channel. */
535 SILC_CLIENT_CMD_FUNC(invite)
537 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
538 SilcClient client = cmd->client;
539 SilcClientConnection conn = cmd->conn;
540 SilcClientEntry client_entry = NULL;
541 SilcChannelEntry channel;
542 SilcBuffer buffer, clidp, chidp;
543 uint32 num = 0, type = 0;
544 char *nickname = NULL, *server = NULL, *name;
548 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
554 cmd->client->ops->say(cmd->client, conn,
555 "Usage: /INVITE <channel> [<nickname>[@server>]"
556 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
561 if (cmd->argv[1][0] == '*') {
562 if (!conn->current_channel) {
563 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
568 channel = conn->current_channel;
572 channel = silc_client_get_channel(cmd->client, conn, name);
574 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
580 /* Parse the typed nickname. */
581 if (cmd->argc == 3) {
582 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
583 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
584 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
589 /* Find client entry */
590 client_entry = silc_idlist_get_client(client, conn, nickname,
603 /* Client entry not found, it was requested thus mark this to be
605 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
607 silc_client_command_destructor,
608 silc_client_command_invite,
609 silc_client_command_dup(cmd));
614 cmd->client->ops->say(cmd->client, conn,
615 "Inviting %s to channel %s", cmd->argv[2],
616 channel->channel_name);
618 invite = cmd->argv[2];
620 if (cmd->argv[2][0] == '+')
627 /* Send the command */
628 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
630 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
631 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
632 ++conn->cmd_ident, 3,
633 1, chidp->data, chidp->len,
634 2, clidp->data, clidp->len,
635 type, invite, invite ?
637 silc_buffer_free(clidp);
639 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
640 ++conn->cmd_ident, 2,
641 1, chidp->data, chidp->len,
642 type, invite, invite ?
646 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
647 0, NULL, NULL, buffer->data, buffer->len, TRUE);
648 silc_buffer_free(buffer);
649 silc_buffer_free(chidp);
651 /* Notify application */
659 silc_client_command_free(cmd);
664 SilcClientConnection conn;
667 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
669 QuitInternal q = (QuitInternal)context;
671 /* Close connection */
672 q->client->ops->disconnect(q->client, q->conn);
673 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
678 /* Command QUIT. Closes connection with current server. */
680 SILC_CLIENT_CMD_FUNC(quit)
682 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
687 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
693 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
694 &cmd->argv[1], &cmd->argv_lens[1],
695 &cmd->argv_types[1], 0);
697 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
698 NULL, NULL, NULL, 0);
699 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
701 buffer->data, buffer->len, TRUE);
702 silc_buffer_free(buffer);
704 q = silc_calloc(1, sizeof(*q));
705 q->client = cmd->client;
708 /* We quit the connection with little timeout */
709 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
710 silc_client_command_quit_cb, (void *)q,
711 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
713 /* Notify application */
717 silc_client_command_free(cmd);
720 /* Command KILL. Router operator can use this command to remove an client
721 fromthe SILC Network. */
723 SILC_CLIENT_CMD_FUNC(kill)
725 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
726 SilcClientConnection conn = cmd->conn;
727 SilcBuffer buffer, idp;
728 SilcClientEntry target;
730 char *nickname = NULL, *server = NULL;
733 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
739 cmd->client->ops->say(cmd->client, conn,
740 "Usage: /KILL <nickname> [<comment>]");
745 /* Parse the typed nickname. */
746 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
747 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
752 /* Get the target client */
753 target = silc_idlist_get_client(cmd->client, conn, nickname,
765 /* Client entry not found, it was requested thus mark this to be
767 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
769 silc_client_command_destructor,
770 silc_client_command_kill,
771 silc_client_command_dup(cmd));
776 /* Send the KILL command to the server */
777 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
779 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
780 1, idp->data, idp->len);
782 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
783 1, idp->data, idp->len,
785 strlen(cmd->argv[2]));
786 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
787 0, NULL, NULL, buffer->data, buffer->len, TRUE);
788 silc_buffer_free(buffer);
789 silc_buffer_free(idp);
791 /* Notify application */
799 silc_client_command_free(cmd);
802 /* Command INFO. Request information about specific server. If specific
803 server is not provided the current server is used. */
805 SILC_CLIENT_CMD_FUNC(info)
807 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
808 SilcClientConnection conn = cmd->conn;
813 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
819 name = strdup(cmd->argv[1]);
821 /* Send the command */
823 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
824 1, name, strlen(name));
826 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
827 NULL, NULL, NULL, 0);
828 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
829 0, NULL, NULL, buffer->data, buffer->len, TRUE);
830 silc_buffer_free(buffer);
834 /* Notify application */
838 silc_client_command_free(cmd);
841 /* Command PING. Sends ping to server. This is used to test the
842 communication channel. */
844 SILC_CLIENT_CMD_FUNC(ping)
846 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
847 SilcClientConnection conn = cmd->conn;
854 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
859 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
860 name = strdup(conn->remote_host);
862 /* Send the command */
863 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
864 1, conn->remote_id_data,
865 silc_id_get_len(conn->remote_id,
867 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
868 0, NULL, NULL, buffer->data, buffer->len, TRUE);
869 silc_buffer_free(buffer);
871 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
879 /* Start counting time */
880 for (i = 0; i < conn->ping_count; i++) {
881 if (conn->ping[i].dest_id == NULL) {
882 conn->ping[i].start_time = time(NULL);
883 conn->ping[i].dest_id = id;
884 conn->ping[i].dest_name = name;
889 if (i >= conn->ping_count) {
890 i = conn->ping_count;
891 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
892 conn->ping[i].start_time = time(NULL);
893 conn->ping[i].dest_id = id;
894 conn->ping[i].dest_name = name;
898 /* Notify application */
902 silc_client_command_free(cmd);
905 SILC_CLIENT_CMD_FUNC(notice)
909 /* Command JOIN. Joins to a channel. */
911 SILC_CLIENT_CMD_FUNC(join)
913 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
914 SilcClientConnection conn = cmd->conn;
915 SilcIDCacheEntry id_cache = NULL;
916 SilcBuffer buffer, idp;
919 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
925 /* Show channels currently joined to */
930 /* See if we have joined to the requested channel already */
931 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
933 cmd->client->ops->say(cmd->client, conn,
934 "You are talking to channel %s", cmd->argv[1]);
935 conn->current_channel = (SilcChannelEntry)id_cache->context;
937 cmd->client->screen->bottom_line->channel = cmd->argv[1];
938 silc_screen_print_bottom_line(cmd->client->screen, 0);
943 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
945 /* Send JOIN command to the server */
948 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
949 1, cmd->argv[1], cmd->argv_lens[1],
950 2, idp->data, idp->len);
951 else if (cmd->argc == 3)
954 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
955 1, cmd->argv[1], cmd->argv_lens[1],
956 2, idp->data, idp->len,
957 3, cmd->argv[2], cmd->argv_lens[2]);
960 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
961 1, cmd->argv[1], cmd->argv_lens[1],
962 2, idp->data, idp->len,
963 3, cmd->argv[2], cmd->argv_lens[2],
964 4, cmd->argv[3], cmd->argv_lens[3]);
966 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
967 0, NULL, NULL, buffer->data, buffer->len, TRUE);
968 silc_buffer_free(buffer);
969 silc_buffer_free(idp);
971 /* Notify application */
975 silc_client_command_free(cmd);
978 /* MOTD command. Requests motd from server. */
980 SILC_CLIENT_CMD_FUNC(motd)
982 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
983 SilcClientConnection conn = cmd->conn;
987 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
992 if (cmd->argc < 1 || cmd->argc > 2) {
993 cmd->client->ops->say(cmd->client, conn,
994 "Usage: /MOTD [<server>]");
999 /* Send TOPIC command to the server */
1001 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1002 1, conn->remote_host,
1003 strlen(conn->remote_host));
1005 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1008 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1009 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1010 silc_buffer_free(buffer);
1012 /* Notify application */
1016 silc_client_command_free(cmd);
1019 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1020 modes as client cannot set itself server/router operator privileges. */
1022 SILC_CLIENT_CMD_FUNC(umode)
1024 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1025 SilcClientConnection conn = cmd->conn;
1026 SilcBuffer buffer, idp;
1027 unsigned char *cp, modebuf[4];
1028 uint32 mode, add, len;
1032 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1037 if (cmd->argc < 2) {
1038 cmd->client->ops->say(cmd->client, conn,
1039 "Usage: /UMODE +|-<modes>");
1044 mode = conn->local_entry->mode;
1046 /* Are we adding or removing mode */
1047 if (cmd->argv[1][0] == '-')
1053 cp = cmd->argv[1] + 1;
1055 for (i = 0; i < len; i++) {
1060 mode |= SILC_UMODE_SERVER_OPERATOR;
1061 mode |= SILC_UMODE_ROUTER_OPERATOR;
1063 mode = SILC_UMODE_NONE;
1068 mode |= SILC_UMODE_SERVER_OPERATOR;
1070 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1074 mode |= SILC_UMODE_ROUTER_OPERATOR;
1076 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1080 mode |= SILC_UMODE_GONE;
1082 mode &= ~SILC_UMODE_GONE;
1091 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1092 SILC_PUT32_MSB(mode, modebuf);
1094 /* Send the command packet. We support sending only one mode at once
1095 that requires an argument. */
1097 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1098 1, idp->data, idp->len,
1099 2, modebuf, sizeof(modebuf));
1100 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1101 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1102 silc_buffer_free(buffer);
1103 silc_buffer_free(idp);
1105 /* Notify application */
1109 silc_client_command_free(cmd);
1112 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1113 can be set several at once. Those modes that require argument must be set
1114 separately (unless set with modes that does not require arguments). */
1116 SILC_CLIENT_CMD_FUNC(cmode)
1118 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1119 SilcClientConnection conn = cmd->conn;
1120 SilcChannelEntry channel;
1121 SilcBuffer buffer, chidp, auth = NULL;
1122 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1123 uint32 mode, add, type, len, arg_len = 0;
1127 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1132 if (cmd->argc < 3) {
1133 cmd->client->ops->say(cmd->client, conn,
1134 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1139 if (cmd->argv[1][0] == '*') {
1140 if (!conn->current_channel) {
1141 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1146 channel = conn->current_channel;
1148 name = cmd->argv[1];
1150 channel = silc_client_get_channel(cmd->client, conn, name);
1152 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1158 mode = channel->mode;
1160 /* Are we adding or removing mode */
1161 if (cmd->argv[2][0] == '-')
1166 /* Argument type to be sent to server */
1170 cp = cmd->argv[2] + 1;
1172 for (i = 0; i < len; i++) {
1176 mode |= SILC_CHANNEL_MODE_PRIVATE;
1178 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1182 mode |= SILC_CHANNEL_MODE_SECRET;
1184 mode &= ~SILC_CHANNEL_MODE_SECRET;
1188 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1190 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1194 mode |= SILC_CHANNEL_MODE_INVITE;
1196 mode &= ~SILC_CHANNEL_MODE_INVITE;
1200 mode |= SILC_CHANNEL_MODE_TOPIC;
1202 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1207 mode |= SILC_CHANNEL_MODE_ULIMIT;
1209 ll = atoi(cmd->argv[3]);
1210 SILC_PUT32_MSB(ll, tmp);
1214 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1219 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1222 arg_len = cmd->argv_lens[3];
1224 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1229 mode |= SILC_CHANNEL_MODE_CIPHER;
1232 arg_len = cmd->argv_lens[3];
1234 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1239 mode |= SILC_CHANNEL_MODE_HMAC;
1242 arg_len = cmd->argv_lens[3];
1244 mode &= ~SILC_CHANNEL_MODE_HMAC;
1249 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1252 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1253 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1254 cmd->client->private_key,
1259 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1260 cmd->argv[3], cmd->argv_lens[3]);
1264 arg_len = auth->len;
1266 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1276 if (type && cmd->argc < 3) {
1281 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1282 SILC_PUT32_MSB(mode, modebuf);
1284 /* Send the command packet. We support sending only one mode at once
1285 that requires an argument. */
1288 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1289 1, chidp->data, chidp->len,
1290 2, modebuf, sizeof(modebuf),
1291 type, arg, arg_len);
1294 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1295 1, chidp->data, chidp->len,
1296 2, modebuf, sizeof(modebuf));
1299 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1300 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1301 silc_buffer_free(buffer);
1302 silc_buffer_free(chidp);
1304 silc_buffer_free(auth);
1306 /* Notify application */
1310 silc_client_command_free(cmd);
1313 /* CUMODE command. Changes client's mode on a channel. */
1315 SILC_CLIENT_CMD_FUNC(cumode)
1317 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1318 SilcClientConnection conn = cmd->conn;
1319 SilcChannelEntry channel;
1320 SilcChannelUser chu;
1321 SilcClientEntry client_entry;
1322 SilcBuffer buffer, clidp, chidp, auth = NULL;
1323 unsigned char *name, *cp, modebuf[4];
1324 uint32 mode = 0, add, len;
1325 char *nickname = NULL, *server = NULL;
1330 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1335 if (cmd->argc < 4) {
1336 cmd->client->ops->say(cmd->client, conn,
1337 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1342 if (cmd->argv[1][0] == '*') {
1343 if (!conn->current_channel) {
1344 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1349 channel = conn->current_channel;
1351 name = cmd->argv[1];
1353 channel = silc_client_get_channel(cmd->client, conn, name);
1355 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1361 /* Parse the typed nickname. */
1362 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1363 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1368 /* Find client entry */
1369 client_entry = silc_idlist_get_client(cmd->client, conn,
1370 nickname, server, num, TRUE);
1371 if (!client_entry) {
1377 /* Client entry not found, it was requested thus mark this to be
1379 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1381 silc_client_command_destructor,
1382 silc_client_command_cumode,
1383 silc_client_command_dup(cmd));
1388 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1389 if (chu->client == client_entry) {
1395 /* Are we adding or removing mode */
1396 if (cmd->argv[2][0] == '-')
1402 cp = cmd->argv[2] + 1;
1404 for (i = 0; i < len; i++) {
1408 mode |= SILC_CHANNEL_UMODE_CHANFO;
1409 mode |= SILC_CHANNEL_UMODE_CHANOP;
1411 mode = SILC_CHANNEL_UMODE_NONE;
1416 if (cmd->argc == 5) {
1417 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1418 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1419 cmd->client->private_key,
1424 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1425 cmd->argv[4], cmd->argv_lens[4]);
1428 mode |= SILC_CHANNEL_UMODE_CHANFO;
1430 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1435 mode |= SILC_CHANNEL_UMODE_CHANOP;
1437 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1446 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1447 SILC_PUT32_MSB(mode, modebuf);
1448 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1450 /* Send the command packet. We support sending only one mode at once
1451 that requires an argument. */
1452 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1453 1, chidp->data, chidp->len,
1455 3, clidp->data, clidp->len,
1456 4, auth ? auth->data : NULL,
1457 auth ? auth->len : 0);
1459 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1460 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1461 silc_buffer_free(buffer);
1462 silc_buffer_free(chidp);
1463 silc_buffer_free(clidp);
1465 silc_buffer_free(auth);
1467 /* Notify application */
1472 silc_free(nickname);
1475 silc_client_command_free(cmd);
1478 /* KICK command. Kicks a client out of channel. */
1480 SILC_CLIENT_CMD_FUNC(kick)
1482 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1483 SilcClientConnection conn = cmd->conn;
1484 SilcIDCacheEntry id_cache = NULL;
1485 SilcChannelEntry channel;
1486 SilcBuffer buffer, idp, idp2;
1487 SilcClientEntry target;
1490 char *nickname = NULL, *server = NULL;
1493 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1498 if (cmd->argc < 3) {
1499 cmd->client->ops->say(cmd->client, conn,
1500 "Usage: /KICK <channel> <nickname> [<comment>]");
1505 if (cmd->argv[1][0] == '*') {
1506 if (!conn->current_channel) {
1507 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1511 name = conn->current_channel->channel_name;
1513 name = cmd->argv[1];
1516 if (!conn->current_channel) {
1517 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1522 /* Get the Channel ID of the channel */
1523 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1524 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1529 channel = (SilcChannelEntry)id_cache->context;
1531 /* Parse the typed nickname. */
1532 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1533 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1538 /* Get the target client */
1539 target = silc_idlist_get_client(cmd->client, conn, nickname,
1540 server, num, FALSE);
1542 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1548 /* Send KICK command to the server */
1549 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1550 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1552 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1553 1, idp->data, idp->len,
1554 2, idp2->data, idp2->len);
1556 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1557 1, idp->data, idp->len,
1558 2, idp2->data, idp2->len,
1560 strlen(cmd->argv[3]));
1561 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1562 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1563 silc_buffer_free(buffer);
1564 silc_buffer_free(idp);
1565 silc_buffer_free(idp2);
1567 /* Notify application */
1572 silc_free(nickname);
1575 silc_client_command_free(cmd);
1578 /* OPER command. Used to obtain server operator privileges. */
1580 SILC_CLIENT_CMD_FUNC(oper)
1582 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1583 SilcClientConnection conn = cmd->conn;
1585 unsigned char *auth_data;
1589 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1594 if (cmd->argc < 2) {
1595 cmd->client->ops->say(cmd->client, conn,
1596 "Usage: /OPER <username> [<public key>]");
1601 if (cmd->argc == 3) {
1602 /* XXX Get public key */
1607 /* Get passphrase */
1609 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1615 /* Encode the authentication payload */
1616 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1617 auth_data, strlen(auth_data));
1620 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1622 strlen(cmd->argv[1]),
1623 2, auth->data, auth->len);
1624 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1625 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1627 silc_buffer_free(buffer);
1628 silc_buffer_free(auth);
1629 memset(auth_data, 0, strlen(auth_data));
1630 silc_free(auth_data);
1632 /* Notify application */
1636 silc_client_command_free(cmd);
1639 /* SILCOPER command. Used to obtain router operator privileges. */
1641 SILC_CLIENT_CMD_FUNC(silcoper)
1643 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1644 SilcClientConnection conn = cmd->conn;
1646 unsigned char *auth_data;
1650 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1655 if (cmd->argc < 2) {
1656 cmd->client->ops->say(cmd->client, conn,
1657 "Usage: /SILCOPER <username> [<public key>]");
1662 if (cmd->argc == 3) {
1663 /* XXX Get public key */
1668 /* Get passphrase */
1670 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1676 /* Encode the authentication payload */
1677 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1678 auth_data, strlen(auth_data));
1681 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1683 strlen(cmd->argv[1]),
1684 2, auth->data, auth->len);
1685 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1686 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1688 silc_buffer_free(buffer);
1689 silc_buffer_free(auth);
1690 memset(auth_data, 0, strlen(auth_data));
1691 silc_free(auth_data);
1693 /* Notify application */
1697 silc_client_command_free(cmd);
1700 /* CONNECT command. Connects the server to another server. */
1702 SILC_CLIENT_CMD_FUNC(connect)
1704 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1705 SilcClientConnection conn = cmd->conn;
1707 unsigned char port[4];
1711 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1716 if (cmd->argc < 2) {
1717 cmd->client->ops->say(cmd->client, conn,
1718 "Usage: /CONNECT <server> [<port>]");
1723 if (cmd->argc == 3) {
1724 tmp = atoi(cmd->argv[2]);
1725 SILC_PUT32_MSB(tmp, port);
1729 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1731 strlen(cmd->argv[1]),
1734 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1736 strlen(cmd->argv[1]));
1737 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1738 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1739 silc_buffer_free(buffer);
1741 /* Notify application */
1745 silc_client_command_free(cmd);
1748 /* Command BAN. This is used to manage the ban list of the channel. */
1750 SILC_CLIENT_CMD_FUNC(ban)
1752 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1753 SilcClientConnection conn = cmd->conn;
1754 SilcChannelEntry channel;
1755 SilcBuffer buffer, chidp;
1757 char *name, *ban = NULL;
1760 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1765 if (cmd->argc < 2) {
1766 cmd->client->ops->say(cmd->client, conn,
1767 "Usage: /BAN <channel> "
1768 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1773 if (cmd->argv[1][0] == '*') {
1774 if (!conn->current_channel) {
1775 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1780 channel = conn->current_channel;
1782 name = cmd->argv[1];
1784 channel = silc_client_get_channel(cmd->client, conn, name);
1786 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1792 if (cmd->argc == 3) {
1793 if (cmd->argv[2][0] == '+')
1802 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1804 /* Send the command */
1806 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1807 1, chidp->data, chidp->len,
1808 type, ban, strlen(ban));
1810 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1811 1, chidp->data, chidp->len);
1813 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1814 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1815 silc_buffer_free(buffer);
1816 silc_buffer_free(chidp);
1818 /* Notify application */
1822 silc_client_command_free(cmd);
1825 /* CLOSE command. Close server connection to the remote server */
1827 SILC_CLIENT_CMD_FUNC(close)
1829 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1830 SilcClientConnection conn = cmd->conn;
1832 unsigned char port[4];
1836 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1841 if (cmd->argc < 2) {
1842 cmd->client->ops->say(cmd->client, conn,
1843 "Usage: /CLOSE <server> [<port>]");
1848 if (cmd->argc == 3) {
1849 tmp = atoi(cmd->argv[2]);
1850 SILC_PUT32_MSB(tmp, port);
1854 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1856 strlen(cmd->argv[1]),
1859 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1861 strlen(cmd->argv[1]));
1862 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1863 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1864 silc_buffer_free(buffer);
1866 /* Notify application */
1870 silc_client_command_free(cmd);
1873 /* SHUTDOWN command. Shutdowns the server. */
1875 SILC_CLIENT_CMD_FUNC(shutdown)
1877 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1880 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1885 /* Send the command */
1886 silc_client_send_command(cmd->client, cmd->conn,
1887 SILC_COMMAND_SHUTDOWN, 0, 0);
1889 /* Notify application */
1893 silc_client_command_free(cmd);
1896 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1898 SILC_CLIENT_CMD_FUNC(leave)
1900 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1901 SilcClientConnection conn = cmd->conn;
1902 SilcIDCacheEntry id_cache = NULL;
1903 SilcChannelEntry channel;
1904 SilcBuffer buffer, idp;
1908 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1913 if (cmd->argc != 2) {
1914 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1919 if (cmd->argv[1][0] == '*') {
1920 if (!conn->current_channel) {
1921 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1925 name = conn->current_channel->channel_name;
1927 name = cmd->argv[1];
1930 if (!conn->current_channel) {
1931 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1936 /* Get the Channel ID of the channel */
1937 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1938 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1943 channel = (SilcChannelEntry)id_cache->context;
1945 /* Send LEAVE command to the server */
1946 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1947 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1948 1, idp->data, idp->len);
1949 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1950 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1951 silc_buffer_free(buffer);
1952 silc_buffer_free(idp);
1954 /* We won't talk anymore on this channel */
1955 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1957 conn->current_channel = NULL;
1959 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1960 silc_free(channel->channel_name);
1961 silc_free(channel->id);
1962 silc_free(channel->key);
1963 silc_cipher_free(channel->channel_key);
1966 /* Notify application */
1970 silc_client_command_free(cmd);
1973 /* Command USERS. Requests the USERS of the clients joined on requested
1976 SILC_CLIENT_CMD_FUNC(users)
1978 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1979 SilcClientConnection conn = cmd->conn;
1980 SilcIDCacheEntry id_cache = NULL;
1981 SilcChannelEntry channel;
1982 SilcBuffer buffer, idp;
1986 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1991 if (cmd->argc != 2) {
1992 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1997 if (cmd->argv[1][0] == '*') {
1998 if (!conn->current_channel) {
1999 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2003 name = conn->current_channel->channel_name;
2005 name = cmd->argv[1];
2008 if (!conn->current_channel) {
2009 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2014 /* Get the Channel ID of the channel */
2015 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
2016 /* XXX should resolve the channel ID; LIST command */
2017 cmd->client->ops->say(cmd->client, conn,
2018 "You are not on that channel", name);
2023 channel = (SilcChannelEntry)id_cache->context;
2025 if (!cmd->pending) {
2026 /* Send USERS command to the server */
2027 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2028 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2029 ++conn->cmd_ident, 1,
2030 1, idp->data, idp->len);
2031 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2032 NULL, 0, NULL, NULL, buffer->data,
2034 silc_buffer_free(buffer);
2035 silc_buffer_free(idp);
2037 /* Register pending callback which will recall this command callback with
2038 same context and reprocesses the command. When reprocessing we actually
2039 display the information on the screen. */
2040 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2041 silc_client_command_destructor,
2042 silc_client_command_users,
2043 silc_client_command_dup(cmd));
2044 cmd->pending = TRUE;
2048 /* Notify application */
2052 silc_client_command_free(cmd);
2055 /* Command GETKEY. Used to fetch remote client's public key. */
2057 SILC_CLIENT_CMD_FUNC(getkey)
2059 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2060 SilcClientConnection conn = cmd->conn;
2061 SilcClient client = cmd->client;
2062 SilcClientEntry client_entry = NULL;
2064 char *nickname = NULL, *server = NULL;
2065 SilcBuffer idp, buffer;
2068 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2073 if (cmd->argc < 2) {
2074 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2079 /* Parse the typed nickname. */
2080 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2081 client->ops->say(client, conn, "Bad nickname");
2086 /* Find client entry */
2087 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2089 if (!client_entry) {
2090 /* Client entry not found, it was requested thus mark this to be
2092 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2094 silc_client_command_destructor,
2095 silc_client_command_getkey,
2096 silc_client_command_dup(cmd));
2101 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2102 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2103 1, idp->data, idp->len);
2104 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2105 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2106 silc_buffer_free(buffer);
2107 silc_buffer_free(idp);
2109 /* Notify application */
2113 silc_client_command_free(cmd);