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 /* Sleep for a while */
710 /* We quit the connection with little timeout */
711 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
712 silc_client_command_quit_cb, (void *)q,
713 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
715 /* Notify application */
719 silc_client_command_free(cmd);
722 /* Timeout callback to remove the killed client from cache */
724 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
726 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
727 SilcClient client = cmd->client;
728 SilcClientConnection conn = cmd->conn;
729 SilcClientEntry target;
730 char *nickname = NULL;
732 /* Parse the typed nickname. */
733 if (client->params->nickname_parse)
734 client->params->nickname_parse(cmd->argv[1], &nickname);
736 nickname = strdup(cmd->argv[1]);
738 /* Get the target client */
739 target = silc_idlist_get_client(cmd->client, conn, nickname,
740 cmd->argv[1], FALSE);
742 silc_client_remove_from_channels(client, conn, target);
743 silc_client_del_client(client, conn, target);
747 silc_client_command_free(cmd);
750 /* Kill command's pending command callback to actually remove the killed
751 client from our local cache. */
753 SILC_CLIENT_CMD_FUNC(kill_remove)
755 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
756 SilcClientCommandReplyContext reply =
757 (SilcClientCommandReplyContext)context2;
758 SilcCommandStatus status;
760 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
761 if (status == SILC_STATUS_OK) {
762 /* Remove with timeout */
763 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
764 silc_client_command_kill_remove_later, context,
765 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
769 silc_client_command_free(cmd);
772 /* Command KILL. Router operator can use this command to remove an client
773 fromthe SILC Network. */
775 SILC_CLIENT_CMD_FUNC(kill)
777 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
778 SilcClient client = cmd->client;
779 SilcClientConnection conn = cmd->conn;
780 SilcBuffer buffer, idp;
781 SilcClientEntry target;
782 char *nickname = NULL;
785 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
791 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
792 "Usage: /KILL <nickname> [<comment>]");
797 /* Parse the typed nickname. */
798 if (client->params->nickname_parse)
799 client->params->nickname_parse(cmd->argv[1], &nickname);
801 nickname = strdup(cmd->argv[1]);
803 /* Get the target client */
804 target = silc_idlist_get_client(cmd->client, conn, nickname,
814 /* Client entry not found, it was requested thus mark this to be
816 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
818 silc_client_command_destructor,
819 silc_client_command_kill,
820 silc_client_command_dup(cmd));
825 /* Send the KILL command to the server */
826 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
828 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
829 ++conn->cmd_ident, 1,
830 1, idp->data, idp->len);
832 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
833 ++conn->cmd_ident, 2,
834 1, idp->data, idp->len,
836 strlen(cmd->argv[2]));
837 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
838 0, NULL, NULL, buffer->data, buffer->len, TRUE);
839 silc_buffer_free(buffer);
840 silc_buffer_free(idp);
842 /* Notify application */
845 /* Register a pending callback that will actually remove the killed
846 client from our cache. */
847 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
848 NULL, silc_client_command_kill_remove,
849 silc_client_command_dup(cmd));
853 silc_client_command_free(cmd);
856 /* Command INFO. Request information about specific server. If specific
857 server is not provided the current server is used. */
859 SILC_CLIENT_CMD_FUNC(info)
861 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
862 SilcClientConnection conn = cmd->conn;
867 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
873 name = strdup(cmd->argv[1]);
875 /* Send the command */
877 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
878 1, name, strlen(name));
880 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
881 NULL, NULL, NULL, 0);
882 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
883 0, NULL, NULL, buffer->data, buffer->len, TRUE);
884 silc_buffer_free(buffer);
888 /* Notify application */
892 silc_client_command_free(cmd);
895 /* Command PING. Sends ping to server. This is used to test the
896 communication channel. */
898 SILC_CLIENT_CMD_FUNC(ping)
900 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
901 SilcClientConnection conn = cmd->conn;
907 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
912 /* Send the command */
913 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
914 1, conn->remote_id_data,
915 silc_id_get_len(conn->remote_id,
917 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
918 0, NULL, NULL, buffer->data, buffer->len, TRUE);
919 silc_buffer_free(buffer);
921 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
924 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
929 /* Start counting time */
930 for (i = 0; i < conn->ping_count; i++) {
931 if (conn->ping[i].dest_id == NULL) {
932 conn->ping[i].start_time = time(NULL);
933 conn->ping[i].dest_id = id;
934 conn->ping[i].dest_name = strdup(conn->remote_host);
939 if (i >= conn->ping_count) {
940 i = conn->ping_count;
941 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
942 conn->ping[i].start_time = time(NULL);
943 conn->ping[i].dest_id = id;
944 conn->ping[i].dest_name = strdup(conn->remote_host);
948 /* Notify application */
952 silc_client_command_free(cmd);
955 /* Command JOIN. Joins to a channel. */
957 SILC_CLIENT_CMD_FUNC(join)
959 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
960 SilcClientConnection conn = cmd->conn;
961 SilcIDCacheEntry id_cache = NULL;
962 SilcBuffer buffer, idp;
965 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
970 /* See if we have joined to the requested channel already */
971 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
973 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
974 if (channel->on_channel)
978 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
980 /* Send JOIN command to the server */
983 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
984 1, cmd->argv[1], cmd->argv_lens[1],
985 2, idp->data, idp->len);
986 else if (cmd->argc == 3)
989 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
990 1, cmd->argv[1], cmd->argv_lens[1],
991 2, idp->data, idp->len,
992 3, cmd->argv[2], cmd->argv_lens[2]);
995 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
996 1, cmd->argv[1], cmd->argv_lens[1],
997 2, idp->data, idp->len,
998 3, cmd->argv[2], cmd->argv_lens[2],
999 4, cmd->argv[3], cmd->argv_lens[3]);
1001 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1002 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1003 silc_buffer_free(buffer);
1004 silc_buffer_free(idp);
1006 /* Notify application */
1010 silc_client_command_free(cmd);
1013 /* MOTD command. Requests motd from server. */
1015 SILC_CLIENT_CMD_FUNC(motd)
1017 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1018 SilcClientConnection conn = cmd->conn;
1022 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1027 if (cmd->argc < 1 || cmd->argc > 2) {
1028 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1029 "Usage: /MOTD [<server>]");
1034 /* Send TOPIC command to the server */
1036 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1037 1, conn->remote_host,
1038 strlen(conn->remote_host));
1040 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1043 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1044 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1045 silc_buffer_free(buffer);
1047 /* Notify application */
1051 silc_client_command_free(cmd);
1054 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1055 modes as client cannot set itself server/router operator privileges. */
1057 SILC_CLIENT_CMD_FUNC(umode)
1059 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1060 SilcClientConnection conn = cmd->conn;
1061 SilcBuffer buffer, idp;
1062 unsigned char *cp, modebuf[4];
1063 uint32 mode, add, len;
1067 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1072 if (cmd->argc < 2) {
1073 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1074 "Usage: /UMODE +|-<modes>");
1079 mode = conn->local_entry->mode;
1081 /* Are we adding or removing mode */
1082 if (cmd->argv[1][0] == '-')
1088 cp = cmd->argv[1] + 1;
1090 for (i = 0; i < len; i++) {
1095 mode |= SILC_UMODE_SERVER_OPERATOR;
1096 mode |= SILC_UMODE_ROUTER_OPERATOR;
1098 mode = SILC_UMODE_NONE;
1103 mode |= SILC_UMODE_SERVER_OPERATOR;
1105 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1109 mode |= SILC_UMODE_ROUTER_OPERATOR;
1111 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1115 mode |= SILC_UMODE_GONE;
1117 mode &= ~SILC_UMODE_GONE;
1126 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1127 SILC_PUT32_MSB(mode, modebuf);
1129 /* Send the command packet. We support sending only one mode at once
1130 that requires an argument. */
1132 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1133 1, idp->data, idp->len,
1134 2, modebuf, sizeof(modebuf));
1135 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1136 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1137 silc_buffer_free(buffer);
1138 silc_buffer_free(idp);
1140 /* Notify application */
1144 silc_client_command_free(cmd);
1147 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1148 can be set several at once. Those modes that require argument must be set
1149 separately (unless set with modes that does not require arguments). */
1151 SILC_CLIENT_CMD_FUNC(cmode)
1153 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1154 SilcClientConnection conn = cmd->conn;
1155 SilcChannelEntry channel;
1156 SilcBuffer buffer, chidp, auth = NULL;
1157 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1158 uint32 mode, add, type, len, arg_len = 0;
1162 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1167 if (cmd->argc < 3) {
1168 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1169 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1174 if (cmd->argv[1][0] == '*') {
1175 if (!conn->current_channel) {
1176 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1177 "You are not on any channel");
1182 channel = conn->current_channel;
1184 name = cmd->argv[1];
1186 channel = silc_client_get_channel(cmd->client, conn, name);
1188 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1189 "You are on that channel");
1195 mode = channel->mode;
1197 /* Are we adding or removing mode */
1198 if (cmd->argv[2][0] == '-')
1203 /* Argument type to be sent to server */
1207 cp = cmd->argv[2] + 1;
1209 for (i = 0; i < len; i++) {
1213 mode |= SILC_CHANNEL_MODE_PRIVATE;
1215 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1219 mode |= SILC_CHANNEL_MODE_SECRET;
1221 mode &= ~SILC_CHANNEL_MODE_SECRET;
1225 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1227 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1231 mode |= SILC_CHANNEL_MODE_INVITE;
1233 mode &= ~SILC_CHANNEL_MODE_INVITE;
1237 mode |= SILC_CHANNEL_MODE_TOPIC;
1239 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1244 mode |= SILC_CHANNEL_MODE_ULIMIT;
1246 if (cmd->argc < 4) {
1247 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1248 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1252 ll = atoi(cmd->argv[3]);
1253 SILC_PUT32_MSB(ll, tmp);
1257 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1262 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1264 if (cmd->argc < 4) {
1265 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1266 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1271 arg_len = cmd->argv_lens[3];
1273 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1278 mode |= SILC_CHANNEL_MODE_CIPHER;
1280 if (cmd->argc < 4) {
1281 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1282 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1287 arg_len = cmd->argv_lens[3];
1289 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1294 mode |= SILC_CHANNEL_MODE_HMAC;
1296 if (cmd->argc < 4) {
1297 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1298 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1303 arg_len = cmd->argv_lens[3];
1305 mode &= ~SILC_CHANNEL_MODE_HMAC;
1310 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1313 if (cmd->argc < 4) {
1314 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1315 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1320 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1321 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1322 cmd->client->private_key,
1327 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1328 cmd->argv[3], cmd->argv_lens[3]);
1332 arg_len = auth->len;
1334 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1344 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1345 SILC_PUT32_MSB(mode, modebuf);
1347 /* Send the command packet. We support sending only one mode at once
1348 that requires an argument. */
1351 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1352 1, chidp->data, chidp->len,
1353 2, modebuf, sizeof(modebuf),
1354 type, arg, arg_len);
1357 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1358 1, chidp->data, chidp->len,
1359 2, modebuf, sizeof(modebuf));
1362 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1363 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1364 silc_buffer_free(buffer);
1365 silc_buffer_free(chidp);
1367 silc_buffer_free(auth);
1369 /* Notify application */
1373 silc_client_command_free(cmd);
1376 /* CUMODE command. Changes client's mode on a channel. */
1378 SILC_CLIENT_CMD_FUNC(cumode)
1380 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1381 SilcClient client = cmd->client;
1382 SilcClientConnection conn = cmd->conn;
1383 SilcChannelEntry channel;
1384 SilcChannelUser chu;
1385 SilcClientEntry client_entry;
1386 SilcBuffer buffer, clidp, chidp, auth = NULL;
1387 unsigned char *name, *cp, modebuf[4];
1388 uint32 mode = 0, add, len;
1389 char *nickname = NULL;
1393 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1398 if (cmd->argc < 4) {
1399 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1400 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1405 if (cmd->argv[1][0] == '*') {
1406 if (!conn->current_channel) {
1407 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1408 "You are not on any channel");
1413 channel = conn->current_channel;
1415 name = cmd->argv[1];
1417 channel = silc_client_get_channel(cmd->client, conn, name);
1419 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1420 "You are on that channel");
1426 /* Parse the typed nickname. */
1427 if (client->params->nickname_parse)
1428 client->params->nickname_parse(cmd->argv[3], &nickname);
1430 nickname = strdup(cmd->argv[3]);
1432 /* Find client entry */
1433 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1434 cmd->argv[3], TRUE);
1435 if (!client_entry) {
1441 silc_free(nickname);
1443 /* Client entry not found, it was requested thus mark this to be
1445 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1447 silc_client_command_destructor,
1448 silc_client_command_cumode,
1449 silc_client_command_dup(cmd));
1454 /* Get the current mode */
1455 silc_list_start(channel->clients);
1456 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1457 if (chu->client == client_entry) {
1463 /* Are we adding or removing mode */
1464 if (cmd->argv[2][0] == '-')
1470 cp = cmd->argv[2] + 1;
1472 for (i = 0; i < len; i++) {
1476 mode |= SILC_CHANNEL_UMODE_CHANFO;
1477 mode |= SILC_CHANNEL_UMODE_CHANOP;
1479 mode = SILC_CHANNEL_UMODE_NONE;
1484 if (cmd->argc == 5) {
1485 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1486 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1487 cmd->client->private_key,
1492 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1493 cmd->argv[4], cmd->argv_lens[4]);
1496 mode |= SILC_CHANNEL_UMODE_CHANFO;
1498 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1503 mode |= SILC_CHANNEL_UMODE_CHANOP;
1505 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1514 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1515 SILC_PUT32_MSB(mode, modebuf);
1516 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1518 /* Send the command packet. We support sending only one mode at once
1519 that requires an argument. */
1520 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1522 1, chidp->data, chidp->len,
1524 3, clidp->data, clidp->len,
1525 4, auth ? auth->data : NULL,
1526 auth ? auth->len : 0);
1528 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1529 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1530 silc_buffer_free(buffer);
1531 silc_buffer_free(chidp);
1532 silc_buffer_free(clidp);
1534 silc_buffer_free(auth);
1536 /* Notify application */
1540 silc_free(nickname);
1541 silc_client_command_free(cmd);
1544 /* KICK command. Kicks a client out of channel. */
1546 SILC_CLIENT_CMD_FUNC(kick)
1548 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1549 SilcClient client = cmd->client;
1550 SilcClientConnection conn = cmd->conn;
1551 SilcIDCacheEntry id_cache = NULL;
1552 SilcChannelEntry channel;
1553 SilcBuffer buffer, idp, idp2;
1554 SilcClientEntry target;
1556 char *nickname = NULL;
1559 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1564 if (cmd->argc < 3) {
1565 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1566 "Usage: /KICK <channel> <nickname> [<comment>]");
1571 if (cmd->argv[1][0] == '*') {
1572 if (!conn->current_channel) {
1573 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1574 "You are not on any channel");
1578 name = conn->current_channel->channel_name;
1580 name = cmd->argv[1];
1583 if (!conn->current_channel) {
1584 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1585 "You are not on that channel");
1590 /* Get the Channel ID of the channel */
1591 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1592 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1593 "You are not on that channel");
1598 channel = (SilcChannelEntry)id_cache->context;
1600 /* Parse the typed nickname. */
1601 if (client->params->nickname_parse)
1602 client->params->nickname_parse(cmd->argv[2], &nickname);
1604 nickname = strdup(cmd->argv[2]);
1606 /* Get the target client */
1607 target = silc_idlist_get_client(cmd->client, conn, nickname,
1608 cmd->argv[2], FALSE);
1610 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1611 "No such client: %s",
1617 /* Send KICK command to the server */
1618 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1619 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1621 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1622 1, idp->data, idp->len,
1623 2, idp2->data, idp2->len);
1625 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1626 1, idp->data, idp->len,
1627 2, idp2->data, idp2->len,
1629 strlen(cmd->argv[3]));
1630 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1631 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1632 silc_buffer_free(buffer);
1633 silc_buffer_free(idp);
1634 silc_buffer_free(idp2);
1636 /* Notify application */
1640 silc_free(nickname);
1641 silc_client_command_free(cmd);
1644 static void silc_client_command_oper_send(unsigned char *data,
1645 uint32 data_len, void *context)
1647 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1648 SilcClientConnection conn = cmd->conn;
1649 SilcBuffer buffer, auth;
1651 if (cmd->argc >= 3) {
1652 /* Encode the public key authentication payload */
1653 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1654 cmd->client->private_key,
1659 /* Encode the password authentication payload */
1660 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1664 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1666 strlen(cmd->argv[1]),
1667 2, auth->data, auth->len);
1668 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1669 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1671 silc_buffer_free(buffer);
1672 silc_buffer_free(auth);
1674 /* Notify application */
1678 /* OPER command. Used to obtain server operator privileges. */
1680 SILC_CLIENT_CMD_FUNC(oper)
1682 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1683 SilcClientConnection conn = cmd->conn;
1686 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1691 if (cmd->argc < 2) {
1692 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1693 "Usage: /OPER <username> [-pubkey]");
1698 if (cmd->argc < 3) {
1699 /* Get passphrase */
1700 cmd->client->ops->ask_passphrase(cmd->client, conn,
1701 silc_client_command_oper_send,
1706 silc_client_command_oper_send(NULL, 0, context);
1709 silc_client_command_free(cmd);
1712 static void silc_client_command_silcoper_send(unsigned char *data,
1713 uint32 data_len, void *context)
1715 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1716 SilcClientConnection conn = cmd->conn;
1717 SilcBuffer buffer, auth;
1719 if (cmd->argc >= 3) {
1720 /* Encode the public key authentication payload */
1721 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1722 cmd->client->private_key,
1727 /* Encode the password authentication payload */
1728 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1732 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1734 strlen(cmd->argv[1]),
1735 2, auth->data, auth->len);
1736 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1737 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1739 silc_buffer_free(buffer);
1740 silc_buffer_free(auth);
1742 /* Notify application */
1746 /* SILCOPER command. Used to obtain router operator privileges. */
1748 SILC_CLIENT_CMD_FUNC(silcoper)
1750 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1751 SilcClientConnection conn = cmd->conn;
1754 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1759 if (cmd->argc < 2) {
1760 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1761 "Usage: /SILCOPER <username> [-pubkey]");
1766 if (cmd->argc < 3) {
1767 /* Get passphrase */
1768 cmd->client->ops->ask_passphrase(cmd->client, conn,
1769 silc_client_command_silcoper_send,
1774 silc_client_command_silcoper_send(NULL, 0, context);
1777 silc_client_command_free(cmd);
1780 /* CONNECT command. Connects the server to another server. */
1782 SILC_CLIENT_CMD_FUNC(connect)
1784 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1785 SilcClientConnection conn = cmd->conn;
1787 unsigned char port[4];
1791 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1796 if (cmd->argc < 2) {
1797 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1798 "Usage: /CONNECT <server> [<port>]");
1803 if (cmd->argc == 3) {
1804 tmp = atoi(cmd->argv[2]);
1805 SILC_PUT32_MSB(tmp, port);
1809 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1811 strlen(cmd->argv[1]),
1814 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1816 strlen(cmd->argv[1]));
1817 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1818 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1819 silc_buffer_free(buffer);
1821 /* Notify application */
1825 silc_client_command_free(cmd);
1828 /* Command BAN. This is used to manage the ban list of the channel. */
1830 SILC_CLIENT_CMD_FUNC(ban)
1832 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1833 SilcClientConnection conn = cmd->conn;
1834 SilcChannelEntry channel;
1835 SilcBuffer buffer, chidp;
1837 char *name, *ban = NULL;
1840 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1845 if (cmd->argc < 2) {
1846 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1847 "Usage: /BAN <channel> "
1848 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1853 if (cmd->argv[1][0] == '*') {
1854 if (!conn->current_channel) {
1855 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1856 "You are not on any channel");
1861 channel = conn->current_channel;
1863 name = cmd->argv[1];
1865 channel = silc_client_get_channel(cmd->client, conn, name);
1867 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1868 "You are on that channel");
1874 if (cmd->argc == 3) {
1875 if (cmd->argv[2][0] == '+')
1884 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1886 /* Send the command */
1888 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1889 1, chidp->data, chidp->len,
1890 type, ban, strlen(ban));
1892 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1893 1, chidp->data, chidp->len);
1895 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1896 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1897 silc_buffer_free(buffer);
1898 silc_buffer_free(chidp);
1900 /* Notify application */
1904 silc_client_command_free(cmd);
1907 /* CLOSE command. Close server connection to the remote server */
1909 SILC_CLIENT_CMD_FUNC(close)
1911 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1912 SilcClientConnection conn = cmd->conn;
1914 unsigned char port[4];
1918 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1923 if (cmd->argc < 2) {
1924 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1925 "Usage: /CLOSE <server> [<port>]");
1930 if (cmd->argc == 3) {
1931 tmp = atoi(cmd->argv[2]);
1932 SILC_PUT32_MSB(tmp, port);
1936 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1938 strlen(cmd->argv[1]),
1941 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1943 strlen(cmd->argv[1]));
1944 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1945 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1946 silc_buffer_free(buffer);
1948 /* Notify application */
1952 silc_client_command_free(cmd);
1955 /* SHUTDOWN command. Shutdowns the server. */
1957 SILC_CLIENT_CMD_FUNC(shutdown)
1959 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1962 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1967 /* Send the command */
1968 silc_client_send_command(cmd->client, cmd->conn,
1969 SILC_COMMAND_SHUTDOWN, 0, 0);
1971 /* Notify application */
1975 silc_client_command_free(cmd);
1978 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1980 SILC_CLIENT_CMD_FUNC(leave)
1982 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1983 SilcClientConnection conn = cmd->conn;
1984 SilcIDCacheEntry id_cache = NULL;
1985 SilcChannelEntry channel;
1986 SilcBuffer buffer, idp;
1990 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1995 if (cmd->argc != 2) {
1996 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1997 "Usage: /LEAVE <channel>");
2002 if (cmd->argv[1][0] == '*') {
2003 if (!conn->current_channel) {
2004 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2005 "You are not on any channel");
2009 name = conn->current_channel->channel_name;
2011 name = cmd->argv[1];
2014 /* Get the Channel ID of the channel */
2015 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2016 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2017 "You are not on that channel");
2022 channel = (SilcChannelEntry)id_cache->context;
2023 channel->on_channel = FALSE;
2025 /* Send LEAVE command to the server */
2026 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2027 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2028 1, idp->data, idp->len);
2029 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2030 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2031 silc_buffer_free(buffer);
2032 silc_buffer_free(idp);
2034 /* Notify application */
2037 if (conn->current_channel == channel)
2038 conn->current_channel = NULL;
2040 silc_client_del_channel(cmd->client, cmd->conn, channel);
2043 silc_client_command_free(cmd);
2046 /* Command USERS. Requests the USERS of the clients joined on requested
2049 SILC_CLIENT_CMD_FUNC(users)
2051 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2052 SilcClientConnection conn = cmd->conn;
2057 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2062 if (cmd->argc != 2) {
2063 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2064 "Usage: /USERS <channel>");
2069 if (cmd->argv[1][0] == '*') {
2070 if (!conn->current_channel) {
2071 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2072 "You are not on any channel");
2076 name = conn->current_channel->channel_name;
2078 name = cmd->argv[1];
2081 /* Send USERS command to the server */
2082 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2083 ++conn->cmd_ident, 1,
2084 2, name, strlen(name));
2085 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2086 NULL, 0, NULL, NULL, buffer->data,
2088 silc_buffer_free(buffer);
2090 /* Notify application */
2094 silc_client_command_free(cmd);
2097 /* Command GETKEY. Used to fetch remote client's public key. */
2099 SILC_CLIENT_CMD_FUNC(getkey)
2101 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2102 SilcClientConnection conn = cmd->conn;
2103 SilcClient client = cmd->client;
2104 SilcClientEntry client_entry = NULL;
2105 SilcServerEntry server_entry = NULL;
2106 char *nickname = NULL;
2107 SilcBuffer idp, buffer;
2110 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2115 if (cmd->argc < 2) {
2116 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2117 "Usage: /GETKEY <nickname or server name>");
2123 SilcClientCommandReplyContext reply =
2124 (SilcClientCommandReplyContext)context2;
2125 SilcCommandStatus status;
2126 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2127 SILC_GET16_MSB(status, tmp);
2129 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2130 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2131 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2133 silc_client_command_status_message(status));
2139 /* Parse the typed nickname. */
2140 if (client->params->nickname_parse)
2141 client->params->nickname_parse(cmd->argv[1], &nickname);
2143 nickname = strdup(cmd->argv[1]);
2145 /* Find client entry */
2146 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2148 if (!client_entry) {
2149 /* Check whether user requested server actually */
2150 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2152 if (!server_entry && !cmd->pending) {
2153 /* No. what ever user wants we don't have it, so resolve it. We
2154 will try to resolve both client and server, one of them is
2155 bound to be wrong. */
2157 /* This will send the IDENTIFY command */
2158 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2159 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2161 silc_client_command_destructor,
2162 silc_client_command_getkey,
2163 silc_client_command_dup(cmd));
2165 /* This sends the IDENTIFY command to resolve the server. */
2166 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2167 ++conn->cmd_ident, 1,
2168 2, cmd->argv[1], cmd->argv_lens[1]);
2169 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2170 conn->cmd_ident, NULL,
2171 silc_client_command_getkey,
2172 silc_client_command_dup(cmd));
2175 silc_free(nickname);
2179 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2181 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2184 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2185 1, idp->data, idp->len);
2186 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2187 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2188 silc_buffer_free(buffer);
2189 silc_buffer_free(idp);
2191 /* Notify application */
2195 silc_free(nickname);
2196 silc_client_command_free(cmd);