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 /* 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 */
368 silc_free(conn->nickname);
369 conn->nickname = strdup(cmd->argv[1]);
370 conn->local_entry->nickname = conn->nickname;
371 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
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;
999 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1004 /* See if we have joined to the requested channel already */
1005 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
1007 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
1008 if (channel->on_channel)
1012 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1014 if (cmd->argv_lens[1] > 256)
1015 cmd->argv_lens[1] = 256;
1017 /* Send JOIN command to the server */
1020 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
1021 1, cmd->argv[1], cmd->argv_lens[1],
1022 2, idp->data, idp->len);
1023 else if (cmd->argc == 3)
1026 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
1027 1, cmd->argv[1], cmd->argv_lens[1],
1028 2, idp->data, idp->len,
1029 3, cmd->argv[2], cmd->argv_lens[2]);
1032 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
1033 1, cmd->argv[1], cmd->argv_lens[1],
1034 2, idp->data, idp->len,
1035 3, cmd->argv[2], cmd->argv_lens[2],
1036 4, cmd->argv[3], cmd->argv_lens[3]);
1038 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1039 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1040 silc_buffer_free(buffer);
1041 silc_buffer_free(idp);
1043 /* Notify application */
1047 silc_client_command_free(cmd);
1050 /* MOTD command. Requests motd from server. */
1052 SILC_CLIENT_CMD_FUNC(motd)
1054 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1055 SilcClientConnection conn = cmd->conn;
1059 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1064 if (cmd->argc < 1 || cmd->argc > 2) {
1065 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1066 "Usage: /MOTD [<server>]");
1071 /* Send TOPIC command to the server */
1073 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1074 1, conn->remote_host,
1075 strlen(conn->remote_host));
1077 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1080 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1081 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1082 silc_buffer_free(buffer);
1084 /* Notify application */
1088 silc_client_command_free(cmd);
1091 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1092 modes as client cannot set itself server/router operator privileges. */
1094 SILC_CLIENT_CMD_FUNC(umode)
1096 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1097 SilcClientConnection conn = cmd->conn;
1098 SilcBuffer buffer, idp;
1099 unsigned char *cp, modebuf[4];
1100 uint32 mode, add, len;
1104 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1109 if (cmd->argc < 2) {
1110 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1111 "Usage: /UMODE +|-<modes>");
1116 mode = conn->local_entry->mode;
1118 /* Are we adding or removing mode */
1119 if (cmd->argv[1][0] == '-')
1125 cp = cmd->argv[1] + 1;
1127 for (i = 0; i < len; i++) {
1132 mode |= SILC_UMODE_SERVER_OPERATOR;
1133 mode |= SILC_UMODE_ROUTER_OPERATOR;
1135 mode = SILC_UMODE_NONE;
1140 mode |= SILC_UMODE_SERVER_OPERATOR;
1142 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1146 mode |= SILC_UMODE_ROUTER_OPERATOR;
1148 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1152 mode |= SILC_UMODE_GONE;
1154 mode &= ~SILC_UMODE_GONE;
1163 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1164 SILC_PUT32_MSB(mode, modebuf);
1166 /* Send the command packet. We support sending only one mode at once
1167 that requires an argument. */
1169 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1170 1, idp->data, idp->len,
1171 2, modebuf, sizeof(modebuf));
1172 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1173 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1174 silc_buffer_free(buffer);
1175 silc_buffer_free(idp);
1177 /* Notify application */
1181 silc_client_command_free(cmd);
1184 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1185 can be set several at once. Those modes that require argument must be set
1186 separately (unless set with modes that does not require arguments). */
1188 SILC_CLIENT_CMD_FUNC(cmode)
1190 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1191 SilcClientConnection conn = cmd->conn;
1192 SilcChannelEntry channel;
1193 SilcBuffer buffer, chidp, auth = NULL;
1194 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1195 uint32 mode, add, type, len, arg_len = 0;
1199 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1204 if (cmd->argc < 3) {
1205 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1206 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1211 if (cmd->argv[1][0] == '*') {
1212 if (!conn->current_channel) {
1213 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1214 "You are not on any channel");
1219 channel = conn->current_channel;
1221 name = cmd->argv[1];
1223 channel = silc_client_get_channel(cmd->client, conn, name);
1225 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1226 "You are on that channel");
1232 mode = channel->mode;
1234 /* Are we adding or removing mode */
1235 if (cmd->argv[2][0] == '-')
1240 /* Argument type to be sent to server */
1244 cp = cmd->argv[2] + 1;
1246 for (i = 0; i < len; i++) {
1250 mode |= SILC_CHANNEL_MODE_PRIVATE;
1252 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1256 mode |= SILC_CHANNEL_MODE_SECRET;
1258 mode &= ~SILC_CHANNEL_MODE_SECRET;
1262 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1264 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1268 mode |= SILC_CHANNEL_MODE_INVITE;
1270 mode &= ~SILC_CHANNEL_MODE_INVITE;
1274 mode |= SILC_CHANNEL_MODE_TOPIC;
1276 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1281 mode |= SILC_CHANNEL_MODE_ULIMIT;
1283 if (cmd->argc < 4) {
1284 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1285 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1289 ll = atoi(cmd->argv[3]);
1290 SILC_PUT32_MSB(ll, tmp);
1294 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1299 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1301 if (cmd->argc < 4) {
1302 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1303 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1308 arg_len = cmd->argv_lens[3];
1310 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1315 mode |= SILC_CHANNEL_MODE_CIPHER;
1317 if (cmd->argc < 4) {
1318 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1319 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1324 arg_len = cmd->argv_lens[3];
1326 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1331 mode |= SILC_CHANNEL_MODE_HMAC;
1333 if (cmd->argc < 4) {
1334 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1335 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1340 arg_len = cmd->argv_lens[3];
1342 mode &= ~SILC_CHANNEL_MODE_HMAC;
1347 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1350 if (cmd->argc < 4) {
1351 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1352 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1357 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1358 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1359 cmd->client->private_key,
1364 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1365 cmd->argv[3], cmd->argv_lens[3]);
1369 arg_len = auth->len;
1371 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1381 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1382 SILC_PUT32_MSB(mode, modebuf);
1384 /* Send the command packet. We support sending only one mode at once
1385 that requires an argument. */
1388 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1389 1, chidp->data, chidp->len,
1390 2, modebuf, sizeof(modebuf),
1391 type, arg, arg_len);
1394 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1395 1, chidp->data, chidp->len,
1396 2, modebuf, sizeof(modebuf));
1399 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1400 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1401 silc_buffer_free(buffer);
1402 silc_buffer_free(chidp);
1404 silc_buffer_free(auth);
1406 /* Notify application */
1410 silc_client_command_free(cmd);
1413 /* CUMODE command. Changes client's mode on a channel. */
1415 SILC_CLIENT_CMD_FUNC(cumode)
1417 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1418 SilcClient client = cmd->client;
1419 SilcClientConnection conn = cmd->conn;
1420 SilcChannelEntry channel;
1421 SilcChannelUser chu;
1422 SilcClientEntry client_entry;
1423 SilcBuffer buffer, clidp, chidp, auth = NULL;
1424 unsigned char *name, *cp, modebuf[4];
1425 uint32 mode = 0, add, len;
1426 char *nickname = NULL;
1430 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1435 if (cmd->argc < 4) {
1436 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1437 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1442 if (cmd->argv[1][0] == '*') {
1443 if (!conn->current_channel) {
1444 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1445 "You are not on any channel");
1450 channel = conn->current_channel;
1452 name = cmd->argv[1];
1454 channel = silc_client_get_channel(cmd->client, conn, name);
1456 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1457 "You are on that channel");
1463 /* Parse the typed nickname. */
1464 if (client->params->nickname_parse)
1465 client->params->nickname_parse(cmd->argv[3], &nickname);
1467 nickname = strdup(cmd->argv[3]);
1469 /* Find client entry */
1470 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1471 cmd->argv[3], TRUE);
1472 if (!client_entry) {
1478 silc_free(nickname);
1480 /* Client entry not found, it was requested thus mark this to be
1482 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1484 silc_client_command_destructor,
1485 silc_client_command_cumode,
1486 silc_client_command_dup(cmd));
1491 /* Get the current mode */
1492 silc_list_start(channel->clients);
1493 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1494 if (chu->client == client_entry) {
1500 /* Are we adding or removing mode */
1501 if (cmd->argv[2][0] == '-')
1507 cp = cmd->argv[2] + 1;
1509 for (i = 0; i < len; i++) {
1513 mode |= SILC_CHANNEL_UMODE_CHANFO;
1514 mode |= SILC_CHANNEL_UMODE_CHANOP;
1516 mode = SILC_CHANNEL_UMODE_NONE;
1521 if (cmd->argc == 5) {
1522 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1523 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1524 cmd->client->private_key,
1529 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1530 cmd->argv[4], cmd->argv_lens[4]);
1533 mode |= SILC_CHANNEL_UMODE_CHANFO;
1535 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1540 mode |= SILC_CHANNEL_UMODE_CHANOP;
1542 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1551 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1552 SILC_PUT32_MSB(mode, modebuf);
1553 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1555 /* Send the command packet. We support sending only one mode at once
1556 that requires an argument. */
1557 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1559 1, chidp->data, chidp->len,
1561 3, clidp->data, clidp->len,
1562 4, auth ? auth->data : NULL,
1563 auth ? auth->len : 0);
1565 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1566 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1567 silc_buffer_free(buffer);
1568 silc_buffer_free(chidp);
1569 silc_buffer_free(clidp);
1571 silc_buffer_free(auth);
1573 /* Notify application */
1577 silc_free(nickname);
1578 silc_client_command_free(cmd);
1581 /* KICK command. Kicks a client out of channel. */
1583 SILC_CLIENT_CMD_FUNC(kick)
1585 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1586 SilcClient client = cmd->client;
1587 SilcClientConnection conn = cmd->conn;
1588 SilcIDCacheEntry id_cache = NULL;
1589 SilcChannelEntry channel;
1590 SilcBuffer buffer, idp, idp2;
1591 SilcClientEntry target;
1593 char *nickname = NULL;
1596 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1601 if (cmd->argc < 3) {
1602 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1603 "Usage: /KICK <channel> <nickname> [<comment>]");
1608 if (cmd->argv[1][0] == '*') {
1609 if (!conn->current_channel) {
1610 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1611 "You are not on any channel");
1615 name = conn->current_channel->channel_name;
1617 name = cmd->argv[1];
1620 if (!conn->current_channel) {
1621 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1622 "You are not on that channel");
1627 /* Get the Channel ID of the channel */
1628 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1629 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1630 "You are not on that channel");
1635 channel = (SilcChannelEntry)id_cache->context;
1637 /* Parse the typed nickname. */
1638 if (client->params->nickname_parse)
1639 client->params->nickname_parse(cmd->argv[2], &nickname);
1641 nickname = strdup(cmd->argv[2]);
1643 /* Get the target client */
1644 target = silc_idlist_get_client(cmd->client, conn, nickname,
1645 cmd->argv[2], FALSE);
1647 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1648 "No such client: %s",
1654 /* Send KICK command to the server */
1655 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1656 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1658 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1659 1, idp->data, idp->len,
1660 2, idp2->data, idp2->len);
1662 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1663 1, idp->data, idp->len,
1664 2, idp2->data, idp2->len,
1666 strlen(cmd->argv[3]));
1667 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1668 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1669 silc_buffer_free(buffer);
1670 silc_buffer_free(idp);
1671 silc_buffer_free(idp2);
1673 /* Notify application */
1677 silc_free(nickname);
1678 silc_client_command_free(cmd);
1681 static void silc_client_command_oper_send(unsigned char *data,
1682 uint32 data_len, void *context)
1684 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1685 SilcClientConnection conn = cmd->conn;
1686 SilcBuffer buffer, auth;
1688 if (cmd->argc >= 3) {
1689 /* Encode the public key authentication payload */
1690 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1691 cmd->client->private_key,
1696 /* Encode the password authentication payload */
1697 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1701 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1703 strlen(cmd->argv[1]),
1704 2, auth->data, auth->len);
1705 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1706 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1708 silc_buffer_free(buffer);
1709 silc_buffer_free(auth);
1711 /* Notify application */
1715 /* OPER command. Used to obtain server operator privileges. */
1717 SILC_CLIENT_CMD_FUNC(oper)
1719 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1720 SilcClientConnection conn = cmd->conn;
1723 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1728 if (cmd->argc < 2) {
1729 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1730 "Usage: /OPER <username> [-pubkey]");
1735 if (cmd->argc < 3) {
1736 /* Get passphrase */
1737 cmd->client->ops->ask_passphrase(cmd->client, conn,
1738 silc_client_command_oper_send,
1743 silc_client_command_oper_send(NULL, 0, context);
1746 silc_client_command_free(cmd);
1749 static void silc_client_command_silcoper_send(unsigned char *data,
1750 uint32 data_len, void *context)
1752 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1753 SilcClientConnection conn = cmd->conn;
1754 SilcBuffer buffer, auth;
1756 if (cmd->argc >= 3) {
1757 /* Encode the public key authentication payload */
1758 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1759 cmd->client->private_key,
1764 /* Encode the password authentication payload */
1765 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1769 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1771 strlen(cmd->argv[1]),
1772 2, auth->data, auth->len);
1773 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1774 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1776 silc_buffer_free(buffer);
1777 silc_buffer_free(auth);
1779 /* Notify application */
1783 /* SILCOPER command. Used to obtain router operator privileges. */
1785 SILC_CLIENT_CMD_FUNC(silcoper)
1787 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1788 SilcClientConnection conn = cmd->conn;
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: /SILCOPER <username> [-pubkey]");
1803 if (cmd->argc < 3) {
1804 /* Get passphrase */
1805 cmd->client->ops->ask_passphrase(cmd->client, conn,
1806 silc_client_command_silcoper_send,
1811 silc_client_command_silcoper_send(NULL, 0, context);
1814 silc_client_command_free(cmd);
1817 /* CONNECT command. Connects the server to another server. */
1819 SILC_CLIENT_CMD_FUNC(connect)
1821 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1822 SilcClientConnection conn = cmd->conn;
1824 unsigned char port[4];
1828 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1833 if (cmd->argc < 2) {
1834 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1835 "Usage: /CONNECT <server> [<port>]");
1840 if (cmd->argc == 3) {
1841 tmp = atoi(cmd->argv[2]);
1842 SILC_PUT32_MSB(tmp, port);
1846 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1848 strlen(cmd->argv[1]),
1851 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1853 strlen(cmd->argv[1]));
1854 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1855 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1856 silc_buffer_free(buffer);
1858 /* Notify application */
1862 silc_client_command_free(cmd);
1865 /* Command BAN. This is used to manage the ban list of the channel. */
1867 SILC_CLIENT_CMD_FUNC(ban)
1869 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1870 SilcClientConnection conn = cmd->conn;
1871 SilcChannelEntry channel;
1872 SilcBuffer buffer, chidp;
1874 char *name, *ban = NULL;
1877 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1882 if (cmd->argc < 2) {
1883 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1884 "Usage: /BAN <channel> "
1885 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1890 if (cmd->argv[1][0] == '*') {
1891 if (!conn->current_channel) {
1892 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1893 "You are not on any channel");
1898 channel = conn->current_channel;
1900 name = cmd->argv[1];
1902 channel = silc_client_get_channel(cmd->client, conn, name);
1904 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1905 "You are on that channel");
1911 if (cmd->argc == 3) {
1912 if (cmd->argv[2][0] == '+')
1921 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1923 /* Send the command */
1925 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1926 1, chidp->data, chidp->len,
1927 type, ban, strlen(ban));
1929 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1930 1, chidp->data, chidp->len);
1932 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1933 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1934 silc_buffer_free(buffer);
1935 silc_buffer_free(chidp);
1937 /* Notify application */
1941 silc_client_command_free(cmd);
1944 /* CLOSE command. Close server connection to the remote server */
1946 SILC_CLIENT_CMD_FUNC(close)
1948 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1949 SilcClientConnection conn = cmd->conn;
1951 unsigned char port[4];
1955 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1960 if (cmd->argc < 2) {
1961 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1962 "Usage: /CLOSE <server> [<port>]");
1967 if (cmd->argc == 3) {
1968 tmp = atoi(cmd->argv[2]);
1969 SILC_PUT32_MSB(tmp, port);
1973 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1975 strlen(cmd->argv[1]),
1978 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1980 strlen(cmd->argv[1]));
1981 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1982 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1983 silc_buffer_free(buffer);
1985 /* Notify application */
1989 silc_client_command_free(cmd);
1992 /* SHUTDOWN command. Shutdowns the server. */
1994 SILC_CLIENT_CMD_FUNC(shutdown)
1996 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1999 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2004 /* Send the command */
2005 silc_client_send_command(cmd->client, cmd->conn,
2006 SILC_COMMAND_SHUTDOWN, 0, 0);
2008 /* Notify application */
2012 silc_client_command_free(cmd);
2015 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2017 SILC_CLIENT_CMD_FUNC(leave)
2019 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2020 SilcClientConnection conn = cmd->conn;
2021 SilcIDCacheEntry id_cache = NULL;
2022 SilcChannelEntry channel;
2023 SilcBuffer buffer, idp;
2027 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2032 if (cmd->argc != 2) {
2033 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2034 "Usage: /LEAVE <channel>");
2039 if (cmd->argv[1][0] == '*') {
2040 if (!conn->current_channel) {
2041 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2042 "You are not on any channel");
2046 name = conn->current_channel->channel_name;
2048 name = cmd->argv[1];
2051 /* Get the Channel ID of the channel */
2052 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2053 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2054 "You are not on that channel");
2059 channel = (SilcChannelEntry)id_cache->context;
2060 channel->on_channel = FALSE;
2062 /* Send LEAVE command to the server */
2063 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2064 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2065 1, idp->data, idp->len);
2066 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2067 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2068 silc_buffer_free(buffer);
2069 silc_buffer_free(idp);
2071 /* Notify application */
2074 if (conn->current_channel == channel)
2075 conn->current_channel = NULL;
2077 silc_client_del_channel(cmd->client, cmd->conn, channel);
2080 silc_client_command_free(cmd);
2083 /* Command USERS. Requests the USERS of the clients joined on requested
2086 SILC_CLIENT_CMD_FUNC(users)
2088 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2089 SilcClientConnection conn = cmd->conn;
2094 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2099 if (cmd->argc != 2) {
2100 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2101 "Usage: /USERS <channel>");
2106 if (cmd->argv[1][0] == '*') {
2107 if (!conn->current_channel) {
2108 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2109 "You are not on any channel");
2113 name = conn->current_channel->channel_name;
2115 name = cmd->argv[1];
2118 /* Send USERS command to the server */
2119 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2120 ++conn->cmd_ident, 1,
2121 2, name, strlen(name));
2122 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2123 NULL, 0, NULL, NULL, buffer->data,
2125 silc_buffer_free(buffer);
2127 /* Notify application */
2131 silc_client_command_free(cmd);
2134 /* Command GETKEY. Used to fetch remote client's public key. */
2136 SILC_CLIENT_CMD_FUNC(getkey)
2138 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2139 SilcClientConnection conn = cmd->conn;
2140 SilcClient client = cmd->client;
2141 SilcClientEntry client_entry = NULL;
2142 SilcServerEntry server_entry = NULL;
2143 char *nickname = NULL;
2144 SilcBuffer idp, buffer;
2147 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2152 if (cmd->argc < 2) {
2153 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2154 "Usage: /GETKEY <nickname or server name>");
2160 SilcClientCommandReplyContext reply =
2161 (SilcClientCommandReplyContext)context2;
2162 SilcCommandStatus status;
2163 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2164 SILC_GET16_MSB(status, tmp);
2166 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2167 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2168 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2170 silc_client_command_status_message(status));
2176 /* Parse the typed nickname. */
2177 if (client->params->nickname_parse)
2178 client->params->nickname_parse(cmd->argv[1], &nickname);
2180 nickname = strdup(cmd->argv[1]);
2182 /* Find client entry */
2183 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2185 if (!client_entry) {
2186 /* Check whether user requested server actually */
2187 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2189 if (!server_entry) {
2195 /* No. what ever user wants we don't have it, so resolve it. We
2196 will try to resolve both client and server, one of them is
2197 bound to be wrong. */
2199 /* This will send the IDENTIFY command */
2200 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2201 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2203 silc_client_command_destructor,
2204 silc_client_command_getkey,
2205 silc_client_command_dup(cmd));
2207 /* This sends the IDENTIFY command to resolve the server. */
2208 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2209 ++conn->cmd_ident, 1,
2210 2, cmd->argv[1], cmd->argv_lens[1]);
2211 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2212 conn->cmd_ident, NULL,
2213 silc_client_command_getkey,
2214 silc_client_command_dup(cmd));
2217 silc_free(nickname);
2221 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2223 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2226 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2227 1, idp->data, idp->len);
2228 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2229 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2230 silc_buffer_free(buffer);
2231 silc_buffer_free(idp);
2233 /* Notify application */
2237 silc_free(nickname);
2238 silc_client_command_free(cmd);