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,
866 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
867 0, NULL, NULL, buffer->data, buffer->len, TRUE);
868 silc_buffer_free(buffer);
870 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
873 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
878 /* Start counting time */
879 for (i = 0; i < conn->ping_count; i++) {
880 if (conn->ping[i].dest_id == NULL) {
881 conn->ping[i].start_time = time(NULL);
882 conn->ping[i].dest_id = id;
883 conn->ping[i].dest_name = name;
888 if (i >= conn->ping_count) {
889 i = conn->ping_count;
890 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
891 conn->ping[i].start_time = time(NULL);
892 conn->ping[i].dest_id = id;
893 conn->ping[i].dest_name = name;
897 /* Notify application */
901 silc_client_command_free(cmd);
904 SILC_CLIENT_CMD_FUNC(notice)
908 /* Command JOIN. Joins to a channel. */
910 SILC_CLIENT_CMD_FUNC(join)
912 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
913 SilcClientConnection conn = cmd->conn;
914 SilcIDCacheEntry id_cache = NULL;
915 SilcBuffer buffer, idp;
918 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
924 /* Show channels currently joined to */
929 /* See if we have joined to the requested channel already */
930 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
932 cmd->client->ops->say(cmd->client, conn,
933 "You are talking to channel %s", cmd->argv[1]);
934 conn->current_channel = (SilcChannelEntry)id_cache->context;
936 cmd->client->screen->bottom_line->channel = cmd->argv[1];
937 silc_screen_print_bottom_line(cmd->client->screen, 0);
942 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
944 /* Send JOIN command to the server */
947 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
948 1, cmd->argv[1], cmd->argv_lens[1],
949 2, idp->data, idp->len);
950 else if (cmd->argc == 3)
953 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
954 1, cmd->argv[1], cmd->argv_lens[1],
955 2, idp->data, idp->len,
956 3, cmd->argv[2], cmd->argv_lens[2]);
959 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
960 1, cmd->argv[1], cmd->argv_lens[1],
961 2, idp->data, idp->len,
962 3, cmd->argv[2], cmd->argv_lens[2],
963 4, cmd->argv[3], cmd->argv_lens[3]);
965 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
966 0, NULL, NULL, buffer->data, buffer->len, TRUE);
967 silc_buffer_free(buffer);
968 silc_buffer_free(idp);
970 /* Notify application */
974 silc_client_command_free(cmd);
977 /* MOTD command. Requests motd from server. */
979 SILC_CLIENT_CMD_FUNC(motd)
981 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
982 SilcClientConnection conn = cmd->conn;
986 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
991 if (cmd->argc < 1 || cmd->argc > 2) {
992 cmd->client->ops->say(cmd->client, conn,
993 "Usage: /MOTD [<server>]");
998 /* Send TOPIC command to the server */
1000 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1001 1, conn->remote_host,
1002 strlen(conn->remote_host));
1004 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1007 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1008 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1009 silc_buffer_free(buffer);
1011 /* Notify application */
1015 silc_client_command_free(cmd);
1018 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1019 modes as client cannot set itself server/router operator privileges. */
1021 SILC_CLIENT_CMD_FUNC(umode)
1023 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1024 SilcClientConnection conn = cmd->conn;
1025 SilcBuffer buffer, idp;
1026 unsigned char *cp, modebuf[4];
1027 uint32 mode, add, len;
1031 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1036 if (cmd->argc < 2) {
1037 cmd->client->ops->say(cmd->client, conn,
1038 "Usage: /UMODE +|-<modes>");
1043 mode = conn->local_entry->mode;
1045 /* Are we adding or removing mode */
1046 if (cmd->argv[1][0] == '-')
1052 cp = cmd->argv[1] + 1;
1054 for (i = 0; i < len; i++) {
1059 mode |= SILC_UMODE_SERVER_OPERATOR;
1060 mode |= SILC_UMODE_ROUTER_OPERATOR;
1062 mode = SILC_UMODE_NONE;
1067 mode |= SILC_UMODE_SERVER_OPERATOR;
1069 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1073 mode |= SILC_UMODE_ROUTER_OPERATOR;
1075 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1079 mode |= SILC_UMODE_GONE;
1081 mode &= ~SILC_UMODE_GONE;
1090 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1091 SILC_PUT32_MSB(mode, modebuf);
1093 /* Send the command packet. We support sending only one mode at once
1094 that requires an argument. */
1096 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1097 1, idp->data, idp->len,
1098 2, modebuf, sizeof(modebuf));
1099 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1100 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1101 silc_buffer_free(buffer);
1102 silc_buffer_free(idp);
1104 /* Notify application */
1108 silc_client_command_free(cmd);
1111 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1112 can be set several at once. Those modes that require argument must be set
1113 separately (unless set with modes that does not require arguments). */
1115 SILC_CLIENT_CMD_FUNC(cmode)
1117 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1118 SilcClientConnection conn = cmd->conn;
1119 SilcChannelEntry channel;
1120 SilcBuffer buffer, chidp, auth = NULL;
1121 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1122 uint32 mode, add, type, len, arg_len = 0;
1126 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1131 if (cmd->argc < 3) {
1132 cmd->client->ops->say(cmd->client, conn,
1133 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1138 if (cmd->argv[1][0] == '*') {
1139 if (!conn->current_channel) {
1140 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1145 channel = conn->current_channel;
1147 name = cmd->argv[1];
1149 channel = silc_client_get_channel(cmd->client, conn, name);
1151 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1157 mode = channel->mode;
1159 /* Are we adding or removing mode */
1160 if (cmd->argv[2][0] == '-')
1165 /* Argument type to be sent to server */
1169 cp = cmd->argv[2] + 1;
1171 for (i = 0; i < len; i++) {
1175 mode |= SILC_CHANNEL_MODE_PRIVATE;
1177 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1181 mode |= SILC_CHANNEL_MODE_SECRET;
1183 mode &= ~SILC_CHANNEL_MODE_SECRET;
1187 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1189 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1193 mode |= SILC_CHANNEL_MODE_INVITE;
1195 mode &= ~SILC_CHANNEL_MODE_INVITE;
1199 mode |= SILC_CHANNEL_MODE_TOPIC;
1201 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1206 mode |= SILC_CHANNEL_MODE_ULIMIT;
1208 ll = atoi(cmd->argv[3]);
1209 SILC_PUT32_MSB(ll, tmp);
1213 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1218 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1221 arg_len = cmd->argv_lens[3];
1223 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1228 mode |= SILC_CHANNEL_MODE_CIPHER;
1231 arg_len = cmd->argv_lens[3];
1233 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1238 mode |= SILC_CHANNEL_MODE_HMAC;
1241 arg_len = cmd->argv_lens[3];
1243 mode &= ~SILC_CHANNEL_MODE_HMAC;
1248 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1251 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1252 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1253 cmd->client->private_key,
1258 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1259 cmd->argv[3], cmd->argv_lens[3]);
1263 arg_len = auth->len;
1265 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1275 if (type && cmd->argc < 3) {
1280 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1281 SILC_PUT32_MSB(mode, modebuf);
1283 /* Send the command packet. We support sending only one mode at once
1284 that requires an argument. */
1287 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1288 1, chidp->data, chidp->len,
1289 2, modebuf, sizeof(modebuf),
1290 type, arg, arg_len);
1293 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1294 1, chidp->data, chidp->len,
1295 2, modebuf, sizeof(modebuf));
1298 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1299 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1300 silc_buffer_free(buffer);
1301 silc_buffer_free(chidp);
1303 silc_buffer_free(auth);
1305 /* Notify application */
1309 silc_client_command_free(cmd);
1312 /* CUMODE command. Changes client's mode on a channel. */
1314 SILC_CLIENT_CMD_FUNC(cumode)
1316 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1317 SilcClientConnection conn = cmd->conn;
1318 SilcChannelEntry channel;
1319 SilcChannelUser chu;
1320 SilcClientEntry client_entry;
1321 SilcBuffer buffer, clidp, chidp, auth = NULL;
1322 unsigned char *name, *cp, modebuf[4];
1323 uint32 mode = 0, add, len;
1324 char *nickname = NULL, *server = NULL;
1329 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1334 if (cmd->argc < 4) {
1335 cmd->client->ops->say(cmd->client, conn,
1336 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1341 if (cmd->argv[1][0] == '*') {
1342 if (!conn->current_channel) {
1343 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1348 channel = conn->current_channel;
1350 name = cmd->argv[1];
1352 channel = silc_client_get_channel(cmd->client, conn, name);
1354 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1360 /* Parse the typed nickname. */
1361 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1362 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1367 /* Find client entry */
1368 client_entry = silc_idlist_get_client(cmd->client, conn,
1369 nickname, server, num, TRUE);
1370 if (!client_entry) {
1376 /* Client entry not found, it was requested thus mark this to be
1378 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1380 silc_client_command_destructor,
1381 silc_client_command_cumode,
1382 silc_client_command_dup(cmd));
1387 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1388 if (chu->client == client_entry) {
1394 /* Are we adding or removing mode */
1395 if (cmd->argv[2][0] == '-')
1401 cp = cmd->argv[2] + 1;
1403 for (i = 0; i < len; i++) {
1407 mode |= SILC_CHANNEL_UMODE_CHANFO;
1408 mode |= SILC_CHANNEL_UMODE_CHANOP;
1410 mode = SILC_CHANNEL_UMODE_NONE;
1415 if (cmd->argc == 5) {
1416 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1417 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1418 cmd->client->private_key,
1423 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1424 cmd->argv[4], cmd->argv_lens[4]);
1427 mode |= SILC_CHANNEL_UMODE_CHANFO;
1429 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1434 mode |= SILC_CHANNEL_UMODE_CHANOP;
1436 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1445 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1446 SILC_PUT32_MSB(mode, modebuf);
1447 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1449 /* Send the command packet. We support sending only one mode at once
1450 that requires an argument. */
1451 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1452 1, chidp->data, chidp->len,
1454 3, clidp->data, clidp->len,
1455 4, auth ? auth->data : NULL,
1456 auth ? auth->len : 0);
1458 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1459 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1460 silc_buffer_free(buffer);
1461 silc_buffer_free(chidp);
1462 silc_buffer_free(clidp);
1464 silc_buffer_free(auth);
1466 /* Notify application */
1471 silc_free(nickname);
1474 silc_client_command_free(cmd);
1477 /* KICK command. Kicks a client out of channel. */
1479 SILC_CLIENT_CMD_FUNC(kick)
1481 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1482 SilcClientConnection conn = cmd->conn;
1483 SilcIDCacheEntry id_cache = NULL;
1484 SilcChannelEntry channel;
1485 SilcBuffer buffer, idp, idp2;
1486 SilcClientEntry target;
1489 char *nickname = NULL, *server = NULL;
1492 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1497 if (cmd->argc < 3) {
1498 cmd->client->ops->say(cmd->client, conn,
1499 "Usage: /KICK <channel> <nickname> [<comment>]");
1504 if (cmd->argv[1][0] == '*') {
1505 if (!conn->current_channel) {
1506 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1510 name = conn->current_channel->channel_name;
1512 name = cmd->argv[1];
1515 if (!conn->current_channel) {
1516 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1521 /* Get the Channel ID of the channel */
1522 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1523 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1528 channel = (SilcChannelEntry)id_cache->context;
1530 /* Parse the typed nickname. */
1531 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1532 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1537 /* Get the target client */
1538 target = silc_idlist_get_client(cmd->client, conn, nickname,
1539 server, num, FALSE);
1541 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1547 /* Send KICK command to the server */
1548 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1549 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1551 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1552 1, idp->data, idp->len,
1553 2, idp2->data, idp2->len);
1555 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1556 1, idp->data, idp->len,
1557 2, idp2->data, idp2->len,
1559 strlen(cmd->argv[3]));
1560 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1561 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1562 silc_buffer_free(buffer);
1563 silc_buffer_free(idp);
1564 silc_buffer_free(idp2);
1566 /* Notify application */
1571 silc_free(nickname);
1574 silc_client_command_free(cmd);
1577 /* OPER command. Used to obtain server operator privileges. */
1579 SILC_CLIENT_CMD_FUNC(oper)
1581 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1582 SilcClientConnection conn = cmd->conn;
1584 unsigned char *auth_data;
1588 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1593 if (cmd->argc < 2) {
1594 cmd->client->ops->say(cmd->client, conn,
1595 "Usage: /OPER <username> [<public key>]");
1600 if (cmd->argc == 3) {
1601 /* XXX Get public key */
1606 /* Get passphrase */
1608 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1614 /* Encode the authentication payload */
1615 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1616 auth_data, strlen(auth_data));
1619 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1621 strlen(cmd->argv[1]),
1622 2, auth->data, auth->len);
1623 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1624 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1626 silc_buffer_free(buffer);
1627 silc_buffer_free(auth);
1628 memset(auth_data, 0, strlen(auth_data));
1629 silc_free(auth_data);
1631 /* Notify application */
1635 silc_client_command_free(cmd);
1638 /* SILCOPER command. Used to obtain router operator privileges. */
1640 SILC_CLIENT_CMD_FUNC(silcoper)
1642 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1643 SilcClientConnection conn = cmd->conn;
1645 unsigned char *auth_data;
1649 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1654 if (cmd->argc < 2) {
1655 cmd->client->ops->say(cmd->client, conn,
1656 "Usage: /SILCOPER <username> [<public key>]");
1661 if (cmd->argc == 3) {
1662 /* XXX Get public key */
1667 /* Get passphrase */
1669 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1675 /* Encode the authentication payload */
1676 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1677 auth_data, strlen(auth_data));
1680 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1682 strlen(cmd->argv[1]),
1683 2, auth->data, auth->len);
1684 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1685 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1687 silc_buffer_free(buffer);
1688 silc_buffer_free(auth);
1689 memset(auth_data, 0, strlen(auth_data));
1690 silc_free(auth_data);
1692 /* Notify application */
1696 silc_client_command_free(cmd);
1699 /* CONNECT command. Connects the server to another server. */
1701 SILC_CLIENT_CMD_FUNC(connect)
1703 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1704 SilcClientConnection conn = cmd->conn;
1706 unsigned char port[4];
1710 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1715 if (cmd->argc < 2) {
1716 cmd->client->ops->say(cmd->client, conn,
1717 "Usage: /CONNECT <server> [<port>]");
1722 if (cmd->argc == 3) {
1723 tmp = atoi(cmd->argv[2]);
1724 SILC_PUT32_MSB(tmp, port);
1728 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1730 strlen(cmd->argv[1]),
1733 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1735 strlen(cmd->argv[1]));
1736 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1737 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1738 silc_buffer_free(buffer);
1740 /* Notify application */
1744 silc_client_command_free(cmd);
1747 /* Command BAN. This is used to manage the ban list of the channel. */
1749 SILC_CLIENT_CMD_FUNC(ban)
1751 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1752 SilcClientConnection conn = cmd->conn;
1753 SilcChannelEntry channel;
1754 SilcBuffer buffer, chidp;
1756 char *name, *ban = NULL;
1759 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1764 if (cmd->argc < 2) {
1765 cmd->client->ops->say(cmd->client, conn,
1766 "Usage: /BAN <channel> "
1767 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1772 if (cmd->argv[1][0] == '*') {
1773 if (!conn->current_channel) {
1774 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1779 channel = conn->current_channel;
1781 name = cmd->argv[1];
1783 channel = silc_client_get_channel(cmd->client, conn, name);
1785 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1791 if (cmd->argc == 3) {
1792 if (cmd->argv[2][0] == '+')
1801 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1803 /* Send the command */
1805 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1806 1, chidp->data, chidp->len,
1807 type, ban, strlen(ban));
1809 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1810 1, chidp->data, chidp->len);
1812 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1813 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1814 silc_buffer_free(buffer);
1815 silc_buffer_free(chidp);
1817 /* Notify application */
1821 silc_client_command_free(cmd);
1824 /* CLOSE command. Close server connection to the remote server */
1826 SILC_CLIENT_CMD_FUNC(close)
1828 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1829 SilcClientConnection conn = cmd->conn;
1831 unsigned char port[4];
1835 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1840 if (cmd->argc < 2) {
1841 cmd->client->ops->say(cmd->client, conn,
1842 "Usage: /CLOSE <server> [<port>]");
1847 if (cmd->argc == 3) {
1848 tmp = atoi(cmd->argv[2]);
1849 SILC_PUT32_MSB(tmp, port);
1853 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1855 strlen(cmd->argv[1]),
1858 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1860 strlen(cmd->argv[1]));
1861 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1862 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1863 silc_buffer_free(buffer);
1865 /* Notify application */
1869 silc_client_command_free(cmd);
1872 /* SHUTDOWN command. Shutdowns the server. */
1874 SILC_CLIENT_CMD_FUNC(shutdown)
1876 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1879 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1884 /* Send the command */
1885 silc_client_send_command(cmd->client, cmd->conn,
1886 SILC_COMMAND_SHUTDOWN, 0, 0);
1888 /* Notify application */
1892 silc_client_command_free(cmd);
1895 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1897 SILC_CLIENT_CMD_FUNC(leave)
1899 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1900 SilcClientConnection conn = cmd->conn;
1901 SilcIDCacheEntry id_cache = NULL;
1902 SilcChannelEntry channel;
1903 SilcBuffer buffer, idp;
1907 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1912 if (cmd->argc != 2) {
1913 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1918 if (cmd->argv[1][0] == '*') {
1919 if (!conn->current_channel) {
1920 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1924 name = conn->current_channel->channel_name;
1926 name = cmd->argv[1];
1929 if (!conn->current_channel) {
1930 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1935 /* Get the Channel ID of the channel */
1936 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1937 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1942 channel = (SilcChannelEntry)id_cache->context;
1944 /* Send LEAVE command to the server */
1945 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1946 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1947 1, idp->data, idp->len);
1948 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1949 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1950 silc_buffer_free(buffer);
1951 silc_buffer_free(idp);
1953 /* We won't talk anymore on this channel */
1954 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1956 conn->current_channel = NULL;
1958 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1959 silc_free(channel->channel_name);
1960 silc_free(channel->id);
1961 silc_free(channel->key);
1962 silc_cipher_free(channel->channel_key);
1965 /* Notify application */
1969 silc_client_command_free(cmd);
1972 /* Command USERS. Requests the USERS of the clients joined on requested
1975 SILC_CLIENT_CMD_FUNC(users)
1977 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1978 SilcClientConnection conn = cmd->conn;
1979 SilcIDCacheEntry id_cache = NULL;
1980 SilcChannelEntry channel;
1981 SilcBuffer buffer, idp;
1985 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1990 if (cmd->argc != 2) {
1991 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1996 if (cmd->argv[1][0] == '*') {
1997 if (!conn->current_channel) {
1998 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2002 name = conn->current_channel->channel_name;
2004 name = cmd->argv[1];
2007 if (!conn->current_channel) {
2008 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2013 /* Get the Channel ID of the channel */
2014 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
2015 /* XXX should resolve the channel ID; LIST command */
2016 cmd->client->ops->say(cmd->client, conn,
2017 "You are not on that channel", name);
2022 channel = (SilcChannelEntry)id_cache->context;
2024 if (!cmd->pending) {
2025 /* Send USERS command to the server */
2026 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2027 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2028 ++conn->cmd_ident, 1,
2029 1, idp->data, idp->len);
2030 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2031 NULL, 0, NULL, NULL, buffer->data,
2033 silc_buffer_free(buffer);
2034 silc_buffer_free(idp);
2036 /* Register pending callback which will recall this command callback with
2037 same context and reprocesses the command. When reprocessing we actually
2038 display the information on the screen. */
2039 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2040 silc_client_command_destructor,
2041 silc_client_command_users,
2042 silc_client_command_dup(cmd));
2043 cmd->pending = TRUE;
2047 /* Notify application */
2051 silc_client_command_free(cmd);
2054 /* Command GETKEY. Used to fetch remote client's public key. */
2056 SILC_CLIENT_CMD_FUNC(getkey)
2058 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2059 SilcClientConnection conn = cmd->conn;
2060 SilcClient client = cmd->client;
2061 SilcClientEntry client_entry = NULL;
2063 char *nickname = NULL, *server = NULL;
2064 SilcBuffer idp, buffer;
2067 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2072 if (cmd->argc < 2) {
2073 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2078 /* Parse the typed nickname. */
2079 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2080 client->ops->say(client, conn, "Bad nickname");
2085 /* Find client entry */
2086 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2088 if (!client_entry) {
2089 /* Client entry not found, it was requested thus mark this to be
2091 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2093 silc_client_command_destructor,
2094 silc_client_command_getkey,
2095 silc_client_command_dup(cmd));
2100 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2101 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2102 1, idp->data, idp->len);
2103 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2104 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2105 silc_buffer_free(buffer);
2106 silc_buffer_free(idp);
2108 /* Notify application */
2112 silc_client_command_free(cmd);