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 /* Notify application */
804 silc_client_command_free(cmd);
807 /* Command INFO. Request information about specific server. If specific
808 server is not provided the current server is used. */
810 SILC_CLIENT_CMD_FUNC(info)
812 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
813 SilcClientConnection conn = cmd->conn;
818 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
824 name = strdup(cmd->argv[1]);
826 /* Send the command */
828 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
829 1, name, strlen(name));
831 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
832 NULL, NULL, NULL, 0);
833 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
834 0, NULL, NULL, buffer->data, buffer->len, TRUE);
835 silc_buffer_free(buffer);
839 /* Notify application */
843 silc_client_command_free(cmd);
846 /* Command PING. Sends ping to server. This is used to test the
847 communication channel. */
849 SILC_CLIENT_CMD_FUNC(ping)
851 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
852 SilcClientConnection conn = cmd->conn;
859 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
864 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
865 name = strdup(conn->remote_host);
867 /* Send the command */
868 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
869 1, conn->remote_id_data,
870 silc_id_get_len(conn->remote_id,
872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
874 silc_buffer_free(buffer);
876 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
879 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
884 /* Start counting time */
885 for (i = 0; i < conn->ping_count; i++) {
886 if (conn->ping[i].dest_id == NULL) {
887 conn->ping[i].start_time = time(NULL);
888 conn->ping[i].dest_id = id;
889 conn->ping[i].dest_name = name;
894 if (i >= conn->ping_count) {
895 i = conn->ping_count;
896 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
897 conn->ping[i].start_time = time(NULL);
898 conn->ping[i].dest_id = id;
899 conn->ping[i].dest_name = name;
903 /* Notify application */
907 silc_client_command_free(cmd);
910 SILC_CLIENT_CMD_FUNC(notice)
914 /* Command JOIN. Joins to a channel. */
916 SILC_CLIENT_CMD_FUNC(join)
918 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
919 SilcClientConnection conn = cmd->conn;
920 SilcIDCacheEntry id_cache = NULL;
921 SilcBuffer buffer, idp;
924 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
930 /* Show channels currently joined to */
935 /* See if we have joined to the requested channel already */
936 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
939 cmd->client->ops->say(cmd->client, conn,
940 "You are talking to channel %s", cmd->argv[1]);
941 conn->current_channel = (SilcChannelEntry)id_cache->context;
942 cmd->client->screen->bottom_line->channel = cmd->argv[1];
943 silc_screen_print_bottom_line(cmd->client->screen, 0);
948 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
950 /* Send JOIN command to the server */
953 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
954 1, cmd->argv[1], cmd->argv_lens[1],
955 2, idp->data, idp->len);
956 else if (cmd->argc == 3)
959 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
960 1, cmd->argv[1], cmd->argv_lens[1],
961 2, idp->data, idp->len,
962 3, cmd->argv[2], cmd->argv_lens[2]);
965 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
966 1, cmd->argv[1], cmd->argv_lens[1],
967 2, idp->data, idp->len,
968 3, cmd->argv[2], cmd->argv_lens[2],
969 4, cmd->argv[3], cmd->argv_lens[3]);
971 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
972 0, NULL, NULL, buffer->data, buffer->len, TRUE);
973 silc_buffer_free(buffer);
974 silc_buffer_free(idp);
976 /* Notify application */
980 silc_client_command_free(cmd);
983 /* MOTD command. Requests motd from server. */
985 SILC_CLIENT_CMD_FUNC(motd)
987 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
988 SilcClientConnection conn = cmd->conn;
992 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
997 if (cmd->argc < 1 || cmd->argc > 2) {
998 cmd->client->ops->say(cmd->client, conn,
999 "Usage: /MOTD [<server>]");
1004 /* Send TOPIC command to the server */
1006 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1007 1, conn->remote_host,
1008 strlen(conn->remote_host));
1010 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1013 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1014 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1015 silc_buffer_free(buffer);
1017 /* Notify application */
1021 silc_client_command_free(cmd);
1024 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1025 modes as client cannot set itself server/router operator privileges. */
1027 SILC_CLIENT_CMD_FUNC(umode)
1029 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1030 SilcClientConnection conn = cmd->conn;
1031 SilcBuffer buffer, idp;
1032 unsigned char *cp, modebuf[4];
1033 uint32 mode, add, len;
1037 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1042 if (cmd->argc < 2) {
1043 cmd->client->ops->say(cmd->client, conn,
1044 "Usage: /UMODE +|-<modes>");
1049 mode = conn->local_entry->mode;
1051 /* Are we adding or removing mode */
1052 if (cmd->argv[1][0] == '-')
1058 cp = cmd->argv[1] + 1;
1060 for (i = 0; i < len; i++) {
1065 mode |= SILC_UMODE_SERVER_OPERATOR;
1066 mode |= SILC_UMODE_ROUTER_OPERATOR;
1068 mode = SILC_UMODE_NONE;
1073 mode |= SILC_UMODE_SERVER_OPERATOR;
1075 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1079 mode |= SILC_UMODE_ROUTER_OPERATOR;
1081 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1085 mode |= SILC_UMODE_GONE;
1087 mode &= ~SILC_UMODE_GONE;
1096 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1097 SILC_PUT32_MSB(mode, modebuf);
1099 /* Send the command packet. We support sending only one mode at once
1100 that requires an argument. */
1102 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1103 1, idp->data, idp->len,
1104 2, modebuf, sizeof(modebuf));
1105 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1106 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1107 silc_buffer_free(buffer);
1108 silc_buffer_free(idp);
1110 /* Notify application */
1114 silc_client_command_free(cmd);
1117 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1118 can be set several at once. Those modes that require argument must be set
1119 separately (unless set with modes that does not require arguments). */
1121 SILC_CLIENT_CMD_FUNC(cmode)
1123 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1124 SilcClientConnection conn = cmd->conn;
1125 SilcChannelEntry channel;
1126 SilcBuffer buffer, chidp, auth = NULL;
1127 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1128 uint32 mode, add, type, len, arg_len = 0;
1132 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1137 if (cmd->argc < 3) {
1138 cmd->client->ops->say(cmd->client, conn,
1139 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1144 if (cmd->argv[1][0] == '*') {
1145 if (!conn->current_channel) {
1146 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1151 channel = conn->current_channel;
1153 name = cmd->argv[1];
1155 channel = silc_client_get_channel(cmd->client, conn, name);
1157 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1163 mode = channel->mode;
1165 /* Are we adding or removing mode */
1166 if (cmd->argv[2][0] == '-')
1171 /* Argument type to be sent to server */
1175 cp = cmd->argv[2] + 1;
1177 for (i = 0; i < len; i++) {
1181 mode |= SILC_CHANNEL_MODE_PRIVATE;
1183 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1187 mode |= SILC_CHANNEL_MODE_SECRET;
1189 mode &= ~SILC_CHANNEL_MODE_SECRET;
1193 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1195 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1199 mode |= SILC_CHANNEL_MODE_INVITE;
1201 mode &= ~SILC_CHANNEL_MODE_INVITE;
1205 mode |= SILC_CHANNEL_MODE_TOPIC;
1207 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1212 mode |= SILC_CHANNEL_MODE_ULIMIT;
1214 if (cmd->argc < 4) {
1215 cmd->client->ops->say(cmd->client, conn,
1216 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1220 ll = atoi(cmd->argv[3]);
1221 SILC_PUT32_MSB(ll, tmp);
1225 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1230 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1232 if (cmd->argc < 4) {
1233 cmd->client->ops->say(cmd->client, conn,
1234 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1239 arg_len = cmd->argv_lens[3];
1241 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1246 mode |= SILC_CHANNEL_MODE_CIPHER;
1248 if (cmd->argc < 4) {
1249 cmd->client->ops->say(cmd->client, conn,
1250 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1255 arg_len = cmd->argv_lens[3];
1257 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1262 mode |= SILC_CHANNEL_MODE_HMAC;
1264 if (cmd->argc < 4) {
1265 cmd->client->ops->say(cmd->client, conn,
1266 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1271 arg_len = cmd->argv_lens[3];
1273 mode &= ~SILC_CHANNEL_MODE_HMAC;
1278 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1281 if (cmd->argc < 4) {
1282 cmd->client->ops->say(cmd->client, conn,
1283 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1288 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1289 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1290 cmd->client->private_key,
1295 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1296 cmd->argv[3], cmd->argv_lens[3]);
1300 arg_len = auth->len;
1302 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1312 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1313 SILC_PUT32_MSB(mode, modebuf);
1315 /* Send the command packet. We support sending only one mode at once
1316 that requires an argument. */
1319 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1320 1, chidp->data, chidp->len,
1321 2, modebuf, sizeof(modebuf),
1322 type, arg, arg_len);
1325 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1326 1, chidp->data, chidp->len,
1327 2, modebuf, sizeof(modebuf));
1330 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1331 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1332 silc_buffer_free(buffer);
1333 silc_buffer_free(chidp);
1335 silc_buffer_free(auth);
1337 /* Notify application */
1341 silc_client_command_free(cmd);
1344 /* CUMODE command. Changes client's mode on a channel. */
1346 SILC_CLIENT_CMD_FUNC(cumode)
1348 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1349 SilcClientConnection conn = cmd->conn;
1350 SilcChannelEntry channel;
1351 SilcChannelUser chu;
1352 SilcClientEntry client_entry;
1353 SilcBuffer buffer, clidp, chidp, auth = NULL;
1354 unsigned char *name, *cp, modebuf[4];
1355 uint32 mode = 0, add, len;
1356 char *nickname = NULL, *server = NULL;
1361 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1366 if (cmd->argc < 4) {
1367 cmd->client->ops->say(cmd->client, conn,
1368 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1373 if (cmd->argv[1][0] == '*') {
1374 if (!conn->current_channel) {
1375 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1380 channel = conn->current_channel;
1382 name = cmd->argv[1];
1384 channel = silc_client_get_channel(cmd->client, conn, name);
1386 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1392 /* Parse the typed nickname. */
1393 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1394 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1399 /* Find client entry */
1400 client_entry = silc_idlist_get_client(cmd->client, conn,
1401 nickname, server, num, TRUE);
1402 if (!client_entry) {
1408 /* Client entry not found, it was requested thus mark this to be
1410 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1412 silc_client_command_destructor,
1413 silc_client_command_cumode,
1414 silc_client_command_dup(cmd));
1419 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1420 if (chu->client == client_entry) {
1426 /* Are we adding or removing mode */
1427 if (cmd->argv[2][0] == '-')
1433 cp = cmd->argv[2] + 1;
1435 for (i = 0; i < len; i++) {
1439 mode |= SILC_CHANNEL_UMODE_CHANFO;
1440 mode |= SILC_CHANNEL_UMODE_CHANOP;
1442 mode = SILC_CHANNEL_UMODE_NONE;
1447 if (cmd->argc == 5) {
1448 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1449 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1450 cmd->client->private_key,
1455 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1456 cmd->argv[4], cmd->argv_lens[4]);
1459 mode |= SILC_CHANNEL_UMODE_CHANFO;
1461 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1466 mode |= SILC_CHANNEL_UMODE_CHANOP;
1468 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1477 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1478 SILC_PUT32_MSB(mode, modebuf);
1479 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1481 /* Send the command packet. We support sending only one mode at once
1482 that requires an argument. */
1483 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1484 1, chidp->data, chidp->len,
1486 3, clidp->data, clidp->len,
1487 4, auth ? auth->data : NULL,
1488 auth ? auth->len : 0);
1490 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1491 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1492 silc_buffer_free(buffer);
1493 silc_buffer_free(chidp);
1494 silc_buffer_free(clidp);
1496 silc_buffer_free(auth);
1498 /* Notify application */
1503 silc_free(nickname);
1506 silc_client_command_free(cmd);
1509 /* KICK command. Kicks a client out of channel. */
1511 SILC_CLIENT_CMD_FUNC(kick)
1513 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1514 SilcClientConnection conn = cmd->conn;
1515 SilcIDCacheEntry id_cache = NULL;
1516 SilcChannelEntry channel;
1517 SilcBuffer buffer, idp, idp2;
1518 SilcClientEntry target;
1521 char *nickname = NULL, *server = NULL;
1524 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1529 if (cmd->argc < 3) {
1530 cmd->client->ops->say(cmd->client, conn,
1531 "Usage: /KICK <channel> <nickname> [<comment>]");
1536 if (cmd->argv[1][0] == '*') {
1537 if (!conn->current_channel) {
1538 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1542 name = conn->current_channel->channel_name;
1544 name = cmd->argv[1];
1547 if (!conn->current_channel) {
1548 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1553 /* Get the Channel ID of the channel */
1554 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1555 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1560 channel = (SilcChannelEntry)id_cache->context;
1562 /* Parse the typed nickname. */
1563 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1564 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1569 /* Get the target client */
1570 target = silc_idlist_get_client(cmd->client, conn, nickname,
1571 server, num, FALSE);
1573 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1579 /* Send KICK command to the server */
1580 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1581 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1583 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1584 1, idp->data, idp->len,
1585 2, idp2->data, idp2->len);
1587 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1588 1, idp->data, idp->len,
1589 2, idp2->data, idp2->len,
1591 strlen(cmd->argv[3]));
1592 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1593 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1594 silc_buffer_free(buffer);
1595 silc_buffer_free(idp);
1596 silc_buffer_free(idp2);
1598 /* Notify application */
1603 silc_free(nickname);
1606 silc_client_command_free(cmd);
1609 static void silc_client_command_oper_send(unsigned char *data,
1610 uint32 data_len, void *context)
1612 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1613 SilcClientConnection conn = cmd->conn;
1614 SilcBuffer buffer, auth;
1616 if (cmd->argc == 3) {
1617 /* Pulic key auth XXX TODO */
1620 /* Encode the authentication payload */
1621 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1625 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1627 strlen(cmd->argv[1]),
1628 2, auth->data, auth->len);
1629 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1630 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1632 silc_buffer_free(buffer);
1633 silc_buffer_free(auth);
1635 /* Notify application */
1639 /* OPER command. Used to obtain server operator privileges. */
1641 SILC_CLIENT_CMD_FUNC(oper)
1643 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1644 SilcClientConnection conn = cmd->conn;
1645 unsigned char *auth_data;
1646 uint32 auth_data_len = 0;
1649 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1654 if (cmd->argc < 2) {
1655 cmd->client->ops->say(cmd->client, conn,
1656 "Usage: /OPER <username> [<public key>]");
1661 if (cmd->argc == 3) {
1662 /* XXX Get public key */
1667 /* Get passphrase */
1668 cmd->client->ops->ask_passphrase(cmd->client, conn,
1669 silc_client_command_oper_send,
1674 silc_client_command_oper_send(auth_data, auth_data_len, context);
1676 memset(auth_data, 0, auth_data_len);
1677 silc_free(auth_data);
1679 /* Notify application */
1683 silc_client_command_free(cmd);
1686 static void silc_client_command_silcoper_send(unsigned char *data,
1687 uint32 data_len, void *context)
1689 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1690 SilcClientConnection conn = cmd->conn;
1691 SilcBuffer buffer, auth;
1693 if (cmd->argc == 3) {
1694 /* Pulic key auth XXX TODO */
1697 /* Encode the authentication payload */
1698 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1702 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1704 strlen(cmd->argv[1]),
1705 2, auth->data, auth->len);
1706 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1707 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1709 silc_buffer_free(buffer);
1710 silc_buffer_free(auth);
1712 /* Notify application */
1716 /* SILCOPER command. Used to obtain router operator privileges. */
1718 SILC_CLIENT_CMD_FUNC(silcoper)
1720 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1721 SilcClientConnection conn = cmd->conn;
1722 unsigned char *auth_data;
1723 uint32 auth_data_len = 0;
1726 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1731 if (cmd->argc < 2) {
1732 cmd->client->ops->say(cmd->client, conn,
1733 "Usage: /SILCOPER <username> [<public key>]");
1738 if (cmd->argc == 3) {
1739 /* XXX Get public key */
1744 /* Get passphrase */
1745 cmd->client->ops->ask_passphrase(cmd->client, conn,
1746 silc_client_command_silcoper_send,
1751 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1753 memset(auth_data, 0, auth_data_len);
1754 silc_free(auth_data);
1756 /* Notify application */
1760 silc_client_command_free(cmd);
1763 /* CONNECT command. Connects the server to another server. */
1765 SILC_CLIENT_CMD_FUNC(connect)
1767 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1768 SilcClientConnection conn = cmd->conn;
1770 unsigned char port[4];
1774 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1779 if (cmd->argc < 2) {
1780 cmd->client->ops->say(cmd->client, conn,
1781 "Usage: /CONNECT <server> [<port>]");
1786 if (cmd->argc == 3) {
1787 tmp = atoi(cmd->argv[2]);
1788 SILC_PUT32_MSB(tmp, port);
1792 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1794 strlen(cmd->argv[1]),
1797 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1799 strlen(cmd->argv[1]));
1800 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1801 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1802 silc_buffer_free(buffer);
1804 /* Notify application */
1808 silc_client_command_free(cmd);
1811 /* Command BAN. This is used to manage the ban list of the channel. */
1813 SILC_CLIENT_CMD_FUNC(ban)
1815 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1816 SilcClientConnection conn = cmd->conn;
1817 SilcChannelEntry channel;
1818 SilcBuffer buffer, chidp;
1820 char *name, *ban = NULL;
1823 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1828 if (cmd->argc < 2) {
1829 cmd->client->ops->say(cmd->client, conn,
1830 "Usage: /BAN <channel> "
1831 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1836 if (cmd->argv[1][0] == '*') {
1837 if (!conn->current_channel) {
1838 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1843 channel = conn->current_channel;
1845 name = cmd->argv[1];
1847 channel = silc_client_get_channel(cmd->client, conn, name);
1849 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1855 if (cmd->argc == 3) {
1856 if (cmd->argv[2][0] == '+')
1865 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1867 /* Send the command */
1869 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1870 1, chidp->data, chidp->len,
1871 type, ban, strlen(ban));
1873 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1874 1, chidp->data, chidp->len);
1876 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1877 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1878 silc_buffer_free(buffer);
1879 silc_buffer_free(chidp);
1881 /* Notify application */
1885 silc_client_command_free(cmd);
1888 /* CLOSE command. Close server connection to the remote server */
1890 SILC_CLIENT_CMD_FUNC(close)
1892 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1893 SilcClientConnection conn = cmd->conn;
1895 unsigned char port[4];
1899 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1904 if (cmd->argc < 2) {
1905 cmd->client->ops->say(cmd->client, conn,
1906 "Usage: /CLOSE <server> [<port>]");
1911 if (cmd->argc == 3) {
1912 tmp = atoi(cmd->argv[2]);
1913 SILC_PUT32_MSB(tmp, port);
1917 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1919 strlen(cmd->argv[1]),
1922 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1924 strlen(cmd->argv[1]));
1925 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1926 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1927 silc_buffer_free(buffer);
1929 /* Notify application */
1933 silc_client_command_free(cmd);
1936 /* SHUTDOWN command. Shutdowns the server. */
1938 SILC_CLIENT_CMD_FUNC(shutdown)
1940 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1943 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1948 /* Send the command */
1949 silc_client_send_command(cmd->client, cmd->conn,
1950 SILC_COMMAND_SHUTDOWN, 0, 0);
1952 /* Notify application */
1956 silc_client_command_free(cmd);
1959 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1961 SILC_CLIENT_CMD_FUNC(leave)
1963 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1964 SilcClientConnection conn = cmd->conn;
1965 SilcIDCacheEntry id_cache = NULL;
1966 SilcChannelEntry channel;
1967 SilcBuffer buffer, idp;
1971 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1976 if (cmd->argc != 2) {
1977 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1982 if (cmd->argv[1][0] == '*') {
1983 if (!conn->current_channel) {
1984 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1988 name = conn->current_channel->channel_name;
1990 name = cmd->argv[1];
1993 /* Get the Channel ID of the channel */
1994 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1995 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2000 channel = (SilcChannelEntry)id_cache->context;
2002 /* Send LEAVE command to the server */
2003 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2004 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2005 1, idp->data, idp->len);
2006 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2007 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2008 silc_buffer_free(buffer);
2009 silc_buffer_free(idp);
2011 /* Notify application */
2014 if (conn->current_channel == channel)
2015 conn->current_channel = NULL;
2017 silc_idcache_del_by_id(conn->channel_cache, channel->id);
2018 silc_free(channel->channel_name);
2019 silc_free(channel->id);
2020 silc_free(channel->key);
2021 silc_cipher_free(channel->channel_key);
2025 silc_client_command_free(cmd);
2028 /* Command USERS. Requests the USERS of the clients joined on requested
2031 SILC_CLIENT_CMD_FUNC(users)
2033 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2034 SilcClientConnection conn = cmd->conn;
2035 SilcIDCacheEntry id_cache = NULL;
2036 SilcChannelEntry channel;
2037 SilcBuffer buffer, idp;
2041 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2046 if (cmd->argc != 2) {
2047 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
2052 if (cmd->argv[1][0] == '*') {
2053 if (!conn->current_channel) {
2054 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2058 name = conn->current_channel->channel_name;
2060 name = cmd->argv[1];
2063 if (!conn->current_channel) {
2064 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2069 /* Get the Channel ID of the channel */
2070 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2071 /* XXX should resolve the channel ID; LIST command */
2072 cmd->client->ops->say(cmd->client, conn,
2073 "You are not on that channel", name);
2078 channel = (SilcChannelEntry)id_cache->context;
2080 if (!cmd->pending) {
2081 /* Send USERS command to the server */
2082 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2083 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2084 ++conn->cmd_ident, 1,
2085 1, idp->data, idp->len);
2086 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2087 NULL, 0, NULL, NULL, buffer->data,
2089 silc_buffer_free(buffer);
2090 silc_buffer_free(idp);
2092 /* Register pending callback which will recall this command callback with
2093 same context and reprocesses the command. When reprocessing we actually
2094 display the information on the screen. */
2095 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2096 silc_client_command_destructor,
2097 silc_client_command_users,
2098 silc_client_command_dup(cmd));
2099 cmd->pending = TRUE;
2103 /* Notify application */
2107 silc_client_command_free(cmd);
2110 /* Command GETKEY. Used to fetch remote client's public key. */
2112 SILC_CLIENT_CMD_FUNC(getkey)
2114 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2115 SilcClientConnection conn = cmd->conn;
2116 SilcClient client = cmd->client;
2117 SilcClientEntry client_entry = NULL;
2119 char *nickname = NULL, *server = NULL;
2120 SilcBuffer idp, buffer;
2123 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2128 if (cmd->argc < 2) {
2129 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2134 /* Parse the typed nickname. */
2135 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2136 client->ops->say(client, conn, "Bad nickname");
2141 /* Find client entry */
2142 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2144 if (!client_entry) {
2145 /* Client entry not found, it was requested thus mark this to be
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));
2156 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2157 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2158 1, idp->data, idp->len);
2159 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2160 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2161 silc_buffer_free(buffer);
2162 silc_buffer_free(idp);
2164 /* Notify application */
2168 silc_client_command_free(cmd);