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]);
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 if (cmd->argc < 2 || cmd->argc > 3) {
248 cmd->client->ops->say(cmd->client, conn,
249 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
254 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
255 cmd->argc - 1, ++cmd->argv,
256 ++cmd->argv_lens, ++cmd->argv_types,
258 silc_client_packet_send(cmd->client, cmd->conn->sock,
259 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
260 buffer->data, buffer->len, TRUE);
261 silc_buffer_free(buffer);
266 /* Notify application */
270 silc_client_command_free(cmd);
273 /* Command WHOWAS. This command is used to query history information about
274 specific user that used to exist in the network. */
276 SILC_CLIENT_CMD_FUNC(whowas)
278 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
279 SilcClientConnection conn = cmd->conn;
283 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
288 if (cmd->argc < 2 || cmd->argc > 3) {
289 cmd->client->ops->say(cmd->client, conn,
290 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
295 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
296 cmd->argc - 1, ++cmd->argv,
297 ++cmd->argv_lens, ++cmd->argv_types,
299 silc_client_packet_send(cmd->client, cmd->conn->sock,
300 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
301 buffer->data, buffer->len, TRUE);
302 silc_buffer_free(buffer);
307 /* Notify application */
311 silc_client_command_free(cmd);
314 /* Command IDENTIFY. This command is used to query information about
315 specific user, especially ID's. */
317 SILC_CLIENT_CMD_FUNC(identify)
319 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
320 SilcClientConnection conn = cmd->conn;
324 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
329 if (cmd->argc < 2 || cmd->argc > 3) {
330 cmd->client->ops->say(cmd->client, conn,
331 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
336 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
337 cmd->argc - 1, ++cmd->argv,
338 ++cmd->argv_lens, ++cmd->argv_types,
340 silc_client_packet_send(cmd->client, cmd->conn->sock,
341 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
342 buffer->data, buffer->len, TRUE);
343 silc_buffer_free(buffer);
348 /* Notify application */
352 silc_client_command_free(cmd);
355 /* Command NICK. Shows current nickname/sets new nickname on current
358 SILC_CLIENT_CMD_FUNC(nick)
360 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
361 SilcClientConnection conn = cmd->conn;
365 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
371 cmd->client->ops->say(cmd->client, conn, "Usage: /NICK <nickname>");
376 if (!strcmp(conn->nickname, cmd->argv[1]))
379 /* Show current nickname */
382 cmd->client->ops->say(cmd->client, conn,
383 "Your nickname is %s on server %s",
384 conn->nickname, conn->remote_host);
386 cmd->client->ops->say(cmd->client, conn,
387 "Your nickname is %s", conn->nickname);
390 /* XXX Notify application */
395 /* Set new nickname */
396 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
397 cmd->argc - 1, ++cmd->argv,
398 ++cmd->argv_lens, ++cmd->argv_types,
399 ++cmd->conn->cmd_ident);
400 silc_client_packet_send(cmd->client, cmd->conn->sock,
401 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
402 buffer->data, buffer->len, TRUE);
403 silc_buffer_free(buffer);
408 silc_free(conn->nickname);
409 conn->nickname = strdup(cmd->argv[1]);
411 /* Notify application */
415 silc_client_command_free(cmd);
418 /* Command LIST. Lists channels on the current server. */
420 SILC_CLIENT_CMD_FUNC(list)
422 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
423 SilcClientConnection conn = cmd->conn;
424 SilcIDCacheEntry id_cache = NULL;
425 SilcChannelEntry channel;
426 SilcBuffer buffer, idp = NULL;
430 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
435 if (cmd->argc == 2) {
438 /* Get the Channel ID of the channel */
439 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
440 channel = (SilcChannelEntry)id_cache->context;
441 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
446 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
447 ++conn->cmd_ident, 0);
449 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
450 ++conn->cmd_ident, 1,
451 1, idp->data, idp->len);
453 silc_client_packet_send(cmd->client, cmd->conn->sock,
454 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
455 buffer->data, buffer->len, TRUE);
456 silc_buffer_free(buffer);
458 silc_buffer_free(idp);
460 /* Notify application */
464 silc_client_command_free(cmd);
467 /* Command TOPIC. Sets/shows topic on a channel. */
469 SILC_CLIENT_CMD_FUNC(topic)
471 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
472 SilcClientConnection conn = cmd->conn;
473 SilcIDCacheEntry id_cache = NULL;
474 SilcChannelEntry channel;
475 SilcBuffer buffer, idp;
479 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
484 if (cmd->argc < 2 || cmd->argc > 3) {
485 cmd->client->ops->say(cmd->client, conn,
486 "Usage: /TOPIC <channel> [<topic>]");
491 if (cmd->argv[1][0] == '*') {
492 if (!conn->current_channel) {
493 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
497 name = conn->current_channel->channel_name;
502 if (!conn->current_channel) {
503 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
508 /* Get the Channel ID of the channel */
509 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
510 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
515 channel = (SilcChannelEntry)id_cache->context;
517 /* Send TOPIC command to the server */
518 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
520 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
521 ++conn->cmd_ident, 2,
522 1, idp->data, idp->len,
524 strlen(cmd->argv[2]));
526 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
527 ++conn->cmd_ident, 1,
528 1, idp->data, idp->len);
529 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
530 0, NULL, NULL, buffer->data, buffer->len, TRUE);
531 silc_buffer_free(buffer);
532 silc_buffer_free(idp);
534 /* Notify application */
538 silc_client_command_free(cmd);
541 /* Command INVITE. Invites specific client to join a channel. This is
542 also used to mange the invite list of the channel. */
544 SILC_CLIENT_CMD_FUNC(invite)
546 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
547 SilcClient client = cmd->client;
548 SilcClientConnection conn = cmd->conn;
549 SilcClientEntry client_entry = NULL;
550 SilcChannelEntry channel;
551 SilcBuffer buffer, clidp, chidp;
552 uint32 num = 0, type = 0;
553 char *nickname = NULL, *server = NULL, *name;
557 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
563 cmd->client->ops->say(cmd->client, conn,
564 "Usage: /INVITE <channel> [<nickname>[@server>]"
565 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
570 if (cmd->argv[1][0] == '*') {
571 if (!conn->current_channel) {
572 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
577 channel = conn->current_channel;
581 channel = silc_client_get_channel(cmd->client, conn, name);
583 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
589 /* Parse the typed nickname. */
590 if (cmd->argc == 3) {
591 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
592 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
593 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
598 /* Find client entry */
599 client_entry = silc_idlist_get_client(client, conn, nickname,
612 /* Client entry not found, it was requested thus mark this to be
614 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
616 silc_client_command_destructor,
617 silc_client_command_invite,
618 silc_client_command_dup(cmd));
623 invite = cmd->argv[2];
625 if (cmd->argv[2][0] == '+')
632 /* Send the command */
633 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
635 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
636 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
637 ++conn->cmd_ident, 3,
638 1, chidp->data, chidp->len,
639 2, clidp->data, clidp->len,
640 type, invite, invite ?
642 silc_buffer_free(clidp);
644 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
645 ++conn->cmd_ident, 2,
646 1, chidp->data, chidp->len,
647 type, invite, invite ?
651 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
652 0, NULL, NULL, buffer->data, buffer->len, TRUE);
653 silc_buffer_free(buffer);
654 silc_buffer_free(chidp);
656 /* Notify application */
664 silc_client_command_free(cmd);
669 SilcClientConnection conn;
672 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
674 QuitInternal q = (QuitInternal)context;
676 /* Close connection */
677 q->client->ops->disconnect(q->client, q->conn);
678 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
683 /* Command QUIT. Closes connection with current server. */
685 SILC_CLIENT_CMD_FUNC(quit)
687 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
692 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
698 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
699 &cmd->argv[1], &cmd->argv_lens[1],
700 &cmd->argv_types[1], 0);
702 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
703 NULL, NULL, NULL, 0);
704 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
706 buffer->data, buffer->len, TRUE);
707 silc_buffer_free(buffer);
709 q = silc_calloc(1, sizeof(*q));
710 q->client = cmd->client;
713 /* We quit the connection with little timeout */
714 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
715 silc_client_command_quit_cb, (void *)q,
716 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
718 /* Notify application */
722 silc_client_command_free(cmd);
725 /* Command KILL. Router operator can use this command to remove an client
726 fromthe SILC Network. */
728 SILC_CLIENT_CMD_FUNC(kill)
730 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
731 SilcClientConnection conn = cmd->conn;
732 SilcBuffer buffer, idp;
733 SilcClientEntry target;
735 char *nickname = NULL, *server = NULL;
738 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
744 cmd->client->ops->say(cmd->client, conn,
745 "Usage: /KILL <nickname> [<comment>]");
750 /* Parse the typed nickname. */
751 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
752 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
757 /* Get the target client */
758 target = silc_idlist_get_client(cmd->client, conn, nickname,
770 /* Client entry not found, it was requested thus mark this to be
772 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
774 silc_client_command_destructor,
775 silc_client_command_kill,
776 silc_client_command_dup(cmd));
781 /* Send the KILL command to the server */
782 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
784 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
785 1, idp->data, idp->len);
787 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
788 1, idp->data, idp->len,
790 strlen(cmd->argv[2]));
791 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
792 0, NULL, NULL, buffer->data, buffer->len, TRUE);
793 silc_buffer_free(buffer);
794 silc_buffer_free(idp);
796 /* Remove the client entry from the local cache. */
797 silc_idcache_del_by_context(conn->client_cache, target);
798 if (target->nickname)
799 silc_free(target->nickname);
801 silc_free(target->server);
803 silc_free(target->id);
804 if (target->send_key)
805 silc_cipher_free(target->send_key);
806 if (target->receive_key)
807 silc_cipher_free(target->receive_key);
810 /* Notify application */
818 silc_client_command_free(cmd);
821 /* Command INFO. Request information about specific server. If specific
822 server is not provided the current server is used. */
824 SILC_CLIENT_CMD_FUNC(info)
826 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
827 SilcClientConnection conn = cmd->conn;
832 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
838 name = strdup(cmd->argv[1]);
840 /* Send the command */
842 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
843 1, name, strlen(name));
845 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
846 NULL, NULL, NULL, 0);
847 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
848 0, NULL, NULL, buffer->data, buffer->len, TRUE);
849 silc_buffer_free(buffer);
853 /* Notify application */
857 silc_client_command_free(cmd);
860 /* Command PING. Sends ping to server. This is used to test the
861 communication channel. */
863 SILC_CLIENT_CMD_FUNC(ping)
865 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
866 SilcClientConnection conn = cmd->conn;
873 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
878 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
879 name = strdup(conn->remote_host);
881 /* Send the command */
882 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
883 1, conn->remote_id_data,
884 silc_id_get_len(conn->remote_id,
886 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
887 0, NULL, NULL, buffer->data, buffer->len, TRUE);
888 silc_buffer_free(buffer);
890 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
893 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
898 /* Start counting time */
899 for (i = 0; i < conn->ping_count; i++) {
900 if (conn->ping[i].dest_id == NULL) {
901 conn->ping[i].start_time = time(NULL);
902 conn->ping[i].dest_id = id;
903 conn->ping[i].dest_name = name;
908 if (i >= conn->ping_count) {
909 i = conn->ping_count;
910 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
911 conn->ping[i].start_time = time(NULL);
912 conn->ping[i].dest_id = id;
913 conn->ping[i].dest_name = name;
917 /* Notify application */
921 silc_client_command_free(cmd);
924 SILC_CLIENT_CMD_FUNC(notice)
928 /* Command JOIN. Joins to a channel. */
930 SILC_CLIENT_CMD_FUNC(join)
932 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
933 SilcClientConnection conn = cmd->conn;
934 SilcIDCacheEntry id_cache = NULL;
935 SilcBuffer buffer, idp;
938 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
944 /* Show channels currently joined to */
949 /* See if we have joined to the requested channel already */
950 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
953 cmd->client->ops->say(cmd->client, conn,
954 "You are talking to channel %s", cmd->argv[1]);
955 conn->current_channel = (SilcChannelEntry)id_cache->context;
956 cmd->client->screen->bottom_line->channel = cmd->argv[1];
957 silc_screen_print_bottom_line(cmd->client->screen, 0);
962 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
964 /* Send JOIN command to the server */
967 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
968 1, cmd->argv[1], cmd->argv_lens[1],
969 2, idp->data, idp->len);
970 else if (cmd->argc == 3)
973 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
974 1, cmd->argv[1], cmd->argv_lens[1],
975 2, idp->data, idp->len,
976 3, cmd->argv[2], cmd->argv_lens[2]);
979 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
980 1, cmd->argv[1], cmd->argv_lens[1],
981 2, idp->data, idp->len,
982 3, cmd->argv[2], cmd->argv_lens[2],
983 4, cmd->argv[3], cmd->argv_lens[3]);
985 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
986 0, NULL, NULL, buffer->data, buffer->len, TRUE);
987 silc_buffer_free(buffer);
988 silc_buffer_free(idp);
990 /* Notify application */
994 silc_client_command_free(cmd);
997 /* MOTD command. Requests motd from server. */
999 SILC_CLIENT_CMD_FUNC(motd)
1001 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1002 SilcClientConnection conn = cmd->conn;
1006 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1011 if (cmd->argc < 1 || cmd->argc > 2) {
1012 cmd->client->ops->say(cmd->client, conn,
1013 "Usage: /MOTD [<server>]");
1018 /* Send TOPIC command to the server */
1020 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1021 1, conn->remote_host,
1022 strlen(conn->remote_host));
1024 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1027 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1028 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1029 silc_buffer_free(buffer);
1031 /* Notify application */
1035 silc_client_command_free(cmd);
1038 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1039 modes as client cannot set itself server/router operator privileges. */
1041 SILC_CLIENT_CMD_FUNC(umode)
1043 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1044 SilcClientConnection conn = cmd->conn;
1045 SilcBuffer buffer, idp;
1046 unsigned char *cp, modebuf[4];
1047 uint32 mode, add, len;
1051 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1056 if (cmd->argc < 2) {
1057 cmd->client->ops->say(cmd->client, conn,
1058 "Usage: /UMODE +|-<modes>");
1063 mode = conn->local_entry->mode;
1065 /* Are we adding or removing mode */
1066 if (cmd->argv[1][0] == '-')
1072 cp = cmd->argv[1] + 1;
1074 for (i = 0; i < len; i++) {
1079 mode |= SILC_UMODE_SERVER_OPERATOR;
1080 mode |= SILC_UMODE_ROUTER_OPERATOR;
1082 mode = SILC_UMODE_NONE;
1087 mode |= SILC_UMODE_SERVER_OPERATOR;
1089 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1093 mode |= SILC_UMODE_ROUTER_OPERATOR;
1095 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1099 mode |= SILC_UMODE_GONE;
1101 mode &= ~SILC_UMODE_GONE;
1110 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1111 SILC_PUT32_MSB(mode, modebuf);
1113 /* Send the command packet. We support sending only one mode at once
1114 that requires an argument. */
1116 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1117 1, idp->data, idp->len,
1118 2, modebuf, sizeof(modebuf));
1119 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1120 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1121 silc_buffer_free(buffer);
1122 silc_buffer_free(idp);
1124 /* Notify application */
1128 silc_client_command_free(cmd);
1131 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1132 can be set several at once. Those modes that require argument must be set
1133 separately (unless set with modes that does not require arguments). */
1135 SILC_CLIENT_CMD_FUNC(cmode)
1137 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1138 SilcClientConnection conn = cmd->conn;
1139 SilcChannelEntry channel;
1140 SilcBuffer buffer, chidp, auth = NULL;
1141 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1142 uint32 mode, add, type, len, arg_len = 0;
1146 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1151 if (cmd->argc < 3) {
1152 cmd->client->ops->say(cmd->client, conn,
1153 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1158 if (cmd->argv[1][0] == '*') {
1159 if (!conn->current_channel) {
1160 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1165 channel = conn->current_channel;
1167 name = cmd->argv[1];
1169 channel = silc_client_get_channel(cmd->client, conn, name);
1171 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1177 mode = channel->mode;
1179 /* Are we adding or removing mode */
1180 if (cmd->argv[2][0] == '-')
1185 /* Argument type to be sent to server */
1189 cp = cmd->argv[2] + 1;
1191 for (i = 0; i < len; i++) {
1195 mode |= SILC_CHANNEL_MODE_PRIVATE;
1197 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1201 mode |= SILC_CHANNEL_MODE_SECRET;
1203 mode &= ~SILC_CHANNEL_MODE_SECRET;
1207 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1209 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1213 mode |= SILC_CHANNEL_MODE_INVITE;
1215 mode &= ~SILC_CHANNEL_MODE_INVITE;
1219 mode |= SILC_CHANNEL_MODE_TOPIC;
1221 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1226 mode |= SILC_CHANNEL_MODE_ULIMIT;
1228 if (cmd->argc < 4) {
1229 cmd->client->ops->say(cmd->client, conn,
1230 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1234 ll = atoi(cmd->argv[3]);
1235 SILC_PUT32_MSB(ll, tmp);
1239 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1244 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1246 if (cmd->argc < 4) {
1247 cmd->client->ops->say(cmd->client, conn,
1248 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1253 arg_len = cmd->argv_lens[3];
1255 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1260 mode |= SILC_CHANNEL_MODE_CIPHER;
1262 if (cmd->argc < 4) {
1263 cmd->client->ops->say(cmd->client, conn,
1264 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1269 arg_len = cmd->argv_lens[3];
1271 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1276 mode |= SILC_CHANNEL_MODE_HMAC;
1278 if (cmd->argc < 4) {
1279 cmd->client->ops->say(cmd->client, conn,
1280 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1285 arg_len = cmd->argv_lens[3];
1287 mode &= ~SILC_CHANNEL_MODE_HMAC;
1292 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1295 if (cmd->argc < 4) {
1296 cmd->client->ops->say(cmd->client, conn,
1297 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1302 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1303 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1304 cmd->client->private_key,
1309 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1310 cmd->argv[3], cmd->argv_lens[3]);
1314 arg_len = auth->len;
1316 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1326 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1327 SILC_PUT32_MSB(mode, modebuf);
1329 /* Send the command packet. We support sending only one mode at once
1330 that requires an argument. */
1333 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1334 1, chidp->data, chidp->len,
1335 2, modebuf, sizeof(modebuf),
1336 type, arg, arg_len);
1339 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1340 1, chidp->data, chidp->len,
1341 2, modebuf, sizeof(modebuf));
1344 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1345 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1346 silc_buffer_free(buffer);
1347 silc_buffer_free(chidp);
1349 silc_buffer_free(auth);
1351 /* Notify application */
1355 silc_client_command_free(cmd);
1358 /* CUMODE command. Changes client's mode on a channel. */
1360 SILC_CLIENT_CMD_FUNC(cumode)
1362 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1363 SilcClientConnection conn = cmd->conn;
1364 SilcChannelEntry channel;
1365 SilcChannelUser chu;
1366 SilcClientEntry client_entry;
1367 SilcBuffer buffer, clidp, chidp, auth = NULL;
1368 unsigned char *name, *cp, modebuf[4];
1369 uint32 mode = 0, add, len;
1370 char *nickname = NULL, *server = NULL;
1375 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1380 if (cmd->argc < 4) {
1381 cmd->client->ops->say(cmd->client, conn,
1382 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1387 if (cmd->argv[1][0] == '*') {
1388 if (!conn->current_channel) {
1389 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1394 channel = conn->current_channel;
1396 name = cmd->argv[1];
1398 channel = silc_client_get_channel(cmd->client, conn, name);
1400 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1406 /* Parse the typed nickname. */
1407 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1408 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1413 /* Find client entry */
1414 client_entry = silc_idlist_get_client(cmd->client, conn,
1415 nickname, server, num, TRUE);
1416 if (!client_entry) {
1422 /* Client entry not found, it was requested thus mark this to be
1424 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1426 silc_client_command_destructor,
1427 silc_client_command_cumode,
1428 silc_client_command_dup(cmd));
1433 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1434 if (chu->client == client_entry) {
1440 /* Are we adding or removing mode */
1441 if (cmd->argv[2][0] == '-')
1447 cp = cmd->argv[2] + 1;
1449 for (i = 0; i < len; i++) {
1453 mode |= SILC_CHANNEL_UMODE_CHANFO;
1454 mode |= SILC_CHANNEL_UMODE_CHANOP;
1456 mode = SILC_CHANNEL_UMODE_NONE;
1461 if (cmd->argc == 5) {
1462 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1463 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1464 cmd->client->private_key,
1469 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1470 cmd->argv[4], cmd->argv_lens[4]);
1473 mode |= SILC_CHANNEL_UMODE_CHANFO;
1475 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1480 mode |= SILC_CHANNEL_UMODE_CHANOP;
1482 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1491 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1492 SILC_PUT32_MSB(mode, modebuf);
1493 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1495 /* Send the command packet. We support sending only one mode at once
1496 that requires an argument. */
1497 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1498 1, chidp->data, chidp->len,
1500 3, clidp->data, clidp->len,
1501 4, auth ? auth->data : NULL,
1502 auth ? auth->len : 0);
1504 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1505 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1506 silc_buffer_free(buffer);
1507 silc_buffer_free(chidp);
1508 silc_buffer_free(clidp);
1510 silc_buffer_free(auth);
1512 /* Notify application */
1517 silc_free(nickname);
1520 silc_client_command_free(cmd);
1523 /* KICK command. Kicks a client out of channel. */
1525 SILC_CLIENT_CMD_FUNC(kick)
1527 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1528 SilcClientConnection conn = cmd->conn;
1529 SilcIDCacheEntry id_cache = NULL;
1530 SilcChannelEntry channel;
1531 SilcBuffer buffer, idp, idp2;
1532 SilcClientEntry target;
1535 char *nickname = NULL, *server = NULL;
1538 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1543 if (cmd->argc < 3) {
1544 cmd->client->ops->say(cmd->client, conn,
1545 "Usage: /KICK <channel> <nickname> [<comment>]");
1550 if (cmd->argv[1][0] == '*') {
1551 if (!conn->current_channel) {
1552 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1556 name = conn->current_channel->channel_name;
1558 name = cmd->argv[1];
1561 if (!conn->current_channel) {
1562 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1567 /* Get the Channel ID of the channel */
1568 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1569 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1574 channel = (SilcChannelEntry)id_cache->context;
1576 /* Parse the typed nickname. */
1577 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1578 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1583 /* Get the target client */
1584 target = silc_idlist_get_client(cmd->client, conn, nickname,
1585 server, num, FALSE);
1587 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1593 /* Send KICK command to the server */
1594 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1595 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1597 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1598 1, idp->data, idp->len,
1599 2, idp2->data, idp2->len);
1601 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1602 1, idp->data, idp->len,
1603 2, idp2->data, idp2->len,
1605 strlen(cmd->argv[3]));
1606 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1607 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1608 silc_buffer_free(buffer);
1609 silc_buffer_free(idp);
1610 silc_buffer_free(idp2);
1612 /* Notify application */
1617 silc_free(nickname);
1620 silc_client_command_free(cmd);
1623 static void silc_client_command_oper_send(unsigned char *data,
1624 uint32 data_len, void *context)
1626 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1627 SilcClientConnection conn = cmd->conn;
1628 SilcBuffer buffer, auth;
1630 if (cmd->argc == 3) {
1631 /* Pulic key auth XXX TODO */
1634 /* Encode the authentication payload */
1635 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1639 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1641 strlen(cmd->argv[1]),
1642 2, auth->data, auth->len);
1643 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1644 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1646 silc_buffer_free(buffer);
1647 silc_buffer_free(auth);
1649 /* Notify application */
1653 /* OPER command. Used to obtain server operator privileges. */
1655 SILC_CLIENT_CMD_FUNC(oper)
1657 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1658 SilcClientConnection conn = cmd->conn;
1659 unsigned char *auth_data;
1660 uint32 auth_data_len = 0;
1663 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1668 if (cmd->argc < 2) {
1669 cmd->client->ops->say(cmd->client, conn,
1670 "Usage: /OPER <username> [<public key>]");
1675 if (cmd->argc == 3) {
1676 /* XXX Get public key */
1681 /* Get passphrase */
1682 cmd->client->ops->ask_passphrase(cmd->client, conn,
1683 silc_client_command_oper_send,
1688 silc_client_command_oper_send(auth_data, auth_data_len, context);
1690 memset(auth_data, 0, auth_data_len);
1691 silc_free(auth_data);
1693 /* Notify application */
1697 silc_client_command_free(cmd);
1700 static void silc_client_command_silcoper_send(unsigned char *data,
1701 uint32 data_len, void *context)
1703 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1704 SilcClientConnection conn = cmd->conn;
1705 SilcBuffer buffer, auth;
1707 if (cmd->argc == 3) {
1708 /* Pulic key auth XXX TODO */
1711 /* Encode the authentication payload */
1712 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1716 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1718 strlen(cmd->argv[1]),
1719 2, auth->data, auth->len);
1720 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1721 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1723 silc_buffer_free(buffer);
1724 silc_buffer_free(auth);
1726 /* Notify application */
1730 /* SILCOPER command. Used to obtain router operator privileges. */
1732 SILC_CLIENT_CMD_FUNC(silcoper)
1734 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1735 SilcClientConnection conn = cmd->conn;
1736 unsigned char *auth_data;
1737 uint32 auth_data_len = 0;
1740 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1745 if (cmd->argc < 2) {
1746 cmd->client->ops->say(cmd->client, conn,
1747 "Usage: /SILCOPER <username> [<public key>]");
1752 if (cmd->argc == 3) {
1753 /* XXX Get public key */
1758 /* Get passphrase */
1759 cmd->client->ops->ask_passphrase(cmd->client, conn,
1760 silc_client_command_silcoper_send,
1765 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1767 memset(auth_data, 0, auth_data_len);
1768 silc_free(auth_data);
1770 /* Notify application */
1774 silc_client_command_free(cmd);
1777 /* CONNECT command. Connects the server to another server. */
1779 SILC_CLIENT_CMD_FUNC(connect)
1781 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1782 SilcClientConnection conn = cmd->conn;
1784 unsigned char port[4];
1788 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1793 if (cmd->argc < 2) {
1794 cmd->client->ops->say(cmd->client, conn,
1795 "Usage: /CONNECT <server> [<port>]");
1800 if (cmd->argc == 3) {
1801 tmp = atoi(cmd->argv[2]);
1802 SILC_PUT32_MSB(tmp, port);
1806 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1808 strlen(cmd->argv[1]),
1811 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1813 strlen(cmd->argv[1]));
1814 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1815 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1816 silc_buffer_free(buffer);
1818 /* Notify application */
1822 silc_client_command_free(cmd);
1825 /* Command BAN. This is used to manage the ban list of the channel. */
1827 SILC_CLIENT_CMD_FUNC(ban)
1829 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1830 SilcClientConnection conn = cmd->conn;
1831 SilcChannelEntry channel;
1832 SilcBuffer buffer, chidp;
1834 char *name, *ban = NULL;
1837 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1842 if (cmd->argc < 2) {
1843 cmd->client->ops->say(cmd->client, conn,
1844 "Usage: /BAN <channel> "
1845 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1850 if (cmd->argv[1][0] == '*') {
1851 if (!conn->current_channel) {
1852 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1857 channel = conn->current_channel;
1859 name = cmd->argv[1];
1861 channel = silc_client_get_channel(cmd->client, conn, name);
1863 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1869 if (cmd->argc == 3) {
1870 if (cmd->argv[2][0] == '+')
1879 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1881 /* Send the command */
1883 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1884 1, chidp->data, chidp->len,
1885 type, ban, strlen(ban));
1887 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1888 1, chidp->data, chidp->len);
1890 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1891 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1892 silc_buffer_free(buffer);
1893 silc_buffer_free(chidp);
1895 /* Notify application */
1899 silc_client_command_free(cmd);
1902 /* CLOSE command. Close server connection to the remote server */
1904 SILC_CLIENT_CMD_FUNC(close)
1906 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1907 SilcClientConnection conn = cmd->conn;
1909 unsigned char port[4];
1913 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1918 if (cmd->argc < 2) {
1919 cmd->client->ops->say(cmd->client, conn,
1920 "Usage: /CLOSE <server> [<port>]");
1925 if (cmd->argc == 3) {
1926 tmp = atoi(cmd->argv[2]);
1927 SILC_PUT32_MSB(tmp, port);
1931 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1933 strlen(cmd->argv[1]),
1936 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1938 strlen(cmd->argv[1]));
1939 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1940 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1941 silc_buffer_free(buffer);
1943 /* Notify application */
1947 silc_client_command_free(cmd);
1950 /* SHUTDOWN command. Shutdowns the server. */
1952 SILC_CLIENT_CMD_FUNC(shutdown)
1954 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1957 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1962 /* Send the command */
1963 silc_client_send_command(cmd->client, cmd->conn,
1964 SILC_COMMAND_SHUTDOWN, 0, 0);
1966 /* Notify application */
1970 silc_client_command_free(cmd);
1973 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1975 SILC_CLIENT_CMD_FUNC(leave)
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: /LEAVE <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 /* Get the Channel ID of the channel */
2008 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2009 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2014 channel = (SilcChannelEntry)id_cache->context;
2016 /* Send LEAVE command to the server */
2017 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2018 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2019 1, idp->data, idp->len);
2020 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2021 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2022 silc_buffer_free(buffer);
2023 silc_buffer_free(idp);
2025 /* Notify application */
2028 if (conn->current_channel == channel)
2029 conn->current_channel = NULL;
2031 silc_idcache_del_by_id(conn->channel_cache, channel->id);
2032 silc_free(channel->channel_name);
2033 silc_free(channel->id);
2034 silc_free(channel->key);
2035 silc_cipher_free(channel->channel_key);
2039 silc_client_command_free(cmd);
2042 /* Command USERS. Requests the USERS of the clients joined on requested
2045 SILC_CLIENT_CMD_FUNC(users)
2047 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2048 SilcClientConnection conn = cmd->conn;
2049 SilcIDCacheEntry id_cache = NULL;
2050 SilcChannelEntry channel;
2051 SilcBuffer buffer, idp;
2055 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2060 if (cmd->argc != 2) {
2061 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
2066 if (cmd->argv[1][0] == '*') {
2067 if (!conn->current_channel) {
2068 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2072 name = conn->current_channel->channel_name;
2074 name = cmd->argv[1];
2077 if (!conn->current_channel) {
2078 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2083 /* Get the Channel ID of the channel */
2084 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2085 /* XXX should resolve the channel ID; LIST command */
2086 cmd->client->ops->say(cmd->client, conn,
2087 "You are not on that channel", name);
2092 channel = (SilcChannelEntry)id_cache->context;
2094 if (!cmd->pending) {
2095 /* Send USERS command to the server */
2096 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2097 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2098 ++conn->cmd_ident, 1,
2099 1, idp->data, idp->len);
2100 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2101 NULL, 0, NULL, NULL, buffer->data,
2103 silc_buffer_free(buffer);
2104 silc_buffer_free(idp);
2106 /* Register pending callback which will recall this command callback with
2107 same context and reprocesses the command. When reprocessing we actually
2108 display the information on the screen. */
2109 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2110 silc_client_command_destructor,
2111 silc_client_command_users,
2112 silc_client_command_dup(cmd));
2113 cmd->pending = TRUE;
2117 /* Notify application */
2121 silc_client_command_free(cmd);
2124 /* Command GETKEY. Used to fetch remote client's public key. */
2126 SILC_CLIENT_CMD_FUNC(getkey)
2128 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2129 SilcClientConnection conn = cmd->conn;
2130 SilcClient client = cmd->client;
2131 SilcClientEntry client_entry = NULL;
2133 char *nickname = NULL, *server = NULL;
2134 SilcBuffer idp, buffer;
2137 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2142 if (cmd->argc < 2) {
2143 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2148 /* Parse the typed nickname. */
2149 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2150 client->ops->say(client, conn, "Bad nickname");
2155 /* Find client entry */
2156 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2158 if (!client_entry) {
2159 /* Client entry not found, it was requested thus mark this to be
2161 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2163 silc_client_command_destructor,
2164 silc_client_command_getkey,
2165 silc_client_command_dup(cmd));
2170 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2171 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2172 1, idp->data, idp->len);
2173 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2174 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2175 silc_buffer_free(buffer);
2176 silc_buffer_free(idp);
2178 /* Notify application */
2182 silc_client_command_free(cmd);