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), SILC_CLIENT_MESSAGE_ERROR, \
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]);
198 silc_free(ctx->argv_lens);
199 silc_free(ctx->argv_types);
204 /* Duplicate Command Context by adding reference counter. The context won't
205 be free'd untill it hits zero. */
207 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
210 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
215 /* Pending command destructor. */
217 static void silc_client_command_destructor(void *context)
219 silc_client_command_free((SilcClientCommandContext)context);
222 /* silc_client_get_client completion callback */
223 void silc_client_command_completion(SilcClient client,
224 SilcClientConnection conn,
225 SilcClientEntry clients,
226 uint32 clients_count,
232 /* Command WHOIS. This command is used to query information about
235 SILC_CLIENT_CMD_FUNC(whois)
237 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
238 SilcClientConnection conn = cmd->conn;
242 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
247 /* Given without arguments fetches client's own information */
249 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
250 silc_client_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
252 1, 3, buffer->data, buffer->len);
253 silc_buffer_free(buffer);
257 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
258 cmd->argc - 1, ++cmd->argv,
259 ++cmd->argv_lens, ++cmd->argv_types,
261 silc_client_packet_send(cmd->client, cmd->conn->sock,
262 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
263 buffer->data, buffer->len, TRUE);
264 silc_buffer_free(buffer);
269 /* Notify application */
273 silc_client_command_free(cmd);
276 /* Command WHOWAS. This command is used to query history information about
277 specific user that used to exist in the network. */
279 SILC_CLIENT_CMD_FUNC(whowas)
281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
282 SilcClientConnection conn = cmd->conn;
286 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
291 if (cmd->argc < 2 || cmd->argc > 3) {
292 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
293 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
298 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
299 cmd->argc - 1, ++cmd->argv,
300 ++cmd->argv_lens, ++cmd->argv_types,
302 silc_client_packet_send(cmd->client, cmd->conn->sock,
303 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
304 buffer->data, buffer->len, TRUE);
305 silc_buffer_free(buffer);
310 /* Notify application */
314 silc_client_command_free(cmd);
317 /* Command IDENTIFY. This command is used to query information about
318 specific user, especially ID's. */
320 SILC_CLIENT_CMD_FUNC(identify)
322 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
323 SilcClientConnection conn = cmd->conn;
327 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
332 if (cmd->argc < 2 || cmd->argc > 3) {
333 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
334 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
340 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
341 ++conn->cmd_ident, 1,
345 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
346 ++conn->cmd_ident, 2,
352 silc_client_packet_send(cmd->client, cmd->conn->sock,
353 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
354 buffer->data, buffer->len, TRUE);
355 silc_buffer_free(buffer);
357 /* Notify application */
361 silc_client_command_free(cmd);
364 /* Command NICK. Shows current nickname/sets new nickname on current
367 SILC_CLIENT_CMD_FUNC(nick)
369 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
370 SilcClientConnection conn = cmd->conn;
374 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
380 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
381 "Usage: /NICK <nickname>");
386 if (!strcmp(conn->nickname, cmd->argv[1]))
389 /* Show current nickname */
392 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
393 "Your nickname is %s on server %s",
394 conn->nickname, conn->remote_host);
396 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
397 "Your nickname is %s", conn->nickname);
400 /* XXX Notify application */
405 /* Set new nickname */
406 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
407 cmd->argc - 1, ++cmd->argv,
408 ++cmd->argv_lens, ++cmd->argv_types,
409 ++cmd->conn->cmd_ident);
410 silc_client_packet_send(cmd->client, cmd->conn->sock,
411 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
412 buffer->data, buffer->len, TRUE);
413 silc_buffer_free(buffer);
418 silc_free(conn->nickname);
419 conn->nickname = strdup(cmd->argv[1]);
421 /* Notify application */
425 silc_client_command_free(cmd);
428 /* Command LIST. Lists channels on the current server. */
430 SILC_CLIENT_CMD_FUNC(list)
432 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
433 SilcClientConnection conn = cmd->conn;
434 SilcIDCacheEntry id_cache = NULL;
435 SilcChannelEntry channel;
436 SilcBuffer buffer, idp = NULL;
440 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
445 if (cmd->argc == 2) {
448 /* Get the Channel ID of the channel */
449 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
450 channel = (SilcChannelEntry)id_cache->context;
451 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
456 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
457 ++conn->cmd_ident, 0);
459 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
460 ++conn->cmd_ident, 1,
461 1, idp->data, idp->len);
463 silc_client_packet_send(cmd->client, cmd->conn->sock,
464 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
465 buffer->data, buffer->len, TRUE);
466 silc_buffer_free(buffer);
468 silc_buffer_free(idp);
470 /* Notify application */
474 silc_client_command_free(cmd);
477 /* Command TOPIC. Sets/shows topic on a channel. */
479 SILC_CLIENT_CMD_FUNC(topic)
481 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
482 SilcClientConnection conn = cmd->conn;
483 SilcIDCacheEntry id_cache = NULL;
484 SilcChannelEntry channel;
485 SilcBuffer buffer, idp;
489 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
494 if (cmd->argc < 2 || cmd->argc > 3) {
495 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
496 "Usage: /TOPIC <channel> [<topic>]");
501 if (cmd->argv[1][0] == '*') {
502 if (!conn->current_channel) {
503 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
507 name = conn->current_channel->channel_name;
512 if (!conn->current_channel) {
513 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
518 /* Get the Channel ID of the channel */
519 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
520 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
525 channel = (SilcChannelEntry)id_cache->context;
527 /* Send TOPIC command to the server */
528 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
530 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
531 ++conn->cmd_ident, 2,
532 1, idp->data, idp->len,
534 strlen(cmd->argv[2]));
536 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
537 ++conn->cmd_ident, 1,
538 1, idp->data, idp->len);
539 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
540 0, NULL, NULL, buffer->data, buffer->len, TRUE);
541 silc_buffer_free(buffer);
542 silc_buffer_free(idp);
544 /* Notify application */
548 silc_client_command_free(cmd);
551 /* Command INVITE. Invites specific client to join a channel. This is
552 also used to mange the invite list of the channel. */
554 SILC_CLIENT_CMD_FUNC(invite)
556 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
557 SilcClient client = cmd->client;
558 SilcClientConnection conn = cmd->conn;
559 SilcClientEntry client_entry = NULL;
560 SilcChannelEntry channel;
561 SilcBuffer buffer, clidp, chidp;
562 uint32 num = 0, type = 0;
563 char *nickname = NULL, *server = NULL, *name;
567 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
573 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
574 "Usage: /INVITE <channel> [<nickname>[@server>]"
575 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
580 if (cmd->argv[1][0] == '*') {
581 if (!conn->current_channel) {
582 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
587 channel = conn->current_channel;
591 channel = silc_client_get_channel(cmd->client, conn, name);
593 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
599 /* Parse the typed nickname. */
600 if (cmd->argc == 3) {
601 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
602 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
603 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
608 /* Find client entry */
609 client_entry = silc_idlist_get_client(client, conn, nickname,
622 /* Client entry not found, it was requested thus mark this to be
624 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
626 silc_client_command_destructor,
627 silc_client_command_invite,
628 silc_client_command_dup(cmd));
633 invite = cmd->argv[2];
635 if (cmd->argv[2][0] == '+')
642 /* Send the command */
643 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
645 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
646 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
647 ++conn->cmd_ident, 3,
648 1, chidp->data, chidp->len,
649 2, clidp->data, clidp->len,
650 type, invite, invite ?
652 silc_buffer_free(clidp);
654 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
655 ++conn->cmd_ident, 2,
656 1, chidp->data, chidp->len,
657 type, invite, invite ?
661 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
662 0, NULL, NULL, buffer->data, buffer->len, TRUE);
663 silc_buffer_free(buffer);
664 silc_buffer_free(chidp);
666 /* Notify application */
674 silc_client_command_free(cmd);
679 SilcClientConnection conn;
682 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
684 QuitInternal q = (QuitInternal)context;
686 /* Close connection */
687 q->client->ops->disconnect(q->client, q->conn);
688 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
693 /* Command QUIT. Closes connection with current server. */
695 SILC_CLIENT_CMD_FUNC(quit)
697 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
702 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
708 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
709 &cmd->argv[1], &cmd->argv_lens[1],
710 &cmd->argv_types[1], 0);
712 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
713 NULL, NULL, NULL, 0);
714 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
716 buffer->data, buffer->len, TRUE);
717 silc_buffer_free(buffer);
719 q = silc_calloc(1, sizeof(*q));
720 q->client = cmd->client;
723 /* We quit the connection with little timeout */
724 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
725 silc_client_command_quit_cb, (void *)q,
726 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
728 /* Notify application */
732 silc_client_command_free(cmd);
735 /* Command KILL. Router operator can use this command to remove an client
736 fromthe SILC Network. */
738 SILC_CLIENT_CMD_FUNC(kill)
740 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
741 SilcClientConnection conn = cmd->conn;
742 SilcBuffer buffer, idp;
743 SilcClientEntry target;
745 char *nickname = NULL, *server = NULL;
748 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
754 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
755 "Usage: /KILL <nickname> [<comment>]");
760 /* Parse the typed nickname. */
761 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
762 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
768 /* Get the target client */
769 target = silc_idlist_get_client(cmd->client, conn, nickname,
781 /* Client entry not found, it was requested thus mark this to be
783 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
785 silc_client_command_destructor,
786 silc_client_command_kill,
787 silc_client_command_dup(cmd));
792 /* Send the KILL command to the server */
793 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
795 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
796 1, idp->data, idp->len);
798 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
799 1, idp->data, idp->len,
801 strlen(cmd->argv[2]));
802 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
803 0, NULL, NULL, buffer->data, buffer->len, TRUE);
804 silc_buffer_free(buffer);
805 silc_buffer_free(idp);
807 /* Notify application */
815 silc_client_command_free(cmd);
818 /* Command INFO. Request information about specific server. If specific
819 server is not provided the current server is used. */
821 SILC_CLIENT_CMD_FUNC(info)
823 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
824 SilcClientConnection conn = cmd->conn;
829 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
835 name = strdup(cmd->argv[1]);
837 /* Send the command */
839 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
840 1, name, strlen(name));
842 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
843 NULL, NULL, NULL, 0);
844 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
845 0, NULL, NULL, buffer->data, buffer->len, TRUE);
846 silc_buffer_free(buffer);
850 /* Notify application */
854 silc_client_command_free(cmd);
857 /* Command PING. Sends ping to server. This is used to test the
858 communication channel. */
860 SILC_CLIENT_CMD_FUNC(ping)
862 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
863 SilcClientConnection conn = cmd->conn;
869 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
874 /* Send the command */
875 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
876 1, conn->remote_id_data,
877 silc_id_get_len(conn->remote_id,
879 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
880 0, NULL, NULL, buffer->data, buffer->len, TRUE);
881 silc_buffer_free(buffer);
883 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
886 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
891 /* Start counting time */
892 for (i = 0; i < conn->ping_count; i++) {
893 if (conn->ping[i].dest_id == NULL) {
894 conn->ping[i].start_time = time(NULL);
895 conn->ping[i].dest_id = id;
896 conn->ping[i].dest_name = strdup(conn->remote_host);
901 if (i >= conn->ping_count) {
902 i = conn->ping_count;
903 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
904 conn->ping[i].start_time = time(NULL);
905 conn->ping[i].dest_id = id;
906 conn->ping[i].dest_name = strdup(conn->remote_host);
910 /* Notify application */
914 silc_client_command_free(cmd);
917 SILC_CLIENT_CMD_FUNC(notice)
921 /* Command JOIN. Joins to a channel. */
923 SILC_CLIENT_CMD_FUNC(join)
925 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
926 SilcClientConnection conn = cmd->conn;
927 SilcIDCacheEntry id_cache = NULL;
928 SilcBuffer buffer, idp;
931 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
937 /* Show channels currently joined to */
942 /* See if we have joined to the requested channel already */
943 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
946 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
947 "You are talking to channel %s", cmd->argv[1]);
948 conn->current_channel = (SilcChannelEntry)id_cache->context;
949 cmd->client->screen->bottom_line->channel = cmd->argv[1];
950 silc_screen_print_bottom_line(cmd->client->screen, 0);
955 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
957 /* Send JOIN command to the server */
960 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
961 1, cmd->argv[1], cmd->argv_lens[1],
962 2, idp->data, idp->len);
963 else if (cmd->argc == 3)
966 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
967 1, cmd->argv[1], cmd->argv_lens[1],
968 2, idp->data, idp->len,
969 3, cmd->argv[2], cmd->argv_lens[2]);
972 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
973 1, cmd->argv[1], cmd->argv_lens[1],
974 2, idp->data, idp->len,
975 3, cmd->argv[2], cmd->argv_lens[2],
976 4, cmd->argv[3], cmd->argv_lens[3]);
978 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
979 0, NULL, NULL, buffer->data, buffer->len, TRUE);
980 silc_buffer_free(buffer);
981 silc_buffer_free(idp);
983 /* Notify application */
987 silc_client_command_free(cmd);
990 /* MOTD command. Requests motd from server. */
992 SILC_CLIENT_CMD_FUNC(motd)
994 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
995 SilcClientConnection conn = cmd->conn;
999 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1004 if (cmd->argc < 1 || cmd->argc > 2) {
1005 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1006 "Usage: /MOTD [<server>]");
1011 /* Send TOPIC command to the server */
1013 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1014 1, conn->remote_host,
1015 strlen(conn->remote_host));
1017 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1020 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1021 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1022 silc_buffer_free(buffer);
1024 /* Notify application */
1028 silc_client_command_free(cmd);
1031 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1032 modes as client cannot set itself server/router operator privileges. */
1034 SILC_CLIENT_CMD_FUNC(umode)
1036 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1037 SilcClientConnection conn = cmd->conn;
1038 SilcBuffer buffer, idp;
1039 unsigned char *cp, modebuf[4];
1040 uint32 mode, add, len;
1044 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1049 if (cmd->argc < 2) {
1050 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1051 "Usage: /UMODE +|-<modes>");
1056 mode = conn->local_entry->mode;
1058 /* Are we adding or removing mode */
1059 if (cmd->argv[1][0] == '-')
1065 cp = cmd->argv[1] + 1;
1067 for (i = 0; i < len; i++) {
1072 mode |= SILC_UMODE_SERVER_OPERATOR;
1073 mode |= SILC_UMODE_ROUTER_OPERATOR;
1075 mode = SILC_UMODE_NONE;
1080 mode |= SILC_UMODE_SERVER_OPERATOR;
1082 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1086 mode |= SILC_UMODE_ROUTER_OPERATOR;
1088 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1092 mode |= SILC_UMODE_GONE;
1094 mode &= ~SILC_UMODE_GONE;
1103 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1104 SILC_PUT32_MSB(mode, modebuf);
1106 /* Send the command packet. We support sending only one mode at once
1107 that requires an argument. */
1109 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1110 1, idp->data, idp->len,
1111 2, modebuf, sizeof(modebuf));
1112 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1113 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1114 silc_buffer_free(buffer);
1115 silc_buffer_free(idp);
1117 /* Notify application */
1121 silc_client_command_free(cmd);
1124 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1125 can be set several at once. Those modes that require argument must be set
1126 separately (unless set with modes that does not require arguments). */
1128 SILC_CLIENT_CMD_FUNC(cmode)
1130 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1131 SilcClientConnection conn = cmd->conn;
1132 SilcChannelEntry channel;
1133 SilcBuffer buffer, chidp, auth = NULL;
1134 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1135 uint32 mode, add, type, len, arg_len = 0;
1139 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1144 if (cmd->argc < 3) {
1145 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1146 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1151 if (cmd->argv[1][0] == '*') {
1152 if (!conn->current_channel) {
1153 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1158 channel = conn->current_channel;
1160 name = cmd->argv[1];
1162 channel = silc_client_get_channel(cmd->client, conn, name);
1164 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
1170 mode = channel->mode;
1172 /* Are we adding or removing mode */
1173 if (cmd->argv[2][0] == '-')
1178 /* Argument type to be sent to server */
1182 cp = cmd->argv[2] + 1;
1184 for (i = 0; i < len; i++) {
1188 mode |= SILC_CHANNEL_MODE_PRIVATE;
1190 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1194 mode |= SILC_CHANNEL_MODE_SECRET;
1196 mode &= ~SILC_CHANNEL_MODE_SECRET;
1200 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1202 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1206 mode |= SILC_CHANNEL_MODE_INVITE;
1208 mode &= ~SILC_CHANNEL_MODE_INVITE;
1212 mode |= SILC_CHANNEL_MODE_TOPIC;
1214 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1219 mode |= SILC_CHANNEL_MODE_ULIMIT;
1221 if (cmd->argc < 4) {
1222 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1223 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1227 ll = atoi(cmd->argv[3]);
1228 SILC_PUT32_MSB(ll, tmp);
1232 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1237 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1239 if (cmd->argc < 4) {
1240 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1241 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1246 arg_len = cmd->argv_lens[3];
1248 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1253 mode |= SILC_CHANNEL_MODE_CIPHER;
1255 if (cmd->argc < 4) {
1256 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1257 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1262 arg_len = cmd->argv_lens[3];
1264 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1269 mode |= SILC_CHANNEL_MODE_HMAC;
1271 if (cmd->argc < 4) {
1272 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1273 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1278 arg_len = cmd->argv_lens[3];
1280 mode &= ~SILC_CHANNEL_MODE_HMAC;
1285 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1288 if (cmd->argc < 4) {
1289 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1290 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1295 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1296 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1297 cmd->client->private_key,
1302 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1303 cmd->argv[3], cmd->argv_lens[3]);
1307 arg_len = auth->len;
1309 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1319 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1320 SILC_PUT32_MSB(mode, modebuf);
1322 /* Send the command packet. We support sending only one mode at once
1323 that requires an argument. */
1326 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1327 1, chidp->data, chidp->len,
1328 2, modebuf, sizeof(modebuf),
1329 type, arg, arg_len);
1332 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1333 1, chidp->data, chidp->len,
1334 2, modebuf, sizeof(modebuf));
1337 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1338 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1339 silc_buffer_free(buffer);
1340 silc_buffer_free(chidp);
1342 silc_buffer_free(auth);
1344 /* Notify application */
1348 silc_client_command_free(cmd);
1351 /* CUMODE command. Changes client's mode on a channel. */
1353 SILC_CLIENT_CMD_FUNC(cumode)
1355 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1356 SilcClientConnection conn = cmd->conn;
1357 SilcChannelEntry channel;
1358 SilcChannelUser chu;
1359 SilcClientEntry client_entry;
1360 SilcBuffer buffer, clidp, chidp, auth = NULL;
1361 unsigned char *name, *cp, modebuf[4];
1362 uint32 mode = 0, add, len;
1363 char *nickname = NULL, *server = NULL;
1368 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1373 if (cmd->argc < 4) {
1374 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1375 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1380 if (cmd->argv[1][0] == '*') {
1381 if (!conn->current_channel) {
1382 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1387 channel = conn->current_channel;
1389 name = cmd->argv[1];
1391 channel = silc_client_get_channel(cmd->client, conn, name);
1393 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
1399 /* Parse the typed nickname. */
1400 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1401 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
1406 /* Find client entry */
1407 client_entry = silc_idlist_get_client(cmd->client, conn,
1408 nickname, server, num, TRUE);
1409 if (!client_entry) {
1415 /* Client entry not found, it was requested thus mark this to be
1417 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1419 silc_client_command_destructor,
1420 silc_client_command_cumode,
1421 silc_client_command_dup(cmd));
1426 /* Get the current mode */
1427 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1428 if (chu->client == client_entry) {
1434 /* Are we adding or removing mode */
1435 if (cmd->argv[2][0] == '-')
1441 cp = cmd->argv[2] + 1;
1443 for (i = 0; i < len; i++) {
1447 mode |= SILC_CHANNEL_UMODE_CHANFO;
1448 mode |= SILC_CHANNEL_UMODE_CHANOP;
1450 mode = SILC_CHANNEL_UMODE_NONE;
1455 if (cmd->argc == 5) {
1456 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1457 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1458 cmd->client->private_key,
1463 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1464 cmd->argv[4], cmd->argv_lens[4]);
1467 mode |= SILC_CHANNEL_UMODE_CHANFO;
1469 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1474 mode |= SILC_CHANNEL_UMODE_CHANOP;
1476 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1485 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1486 SILC_PUT32_MSB(mode, modebuf);
1487 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1489 /* Send the command packet. We support sending only one mode at once
1490 that requires an argument. */
1491 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1492 1, chidp->data, chidp->len,
1494 3, clidp->data, clidp->len,
1495 4, auth ? auth->data : NULL,
1496 auth ? auth->len : 0);
1498 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1499 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1500 silc_buffer_free(buffer);
1501 silc_buffer_free(chidp);
1502 silc_buffer_free(clidp);
1504 silc_buffer_free(auth);
1506 /* Notify application */
1511 silc_free(nickname);
1514 silc_client_command_free(cmd);
1517 /* KICK command. Kicks a client out of channel. */
1519 SILC_CLIENT_CMD_FUNC(kick)
1521 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1522 SilcClientConnection conn = cmd->conn;
1523 SilcIDCacheEntry id_cache = NULL;
1524 SilcChannelEntry channel;
1525 SilcBuffer buffer, idp, idp2;
1526 SilcClientEntry target;
1529 char *nickname = NULL, *server = NULL;
1532 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1537 if (cmd->argc < 3) {
1538 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1539 "Usage: /KICK <channel> <nickname> [<comment>]");
1544 if (cmd->argv[1][0] == '*') {
1545 if (!conn->current_channel) {
1546 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1550 name = conn->current_channel->channel_name;
1552 name = cmd->argv[1];
1555 if (!conn->current_channel) {
1556 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
1561 /* Get the Channel ID of the channel */
1562 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1563 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
1568 channel = (SilcChannelEntry)id_cache->context;
1570 /* Parse the typed nickname. */
1571 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1572 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
1577 /* Get the target client */
1578 target = silc_idlist_get_client(cmd->client, conn, nickname,
1579 server, num, FALSE);
1581 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s",
1587 /* Send KICK command to the server */
1588 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1589 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1591 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1592 1, idp->data, idp->len,
1593 2, idp2->data, idp2->len);
1595 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1596 1, idp->data, idp->len,
1597 2, idp2->data, idp2->len,
1599 strlen(cmd->argv[3]));
1600 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1601 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1602 silc_buffer_free(buffer);
1603 silc_buffer_free(idp);
1604 silc_buffer_free(idp2);
1606 /* Notify application */
1611 silc_free(nickname);
1614 silc_client_command_free(cmd);
1617 static void silc_client_command_oper_send(unsigned char *data,
1618 uint32 data_len, void *context)
1620 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1621 SilcClientConnection conn = cmd->conn;
1622 SilcBuffer buffer, auth;
1624 if (cmd->argc == 3) {
1625 /* Pulic key auth XXX TODO */
1628 /* Encode the authentication payload */
1629 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1633 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1635 strlen(cmd->argv[1]),
1636 2, auth->data, auth->len);
1637 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1638 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1640 silc_buffer_free(buffer);
1641 silc_buffer_free(auth);
1643 /* Notify application */
1647 /* OPER command. Used to obtain server operator privileges. */
1649 SILC_CLIENT_CMD_FUNC(oper)
1651 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1652 SilcClientConnection conn = cmd->conn;
1653 unsigned char *auth_data;
1654 uint32 auth_data_len = 0;
1657 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1662 if (cmd->argc < 2) {
1663 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1664 "Usage: /OPER <username> [<public key>]");
1669 if (cmd->argc == 3) {
1670 /* XXX Get public key */
1675 /* Get passphrase */
1676 cmd->client->ops->ask_passphrase(cmd->client, conn,
1677 silc_client_command_oper_send,
1682 silc_client_command_oper_send(auth_data, auth_data_len, context);
1684 memset(auth_data, 0, auth_data_len);
1685 silc_free(auth_data);
1687 /* Notify application */
1691 silc_client_command_free(cmd);
1694 static void silc_client_command_silcoper_send(unsigned char *data,
1695 uint32 data_len, void *context)
1697 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1698 SilcClientConnection conn = cmd->conn;
1699 SilcBuffer buffer, auth;
1701 if (cmd->argc == 3) {
1702 /* Pulic key auth XXX TODO */
1705 /* Encode the authentication payload */
1706 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1710 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1712 strlen(cmd->argv[1]),
1713 2, auth->data, auth->len);
1714 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1715 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1717 silc_buffer_free(buffer);
1718 silc_buffer_free(auth);
1720 /* Notify application */
1724 /* SILCOPER command. Used to obtain router operator privileges. */
1726 SILC_CLIENT_CMD_FUNC(silcoper)
1728 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1729 SilcClientConnection conn = cmd->conn;
1730 unsigned char *auth_data;
1731 uint32 auth_data_len = 0;
1734 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1739 if (cmd->argc < 2) {
1740 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1741 "Usage: /SILCOPER <username> [<public key>]");
1746 if (cmd->argc == 3) {
1747 /* XXX Get public key */
1752 /* Get passphrase */
1753 cmd->client->ops->ask_passphrase(cmd->client, conn,
1754 silc_client_command_silcoper_send,
1759 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1761 memset(auth_data, 0, auth_data_len);
1762 silc_free(auth_data);
1764 /* Notify application */
1768 silc_client_command_free(cmd);
1771 /* CONNECT command. Connects the server to another server. */
1773 SILC_CLIENT_CMD_FUNC(connect)
1775 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1776 SilcClientConnection conn = cmd->conn;
1778 unsigned char port[4];
1782 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1787 if (cmd->argc < 2) {
1788 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1789 "Usage: /CONNECT <server> [<port>]");
1794 if (cmd->argc == 3) {
1795 tmp = atoi(cmd->argv[2]);
1796 SILC_PUT32_MSB(tmp, port);
1800 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1802 strlen(cmd->argv[1]),
1805 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1807 strlen(cmd->argv[1]));
1808 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1809 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1810 silc_buffer_free(buffer);
1812 /* Notify application */
1816 silc_client_command_free(cmd);
1819 /* Command BAN. This is used to manage the ban list of the channel. */
1821 SILC_CLIENT_CMD_FUNC(ban)
1823 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1824 SilcClientConnection conn = cmd->conn;
1825 SilcChannelEntry channel;
1826 SilcBuffer buffer, chidp;
1828 char *name, *ban = NULL;
1831 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1836 if (cmd->argc < 2) {
1837 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1838 "Usage: /BAN <channel> "
1839 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1844 if (cmd->argv[1][0] == '*') {
1845 if (!conn->current_channel) {
1846 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1851 channel = conn->current_channel;
1853 name = cmd->argv[1];
1855 channel = silc_client_get_channel(cmd->client, conn, name);
1857 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
1863 if (cmd->argc == 3) {
1864 if (cmd->argv[2][0] == '+')
1873 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1875 /* Send the command */
1877 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1878 1, chidp->data, chidp->len,
1879 type, ban, strlen(ban));
1881 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1882 1, chidp->data, chidp->len);
1884 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1885 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1886 silc_buffer_free(buffer);
1887 silc_buffer_free(chidp);
1889 /* Notify application */
1893 silc_client_command_free(cmd);
1896 /* CLOSE command. Close server connection to the remote server */
1898 SILC_CLIENT_CMD_FUNC(close)
1900 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1901 SilcClientConnection conn = cmd->conn;
1903 unsigned char port[4];
1907 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1912 if (cmd->argc < 2) {
1913 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1914 "Usage: /CLOSE <server> [<port>]");
1919 if (cmd->argc == 3) {
1920 tmp = atoi(cmd->argv[2]);
1921 SILC_PUT32_MSB(tmp, port);
1925 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1927 strlen(cmd->argv[1]),
1930 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1932 strlen(cmd->argv[1]));
1933 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1934 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1935 silc_buffer_free(buffer);
1937 /* Notify application */
1941 silc_client_command_free(cmd);
1944 /* SHUTDOWN command. Shutdowns the server. */
1946 SILC_CLIENT_CMD_FUNC(shutdown)
1948 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1951 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1956 /* Send the command */
1957 silc_client_send_command(cmd->client, cmd->conn,
1958 SILC_COMMAND_SHUTDOWN, 0, 0);
1960 /* Notify application */
1964 silc_client_command_free(cmd);
1967 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1969 SILC_CLIENT_CMD_FUNC(leave)
1971 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1972 SilcClientConnection conn = cmd->conn;
1973 SilcIDCacheEntry id_cache = NULL;
1974 SilcChannelEntry channel;
1975 SilcBuffer buffer, idp;
1979 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1984 if (cmd->argc != 2) {
1985 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1986 "Usage: /LEAVE <channel>");
1991 if (cmd->argv[1][0] == '*') {
1992 if (!conn->current_channel) {
1993 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1994 "You are not on any channel");
1998 name = conn->current_channel->channel_name;
2000 name = cmd->argv[1];
2003 /* Get the Channel ID of the channel */
2004 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2005 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2006 "You are not on that channel");
2011 channel = (SilcChannelEntry)id_cache->context;
2013 /* Send LEAVE command to the server */
2014 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2015 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2016 1, idp->data, idp->len);
2017 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2018 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2019 silc_buffer_free(buffer);
2020 silc_buffer_free(idp);
2022 /* Notify application */
2025 if (conn->current_channel == channel)
2026 conn->current_channel = NULL;
2028 silc_idcache_del_by_id(conn->channel_cache, channel->id);
2029 silc_free(channel->channel_name);
2030 silc_free(channel->id);
2031 silc_free(channel->key);
2032 silc_cipher_free(channel->channel_key);
2036 silc_client_command_free(cmd);
2039 /* Command USERS. Requests the USERS of the clients joined on requested
2042 SILC_CLIENT_CMD_FUNC(users)
2044 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2045 SilcClientConnection conn = cmd->conn;
2050 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2055 if (cmd->argc != 2) {
2056 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2057 "Usage: /USERS <channel>");
2062 if (cmd->argv[1][0] == '*') {
2063 if (!conn->current_channel) {
2064 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2065 "You are not on any channel");
2069 name = conn->current_channel->channel_name;
2071 name = cmd->argv[1];
2074 /* Send USERS command to the server */
2075 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2076 ++conn->cmd_ident, 1,
2077 2, name, strlen(name));
2078 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2079 NULL, 0, NULL, NULL, buffer->data,
2081 silc_buffer_free(buffer);
2083 /* Notify application */
2087 silc_client_command_free(cmd);
2090 /* Command GETKEY. Used to fetch remote client's public key. */
2092 SILC_CLIENT_CMD_FUNC(getkey)
2094 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2095 SilcClientConnection conn = cmd->conn;
2096 SilcClient client = cmd->client;
2097 SilcClientEntry client_entry = NULL;
2098 SilcServerEntry server_entry = NULL;
2100 char *nickname = NULL, *server = NULL;
2101 SilcBuffer idp, buffer;
2104 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2109 if (cmd->argc < 2) {
2110 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2111 "Usage: /GETKEY <nickname or server name>");
2116 /* Parse the typed nickname. */
2117 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2118 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
2123 /* Find client entry */
2124 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2126 if (!client_entry) {
2127 /* Check whether user requested server actually */
2128 server_entry = silc_client_get_server(client, conn, nickname);
2130 if (!server_entry) {
2131 /* No. what ever user wants we don't have it, so resolve it. We
2132 will try to resolve both client and server, one of them is
2133 bound to be wrong. */
2135 /* This will send the IDENTIFY command */
2136 silc_idlist_get_client(client, conn, nickname, server, num, TRUE);
2137 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2139 silc_client_command_destructor,
2140 silc_client_command_getkey,
2141 silc_client_command_dup(cmd));
2143 /* This sends the INFO command to resolve the server. */
2144 silc_client_send_command(client, conn, SILC_COMMAND_INFO,
2145 ++conn->cmd_ident, 1,
2146 1, nickname, strlen(nickname));
2147 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2149 silc_client_command_destructor,
2150 silc_client_command_getkey,
2151 silc_client_command_dup(cmd));
2157 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2159 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2162 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2163 1, idp->data, idp->len);
2164 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2165 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2166 silc_buffer_free(buffer);
2167 silc_buffer_free(idp);
2169 /* Notify application */
2173 silc_client_command_free(cmd);