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],
970 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
971 if (channel->on_channel)
975 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
977 /* Send JOIN command to the server */
980 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
981 1, cmd->argv[1], cmd->argv_lens[1],
982 2, idp->data, idp->len);
983 else if (cmd->argc == 3)
986 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
987 1, cmd->argv[1], cmd->argv_lens[1],
988 2, idp->data, idp->len,
989 3, cmd->argv[2], cmd->argv_lens[2]);
992 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
993 1, cmd->argv[1], cmd->argv_lens[1],
994 2, idp->data, idp->len,
995 3, cmd->argv[2], cmd->argv_lens[2],
996 4, cmd->argv[3], cmd->argv_lens[3]);
998 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
999 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1000 silc_buffer_free(buffer);
1001 silc_buffer_free(idp);
1003 /* Notify application */
1007 silc_client_command_free(cmd);
1010 /* MOTD command. Requests motd from server. */
1012 SILC_CLIENT_CMD_FUNC(motd)
1014 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1015 SilcClientConnection conn = cmd->conn;
1019 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1024 if (cmd->argc < 1 || cmd->argc > 2) {
1025 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1026 "Usage: /MOTD [<server>]");
1031 /* Send TOPIC command to the server */
1033 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1034 1, conn->remote_host,
1035 strlen(conn->remote_host));
1037 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1040 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1041 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1042 silc_buffer_free(buffer);
1044 /* Notify application */
1048 silc_client_command_free(cmd);
1051 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1052 modes as client cannot set itself server/router operator privileges. */
1054 SILC_CLIENT_CMD_FUNC(umode)
1056 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1057 SilcClientConnection conn = cmd->conn;
1058 SilcBuffer buffer, idp;
1059 unsigned char *cp, modebuf[4];
1060 uint32 mode, add, len;
1064 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1069 if (cmd->argc < 2) {
1070 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1071 "Usage: /UMODE +|-<modes>");
1076 mode = conn->local_entry->mode;
1078 /* Are we adding or removing mode */
1079 if (cmd->argv[1][0] == '-')
1085 cp = cmd->argv[1] + 1;
1087 for (i = 0; i < len; i++) {
1092 mode |= SILC_UMODE_SERVER_OPERATOR;
1093 mode |= SILC_UMODE_ROUTER_OPERATOR;
1095 mode = SILC_UMODE_NONE;
1100 mode |= SILC_UMODE_SERVER_OPERATOR;
1102 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1106 mode |= SILC_UMODE_ROUTER_OPERATOR;
1108 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1112 mode |= SILC_UMODE_GONE;
1114 mode &= ~SILC_UMODE_GONE;
1123 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1124 SILC_PUT32_MSB(mode, modebuf);
1126 /* Send the command packet. We support sending only one mode at once
1127 that requires an argument. */
1129 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1130 1, idp->data, idp->len,
1131 2, modebuf, sizeof(modebuf));
1132 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1133 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1134 silc_buffer_free(buffer);
1135 silc_buffer_free(idp);
1137 /* Notify application */
1141 silc_client_command_free(cmd);
1144 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1145 can be set several at once. Those modes that require argument must be set
1146 separately (unless set with modes that does not require arguments). */
1148 SILC_CLIENT_CMD_FUNC(cmode)
1150 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1151 SilcClientConnection conn = cmd->conn;
1152 SilcChannelEntry channel;
1153 SilcBuffer buffer, chidp, auth = NULL;
1154 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1155 uint32 mode, add, type, len, arg_len = 0;
1159 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1164 if (cmd->argc < 3) {
1165 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1166 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1171 if (cmd->argv[1][0] == '*') {
1172 if (!conn->current_channel) {
1173 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1174 "You are not on any channel");
1179 channel = conn->current_channel;
1181 name = cmd->argv[1];
1183 channel = silc_client_get_channel(cmd->client, conn, name);
1185 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1186 "You are on that channel");
1192 mode = channel->mode;
1194 /* Are we adding or removing mode */
1195 if (cmd->argv[2][0] == '-')
1200 /* Argument type to be sent to server */
1204 cp = cmd->argv[2] + 1;
1206 for (i = 0; i < len; i++) {
1210 mode |= SILC_CHANNEL_MODE_PRIVATE;
1212 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1216 mode |= SILC_CHANNEL_MODE_SECRET;
1218 mode &= ~SILC_CHANNEL_MODE_SECRET;
1222 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1224 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1228 mode |= SILC_CHANNEL_MODE_INVITE;
1230 mode &= ~SILC_CHANNEL_MODE_INVITE;
1234 mode |= SILC_CHANNEL_MODE_TOPIC;
1236 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1241 mode |= SILC_CHANNEL_MODE_ULIMIT;
1243 if (cmd->argc < 4) {
1244 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1245 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1249 ll = atoi(cmd->argv[3]);
1250 SILC_PUT32_MSB(ll, tmp);
1254 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1259 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1261 if (cmd->argc < 4) {
1262 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1263 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1268 arg_len = cmd->argv_lens[3];
1270 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1275 mode |= SILC_CHANNEL_MODE_CIPHER;
1277 if (cmd->argc < 4) {
1278 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1279 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1284 arg_len = cmd->argv_lens[3];
1286 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1291 mode |= SILC_CHANNEL_MODE_HMAC;
1293 if (cmd->argc < 4) {
1294 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1295 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1300 arg_len = cmd->argv_lens[3];
1302 mode &= ~SILC_CHANNEL_MODE_HMAC;
1307 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1310 if (cmd->argc < 4) {
1311 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1312 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1317 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1318 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1319 cmd->client->private_key,
1324 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1325 cmd->argv[3], cmd->argv_lens[3]);
1329 arg_len = auth->len;
1331 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1341 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1342 SILC_PUT32_MSB(mode, modebuf);
1344 /* Send the command packet. We support sending only one mode at once
1345 that requires an argument. */
1348 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1349 1, chidp->data, chidp->len,
1350 2, modebuf, sizeof(modebuf),
1351 type, arg, arg_len);
1354 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1355 1, chidp->data, chidp->len,
1356 2, modebuf, sizeof(modebuf));
1359 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1360 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1361 silc_buffer_free(buffer);
1362 silc_buffer_free(chidp);
1364 silc_buffer_free(auth);
1366 /* Notify application */
1370 silc_client_command_free(cmd);
1373 /* CUMODE command. Changes client's mode on a channel. */
1375 SILC_CLIENT_CMD_FUNC(cumode)
1377 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1378 SilcClient client = cmd->client;
1379 SilcClientConnection conn = cmd->conn;
1380 SilcChannelEntry channel;
1381 SilcChannelUser chu;
1382 SilcClientEntry client_entry;
1383 SilcBuffer buffer, clidp, chidp, auth = NULL;
1384 unsigned char *name, *cp, modebuf[4];
1385 uint32 mode = 0, add, len;
1386 char *nickname = NULL;
1390 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1395 if (cmd->argc < 4) {
1396 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1397 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1402 if (cmd->argv[1][0] == '*') {
1403 if (!conn->current_channel) {
1404 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1405 "You are not on any channel");
1410 channel = conn->current_channel;
1412 name = cmd->argv[1];
1414 channel = silc_client_get_channel(cmd->client, conn, name);
1416 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1417 "You are on that channel");
1423 /* Parse the typed nickname. */
1424 if (client->params->nickname_parse)
1425 client->params->nickname_parse(cmd->argv[3], &nickname);
1427 nickname = strdup(cmd->argv[3]);
1429 /* Find client entry */
1430 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1431 cmd->argv[3], TRUE);
1432 if (!client_entry) {
1438 silc_free(nickname);
1440 /* Client entry not found, it was requested thus mark this to be
1442 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1444 silc_client_command_destructor,
1445 silc_client_command_cumode,
1446 silc_client_command_dup(cmd));
1451 /* Get the current mode */
1452 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1453 if (chu->client == client_entry) {
1459 /* Are we adding or removing mode */
1460 if (cmd->argv[2][0] == '-')
1466 cp = cmd->argv[2] + 1;
1468 for (i = 0; i < len; i++) {
1472 mode |= SILC_CHANNEL_UMODE_CHANFO;
1473 mode |= SILC_CHANNEL_UMODE_CHANOP;
1475 mode = SILC_CHANNEL_UMODE_NONE;
1480 if (cmd->argc == 5) {
1481 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1482 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1483 cmd->client->private_key,
1488 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1489 cmd->argv[4], cmd->argv_lens[4]);
1492 mode |= SILC_CHANNEL_UMODE_CHANFO;
1494 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1499 mode |= SILC_CHANNEL_UMODE_CHANOP;
1501 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1510 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1511 SILC_PUT32_MSB(mode, modebuf);
1512 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1514 /* Send the command packet. We support sending only one mode at once
1515 that requires an argument. */
1516 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1517 1, chidp->data, chidp->len,
1519 3, clidp->data, clidp->len,
1520 4, auth ? auth->data : NULL,
1521 auth ? auth->len : 0);
1523 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1524 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1525 silc_buffer_free(buffer);
1526 silc_buffer_free(chidp);
1527 silc_buffer_free(clidp);
1529 silc_buffer_free(auth);
1531 /* Notify application */
1535 silc_free(nickname);
1536 silc_client_command_free(cmd);
1539 /* KICK command. Kicks a client out of channel. */
1541 SILC_CLIENT_CMD_FUNC(kick)
1543 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1544 SilcClient client = cmd->client;
1545 SilcClientConnection conn = cmd->conn;
1546 SilcIDCacheEntry id_cache = NULL;
1547 SilcChannelEntry channel;
1548 SilcBuffer buffer, idp, idp2;
1549 SilcClientEntry target;
1551 char *nickname = NULL;
1554 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1559 if (cmd->argc < 3) {
1560 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1561 "Usage: /KICK <channel> <nickname> [<comment>]");
1566 if (cmd->argv[1][0] == '*') {
1567 if (!conn->current_channel) {
1568 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1569 "You are not on any channel");
1573 name = conn->current_channel->channel_name;
1575 name = cmd->argv[1];
1578 if (!conn->current_channel) {
1579 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1580 "You are not on that channel");
1585 /* Get the Channel ID of the channel */
1586 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1587 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1588 "You are not on that channel");
1593 channel = (SilcChannelEntry)id_cache->context;
1595 /* Parse the typed nickname. */
1596 if (client->params->nickname_parse)
1597 client->params->nickname_parse(cmd->argv[2], &nickname);
1599 nickname = strdup(cmd->argv[2]);
1601 /* Get the target client */
1602 target = silc_idlist_get_client(cmd->client, conn, nickname,
1603 cmd->argv[2], FALSE);
1605 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1606 "No such client: %s",
1612 /* Send KICK command to the server */
1613 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1614 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1616 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1617 1, idp->data, idp->len,
1618 2, idp2->data, idp2->len);
1620 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1621 1, idp->data, idp->len,
1622 2, idp2->data, idp2->len,
1624 strlen(cmd->argv[3]));
1625 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1626 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1627 silc_buffer_free(buffer);
1628 silc_buffer_free(idp);
1629 silc_buffer_free(idp2);
1631 /* Notify application */
1635 silc_free(nickname);
1636 silc_client_command_free(cmd);
1639 static void silc_client_command_oper_send(unsigned char *data,
1640 uint32 data_len, void *context)
1642 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1643 SilcClientConnection conn = cmd->conn;
1644 SilcBuffer buffer, auth;
1646 if (cmd->argc >= 3) {
1647 /* Encode the public key authentication payload */
1648 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1649 cmd->client->private_key,
1654 /* Encode the password authentication payload */
1655 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1659 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1661 strlen(cmd->argv[1]),
1662 2, auth->data, auth->len);
1663 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1664 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1666 silc_buffer_free(buffer);
1667 silc_buffer_free(auth);
1669 /* Notify application */
1673 /* OPER command. Used to obtain server operator privileges. */
1675 SILC_CLIENT_CMD_FUNC(oper)
1677 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1678 SilcClientConnection conn = cmd->conn;
1681 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1686 if (cmd->argc < 2) {
1687 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1688 "Usage: /OPER <username> [-pubkey]");
1693 if (cmd->argc < 3) {
1694 /* Get passphrase */
1695 cmd->client->ops->ask_passphrase(cmd->client, conn,
1696 silc_client_command_oper_send,
1701 silc_client_command_oper_send(NULL, 0, context);
1704 silc_client_command_free(cmd);
1707 static void silc_client_command_silcoper_send(unsigned char *data,
1708 uint32 data_len, void *context)
1710 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1711 SilcClientConnection conn = cmd->conn;
1712 SilcBuffer buffer, auth;
1714 if (cmd->argc >= 3) {
1715 /* Encode the public key authentication payload */
1716 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1717 cmd->client->private_key,
1722 /* Encode the password authentication payload */
1723 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1727 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1729 strlen(cmd->argv[1]),
1730 2, auth->data, auth->len);
1731 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1732 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1734 silc_buffer_free(buffer);
1735 silc_buffer_free(auth);
1737 /* Notify application */
1741 /* SILCOPER command. Used to obtain router operator privileges. */
1743 SILC_CLIENT_CMD_FUNC(silcoper)
1745 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1746 SilcClientConnection conn = cmd->conn;
1749 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1754 if (cmd->argc < 2) {
1755 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1756 "Usage: /SILCOPER <username> [-pubkey]");
1761 if (cmd->argc < 3) {
1762 /* Get passphrase */
1763 cmd->client->ops->ask_passphrase(cmd->client, conn,
1764 silc_client_command_silcoper_send,
1769 silc_client_command_silcoper_send(NULL, 0, context);
1772 silc_client_command_free(cmd);
1775 /* CONNECT command. Connects the server to another server. */
1777 SILC_CLIENT_CMD_FUNC(connect)
1779 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1780 SilcClientConnection conn = cmd->conn;
1782 unsigned char port[4];
1786 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1791 if (cmd->argc < 2) {
1792 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1793 "Usage: /CONNECT <server> [<port>]");
1798 if (cmd->argc == 3) {
1799 tmp = atoi(cmd->argv[2]);
1800 SILC_PUT32_MSB(tmp, port);
1804 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1806 strlen(cmd->argv[1]),
1809 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1811 strlen(cmd->argv[1]));
1812 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1813 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1814 silc_buffer_free(buffer);
1816 /* Notify application */
1820 silc_client_command_free(cmd);
1823 /* Command BAN. This is used to manage the ban list of the channel. */
1825 SILC_CLIENT_CMD_FUNC(ban)
1827 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1828 SilcClientConnection conn = cmd->conn;
1829 SilcChannelEntry channel;
1830 SilcBuffer buffer, chidp;
1832 char *name, *ban = NULL;
1835 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1840 if (cmd->argc < 2) {
1841 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1842 "Usage: /BAN <channel> "
1843 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1848 if (cmd->argv[1][0] == '*') {
1849 if (!conn->current_channel) {
1850 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1851 "You are not on any channel");
1856 channel = conn->current_channel;
1858 name = cmd->argv[1];
1860 channel = silc_client_get_channel(cmd->client, conn, name);
1862 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1863 "You are on that channel");
1869 if (cmd->argc == 3) {
1870 if (cmd->argv[2][0] == '+')
1879 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1881 /* Send the command */
1883 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1884 1, chidp->data, chidp->len,
1885 type, ban, strlen(ban));
1887 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1888 1, chidp->data, chidp->len);
1890 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1891 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1892 silc_buffer_free(buffer);
1893 silc_buffer_free(chidp);
1895 /* Notify application */
1899 silc_client_command_free(cmd);
1902 /* CLOSE command. Close server connection to the remote server */
1904 SILC_CLIENT_CMD_FUNC(close)
1906 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1907 SilcClientConnection conn = cmd->conn;
1909 unsigned char port[4];
1913 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1918 if (cmd->argc < 2) {
1919 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1920 "Usage: /CLOSE <server> [<port>]");
1925 if (cmd->argc == 3) {
1926 tmp = atoi(cmd->argv[2]);
1927 SILC_PUT32_MSB(tmp, port);
1931 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1933 strlen(cmd->argv[1]),
1936 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1938 strlen(cmd->argv[1]));
1939 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1940 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1941 silc_buffer_free(buffer);
1943 /* Notify application */
1947 silc_client_command_free(cmd);
1950 /* SHUTDOWN command. Shutdowns the server. */
1952 SILC_CLIENT_CMD_FUNC(shutdown)
1954 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1957 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1962 /* Send the command */
1963 silc_client_send_command(cmd->client, cmd->conn,
1964 SILC_COMMAND_SHUTDOWN, 0, 0);
1966 /* Notify application */
1970 silc_client_command_free(cmd);
1973 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1975 SILC_CLIENT_CMD_FUNC(leave)
1977 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1978 SilcClientConnection conn = cmd->conn;
1979 SilcIDCacheEntry id_cache = NULL;
1980 SilcChannelEntry channel;
1981 SilcBuffer buffer, idp;
1985 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1990 if (cmd->argc != 2) {
1991 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1992 "Usage: /LEAVE <channel>");
1997 if (cmd->argv[1][0] == '*') {
1998 if (!conn->current_channel) {
1999 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2000 "You are not on any channel");
2004 name = conn->current_channel->channel_name;
2006 name = cmd->argv[1];
2009 /* Get the Channel ID of the channel */
2010 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2011 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2012 "You are not on that channel");
2017 channel = (SilcChannelEntry)id_cache->context;
2018 channel->on_channel = FALSE;
2020 /* Send LEAVE command to the server */
2021 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2022 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2023 1, idp->data, idp->len);
2024 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2025 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2026 silc_buffer_free(buffer);
2027 silc_buffer_free(idp);
2029 /* Notify application */
2032 if (conn->current_channel == channel)
2033 conn->current_channel = NULL;
2035 silc_client_del_channel(cmd->client, cmd->conn, channel);
2038 silc_client_command_free(cmd);
2041 /* Command USERS. Requests the USERS of the clients joined on requested
2044 SILC_CLIENT_CMD_FUNC(users)
2046 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2047 SilcClientConnection conn = cmd->conn;
2052 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2057 if (cmd->argc != 2) {
2058 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2059 "Usage: /USERS <channel>");
2064 if (cmd->argv[1][0] == '*') {
2065 if (!conn->current_channel) {
2066 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2067 "You are not on any channel");
2071 name = conn->current_channel->channel_name;
2073 name = cmd->argv[1];
2076 /* Send USERS command to the server */
2077 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2078 ++conn->cmd_ident, 1,
2079 2, name, strlen(name));
2080 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2081 NULL, 0, NULL, NULL, buffer->data,
2083 silc_buffer_free(buffer);
2085 /* Notify application */
2089 silc_client_command_free(cmd);
2092 /* Command GETKEY. Used to fetch remote client's public key. */
2094 SILC_CLIENT_CMD_FUNC(getkey)
2096 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2097 SilcClientConnection conn = cmd->conn;
2098 SilcClient client = cmd->client;
2099 SilcClientEntry client_entry = NULL;
2100 SilcServerEntry server_entry = NULL;
2101 char *nickname = NULL;
2102 SilcBuffer idp, buffer;
2105 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2110 if (cmd->argc < 2) {
2111 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2112 "Usage: /GETKEY <nickname or server name>");
2118 SilcClientCommandReplyContext reply =
2119 (SilcClientCommandReplyContext)context2;
2120 SilcCommandStatus status;
2121 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2122 SILC_GET16_MSB(status, tmp);
2124 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2125 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2126 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2128 silc_client_command_status_message(status));
2134 /* Parse the typed nickname. */
2135 if (client->params->nickname_parse)
2136 client->params->nickname_parse(cmd->argv[1], &nickname);
2138 nickname = strdup(cmd->argv[1]);
2140 /* Find client entry */
2141 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2143 if (!client_entry) {
2144 /* Check whether user requested server actually */
2145 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2147 if (!server_entry && !cmd->pending) {
2148 /* No. what ever user wants we don't have it, so resolve it. We
2149 will try to resolve both client and server, one of them is
2150 bound to be wrong. */
2152 /* This will send the IDENTIFY command */
2153 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2154 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2156 silc_client_command_destructor,
2157 silc_client_command_getkey,
2158 silc_client_command_dup(cmd));
2160 /* This sends the IDENTIFY command to resolve the server. */
2161 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2162 ++conn->cmd_ident, 1,
2163 2, cmd->argv[1], cmd->argv_lens[1]);
2164 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2165 conn->cmd_ident, NULL,
2166 silc_client_command_getkey,
2167 silc_client_command_dup(cmd));
2170 silc_free(nickname);
2174 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2176 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2179 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2180 1, idp->data, idp->len);
2181 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2182 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2183 silc_buffer_free(buffer);
2184 silc_buffer_free(idp);
2186 /* Notify application */
2190 silc_free(nickname);
2191 silc_client_command_free(cmd);