5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
25 /* Client command list. */
26 SilcClientCommand silc_command_list[] =
28 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
30 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
31 SILC_CF_LAG | SILC_CF_REG, 3),
32 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
34 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
36 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
37 SILC_CLIENT_CMD(kill, KILL, "KILL",
38 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
39 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
40 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
41 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
42 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
43 SILC_CLIENT_CMD(oper, OPER, "OPER",
44 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
46 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
48 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
49 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
50 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
51 SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
52 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
54 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
56 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
58 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
60 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2),
62 { NULL, 0, NULL, 0, 0 },
65 #define SILC_NOT_CONNECTED(x, c) \
66 x->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
67 "You are not connected to a server, use /SERVER to connect");
69 /* Command operation that is called at the end of all commands.
71 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
72 cmd, TRUE, cmd->command->cmd)
74 /* Error to application. Usage: COMMAND_ERROR; */
75 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
76 cmd, FALSE, cmd->command->cmd)
78 /* Generic function to send any command. The arguments must be sent already
79 encoded into correct form and in correct order. */
81 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
82 SilcCommand command, uint16 ident,
90 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
91 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
92 NULL, 0, NULL, NULL, packet->data,
94 silc_buffer_free(packet);
97 /* Finds and returns a pointer to the command list. Return NULL if the
98 command is not found. */
100 SilcClientCommand *silc_client_command_find(const char *name)
102 SilcClientCommand *cmd;
104 for (cmd = silc_command_list; cmd->name; cmd++) {
105 if (!strcmp(cmd->name, name))
112 /* Add new pending command to be executed when reply to a command has been
113 received. The `reply_cmd' is the command that will call the `callback'
114 with `context' when reply has been received. If `ident is non-zero
115 the `callback' will be executed when received reply with command
116 identifier `ident'. */
118 void silc_client_command_pending(SilcClientConnection conn,
119 SilcCommand reply_cmd,
121 SilcClientPendingDestructor destructor,
122 SilcCommandCb callback,
125 SilcClientCommandPending *reply;
127 reply = silc_calloc(1, sizeof(*reply));
128 reply->reply_cmd = reply_cmd;
129 reply->ident = ident;
130 reply->context = context;
131 reply->callback = callback;
132 reply->destructor = destructor;
133 silc_dlist_add(conn->pending_commands, reply);
136 /* Deletes pending command by reply command type. */
138 void silc_client_command_pending_del(SilcClientConnection conn,
139 SilcCommand reply_cmd,
142 SilcClientCommandPending *r;
144 silc_dlist_start(conn->pending_commands);
145 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
146 if (r->reply_cmd == reply_cmd && r->ident == ident) {
147 silc_dlist_del(conn->pending_commands, r);
153 /* Checks for pending commands and marks callbacks to be called from
154 the command reply function. Returns TRUE if there were pending command. */
156 int silc_client_command_pending_check(SilcClientConnection conn,
157 SilcClientCommandReplyContext ctx,
161 SilcClientCommandPending *r;
163 silc_dlist_start(conn->pending_commands);
164 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
165 if (r->reply_cmd == command && r->ident == ident) {
166 ctx->context = r->context;
167 ctx->callback = r->callback;
168 ctx->destructor = r->destructor;
177 /* Allocate Command Context */
179 SilcClientCommandContext silc_client_command_alloc()
181 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
186 /* Free command context and its internals */
188 void silc_client_command_free(SilcClientCommandContext ctx)
191 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
193 if (ctx->users < 1) {
196 for (i = 0; i < ctx->argc; i++)
197 silc_free(ctx->argv[i]);
198 silc_free(ctx->argv_lens);
199 silc_free(ctx->argv_types);
204 /* Duplicate Command Context by adding reference counter. The context won't
205 be free'd untill it hits zero. */
207 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
210 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
215 /* Pending command destructor. */
217 static void silc_client_command_destructor(void *context)
219 silc_client_command_free((SilcClientCommandContext)context);
222 /* silc_client_get_client completion callback */
223 void silc_client_command_completion(SilcClient client,
224 SilcClientConnection conn,
225 SilcClientEntry clients,
226 uint32 clients_count,
232 /* Command WHOIS. This command is used to query information about
235 SILC_CLIENT_CMD_FUNC(whois)
237 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
238 SilcClientConnection conn = cmd->conn;
242 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
247 /* Given without arguments fetches client's own information */
249 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
250 silc_client_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
252 1, 3, buffer->data, buffer->len);
253 silc_buffer_free(buffer);
257 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
258 cmd->argc - 1, ++cmd->argv,
259 ++cmd->argv_lens, ++cmd->argv_types,
261 silc_client_packet_send(cmd->client, cmd->conn->sock,
262 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
263 buffer->data, buffer->len, TRUE);
264 silc_buffer_free(buffer);
269 /* Notify application */
273 silc_client_command_free(cmd);
276 /* Command WHOWAS. This command is used to query history information about
277 specific user that used to exist in the network. */
279 SILC_CLIENT_CMD_FUNC(whowas)
281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
282 SilcClientConnection conn = cmd->conn;
286 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
291 if (cmd->argc < 2 || cmd->argc > 3) {
292 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
293 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
298 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
299 cmd->argc - 1, ++cmd->argv,
300 ++cmd->argv_lens, ++cmd->argv_types,
302 silc_client_packet_send(cmd->client, cmd->conn->sock,
303 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
304 buffer->data, buffer->len, TRUE);
305 silc_buffer_free(buffer);
310 /* Notify application */
314 silc_client_command_free(cmd);
317 /* Command IDENTIFY. This command is used to query information about
318 specific user, especially ID's. */
320 SILC_CLIENT_CMD_FUNC(identify)
322 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
323 SilcClientConnection conn = cmd->conn;
327 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
332 if (cmd->argc < 2 || cmd->argc > 3) {
333 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
334 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
339 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
340 cmd->argc - 1, ++cmd->argv,
341 ++cmd->argv_lens, ++cmd->argv_types,
343 silc_client_packet_send(cmd->client, cmd->conn->sock,
344 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
345 buffer->data, buffer->len, TRUE);
346 silc_buffer_free(buffer);
351 /* Notify application */
355 silc_client_command_free(cmd);
358 /* Command NICK. Shows current nickname/sets new nickname on current
361 SILC_CLIENT_CMD_FUNC(nick)
363 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
364 SilcClientConnection conn = cmd->conn;
368 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
374 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /NICK <nickname>");
379 if (!strcmp(conn->nickname, cmd->argv[1]))
382 /* Show current nickname */
385 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
386 "Your nickname is %s on server %s",
387 conn->nickname, conn->remote_host);
389 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
390 "Your nickname is %s", conn->nickname);
393 /* XXX Notify application */
398 /* Set new nickname */
399 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
400 cmd->argc - 1, ++cmd->argv,
401 ++cmd->argv_lens, ++cmd->argv_types,
402 ++cmd->conn->cmd_ident);
403 silc_client_packet_send(cmd->client, cmd->conn->sock,
404 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
405 buffer->data, buffer->len, TRUE);
406 silc_buffer_free(buffer);
411 silc_free(conn->nickname);
412 conn->nickname = strdup(cmd->argv[1]);
414 /* Notify application */
418 silc_client_command_free(cmd);
421 /* Command LIST. Lists channels on the current server. */
423 SILC_CLIENT_CMD_FUNC(list)
425 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
426 SilcClientConnection conn = cmd->conn;
427 SilcIDCacheEntry id_cache = NULL;
428 SilcChannelEntry channel;
429 SilcBuffer buffer, idp = NULL;
433 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
438 if (cmd->argc == 2) {
441 /* Get the Channel ID of the channel */
442 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
443 channel = (SilcChannelEntry)id_cache->context;
444 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
449 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
450 ++conn->cmd_ident, 0);
452 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
453 ++conn->cmd_ident, 1,
454 1, idp->data, idp->len);
456 silc_client_packet_send(cmd->client, cmd->conn->sock,
457 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
458 buffer->data, buffer->len, TRUE);
459 silc_buffer_free(buffer);
461 silc_buffer_free(idp);
463 /* Notify application */
467 silc_client_command_free(cmd);
470 /* Command TOPIC. Sets/shows topic on a channel. */
472 SILC_CLIENT_CMD_FUNC(topic)
474 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
475 SilcClientConnection conn = cmd->conn;
476 SilcIDCacheEntry id_cache = NULL;
477 SilcChannelEntry channel;
478 SilcBuffer buffer, idp;
482 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
487 if (cmd->argc < 2 || cmd->argc > 3) {
488 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
489 "Usage: /TOPIC <channel> [<topic>]");
494 if (cmd->argv[1][0] == '*') {
495 if (!conn->current_channel) {
496 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
500 name = conn->current_channel->channel_name;
505 if (!conn->current_channel) {
506 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
511 /* Get the Channel ID of the channel */
512 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
513 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
518 channel = (SilcChannelEntry)id_cache->context;
520 /* Send TOPIC command to the server */
521 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
523 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
524 ++conn->cmd_ident, 2,
525 1, idp->data, idp->len,
527 strlen(cmd->argv[2]));
529 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
530 ++conn->cmd_ident, 1,
531 1, idp->data, idp->len);
532 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
533 0, NULL, NULL, buffer->data, buffer->len, TRUE);
534 silc_buffer_free(buffer);
535 silc_buffer_free(idp);
537 /* Notify application */
541 silc_client_command_free(cmd);
544 /* Command INVITE. Invites specific client to join a channel. This is
545 also used to mange the invite list of the channel. */
547 SILC_CLIENT_CMD_FUNC(invite)
549 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
550 SilcClient client = cmd->client;
551 SilcClientConnection conn = cmd->conn;
552 SilcClientEntry client_entry = NULL;
553 SilcChannelEntry channel;
554 SilcBuffer buffer, clidp, chidp;
555 uint32 num = 0, type = 0;
556 char *nickname = NULL, *server = NULL, *name;
560 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
566 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
567 "Usage: /INVITE <channel> [<nickname>[@server>]"
568 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
573 if (cmd->argv[1][0] == '*') {
574 if (!conn->current_channel) {
575 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
580 channel = conn->current_channel;
584 channel = silc_client_get_channel(cmd->client, conn, name);
586 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
592 /* Parse the typed nickname. */
593 if (cmd->argc == 3) {
594 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
595 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
596 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
601 /* Find client entry */
602 client_entry = silc_idlist_get_client(client, conn, nickname,
615 /* Client entry not found, it was requested thus mark this to be
617 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
619 silc_client_command_destructor,
620 silc_client_command_invite,
621 silc_client_command_dup(cmd));
626 invite = cmd->argv[2];
628 if (cmd->argv[2][0] == '+')
635 /* Send the command */
636 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
638 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
639 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
640 ++conn->cmd_ident, 3,
641 1, chidp->data, chidp->len,
642 2, clidp->data, clidp->len,
643 type, invite, invite ?
645 silc_buffer_free(clidp);
647 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
648 ++conn->cmd_ident, 2,
649 1, chidp->data, chidp->len,
650 type, invite, invite ?
654 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
655 0, NULL, NULL, buffer->data, buffer->len, TRUE);
656 silc_buffer_free(buffer);
657 silc_buffer_free(chidp);
659 /* Notify application */
667 silc_client_command_free(cmd);
672 SilcClientConnection conn;
675 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
677 QuitInternal q = (QuitInternal)context;
679 /* Close connection */
680 q->client->ops->disconnect(q->client, q->conn);
681 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
686 /* Command QUIT. Closes connection with current server. */
688 SILC_CLIENT_CMD_FUNC(quit)
690 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
695 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
701 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
702 &cmd->argv[1], &cmd->argv_lens[1],
703 &cmd->argv_types[1], 0);
705 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
706 NULL, NULL, NULL, 0);
707 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
709 buffer->data, buffer->len, TRUE);
710 silc_buffer_free(buffer);
712 q = silc_calloc(1, sizeof(*q));
713 q->client = cmd->client;
716 /* We quit the connection with little timeout */
717 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
718 silc_client_command_quit_cb, (void *)q,
719 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
721 /* Notify application */
725 silc_client_command_free(cmd);
728 /* Command KILL. Router operator can use this command to remove an client
729 fromthe SILC Network. */
731 SILC_CLIENT_CMD_FUNC(kill)
733 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
734 SilcClientConnection conn = cmd->conn;
735 SilcBuffer buffer, idp;
736 SilcClientEntry target;
738 char *nickname = NULL, *server = NULL;
741 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
747 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
748 "Usage: /KILL <nickname> [<comment>]");
753 /* Parse the typed nickname. */
754 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
755 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
761 /* Get the target client */
762 target = silc_idlist_get_client(cmd->client, conn, nickname,
774 /* Client entry not found, it was requested thus mark this to be
776 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
778 silc_client_command_destructor,
779 silc_client_command_kill,
780 silc_client_command_dup(cmd));
785 /* Send the KILL command to the server */
786 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
788 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
789 1, idp->data, idp->len);
791 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
792 1, idp->data, idp->len,
794 strlen(cmd->argv[2]));
795 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
796 0, NULL, NULL, buffer->data, buffer->len, TRUE);
797 silc_buffer_free(buffer);
798 silc_buffer_free(idp);
800 /* Notify application */
808 silc_client_command_free(cmd);
811 /* Command INFO. Request information about specific server. If specific
812 server is not provided the current server is used. */
814 SILC_CLIENT_CMD_FUNC(info)
816 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
817 SilcClientConnection conn = cmd->conn;
822 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
828 name = strdup(cmd->argv[1]);
830 /* Send the command */
832 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
833 1, name, strlen(name));
835 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
836 NULL, NULL, NULL, 0);
837 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
838 0, NULL, NULL, buffer->data, buffer->len, TRUE);
839 silc_buffer_free(buffer);
843 /* Notify application */
847 silc_client_command_free(cmd);
850 /* Command PING. Sends ping to server. This is used to test the
851 communication channel. */
853 SILC_CLIENT_CMD_FUNC(ping)
855 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
856 SilcClientConnection conn = cmd->conn;
862 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
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 = strdup(conn->remote_host);
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 = strdup(conn->remote_host);
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO, "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, SILC_CLIENT_MESSAGE_INFO, "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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO, "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, SILC_CLIENT_MESSAGE_INFO, "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, SILC_CLIENT_MESSAGE_INFO, "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 /* Get the current mode */
1420 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1421 if (chu->client == client_entry) {
1427 /* Are we adding or removing mode */
1428 if (cmd->argv[2][0] == '-')
1434 cp = cmd->argv[2] + 1;
1436 for (i = 0; i < len; i++) {
1440 mode |= SILC_CHANNEL_UMODE_CHANFO;
1441 mode |= SILC_CHANNEL_UMODE_CHANOP;
1443 mode = SILC_CHANNEL_UMODE_NONE;
1448 if (cmd->argc == 5) {
1449 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1450 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1451 cmd->client->private_key,
1456 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1457 cmd->argv[4], cmd->argv_lens[4]);
1460 mode |= SILC_CHANNEL_UMODE_CHANFO;
1462 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1467 mode |= SILC_CHANNEL_UMODE_CHANOP;
1469 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1478 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1479 SILC_PUT32_MSB(mode, modebuf);
1480 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1482 /* Send the command packet. We support sending only one mode at once
1483 that requires an argument. */
1484 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1485 1, chidp->data, chidp->len,
1487 3, clidp->data, clidp->len,
1488 4, auth ? auth->data : NULL,
1489 auth ? auth->len : 0);
1491 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1492 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1493 silc_buffer_free(buffer);
1494 silc_buffer_free(chidp);
1495 silc_buffer_free(clidp);
1497 silc_buffer_free(auth);
1499 /* Notify application */
1504 silc_free(nickname);
1507 silc_client_command_free(cmd);
1510 /* KICK command. Kicks a client out of channel. */
1512 SILC_CLIENT_CMD_FUNC(kick)
1514 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1515 SilcClientConnection conn = cmd->conn;
1516 SilcIDCacheEntry id_cache = NULL;
1517 SilcChannelEntry channel;
1518 SilcBuffer buffer, idp, idp2;
1519 SilcClientEntry target;
1522 char *nickname = NULL, *server = NULL;
1525 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1530 if (cmd->argc < 3) {
1531 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1532 "Usage: /KICK <channel> <nickname> [<comment>]");
1537 if (cmd->argv[1][0] == '*') {
1538 if (!conn->current_channel) {
1539 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1543 name = conn->current_channel->channel_name;
1545 name = cmd->argv[1];
1548 if (!conn->current_channel) {
1549 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
1554 /* Get the Channel ID of the channel */
1555 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1556 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
1561 channel = (SilcChannelEntry)id_cache->context;
1563 /* Parse the typed nickname. */
1564 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1565 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
1570 /* Get the target client */
1571 target = silc_idlist_get_client(cmd->client, conn, nickname,
1572 server, num, FALSE);
1574 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s",
1580 /* Send KICK command to the server */
1581 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1582 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1584 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1585 1, idp->data, idp->len,
1586 2, idp2->data, idp2->len);
1588 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1589 1, idp->data, idp->len,
1590 2, idp2->data, idp2->len,
1592 strlen(cmd->argv[3]));
1593 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1594 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1595 silc_buffer_free(buffer);
1596 silc_buffer_free(idp);
1597 silc_buffer_free(idp2);
1599 /* Notify application */
1604 silc_free(nickname);
1607 silc_client_command_free(cmd);
1610 static void silc_client_command_oper_send(unsigned char *data,
1611 uint32 data_len, void *context)
1613 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1614 SilcClientConnection conn = cmd->conn;
1615 SilcBuffer buffer, auth;
1617 if (cmd->argc == 3) {
1618 /* Pulic key auth XXX TODO */
1621 /* Encode the authentication payload */
1622 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1626 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1628 strlen(cmd->argv[1]),
1629 2, auth->data, auth->len);
1630 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1631 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1633 silc_buffer_free(buffer);
1634 silc_buffer_free(auth);
1636 /* Notify application */
1640 /* OPER command. Used to obtain server operator privileges. */
1642 SILC_CLIENT_CMD_FUNC(oper)
1644 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1645 SilcClientConnection conn = cmd->conn;
1646 unsigned char *auth_data;
1647 uint32 auth_data_len = 0;
1650 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1655 if (cmd->argc < 2) {
1656 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1657 "Usage: /OPER <username> [<public key>]");
1662 if (cmd->argc == 3) {
1663 /* XXX Get public key */
1668 /* Get passphrase */
1669 cmd->client->ops->ask_passphrase(cmd->client, conn,
1670 silc_client_command_oper_send,
1675 silc_client_command_oper_send(auth_data, auth_data_len, context);
1677 memset(auth_data, 0, auth_data_len);
1678 silc_free(auth_data);
1680 /* Notify application */
1684 silc_client_command_free(cmd);
1687 static void silc_client_command_silcoper_send(unsigned char *data,
1688 uint32 data_len, void *context)
1690 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1691 SilcClientConnection conn = cmd->conn;
1692 SilcBuffer buffer, auth;
1694 if (cmd->argc == 3) {
1695 /* Pulic key auth XXX TODO */
1698 /* Encode the authentication payload */
1699 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1703 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1705 strlen(cmd->argv[1]),
1706 2, auth->data, auth->len);
1707 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1708 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1710 silc_buffer_free(buffer);
1711 silc_buffer_free(auth);
1713 /* Notify application */
1717 /* SILCOPER command. Used to obtain router operator privileges. */
1719 SILC_CLIENT_CMD_FUNC(silcoper)
1721 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1722 SilcClientConnection conn = cmd->conn;
1723 unsigned char *auth_data;
1724 uint32 auth_data_len = 0;
1727 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1732 if (cmd->argc < 2) {
1733 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1734 "Usage: /SILCOPER <username> [<public key>]");
1739 if (cmd->argc == 3) {
1740 /* XXX Get public key */
1745 /* Get passphrase */
1746 cmd->client->ops->ask_passphrase(cmd->client, conn,
1747 silc_client_command_silcoper_send,
1752 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1754 memset(auth_data, 0, auth_data_len);
1755 silc_free(auth_data);
1757 /* Notify application */
1761 silc_client_command_free(cmd);
1764 /* CONNECT command. Connects the server to another server. */
1766 SILC_CLIENT_CMD_FUNC(connect)
1768 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1769 SilcClientConnection conn = cmd->conn;
1771 unsigned char port[4];
1775 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1780 if (cmd->argc < 2) {
1781 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1782 "Usage: /CONNECT <server> [<port>]");
1787 if (cmd->argc == 3) {
1788 tmp = atoi(cmd->argv[2]);
1789 SILC_PUT32_MSB(tmp, port);
1793 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1795 strlen(cmd->argv[1]),
1798 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1800 strlen(cmd->argv[1]));
1801 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1802 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1803 silc_buffer_free(buffer);
1805 /* Notify application */
1809 silc_client_command_free(cmd);
1812 /* Command BAN. This is used to manage the ban list of the channel. */
1814 SILC_CLIENT_CMD_FUNC(ban)
1816 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1817 SilcClientConnection conn = cmd->conn;
1818 SilcChannelEntry channel;
1819 SilcBuffer buffer, chidp;
1821 char *name, *ban = NULL;
1824 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1829 if (cmd->argc < 2) {
1830 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1831 "Usage: /BAN <channel> "
1832 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1837 if (cmd->argv[1][0] == '*') {
1838 if (!conn->current_channel) {
1839 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1844 channel = conn->current_channel;
1846 name = cmd->argv[1];
1848 channel = silc_client_get_channel(cmd->client, conn, name);
1850 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are on that channel");
1856 if (cmd->argc == 3) {
1857 if (cmd->argv[2][0] == '+')
1866 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1868 /* Send the command */
1870 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1871 1, chidp->data, chidp->len,
1872 type, ban, strlen(ban));
1874 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1875 1, chidp->data, chidp->len);
1877 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1878 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1879 silc_buffer_free(buffer);
1880 silc_buffer_free(chidp);
1882 /* Notify application */
1886 silc_client_command_free(cmd);
1889 /* CLOSE command. Close server connection to the remote server */
1891 SILC_CLIENT_CMD_FUNC(close)
1893 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1894 SilcClientConnection conn = cmd->conn;
1896 unsigned char port[4];
1900 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1905 if (cmd->argc < 2) {
1906 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1907 "Usage: /CLOSE <server> [<port>]");
1912 if (cmd->argc == 3) {
1913 tmp = atoi(cmd->argv[2]);
1914 SILC_PUT32_MSB(tmp, port);
1918 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1920 strlen(cmd->argv[1]),
1923 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1925 strlen(cmd->argv[1]));
1926 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1927 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1928 silc_buffer_free(buffer);
1930 /* Notify application */
1934 silc_client_command_free(cmd);
1937 /* SHUTDOWN command. Shutdowns the server. */
1939 SILC_CLIENT_CMD_FUNC(shutdown)
1941 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1944 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1949 /* Send the command */
1950 silc_client_send_command(cmd->client, cmd->conn,
1951 SILC_COMMAND_SHUTDOWN, 0, 0);
1953 /* Notify application */
1957 silc_client_command_free(cmd);
1960 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1962 SILC_CLIENT_CMD_FUNC(leave)
1964 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1965 SilcClientConnection conn = cmd->conn;
1966 SilcIDCacheEntry id_cache = NULL;
1967 SilcChannelEntry channel;
1968 SilcBuffer buffer, idp;
1972 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1977 if (cmd->argc != 2) {
1978 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /LEAVE <channel>");
1983 if (cmd->argv[1][0] == '*') {
1984 if (!conn->current_channel) {
1985 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
1989 name = conn->current_channel->channel_name;
1991 name = cmd->argv[1];
1994 /* Get the Channel ID of the channel */
1995 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1996 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
2001 channel = (SilcChannelEntry)id_cache->context;
2003 /* Send LEAVE command to the server */
2004 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2005 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2006 1, idp->data, idp->len);
2007 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2008 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2009 silc_buffer_free(buffer);
2010 silc_buffer_free(idp);
2012 /* Notify application */
2015 if (conn->current_channel == channel)
2016 conn->current_channel = NULL;
2018 silc_idcache_del_by_id(conn->channel_cache, channel->id);
2019 silc_free(channel->channel_name);
2020 silc_free(channel->id);
2021 silc_free(channel->key);
2022 silc_cipher_free(channel->channel_key);
2026 silc_client_command_free(cmd);
2029 /* Command USERS. Requests the USERS of the clients joined on requested
2032 SILC_CLIENT_CMD_FUNC(users)
2034 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2035 SilcClientConnection conn = cmd->conn;
2036 SilcIDCacheEntry id_cache = NULL;
2037 SilcChannelEntry channel;
2038 SilcBuffer buffer, idp;
2042 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2047 if (cmd->argc != 2) {
2048 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /USERS <channel>");
2053 if (cmd->argv[1][0] == '*') {
2054 if (!conn->current_channel) {
2055 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel");
2059 name = conn->current_channel->channel_name;
2061 name = cmd->argv[1];
2064 if (!conn->current_channel) {
2065 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel");
2070 /* Get the Channel ID of the channel */
2071 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2072 /* XXX should resolve the channel ID; LIST command */
2073 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2074 "You are not on that channel", name);
2079 channel = (SilcChannelEntry)id_cache->context;
2081 if (!cmd->pending) {
2082 /* Send USERS command to the server */
2083 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2084 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2085 ++conn->cmd_ident, 1,
2086 1, idp->data, idp->len);
2087 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2088 NULL, 0, NULL, NULL, buffer->data,
2090 silc_buffer_free(buffer);
2091 silc_buffer_free(idp);
2093 /* Register pending callback which will recall this command callback with
2094 same context and reprocesses the command. When reprocessing we actually
2095 display the information on the screen. */
2096 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2097 silc_client_command_destructor,
2098 silc_client_command_users,
2099 silc_client_command_dup(cmd));
2100 cmd->pending = TRUE;
2104 /* Notify application */
2108 silc_client_command_free(cmd);
2111 /* Command GETKEY. Used to fetch remote client's public key. */
2113 SILC_CLIENT_CMD_FUNC(getkey)
2115 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2116 SilcClientConnection conn = cmd->conn;
2117 SilcClient client = cmd->client;
2118 SilcClientEntry client_entry = NULL;
2120 char *nickname = NULL, *server = NULL;
2121 SilcBuffer idp, buffer;
2124 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2129 if (cmd->argc < 2) {
2130 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /GETKEY <nickname>");
2135 /* Parse the typed nickname. */
2136 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2137 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
2142 /* Find client entry */
2143 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2145 if (!client_entry) {
2146 /* Client entry not found, it was requested thus mark this to be
2148 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2150 silc_client_command_destructor,
2151 silc_client_command_getkey,
2152 silc_client_command_dup(cmd));
2157 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2158 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2159 1, idp->data, idp->len);
2160 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2161 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2162 silc_buffer_free(buffer);
2163 silc_buffer_free(idp);
2165 /* Notify application */
2169 silc_client_command_free(cmd);