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, 9),
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 /* Pending callbcak that will be called after the NICK command was
353 replied by the server. This sets the nickname if there were no
356 SILC_CLIENT_CMD_FUNC(nick_change)
358 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
359 SilcClientConnection conn = cmd->conn;
360 SilcClientCommandReplyContext reply =
361 (SilcClientCommandReplyContext)context2;
362 SilcCommandStatus status;
364 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
365 if (status == SILC_STATUS_OK) {
366 /* Set the nickname */
367 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
369 silc_free(conn->nickname);
370 conn->nickname = strdup(cmd->argv[1]);
371 conn->local_entry->nickname = conn->nickname;
372 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
373 conn->local_entry->id, conn->local_entry, FALSE);
379 silc_client_command_free(cmd);
382 /* Command NICK. Shows current nickname/sets new nickname on current
385 SILC_CLIENT_CMD_FUNC(nick)
387 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
388 SilcClientConnection conn = cmd->conn;
392 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
398 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
399 "Usage: /NICK <nickname>");
404 if (!strcmp(conn->nickname, cmd->argv[1]))
407 /* Show current nickname */
410 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
411 "Your nickname is %s on server %s",
412 conn->nickname, conn->remote_host);
414 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
415 "Your nickname is %s", conn->nickname);
422 if (cmd->argv_lens[1] > 128)
423 cmd->argv_lens[1] = 128;
425 /* Send the NICK command */
426 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
430 ++cmd->conn->cmd_ident);
431 silc_client_packet_send(cmd->client, cmd->conn->sock,
432 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
433 buffer->data, buffer->len, TRUE);
434 silc_buffer_free(buffer);
436 /* Register pending callback that will actually set the new nickname
437 if there were no errors returned by the server. */
438 silc_client_command_pending(conn, SILC_COMMAND_NICK,
439 cmd->conn->cmd_ident,
440 silc_client_command_destructor,
441 silc_client_command_nick_change,
442 silc_client_command_dup(cmd));
447 silc_client_command_free(cmd);
450 /* Command LIST. Lists channels on the current server. */
452 SILC_CLIENT_CMD_FUNC(list)
454 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
455 SilcClientConnection conn = cmd->conn;
456 SilcIDCacheEntry id_cache = NULL;
457 SilcChannelEntry channel;
458 SilcBuffer buffer, idp = NULL;
462 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
467 if (cmd->argc == 2) {
470 /* Get the Channel ID of the channel */
471 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
472 channel = (SilcChannelEntry)id_cache->context;
473 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
478 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
479 ++conn->cmd_ident, 0);
481 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
482 ++conn->cmd_ident, 1,
483 1, idp->data, idp->len);
485 silc_client_packet_send(cmd->client, cmd->conn->sock,
486 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
487 buffer->data, buffer->len, TRUE);
488 silc_buffer_free(buffer);
490 silc_buffer_free(idp);
492 /* Notify application */
496 silc_client_command_free(cmd);
499 /* Command TOPIC. Sets/shows topic on a channel. */
501 SILC_CLIENT_CMD_FUNC(topic)
503 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
504 SilcClientConnection conn = cmd->conn;
505 SilcIDCacheEntry id_cache = NULL;
506 SilcChannelEntry channel;
507 SilcBuffer buffer, idp;
511 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
516 if (cmd->argc < 2 || cmd->argc > 3) {
517 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
518 "Usage: /TOPIC <channel> [<topic>]");
523 if (cmd->argv[1][0] == '*') {
524 if (!conn->current_channel) {
525 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
526 "You are not on any channel");
530 name = conn->current_channel->channel_name;
535 if (!conn->current_channel) {
536 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
537 "You are not on that channel");
542 /* Get the Channel ID of the channel */
543 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
544 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
545 "You are not on that channel");
550 channel = (SilcChannelEntry)id_cache->context;
552 /* Send TOPIC command to the server */
553 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
555 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
556 ++conn->cmd_ident, 2,
557 1, idp->data, idp->len,
559 strlen(cmd->argv[2]));
561 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
562 ++conn->cmd_ident, 1,
563 1, idp->data, idp->len);
564 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
565 0, NULL, NULL, buffer->data, buffer->len, TRUE);
566 silc_buffer_free(buffer);
567 silc_buffer_free(idp);
569 /* Notify application */
573 silc_client_command_free(cmd);
576 /* Command INVITE. Invites specific client to join a channel. This is
577 also used to mange the invite list of the channel. */
579 SILC_CLIENT_CMD_FUNC(invite)
581 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
582 SilcClient client = cmd->client;
583 SilcClientConnection conn = cmd->conn;
584 SilcClientEntry client_entry = NULL;
585 SilcChannelEntry channel;
586 SilcBuffer buffer, clidp, chidp;
588 char *nickname = NULL, *name;
592 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
598 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
599 "Usage: /INVITE <channel> [<nickname>[@server>]"
600 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
605 if (cmd->argv[1][0] == '*') {
606 if (!conn->current_channel) {
607 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
608 "You are not on any channel");
613 channel = conn->current_channel;
617 channel = silc_client_get_channel(cmd->client, conn, name);
619 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
620 "You are on that channel");
626 /* Parse the typed nickname. */
627 if (cmd->argc == 3) {
628 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
629 if (client->params->nickname_parse)
630 client->params->nickname_parse(cmd->argv[2], &nickname);
632 nickname = strdup(cmd->argv[2]);
634 /* Find client entry */
635 client_entry = silc_idlist_get_client(client, conn, nickname,
644 /* Client entry not found, it was requested thus mark this to be
646 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
648 silc_client_command_destructor,
649 silc_client_command_invite,
650 silc_client_command_dup(cmd));
655 invite = cmd->argv[2];
657 if (cmd->argv[2][0] == '+')
664 /* Send the command */
665 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
667 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
668 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
669 ++conn->cmd_ident, 3,
670 1, chidp->data, chidp->len,
671 2, clidp->data, clidp->len,
672 type, invite, invite ?
674 silc_buffer_free(clidp);
676 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
677 ++conn->cmd_ident, 2,
678 1, chidp->data, chidp->len,
679 type, invite, invite ?
683 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
684 0, NULL, NULL, buffer->data, buffer->len, TRUE);
685 silc_buffer_free(buffer);
686 silc_buffer_free(chidp);
688 /* Notify application */
693 silc_client_command_free(cmd);
698 SilcClientConnection conn;
701 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
703 QuitInternal q = (QuitInternal)context;
705 /* Close connection */
706 q->client->ops->disconnect(q->client, q->conn);
707 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
712 /* Command QUIT. Closes connection with current server. */
714 SILC_CLIENT_CMD_FUNC(quit)
716 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
721 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
727 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
728 &cmd->argv[1], &cmd->argv_lens[1],
729 &cmd->argv_types[1], 0);
731 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
732 NULL, NULL, NULL, 0);
733 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
735 buffer->data, buffer->len, TRUE);
736 silc_buffer_free(buffer);
738 q = silc_calloc(1, sizeof(*q));
739 q->client = cmd->client;
742 /* Sleep for a while */
745 /* We quit the connection with little timeout */
746 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
747 silc_client_command_quit_cb, (void *)q,
748 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
750 /* Notify application */
754 silc_client_command_free(cmd);
757 /* Timeout callback to remove the killed client from cache */
759 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
761 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
762 SilcClient client = cmd->client;
763 SilcClientConnection conn = cmd->conn;
764 SilcClientEntry target;
765 char *nickname = NULL;
767 /* Parse the typed nickname. */
768 if (client->params->nickname_parse)
769 client->params->nickname_parse(cmd->argv[1], &nickname);
771 nickname = strdup(cmd->argv[1]);
773 /* Get the target client */
774 target = silc_idlist_get_client(cmd->client, conn, nickname,
775 cmd->argv[1], FALSE);
777 silc_client_remove_from_channels(client, conn, target);
778 silc_client_del_client(client, conn, target);
782 silc_client_command_free(cmd);
785 /* Kill command's pending command callback to actually remove the killed
786 client from our local cache. */
788 SILC_CLIENT_CMD_FUNC(kill_remove)
790 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
791 SilcClientCommandReplyContext reply =
792 (SilcClientCommandReplyContext)context2;
793 SilcCommandStatus status;
795 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
796 if (status == SILC_STATUS_OK) {
797 /* Remove with timeout */
798 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
799 silc_client_command_kill_remove_later, context,
800 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
804 silc_client_command_free(cmd);
807 /* Command KILL. Router operator can use this command to remove an client
808 fromthe SILC Network. */
810 SILC_CLIENT_CMD_FUNC(kill)
812 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
813 SilcClient client = cmd->client;
814 SilcClientConnection conn = cmd->conn;
815 SilcBuffer buffer, idp;
816 SilcClientEntry target;
817 char *nickname = NULL;
820 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
826 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
827 "Usage: /KILL <nickname> [<comment>]");
832 /* Parse the typed nickname. */
833 if (client->params->nickname_parse)
834 client->params->nickname_parse(cmd->argv[1], &nickname);
836 nickname = strdup(cmd->argv[1]);
838 /* Get the target client */
839 target = silc_idlist_get_client(cmd->client, conn, nickname,
849 /* Client entry not found, it was requested thus mark this to be
851 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
853 silc_client_command_destructor,
854 silc_client_command_kill,
855 silc_client_command_dup(cmd));
860 /* Send the KILL command to the server */
861 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
863 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
864 ++conn->cmd_ident, 1,
865 1, idp->data, idp->len);
867 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
868 ++conn->cmd_ident, 2,
869 1, idp->data, idp->len,
871 strlen(cmd->argv[2]));
872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
874 silc_buffer_free(buffer);
875 silc_buffer_free(idp);
877 /* Notify application */
880 /* Register a pending callback that will actually remove the killed
881 client from our cache. */
882 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
883 NULL, silc_client_command_kill_remove,
884 silc_client_command_dup(cmd));
888 silc_client_command_free(cmd);
891 /* Command INFO. Request information about specific server. If specific
892 server is not provided the current server is used. */
894 SILC_CLIENT_CMD_FUNC(info)
896 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
897 SilcClientConnection conn = cmd->conn;
902 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
908 name = strdup(cmd->argv[1]);
910 /* Send the command */
912 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
913 1, name, strlen(name));
915 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
916 NULL, NULL, NULL, 0);
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);
923 /* Notify application */
927 silc_client_command_free(cmd);
930 /* Command PING. Sends ping to server. This is used to test the
931 communication channel. */
933 SILC_CLIENT_CMD_FUNC(ping)
935 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
936 SilcClientConnection conn = cmd->conn;
942 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
947 /* Send the command */
948 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
949 1, conn->remote_id_data,
950 silc_id_get_len(conn->remote_id,
952 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
953 0, NULL, NULL, buffer->data, buffer->len, TRUE);
954 silc_buffer_free(buffer);
956 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
964 /* Start counting time */
965 for (i = 0; i < conn->ping_count; i++) {
966 if (conn->ping[i].dest_id == NULL) {
967 conn->ping[i].start_time = time(NULL);
968 conn->ping[i].dest_id = id;
969 conn->ping[i].dest_name = strdup(conn->remote_host);
973 if (i >= conn->ping_count) {
974 i = conn->ping_count;
975 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
976 conn->ping[i].start_time = time(NULL);
977 conn->ping[i].dest_id = id;
978 conn->ping[i].dest_name = strdup(conn->remote_host);
982 /* Notify application */
986 silc_client_command_free(cmd);
989 /* Command JOIN. Joins to a channel. */
991 SILC_CLIENT_CMD_FUNC(join)
993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
994 SilcClientConnection conn = cmd->conn;
995 SilcIDCacheEntry id_cache = NULL;
996 SilcBuffer buffer, idp, auth = NULL;
997 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
1001 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1006 if (cmd->argc < 2) {
1011 /* See if we have joined to the requested channel already */
1012 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
1014 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
1015 if (channel->on_channel)
1019 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1021 if (cmd->argv_lens[1] > 256)
1022 cmd->argv_lens[1] = 256;
1024 name = cmd->argv[1];
1026 for (i = 2; i < cmd->argc; i++) {
1027 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc >= i + 1) {
1028 cipher = cmd->argv[i + 1];
1030 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc >= i + 1) {
1031 hmac = cmd->argv[i + 1];
1033 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc >= i + 1) {
1034 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
1035 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1036 cmd->client->private_key,
1041 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1043 cmd->argv_lens[i + 1]);
1047 passphrase = cmd->argv[i];
1051 /* Send JOIN command to the server */
1053 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1054 1, name, strlen(name),
1055 2, idp->data, idp->len,
1057 passphrase ? strlen(passphrase) : 0,
1058 4, cipher, cipher ? strlen(cipher) : 0,
1059 5, hmac, hmac ? strlen(hmac) : 0,
1060 6, auth ? auth->data : NULL,
1061 auth ? auth->len : 0);
1062 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1063 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1064 silc_buffer_free(buffer);
1065 silc_buffer_free(idp);
1067 silc_buffer_free(auth);
1069 /* Notify application */
1073 silc_client_command_free(cmd);
1076 /* MOTD command. Requests motd from server. */
1078 SILC_CLIENT_CMD_FUNC(motd)
1080 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1081 SilcClientConnection conn = cmd->conn;
1085 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1090 if (cmd->argc < 1 || cmd->argc > 2) {
1091 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1092 "Usage: /MOTD [<server>]");
1097 /* Send TOPIC command to the server */
1099 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1100 1, conn->remote_host,
1101 strlen(conn->remote_host));
1103 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1106 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1107 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1108 silc_buffer_free(buffer);
1110 /* Notify application */
1114 silc_client_command_free(cmd);
1117 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1118 modes as client cannot set itself server/router operator privileges. */
1120 SILC_CLIENT_CMD_FUNC(umode)
1122 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1123 SilcClientConnection conn = cmd->conn;
1124 SilcBuffer buffer, idp;
1125 unsigned char *cp, modebuf[4];
1126 uint32 mode, add, len;
1130 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1135 if (cmd->argc < 2) {
1136 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1137 "Usage: /UMODE +|-<modes>");
1142 mode = conn->local_entry->mode;
1144 /* Are we adding or removing mode */
1145 if (cmd->argv[1][0] == '-')
1151 cp = cmd->argv[1] + 1;
1153 for (i = 0; i < len; i++) {
1158 mode |= SILC_UMODE_SERVER_OPERATOR;
1159 mode |= SILC_UMODE_ROUTER_OPERATOR;
1161 mode = SILC_UMODE_NONE;
1166 mode |= SILC_UMODE_SERVER_OPERATOR;
1168 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1172 mode |= SILC_UMODE_ROUTER_OPERATOR;
1174 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1178 mode |= SILC_UMODE_GONE;
1180 mode &= ~SILC_UMODE_GONE;
1189 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1190 SILC_PUT32_MSB(mode, modebuf);
1192 /* Send the command packet. We support sending only one mode at once
1193 that requires an argument. */
1195 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1196 1, idp->data, idp->len,
1197 2, modebuf, sizeof(modebuf));
1198 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1199 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1200 silc_buffer_free(buffer);
1201 silc_buffer_free(idp);
1203 /* Notify application */
1207 silc_client_command_free(cmd);
1210 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1211 can be set several at once. Those modes that require argument must be set
1212 separately (unless set with modes that does not require arguments). */
1214 SILC_CLIENT_CMD_FUNC(cmode)
1216 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1217 SilcClientConnection conn = cmd->conn;
1218 SilcChannelEntry channel;
1219 SilcBuffer buffer, chidp, auth = NULL;
1220 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1221 uint32 mode, add, type, len, arg_len = 0;
1225 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1230 if (cmd->argc < 3) {
1231 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1232 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1237 if (cmd->argv[1][0] == '*') {
1238 if (!conn->current_channel) {
1239 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1240 "You are not on any channel");
1245 channel = conn->current_channel;
1247 name = cmd->argv[1];
1249 channel = silc_client_get_channel(cmd->client, conn, name);
1251 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1252 "You are on that channel");
1258 mode = channel->mode;
1260 /* Are we adding or removing mode */
1261 if (cmd->argv[2][0] == '-')
1266 /* Argument type to be sent to server */
1270 cp = cmd->argv[2] + 1;
1272 for (i = 0; i < len; i++) {
1276 mode |= SILC_CHANNEL_MODE_PRIVATE;
1278 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1282 mode |= SILC_CHANNEL_MODE_SECRET;
1284 mode &= ~SILC_CHANNEL_MODE_SECRET;
1288 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1290 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1294 mode |= SILC_CHANNEL_MODE_INVITE;
1296 mode &= ~SILC_CHANNEL_MODE_INVITE;
1300 mode |= SILC_CHANNEL_MODE_TOPIC;
1302 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1307 mode |= SILC_CHANNEL_MODE_ULIMIT;
1309 if (cmd->argc < 4) {
1310 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1311 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1315 ll = atoi(cmd->argv[3]);
1316 SILC_PUT32_MSB(ll, tmp);
1320 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1325 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1327 if (cmd->argc < 4) {
1328 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1329 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1334 arg_len = cmd->argv_lens[3];
1336 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1341 mode |= SILC_CHANNEL_MODE_CIPHER;
1343 if (cmd->argc < 4) {
1344 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1345 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1350 arg_len = cmd->argv_lens[3];
1352 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1357 mode |= SILC_CHANNEL_MODE_HMAC;
1359 if (cmd->argc < 4) {
1360 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1361 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1366 arg_len = cmd->argv_lens[3];
1368 mode &= ~SILC_CHANNEL_MODE_HMAC;
1373 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1376 if (cmd->argc < 4) {
1377 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1378 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1383 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1384 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1385 cmd->client->private_key,
1390 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1391 cmd->argv[3], cmd->argv_lens[3]);
1395 arg_len = auth->len;
1397 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1407 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1408 SILC_PUT32_MSB(mode, modebuf);
1410 /* Send the command packet. We support sending only one mode at once
1411 that requires an argument. */
1414 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1415 1, chidp->data, chidp->len,
1416 2, modebuf, sizeof(modebuf),
1417 type, arg, arg_len);
1420 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1421 1, chidp->data, chidp->len,
1422 2, modebuf, sizeof(modebuf));
1425 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1426 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1427 silc_buffer_free(buffer);
1428 silc_buffer_free(chidp);
1430 silc_buffer_free(auth);
1432 /* Notify application */
1436 silc_client_command_free(cmd);
1439 /* CUMODE command. Changes client's mode on a channel. */
1441 SILC_CLIENT_CMD_FUNC(cumode)
1443 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1444 SilcClient client = cmd->client;
1445 SilcClientConnection conn = cmd->conn;
1446 SilcChannelEntry channel;
1447 SilcChannelUser chu;
1448 SilcClientEntry client_entry;
1449 SilcBuffer buffer, clidp, chidp, auth = NULL;
1450 unsigned char *name, *cp, modebuf[4];
1451 uint32 mode = 0, add, len;
1452 char *nickname = NULL;
1456 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1461 if (cmd->argc < 4) {
1462 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1463 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1468 if (cmd->argv[1][0] == '*') {
1469 if (!conn->current_channel) {
1470 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1471 "You are not on any channel");
1476 channel = conn->current_channel;
1478 name = cmd->argv[1];
1480 channel = silc_client_get_channel(cmd->client, conn, name);
1482 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1483 "You are on that channel");
1489 /* Parse the typed nickname. */
1490 if (client->params->nickname_parse)
1491 client->params->nickname_parse(cmd->argv[3], &nickname);
1493 nickname = strdup(cmd->argv[3]);
1495 /* Find client entry */
1496 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1497 cmd->argv[3], TRUE);
1498 if (!client_entry) {
1504 silc_free(nickname);
1506 /* Client entry not found, it was requested thus mark this to be
1508 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1510 silc_client_command_destructor,
1511 silc_client_command_cumode,
1512 silc_client_command_dup(cmd));
1517 /* Get the current mode */
1518 silc_list_start(channel->clients);
1519 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1520 if (chu->client == client_entry) {
1526 /* Are we adding or removing mode */
1527 if (cmd->argv[2][0] == '-')
1533 cp = cmd->argv[2] + 1;
1535 for (i = 0; i < len; i++) {
1539 mode |= SILC_CHANNEL_UMODE_CHANFO;
1540 mode |= SILC_CHANNEL_UMODE_CHANOP;
1542 mode = SILC_CHANNEL_UMODE_NONE;
1547 if (cmd->argc == 5) {
1548 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1549 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1550 cmd->client->private_key,
1555 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1556 cmd->argv[4], cmd->argv_lens[4]);
1559 mode |= SILC_CHANNEL_UMODE_CHANFO;
1561 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1566 mode |= SILC_CHANNEL_UMODE_CHANOP;
1568 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1577 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1578 SILC_PUT32_MSB(mode, modebuf);
1579 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1581 /* Send the command packet. We support sending only one mode at once
1582 that requires an argument. */
1583 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1585 1, chidp->data, chidp->len,
1587 3, clidp->data, clidp->len,
1588 4, auth ? auth->data : NULL,
1589 auth ? auth->len : 0);
1591 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1592 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1593 silc_buffer_free(buffer);
1594 silc_buffer_free(chidp);
1595 silc_buffer_free(clidp);
1597 silc_buffer_free(auth);
1599 /* Notify application */
1603 silc_free(nickname);
1604 silc_client_command_free(cmd);
1607 /* KICK command. Kicks a client out of channel. */
1609 SILC_CLIENT_CMD_FUNC(kick)
1611 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1612 SilcClient client = cmd->client;
1613 SilcClientConnection conn = cmd->conn;
1614 SilcIDCacheEntry id_cache = NULL;
1615 SilcChannelEntry channel;
1616 SilcBuffer buffer, idp, idp2;
1617 SilcClientEntry target;
1619 char *nickname = NULL;
1622 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1627 if (cmd->argc < 3) {
1628 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1629 "Usage: /KICK <channel> <nickname> [<comment>]");
1634 if (cmd->argv[1][0] == '*') {
1635 if (!conn->current_channel) {
1636 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1637 "You are not on any channel");
1641 name = conn->current_channel->channel_name;
1643 name = cmd->argv[1];
1646 if (!conn->current_channel) {
1647 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1648 "You are not on that channel");
1653 /* Get the Channel ID of the channel */
1654 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1655 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1656 "You are not on that channel");
1661 channel = (SilcChannelEntry)id_cache->context;
1663 /* Parse the typed nickname. */
1664 if (client->params->nickname_parse)
1665 client->params->nickname_parse(cmd->argv[2], &nickname);
1667 nickname = strdup(cmd->argv[2]);
1669 /* Get the target client */
1670 target = silc_idlist_get_client(cmd->client, conn, nickname,
1671 cmd->argv[2], FALSE);
1673 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1674 "No such client: %s",
1680 /* Send KICK command to the server */
1681 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1682 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1684 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1685 1, idp->data, idp->len,
1686 2, idp2->data, idp2->len);
1688 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1689 1, idp->data, idp->len,
1690 2, idp2->data, idp2->len,
1692 strlen(cmd->argv[3]));
1693 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1694 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1695 silc_buffer_free(buffer);
1696 silc_buffer_free(idp);
1697 silc_buffer_free(idp2);
1699 /* Notify application */
1703 silc_free(nickname);
1704 silc_client_command_free(cmd);
1707 static void silc_client_command_oper_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_OPER, 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 /* OPER command. Used to obtain server operator privileges. */
1743 SILC_CLIENT_CMD_FUNC(oper)
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: /OPER <username> [-pubkey]");
1761 if (cmd->argc < 3) {
1762 /* Get passphrase */
1763 cmd->client->ops->ask_passphrase(cmd->client, conn,
1764 silc_client_command_oper_send,
1769 silc_client_command_oper_send(NULL, 0, context);
1772 silc_client_command_free(cmd);
1775 static void silc_client_command_silcoper_send(unsigned char *data,
1776 uint32 data_len, void *context)
1778 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1779 SilcClientConnection conn = cmd->conn;
1780 SilcBuffer buffer, auth;
1782 if (cmd->argc >= 3) {
1783 /* Encode the public key authentication payload */
1784 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1785 cmd->client->private_key,
1790 /* Encode the password authentication payload */
1791 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1795 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1797 strlen(cmd->argv[1]),
1798 2, auth->data, auth->len);
1799 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1800 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1802 silc_buffer_free(buffer);
1803 silc_buffer_free(auth);
1805 /* Notify application */
1809 /* SILCOPER command. Used to obtain router operator privileges. */
1811 SILC_CLIENT_CMD_FUNC(silcoper)
1813 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1814 SilcClientConnection conn = cmd->conn;
1817 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1822 if (cmd->argc < 2) {
1823 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1824 "Usage: /SILCOPER <username> [-pubkey]");
1829 if (cmd->argc < 3) {
1830 /* Get passphrase */
1831 cmd->client->ops->ask_passphrase(cmd->client, conn,
1832 silc_client_command_silcoper_send,
1837 silc_client_command_silcoper_send(NULL, 0, context);
1840 silc_client_command_free(cmd);
1843 /* CONNECT command. Connects the server to another server. */
1845 SILC_CLIENT_CMD_FUNC(connect)
1847 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1848 SilcClientConnection conn = cmd->conn;
1850 unsigned char port[4];
1854 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1859 if (cmd->argc < 2) {
1860 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1861 "Usage: /CONNECT <server> [<port>]");
1866 if (cmd->argc == 3) {
1867 tmp = atoi(cmd->argv[2]);
1868 SILC_PUT32_MSB(tmp, port);
1872 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1874 strlen(cmd->argv[1]),
1877 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1879 strlen(cmd->argv[1]));
1880 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1881 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1882 silc_buffer_free(buffer);
1884 /* Notify application */
1888 silc_client_command_free(cmd);
1891 /* Command BAN. This is used to manage the ban list of the channel. */
1893 SILC_CLIENT_CMD_FUNC(ban)
1895 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1896 SilcClientConnection conn = cmd->conn;
1897 SilcChannelEntry channel;
1898 SilcBuffer buffer, chidp;
1900 char *name, *ban = NULL;
1903 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1908 if (cmd->argc < 2) {
1909 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1910 "Usage: /BAN <channel> "
1911 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1916 if (cmd->argv[1][0] == '*') {
1917 if (!conn->current_channel) {
1918 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1919 "You are not on any channel");
1924 channel = conn->current_channel;
1926 name = cmd->argv[1];
1928 channel = silc_client_get_channel(cmd->client, conn, name);
1930 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1931 "You are on that channel");
1937 if (cmd->argc == 3) {
1938 if (cmd->argv[2][0] == '+')
1947 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1949 /* Send the command */
1951 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1952 1, chidp->data, chidp->len,
1953 type, ban, strlen(ban));
1955 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1956 1, chidp->data, chidp->len);
1958 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1959 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1960 silc_buffer_free(buffer);
1961 silc_buffer_free(chidp);
1963 /* Notify application */
1967 silc_client_command_free(cmd);
1970 /* CLOSE command. Close server connection to the remote server */
1972 SILC_CLIENT_CMD_FUNC(close)
1974 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1975 SilcClientConnection conn = cmd->conn;
1977 unsigned char port[4];
1981 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1986 if (cmd->argc < 2) {
1987 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1988 "Usage: /CLOSE <server> [<port>]");
1993 if (cmd->argc == 3) {
1994 tmp = atoi(cmd->argv[2]);
1995 SILC_PUT32_MSB(tmp, port);
1999 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
2001 strlen(cmd->argv[1]),
2004 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
2006 strlen(cmd->argv[1]));
2007 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2008 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2009 silc_buffer_free(buffer);
2011 /* Notify application */
2015 silc_client_command_free(cmd);
2018 /* SHUTDOWN command. Shutdowns the server. */
2020 SILC_CLIENT_CMD_FUNC(shutdown)
2022 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2025 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2030 /* Send the command */
2031 silc_client_send_command(cmd->client, cmd->conn,
2032 SILC_COMMAND_SHUTDOWN, 0, 0);
2034 /* Notify application */
2038 silc_client_command_free(cmd);
2041 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2043 SILC_CLIENT_CMD_FUNC(leave)
2045 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2046 SilcClientConnection conn = cmd->conn;
2047 SilcIDCacheEntry id_cache = NULL;
2048 SilcChannelEntry channel;
2049 SilcBuffer buffer, idp;
2053 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2058 if (cmd->argc != 2) {
2059 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2060 "Usage: /LEAVE <channel>");
2065 if (cmd->argv[1][0] == '*') {
2066 if (!conn->current_channel) {
2067 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2068 "You are not on any channel");
2072 name = conn->current_channel->channel_name;
2074 name = cmd->argv[1];
2077 /* Get the Channel ID of the channel */
2078 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2079 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2080 "You are not on that channel");
2085 channel = (SilcChannelEntry)id_cache->context;
2086 channel->on_channel = FALSE;
2088 /* Send LEAVE command to the server */
2089 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2090 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2091 1, idp->data, idp->len);
2092 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2093 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2094 silc_buffer_free(buffer);
2095 silc_buffer_free(idp);
2097 /* Notify application */
2100 if (conn->current_channel == channel)
2101 conn->current_channel = NULL;
2103 silc_client_del_channel(cmd->client, cmd->conn, channel);
2106 silc_client_command_free(cmd);
2109 /* Command USERS. Requests the USERS of the clients joined on requested
2112 SILC_CLIENT_CMD_FUNC(users)
2114 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2115 SilcClientConnection conn = cmd->conn;
2120 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2125 if (cmd->argc != 2) {
2126 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2127 "Usage: /USERS <channel>");
2132 if (cmd->argv[1][0] == '*') {
2133 if (!conn->current_channel) {
2134 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2135 "You are not on any channel");
2139 name = conn->current_channel->channel_name;
2141 name = cmd->argv[1];
2144 /* Send USERS command to the server */
2145 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2146 ++conn->cmd_ident, 1,
2147 2, name, strlen(name));
2148 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2149 NULL, 0, NULL, NULL, buffer->data,
2151 silc_buffer_free(buffer);
2153 /* Notify application */
2157 silc_client_command_free(cmd);
2160 /* Command GETKEY. Used to fetch remote client's public key. */
2162 SILC_CLIENT_CMD_FUNC(getkey)
2164 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2165 SilcClientConnection conn = cmd->conn;
2166 SilcClient client = cmd->client;
2167 SilcClientEntry client_entry = NULL;
2168 SilcServerEntry server_entry = NULL;
2169 char *nickname = NULL;
2170 SilcBuffer idp, buffer;
2173 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2178 if (cmd->argc < 2) {
2179 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2180 "Usage: /GETKEY <nickname or server name>");
2186 SilcClientCommandReplyContext reply =
2187 (SilcClientCommandReplyContext)context2;
2188 SilcCommandStatus status;
2189 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2190 SILC_GET16_MSB(status, tmp);
2192 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2193 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2194 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2196 silc_client_command_status_message(status));
2202 /* Parse the typed nickname. */
2203 if (client->params->nickname_parse)
2204 client->params->nickname_parse(cmd->argv[1], &nickname);
2206 nickname = strdup(cmd->argv[1]);
2208 /* Find client entry */
2209 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2211 if (!client_entry) {
2212 /* Check whether user requested server actually */
2213 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2215 if (!server_entry) {
2221 /* No. what ever user wants we don't have it, so resolve it. We
2222 will try to resolve both client and server, one of them is
2223 bound to be wrong. */
2225 /* This will send the IDENTIFY command */
2226 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2227 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2229 silc_client_command_destructor,
2230 silc_client_command_getkey,
2231 silc_client_command_dup(cmd));
2233 /* This sends the IDENTIFY command to resolve the server. */
2234 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2235 ++conn->cmd_ident, 1,
2236 2, cmd->argv[1], cmd->argv_lens[1]);
2237 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2238 conn->cmd_ident, NULL,
2239 silc_client_command_getkey,
2240 silc_client_command_dup(cmd));
2243 silc_free(nickname);
2247 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2249 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2252 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2253 1, idp->data, idp->len);
2254 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2255 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2256 silc_buffer_free(buffer);
2257 silc_buffer_free(idp);
2259 /* Notify application */
2263 silc_free(nickname);
2264 silc_client_command_free(cmd);