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 /* Command WHOIS. This command is used to query information about
225 SILC_CLIENT_CMD_FUNC(whois)
227 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
228 SilcClientConnection conn = cmd->conn;
232 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
237 /* Given without arguments fetches client's own information */
239 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
240 silc_client_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
242 1, 3, buffer->data, buffer->len);
243 silc_buffer_free(buffer);
247 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
248 cmd->argc - 1, ++cmd->argv,
249 ++cmd->argv_lens, ++cmd->argv_types,
251 silc_client_packet_send(cmd->client, cmd->conn->sock,
252 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
253 buffer->data, buffer->len, TRUE);
254 silc_buffer_free(buffer);
259 /* Notify application */
263 silc_client_command_free(cmd);
266 /* Command WHOWAS. This command is used to query history information about
267 specific user that used to exist in the network. */
269 SILC_CLIENT_CMD_FUNC(whowas)
271 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
272 SilcClientConnection conn = cmd->conn;
276 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
281 if (cmd->argc < 2 || cmd->argc > 3) {
282 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
283 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
288 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
289 cmd->argc - 1, ++cmd->argv,
290 ++cmd->argv_lens, ++cmd->argv_types,
292 silc_client_packet_send(cmd->client, cmd->conn->sock,
293 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
294 buffer->data, buffer->len, TRUE);
295 silc_buffer_free(buffer);
300 /* Notify application */
304 silc_client_command_free(cmd);
307 /* Command IDENTIFY. This command is used to query information about
308 specific user, especially ID's. */
310 SILC_CLIENT_CMD_FUNC(identify)
312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
313 SilcClientConnection conn = cmd->conn;
317 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
322 if (cmd->argc < 2 || cmd->argc > 3) {
328 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
329 ++conn->cmd_ident, 1,
333 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
334 ++conn->cmd_ident, 2,
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);
345 /* Notify application */
349 silc_client_command_free(cmd);
352 /* Command NICK. Shows current nickname/sets new nickname on current
355 SILC_CLIENT_CMD_FUNC(nick)
357 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
358 SilcClientConnection conn = cmd->conn;
362 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
368 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
369 "Usage: /NICK <nickname>");
374 if (!strcmp(conn->nickname, cmd->argv[1]))
377 /* Show current nickname */
380 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
381 "Your nickname is %s on server %s",
382 conn->nickname, conn->remote_host);
384 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
385 "Your nickname is %s", conn->nickname);
392 /* Set new nickname */
393 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
394 cmd->argc - 1, ++cmd->argv,
395 ++cmd->argv_lens, ++cmd->argv_types,
396 ++cmd->conn->cmd_ident);
397 silc_client_packet_send(cmd->client, cmd->conn->sock,
398 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
399 buffer->data, buffer->len, TRUE);
400 silc_buffer_free(buffer);
405 silc_free(conn->nickname);
406 conn->nickname = strdup(cmd->argv[1]);
408 /* Notify application */
412 silc_client_command_free(cmd);
415 /* Command LIST. Lists channels on the current server. */
417 SILC_CLIENT_CMD_FUNC(list)
419 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
420 SilcClientConnection conn = cmd->conn;
421 SilcIDCacheEntry id_cache = NULL;
422 SilcChannelEntry channel;
423 SilcBuffer buffer, idp = NULL;
427 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
432 if (cmd->argc == 2) {
435 /* Get the Channel ID of the channel */
436 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
437 channel = (SilcChannelEntry)id_cache->context;
438 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
443 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
444 ++conn->cmd_ident, 0);
446 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
447 ++conn->cmd_ident, 1,
448 1, idp->data, idp->len);
450 silc_client_packet_send(cmd->client, cmd->conn->sock,
451 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
452 buffer->data, buffer->len, TRUE);
453 silc_buffer_free(buffer);
455 silc_buffer_free(idp);
457 /* Notify application */
461 silc_client_command_free(cmd);
464 /* Command TOPIC. Sets/shows topic on a channel. */
466 SILC_CLIENT_CMD_FUNC(topic)
468 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
469 SilcClientConnection conn = cmd->conn;
470 SilcIDCacheEntry id_cache = NULL;
471 SilcChannelEntry channel;
472 SilcBuffer buffer, idp;
476 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
481 if (cmd->argc < 2 || cmd->argc > 3) {
482 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
483 "Usage: /TOPIC <channel> [<topic>]");
488 if (cmd->argv[1][0] == '*') {
489 if (!conn->current_channel) {
490 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
491 "You are not on any channel");
495 name = conn->current_channel->channel_name;
500 if (!conn->current_channel) {
501 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
502 "You are not on that channel");
507 /* Get the Channel ID of the channel */
508 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
509 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
510 "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;
553 char *nickname = NULL, *name;
557 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
563 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
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, SILC_CLIENT_MESSAGE_INFO,
573 "You are not on any channel");
578 channel = conn->current_channel;
582 channel = silc_client_get_channel(cmd->client, conn, name);
584 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
585 "You are on that channel");
591 /* Parse the typed nickname. */
592 if (cmd->argc == 3) {
593 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
594 if (client->params->nickname_parse)
595 client->params->nickname_parse(cmd->argv[2], &nickname);
597 nickname = strdup(cmd->argv[2]);
599 /* Find client entry */
600 client_entry = silc_idlist_get_client(client, conn, nickname,
609 /* Client entry not found, it was requested thus mark this to be
611 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
613 silc_client_command_destructor,
614 silc_client_command_invite,
615 silc_client_command_dup(cmd));
620 invite = cmd->argv[2];
622 if (cmd->argv[2][0] == '+')
629 /* Send the command */
630 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
632 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
633 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
634 ++conn->cmd_ident, 3,
635 1, chidp->data, chidp->len,
636 2, clidp->data, clidp->len,
637 type, invite, invite ?
639 silc_buffer_free(clidp);
641 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
642 ++conn->cmd_ident, 2,
643 1, chidp->data, chidp->len,
644 type, invite, invite ?
648 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
649 0, NULL, NULL, buffer->data, buffer->len, TRUE);
650 silc_buffer_free(buffer);
651 silc_buffer_free(chidp);
653 /* Notify application */
658 silc_client_command_free(cmd);
663 SilcClientConnection conn;
666 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
668 QuitInternal q = (QuitInternal)context;
670 /* Close connection */
671 q->client->ops->disconnect(q->client, q->conn);
672 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
677 /* Command QUIT. Closes connection with current server. */
679 SILC_CLIENT_CMD_FUNC(quit)
681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
686 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
692 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
693 &cmd->argv[1], &cmd->argv_lens[1],
694 &cmd->argv_types[1], 0);
696 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
697 NULL, NULL, NULL, 0);
698 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
700 buffer->data, buffer->len, TRUE);
701 silc_buffer_free(buffer);
703 q = silc_calloc(1, sizeof(*q));
704 q->client = cmd->client;
707 /* We quit the connection with little timeout */
708 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
709 silc_client_command_quit_cb, (void *)q,
710 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
712 /* Notify application */
716 silc_client_command_free(cmd);
719 /* Timeout callback to remove the killed client from cache */
721 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
723 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
724 SilcClient client = cmd->client;
725 SilcClientConnection conn = cmd->conn;
726 SilcClientEntry target;
727 char *nickname = NULL;
729 /* Parse the typed nickname. */
730 if (client->params->nickname_parse)
731 client->params->nickname_parse(cmd->argv[1], &nickname);
733 nickname = strdup(cmd->argv[1]);
735 /* Get the target client */
736 target = silc_idlist_get_client(cmd->client, conn, nickname,
737 cmd->argv[1], FALSE);
739 silc_client_remove_from_channels(client, conn, target);
740 silc_client_del_client(client, conn, target);
744 silc_client_command_free(cmd);
747 /* Kill command's pending command callback to actually remove the killed
748 client from our local cache. */
750 SILC_CLIENT_CMD_FUNC(kill_remove)
752 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
753 SilcClientCommandReplyContext reply =
754 (SilcClientCommandReplyContext)context2;
755 SilcCommandStatus status;
757 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
758 if (status == SILC_STATUS_OK) {
759 /* Remove with timeout */
760 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
761 silc_client_command_kill_remove_later, context,
762 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
766 silc_client_command_free(cmd);
769 /* Command KILL. Router operator can use this command to remove an client
770 fromthe SILC Network. */
772 SILC_CLIENT_CMD_FUNC(kill)
774 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
775 SilcClient client = cmd->client;
776 SilcClientConnection conn = cmd->conn;
777 SilcBuffer buffer, idp;
778 SilcClientEntry target;
779 char *nickname = NULL;
782 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
788 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
789 "Usage: /KILL <nickname> [<comment>]");
794 /* Parse the typed nickname. */
795 if (client->params->nickname_parse)
796 client->params->nickname_parse(cmd->argv[1], &nickname);
798 nickname = strdup(cmd->argv[1]);
800 /* Get the target client */
801 target = silc_idlist_get_client(cmd->client, conn, nickname,
811 /* Client entry not found, it was requested thus mark this to be
813 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
815 silc_client_command_destructor,
816 silc_client_command_kill,
817 silc_client_command_dup(cmd));
822 /* Send the KILL command to the server */
823 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
825 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
826 ++conn->cmd_ident, 1,
827 1, idp->data, idp->len);
829 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
830 ++conn->cmd_ident, 2,
831 1, idp->data, idp->len,
833 strlen(cmd->argv[2]));
834 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
835 0, NULL, NULL, buffer->data, buffer->len, TRUE);
836 silc_buffer_free(buffer);
837 silc_buffer_free(idp);
839 /* Notify application */
842 /* Register a pending callback that will actually remove the killed
843 client from our cache. */
844 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
845 NULL, silc_client_command_kill_remove,
846 silc_client_command_dup(cmd));
850 silc_client_command_free(cmd);
853 /* Command INFO. Request information about specific server. If specific
854 server is not provided the current server is used. */
856 SILC_CLIENT_CMD_FUNC(info)
858 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
859 SilcClientConnection conn = cmd->conn;
864 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
870 name = strdup(cmd->argv[1]);
872 /* Send the command */
874 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
875 1, name, strlen(name));
877 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
878 NULL, NULL, NULL, 0);
879 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
880 0, NULL, NULL, buffer->data, buffer->len, TRUE);
881 silc_buffer_free(buffer);
885 /* Notify application */
889 silc_client_command_free(cmd);
892 /* Command PING. Sends ping to server. This is used to test the
893 communication channel. */
895 SILC_CLIENT_CMD_FUNC(ping)
897 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
898 SilcClientConnection conn = cmd->conn;
904 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
909 /* Send the command */
910 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
911 1, conn->remote_id_data,
912 silc_id_get_len(conn->remote_id,
914 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
915 0, NULL, NULL, buffer->data, buffer->len, TRUE);
916 silc_buffer_free(buffer);
918 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
921 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
926 /* Start counting time */
927 for (i = 0; i < conn->ping_count; i++) {
928 if (conn->ping[i].dest_id == NULL) {
929 conn->ping[i].start_time = time(NULL);
930 conn->ping[i].dest_id = id;
931 conn->ping[i].dest_name = strdup(conn->remote_host);
936 if (i >= conn->ping_count) {
937 i = conn->ping_count;
938 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
939 conn->ping[i].start_time = time(NULL);
940 conn->ping[i].dest_id = id;
941 conn->ping[i].dest_name = strdup(conn->remote_host);
945 /* Notify application */
949 silc_client_command_free(cmd);
952 /* Command JOIN. Joins to a channel. */
954 SILC_CLIENT_CMD_FUNC(join)
956 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
957 SilcClientConnection conn = cmd->conn;
958 SilcIDCacheEntry id_cache = NULL;
959 SilcBuffer buffer, idp;
962 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
967 /* See if we have joined to the requested channel already */
968 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
972 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
974 /* Send JOIN command to the server */
977 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
978 1, cmd->argv[1], cmd->argv_lens[1],
979 2, idp->data, idp->len);
980 else if (cmd->argc == 3)
983 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
984 1, cmd->argv[1], cmd->argv_lens[1],
985 2, idp->data, idp->len,
986 3, cmd->argv[2], cmd->argv_lens[2]);
989 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
990 1, cmd->argv[1], cmd->argv_lens[1],
991 2, idp->data, idp->len,
992 3, cmd->argv[2], cmd->argv_lens[2],
993 4, cmd->argv[3], cmd->argv_lens[3]);
995 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
996 0, NULL, NULL, buffer->data, buffer->len, TRUE);
997 silc_buffer_free(buffer);
998 silc_buffer_free(idp);
1000 /* Notify application */
1004 silc_client_command_free(cmd);
1007 /* MOTD command. Requests motd from server. */
1009 SILC_CLIENT_CMD_FUNC(motd)
1011 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1012 SilcClientConnection conn = cmd->conn;
1016 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1021 if (cmd->argc < 1 || cmd->argc > 2) {
1022 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1023 "Usage: /MOTD [<server>]");
1028 /* Send TOPIC command to the server */
1030 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1031 1, conn->remote_host,
1032 strlen(conn->remote_host));
1034 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1037 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1038 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1039 silc_buffer_free(buffer);
1041 /* Notify application */
1045 silc_client_command_free(cmd);
1048 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1049 modes as client cannot set itself server/router operator privileges. */
1051 SILC_CLIENT_CMD_FUNC(umode)
1053 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1054 SilcClientConnection conn = cmd->conn;
1055 SilcBuffer buffer, idp;
1056 unsigned char *cp, modebuf[4];
1057 uint32 mode, add, len;
1061 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1066 if (cmd->argc < 2) {
1067 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1068 "Usage: /UMODE +|-<modes>");
1073 mode = conn->local_entry->mode;
1075 /* Are we adding or removing mode */
1076 if (cmd->argv[1][0] == '-')
1082 cp = cmd->argv[1] + 1;
1084 for (i = 0; i < len; i++) {
1089 mode |= SILC_UMODE_SERVER_OPERATOR;
1090 mode |= SILC_UMODE_ROUTER_OPERATOR;
1092 mode = SILC_UMODE_NONE;
1097 mode |= SILC_UMODE_SERVER_OPERATOR;
1099 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1103 mode |= SILC_UMODE_ROUTER_OPERATOR;
1105 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1109 mode |= SILC_UMODE_GONE;
1111 mode &= ~SILC_UMODE_GONE;
1120 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1121 SILC_PUT32_MSB(mode, modebuf);
1123 /* Send the command packet. We support sending only one mode at once
1124 that requires an argument. */
1126 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1127 1, idp->data, idp->len,
1128 2, modebuf, sizeof(modebuf));
1129 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1130 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1131 silc_buffer_free(buffer);
1132 silc_buffer_free(idp);
1134 /* Notify application */
1138 silc_client_command_free(cmd);
1141 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1142 can be set several at once. Those modes that require argument must be set
1143 separately (unless set with modes that does not require arguments). */
1145 SILC_CLIENT_CMD_FUNC(cmode)
1147 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1148 SilcClientConnection conn = cmd->conn;
1149 SilcChannelEntry channel;
1150 SilcBuffer buffer, chidp, auth = NULL;
1151 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1152 uint32 mode, add, type, len, arg_len = 0;
1156 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1161 if (cmd->argc < 3) {
1162 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1163 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1168 if (cmd->argv[1][0] == '*') {
1169 if (!conn->current_channel) {
1170 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1171 "You are not on any channel");
1176 channel = conn->current_channel;
1178 name = cmd->argv[1];
1180 channel = silc_client_get_channel(cmd->client, conn, name);
1182 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1183 "You are on that channel");
1189 mode = channel->mode;
1191 /* Are we adding or removing mode */
1192 if (cmd->argv[2][0] == '-')
1197 /* Argument type to be sent to server */
1201 cp = cmd->argv[2] + 1;
1203 for (i = 0; i < len; i++) {
1207 mode |= SILC_CHANNEL_MODE_PRIVATE;
1209 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1213 mode |= SILC_CHANNEL_MODE_SECRET;
1215 mode &= ~SILC_CHANNEL_MODE_SECRET;
1219 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1221 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1225 mode |= SILC_CHANNEL_MODE_INVITE;
1227 mode &= ~SILC_CHANNEL_MODE_INVITE;
1231 mode |= SILC_CHANNEL_MODE_TOPIC;
1233 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1238 mode |= SILC_CHANNEL_MODE_ULIMIT;
1240 if (cmd->argc < 4) {
1241 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1242 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1246 ll = atoi(cmd->argv[3]);
1247 SILC_PUT32_MSB(ll, tmp);
1251 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1256 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1258 if (cmd->argc < 4) {
1259 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1260 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1265 arg_len = cmd->argv_lens[3];
1267 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1272 mode |= SILC_CHANNEL_MODE_CIPHER;
1274 if (cmd->argc < 4) {
1275 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1276 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1281 arg_len = cmd->argv_lens[3];
1283 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1288 mode |= SILC_CHANNEL_MODE_HMAC;
1290 if (cmd->argc < 4) {
1291 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1292 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1297 arg_len = cmd->argv_lens[3];
1299 mode &= ~SILC_CHANNEL_MODE_HMAC;
1304 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1307 if (cmd->argc < 4) {
1308 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1309 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1314 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1315 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1316 cmd->client->private_key,
1321 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1322 cmd->argv[3], cmd->argv_lens[3]);
1326 arg_len = auth->len;
1328 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1338 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1339 SILC_PUT32_MSB(mode, modebuf);
1341 /* Send the command packet. We support sending only one mode at once
1342 that requires an argument. */
1345 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1346 1, chidp->data, chidp->len,
1347 2, modebuf, sizeof(modebuf),
1348 type, arg, arg_len);
1351 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1352 1, chidp->data, chidp->len,
1353 2, modebuf, sizeof(modebuf));
1356 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1357 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1358 silc_buffer_free(buffer);
1359 silc_buffer_free(chidp);
1361 silc_buffer_free(auth);
1363 /* Notify application */
1367 silc_client_command_free(cmd);
1370 /* CUMODE command. Changes client's mode on a channel. */
1372 SILC_CLIENT_CMD_FUNC(cumode)
1374 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1375 SilcClient client = cmd->client;
1376 SilcClientConnection conn = cmd->conn;
1377 SilcChannelEntry channel;
1378 SilcChannelUser chu;
1379 SilcClientEntry client_entry;
1380 SilcBuffer buffer, clidp, chidp, auth = NULL;
1381 unsigned char *name, *cp, modebuf[4];
1382 uint32 mode = 0, add, len;
1383 char *nickname = NULL;
1387 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1392 if (cmd->argc < 4) {
1393 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1394 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1399 if (cmd->argv[1][0] == '*') {
1400 if (!conn->current_channel) {
1401 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1402 "You are not on any channel");
1407 channel = conn->current_channel;
1409 name = cmd->argv[1];
1411 channel = silc_client_get_channel(cmd->client, conn, name);
1413 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1414 "You are on that channel");
1420 /* Parse the typed nickname. */
1421 if (client->params->nickname_parse)
1422 client->params->nickname_parse(cmd->argv[3], &nickname);
1424 nickname = strdup(cmd->argv[3]);
1426 /* Find client entry */
1427 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1428 cmd->argv[3], TRUE);
1429 if (!client_entry) {
1435 silc_free(nickname);
1437 /* Client entry not found, it was requested thus mark this to be
1439 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1441 silc_client_command_destructor,
1442 silc_client_command_cumode,
1443 silc_client_command_dup(cmd));
1448 /* Get the current mode */
1449 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1450 if (chu->client == client_entry) {
1456 /* Are we adding or removing mode */
1457 if (cmd->argv[2][0] == '-')
1463 cp = cmd->argv[2] + 1;
1465 for (i = 0; i < len; i++) {
1469 mode |= SILC_CHANNEL_UMODE_CHANFO;
1470 mode |= SILC_CHANNEL_UMODE_CHANOP;
1472 mode = SILC_CHANNEL_UMODE_NONE;
1477 if (cmd->argc == 5) {
1478 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1479 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1480 cmd->client->private_key,
1485 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1486 cmd->argv[4], cmd->argv_lens[4]);
1489 mode |= SILC_CHANNEL_UMODE_CHANFO;
1491 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1496 mode |= SILC_CHANNEL_UMODE_CHANOP;
1498 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1507 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1508 SILC_PUT32_MSB(mode, modebuf);
1509 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1511 /* Send the command packet. We support sending only one mode at once
1512 that requires an argument. */
1513 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1514 1, chidp->data, chidp->len,
1516 3, clidp->data, clidp->len,
1517 4, auth ? auth->data : NULL,
1518 auth ? auth->len : 0);
1520 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1521 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1522 silc_buffer_free(buffer);
1523 silc_buffer_free(chidp);
1524 silc_buffer_free(clidp);
1526 silc_buffer_free(auth);
1528 /* Notify application */
1532 silc_free(nickname);
1533 silc_client_command_free(cmd);
1536 /* KICK command. Kicks a client out of channel. */
1538 SILC_CLIENT_CMD_FUNC(kick)
1540 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1541 SilcClient client = cmd->client;
1542 SilcClientConnection conn = cmd->conn;
1543 SilcIDCacheEntry id_cache = NULL;
1544 SilcChannelEntry channel;
1545 SilcBuffer buffer, idp, idp2;
1546 SilcClientEntry target;
1548 char *nickname = NULL;
1551 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1556 if (cmd->argc < 3) {
1557 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1558 "Usage: /KICK <channel> <nickname> [<comment>]");
1563 if (cmd->argv[1][0] == '*') {
1564 if (!conn->current_channel) {
1565 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1566 "You are not on any channel");
1570 name = conn->current_channel->channel_name;
1572 name = cmd->argv[1];
1575 if (!conn->current_channel) {
1576 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1577 "You are not on that channel");
1582 /* Get the Channel ID of the channel */
1583 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1584 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1585 "You are not on that channel");
1590 channel = (SilcChannelEntry)id_cache->context;
1592 /* Parse the typed nickname. */
1593 if (client->params->nickname_parse)
1594 client->params->nickname_parse(cmd->argv[2], &nickname);
1596 nickname = strdup(cmd->argv[2]);
1598 /* Get the target client */
1599 target = silc_idlist_get_client(cmd->client, conn, nickname,
1600 cmd->argv[2], FALSE);
1602 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1603 "No such client: %s",
1609 /* Send KICK command to the server */
1610 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1611 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1613 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1614 1, idp->data, idp->len,
1615 2, idp2->data, idp2->len);
1617 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1618 1, idp->data, idp->len,
1619 2, idp2->data, idp2->len,
1621 strlen(cmd->argv[3]));
1622 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1623 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1624 silc_buffer_free(buffer);
1625 silc_buffer_free(idp);
1626 silc_buffer_free(idp2);
1628 /* Notify application */
1632 silc_free(nickname);
1633 silc_client_command_free(cmd);
1636 static void silc_client_command_oper_send(unsigned char *data,
1637 uint32 data_len, void *context)
1639 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1640 SilcClientConnection conn = cmd->conn;
1641 SilcBuffer buffer, auth;
1643 if (cmd->argc >= 3) {
1644 /* Encode the public key authentication payload */
1645 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1646 cmd->client->private_key,
1651 /* Encode the password authentication payload */
1652 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1656 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1658 strlen(cmd->argv[1]),
1659 2, auth->data, auth->len);
1660 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1661 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1663 silc_buffer_free(buffer);
1664 silc_buffer_free(auth);
1666 /* Notify application */
1670 /* OPER command. Used to obtain server operator privileges. */
1672 SILC_CLIENT_CMD_FUNC(oper)
1674 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1675 SilcClientConnection conn = cmd->conn;
1678 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1683 if (cmd->argc < 2) {
1684 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1685 "Usage: /OPER <username> [-pubkey]");
1690 if (cmd->argc < 3) {
1691 /* Get passphrase */
1692 cmd->client->ops->ask_passphrase(cmd->client, conn,
1693 silc_client_command_oper_send,
1698 silc_client_command_oper_send(NULL, 0, context);
1701 silc_client_command_free(cmd);
1704 static void silc_client_command_silcoper_send(unsigned char *data,
1705 uint32 data_len, void *context)
1707 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1708 SilcClientConnection conn = cmd->conn;
1709 SilcBuffer buffer, auth;
1711 if (cmd->argc >= 3) {
1712 /* Encode the public key authentication payload */
1713 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1714 cmd->client->private_key,
1719 /* Encode the password authentication payload */
1720 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1724 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1726 strlen(cmd->argv[1]),
1727 2, auth->data, auth->len);
1728 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1729 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1731 silc_buffer_free(buffer);
1732 silc_buffer_free(auth);
1734 /* Notify application */
1738 /* SILCOPER command. Used to obtain router operator privileges. */
1740 SILC_CLIENT_CMD_FUNC(silcoper)
1742 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1743 SilcClientConnection conn = cmd->conn;
1746 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1751 if (cmd->argc < 2) {
1752 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1753 "Usage: /SILCOPER <username> [-pubkey]");
1758 if (cmd->argc < 3) {
1759 /* Get passphrase */
1760 cmd->client->ops->ask_passphrase(cmd->client, conn,
1761 silc_client_command_silcoper_send,
1766 silc_client_command_silcoper_send(NULL, 0, context);
1769 silc_client_command_free(cmd);
1772 /* CONNECT command. Connects the server to another server. */
1774 SILC_CLIENT_CMD_FUNC(connect)
1776 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1777 SilcClientConnection conn = cmd->conn;
1779 unsigned char port[4];
1783 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1788 if (cmd->argc < 2) {
1789 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1790 "Usage: /CONNECT <server> [<port>]");
1795 if (cmd->argc == 3) {
1796 tmp = atoi(cmd->argv[2]);
1797 SILC_PUT32_MSB(tmp, port);
1801 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1803 strlen(cmd->argv[1]),
1806 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1808 strlen(cmd->argv[1]));
1809 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1810 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1811 silc_buffer_free(buffer);
1813 /* Notify application */
1817 silc_client_command_free(cmd);
1820 /* Command BAN. This is used to manage the ban list of the channel. */
1822 SILC_CLIENT_CMD_FUNC(ban)
1824 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1825 SilcClientConnection conn = cmd->conn;
1826 SilcChannelEntry channel;
1827 SilcBuffer buffer, chidp;
1829 char *name, *ban = NULL;
1832 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1837 if (cmd->argc < 2) {
1838 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1839 "Usage: /BAN <channel> "
1840 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1845 if (cmd->argv[1][0] == '*') {
1846 if (!conn->current_channel) {
1847 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1848 "You are not on any channel");
1853 channel = conn->current_channel;
1855 name = cmd->argv[1];
1857 channel = silc_client_get_channel(cmd->client, conn, name);
1859 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1860 "You are on that channel");
1866 if (cmd->argc == 3) {
1867 if (cmd->argv[2][0] == '+')
1876 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1878 /* Send the command */
1880 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1881 1, chidp->data, chidp->len,
1882 type, ban, strlen(ban));
1884 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1885 1, chidp->data, chidp->len);
1887 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1888 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1889 silc_buffer_free(buffer);
1890 silc_buffer_free(chidp);
1892 /* Notify application */
1896 silc_client_command_free(cmd);
1899 /* CLOSE command. Close server connection to the remote server */
1901 SILC_CLIENT_CMD_FUNC(close)
1903 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1904 SilcClientConnection conn = cmd->conn;
1906 unsigned char port[4];
1910 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1915 if (cmd->argc < 2) {
1916 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1917 "Usage: /CLOSE <server> [<port>]");
1922 if (cmd->argc == 3) {
1923 tmp = atoi(cmd->argv[2]);
1924 SILC_PUT32_MSB(tmp, port);
1928 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1930 strlen(cmd->argv[1]),
1933 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1935 strlen(cmd->argv[1]));
1936 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1937 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1938 silc_buffer_free(buffer);
1940 /* Notify application */
1944 silc_client_command_free(cmd);
1947 /* SHUTDOWN command. Shutdowns the server. */
1949 SILC_CLIENT_CMD_FUNC(shutdown)
1951 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1954 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1959 /* Send the command */
1960 silc_client_send_command(cmd->client, cmd->conn,
1961 SILC_COMMAND_SHUTDOWN, 0, 0);
1963 /* Notify application */
1967 silc_client_command_free(cmd);
1970 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1972 SILC_CLIENT_CMD_FUNC(leave)
1974 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1975 SilcClientConnection conn = cmd->conn;
1976 SilcIDCacheEntry id_cache = NULL;
1977 SilcChannelEntry channel;
1978 SilcBuffer buffer, idp;
1982 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1987 if (cmd->argc != 2) {
1988 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1989 "Usage: /LEAVE <channel>");
1994 if (cmd->argv[1][0] == '*') {
1995 if (!conn->current_channel) {
1996 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1997 "You are not on any channel");
2001 name = conn->current_channel->channel_name;
2003 name = cmd->argv[1];
2006 /* Get the Channel ID of the channel */
2007 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2008 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2009 "You are not on that channel");
2014 channel = (SilcChannelEntry)id_cache->context;
2016 /* Send LEAVE command to the server */
2017 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2018 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2019 1, idp->data, idp->len);
2020 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2021 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2022 silc_buffer_free(buffer);
2023 silc_buffer_free(idp);
2025 /* Notify application */
2028 if (conn->current_channel == channel)
2029 conn->current_channel = NULL;
2031 silc_client_del_channel(cmd->client, cmd->conn, channel);
2034 silc_client_command_free(cmd);
2037 /* Command USERS. Requests the USERS of the clients joined on requested
2040 SILC_CLIENT_CMD_FUNC(users)
2042 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2043 SilcClientConnection conn = cmd->conn;
2048 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2053 if (cmd->argc != 2) {
2054 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2055 "Usage: /USERS <channel>");
2060 if (cmd->argv[1][0] == '*') {
2061 if (!conn->current_channel) {
2062 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2063 "You are not on any channel");
2067 name = conn->current_channel->channel_name;
2069 name = cmd->argv[1];
2072 /* Send USERS command to the server */
2073 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2074 ++conn->cmd_ident, 1,
2075 2, name, strlen(name));
2076 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2077 NULL, 0, NULL, NULL, buffer->data,
2079 silc_buffer_free(buffer);
2081 /* Notify application */
2085 silc_client_command_free(cmd);
2088 /* Command GETKEY. Used to fetch remote client's public key. */
2090 SILC_CLIENT_CMD_FUNC(getkey)
2092 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2093 SilcClientConnection conn = cmd->conn;
2094 SilcClient client = cmd->client;
2095 SilcClientEntry client_entry = NULL;
2096 SilcServerEntry server_entry = NULL;
2097 char *nickname = NULL;
2098 SilcBuffer idp, buffer;
2101 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2106 if (cmd->argc < 2) {
2107 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2108 "Usage: /GETKEY <nickname or server name>");
2114 SilcClientCommandReplyContext reply =
2115 (SilcClientCommandReplyContext)context2;
2116 SilcCommandStatus status;
2117 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2118 SILC_GET16_MSB(status, tmp);
2120 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2121 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2122 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2124 silc_client_command_status_message(status));
2130 /* Parse the typed nickname. */
2131 if (client->params->nickname_parse)
2132 client->params->nickname_parse(cmd->argv[1], &nickname);
2134 nickname = strdup(cmd->argv[1]);
2136 /* Find client entry */
2137 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2139 if (!client_entry) {
2140 /* Check whether user requested server actually */
2141 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2143 if (!server_entry && !cmd->pending) {
2144 /* No. what ever user wants we don't have it, so resolve it. We
2145 will try to resolve both client and server, one of them is
2146 bound to be wrong. */
2148 /* This will send the IDENTIFY command */
2149 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2150 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2152 silc_client_command_destructor,
2153 silc_client_command_getkey,
2154 silc_client_command_dup(cmd));
2156 /* This sends the IDENTIFY command to resolve the server. */
2157 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2158 ++conn->cmd_ident, 1,
2159 2, cmd->argv[1], cmd->argv_lens[1]);
2160 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2161 conn->cmd_ident, NULL,
2162 silc_client_command_getkey,
2163 silc_client_command_dup(cmd));
2166 silc_free(nickname);
2170 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2172 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2175 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2176 1, idp->data, idp->len);
2177 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2178 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2179 silc_buffer_free(buffer);
2180 silc_buffer_free(idp);
2182 /* Notify application */
2186 silc_free(nickname);
2187 silc_client_command_free(cmd);