5 Author: Pekka Riikonen <priikone@silcnet.org>
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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "clientlibincludes.h"
22 #include "client_internal.h"
24 #define SILC_NOT_CONNECTED(x, c) \
25 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
26 "You are not connected to a server, use /SERVER to connect");
28 /* Command operation that is called at the end of all commands.
30 #define COMMAND cmd->client->internal->ops->command(cmd->client, cmd->conn, \
31 cmd, TRUE, cmd->command->cmd)
33 /* Error to application. Usage: COMMAND_ERROR; */
34 #define COMMAND_ERROR cmd->client->internal->ops->command(cmd->client, \
35 cmd->conn, cmd, FALSE, cmd->command->cmd)
37 /* Generic function to send any command. The arguments must be sent already
38 encoded into correct form and in correct order. */
40 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
41 SilcCommand command, uint16 ident,
49 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
50 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
51 NULL, 0, NULL, NULL, packet->data,
53 silc_buffer_free(packet);
56 /* Finds and returns a pointer to the command list. Return NULL if the
57 command is not found. */
59 SilcClientCommand silc_client_command_find(SilcClient client,
62 SilcClientCommand cmd;
64 silc_list_start(client->internal->commands);
65 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
66 if (cmd->name && !strcmp(cmd->name, name))
73 /* Calls the command (executes it). Application can call this after
74 it has allocated the SilcClientCommandContext with the function
75 silc_client_command_alloc and found the command from the client
76 library by calling silc_client_command_find. This will execute
79 void silc_client_command_call(SilcClientCommand command,
80 SilcClientCommandContext cmd)
82 (*command->command)((void *)cmd, NULL);
85 /* Add new pending command to be executed when reply to a command has been
86 received. The `reply_cmd' is the command that will call the `callback'
87 with `context' when reply has been received. If `ident is non-zero
88 the `callback' will be executed when received reply with command
89 identifier `ident'. */
91 void silc_client_command_pending(SilcClientConnection conn,
92 SilcCommand reply_cmd,
94 SilcClientPendingDestructor destructor,
95 SilcCommandCb callback,
98 SilcClientCommandPending *reply;
100 reply = silc_calloc(1, sizeof(*reply));
101 reply->reply_cmd = reply_cmd;
102 reply->ident = ident;
103 reply->context = context;
104 reply->callback = callback;
105 reply->destructor = destructor;
106 silc_dlist_add(conn->pending_commands, reply);
109 /* Deletes pending command by reply command type. */
111 void silc_client_command_pending_del(SilcClientConnection conn,
112 SilcCommand reply_cmd,
115 SilcClientCommandPending *r;
117 silc_dlist_start(conn->pending_commands);
118 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
119 if (r->reply_cmd == reply_cmd && r->ident == ident) {
120 silc_dlist_del(conn->pending_commands, r);
126 /* Checks for pending commands and marks callbacks to be called from
127 the command reply function. Returns TRUE if there were pending command. */
129 int silc_client_command_pending_check(SilcClientConnection conn,
130 SilcClientCommandReplyContext ctx,
134 SilcClientCommandPending *r;
136 silc_dlist_start(conn->pending_commands);
137 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
138 if (r->reply_cmd == command && r->ident == ident) {
139 ctx->context = r->context;
140 ctx->callback = r->callback;
141 ctx->destructor = r->destructor;
150 /* Allocate Command Context */
152 SilcClientCommandContext silc_client_command_alloc(void)
154 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
159 /* Free command context and its internals */
161 void silc_client_command_free(SilcClientCommandContext ctx)
164 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
166 if (ctx->users < 1) {
169 for (i = 0; i < ctx->argc; i++)
170 silc_free(ctx->argv[i]);
171 silc_free(ctx->argv_lens);
172 silc_free(ctx->argv_types);
177 /* Duplicate Command Context by adding reference counter. The context won't
178 be free'd untill it hits zero. */
180 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
183 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
188 /* Pending command destructor. */
190 static void silc_client_command_destructor(void *context)
192 silc_client_command_free((SilcClientCommandContext)context);
195 /* Command WHOIS. This command is used to query information about
198 SILC_CLIENT_CMD_FUNC(whois)
200 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
201 SilcClientConnection conn = cmd->conn;
205 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
210 /* Given without arguments fetches client's own information */
212 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
213 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
215 1, 3, buffer->data, buffer->len);
216 silc_buffer_free(buffer);
220 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
221 cmd->argc - 1, ++cmd->argv,
222 ++cmd->argv_lens, ++cmd->argv_types,
224 silc_client_packet_send(cmd->client, cmd->conn->sock,
225 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
226 buffer->data, buffer->len, TRUE);
227 silc_buffer_free(buffer);
232 /* Notify application */
236 silc_client_command_free(cmd);
239 /* Command WHOWAS. This command is used to query history information about
240 specific user that used to exist in the network. */
242 SILC_CLIENT_CMD_FUNC(whowas)
244 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
245 SilcClientConnection conn = cmd->conn;
249 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
254 if (cmd->argc < 2 || cmd->argc > 3) {
255 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
256 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
261 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
262 cmd->argc - 1, ++cmd->argv,
263 ++cmd->argv_lens, ++cmd->argv_types,
265 silc_client_packet_send(cmd->client, cmd->conn->sock,
266 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
267 buffer->data, buffer->len, TRUE);
268 silc_buffer_free(buffer);
273 /* Notify application */
277 silc_client_command_free(cmd);
280 /* Command IDENTIFY. This command is used to query information about
281 specific user, especially ID's.
283 NOTE: This command is used only internally by the client library
284 and application MUST NOT call this command directly. */
286 SILC_CLIENT_CMD_FUNC(identify)
288 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
289 SilcClientConnection conn = cmd->conn;
293 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
297 if (cmd->argc < 2 || cmd->argc > 3)
301 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
302 ++conn->cmd_ident, 1,
306 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
307 ++conn->cmd_ident, 2,
313 silc_client_packet_send(cmd->client, cmd->conn->sock,
314 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
315 buffer->data, buffer->len, TRUE);
316 silc_buffer_free(buffer);
319 silc_client_command_free(cmd);
322 /* Pending callbcak that will be called after the NICK command was
323 replied by the server. This sets the nickname if there were no
326 SILC_CLIENT_CMD_FUNC(nick_change)
328 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
329 SilcClientConnection conn = cmd->conn;
330 SilcClientCommandReplyContext reply =
331 (SilcClientCommandReplyContext)context2;
332 SilcCommandStatus status;
334 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
335 if (status == SILC_STATUS_OK) {
336 /* Set the nickname */
337 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
339 silc_free(conn->nickname);
340 conn->nickname = strdup(cmd->argv[1]);
341 conn->local_entry->nickname = conn->nickname;
342 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
343 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
344 conn->local_entry->id, conn->local_entry, 0, NULL);
350 silc_client_command_free(cmd);
353 /* Command NICK. Shows current nickname/sets new nickname on current
356 SILC_CLIENT_CMD_FUNC(nick)
358 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
359 SilcClientConnection conn = cmd->conn;
363 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
369 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
370 "Usage: /NICK <nickname>");
375 if (!strcmp(conn->nickname, cmd->argv[1]))
378 /* Show current nickname */
381 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
382 "Your nickname is %s on server %s",
383 conn->nickname, conn->remote_host);
385 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
386 "Your nickname is %s", conn->nickname);
393 if (cmd->argv_lens[1] > 128)
394 cmd->argv_lens[1] = 128;
396 /* Send the NICK command */
397 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
401 ++cmd->conn->cmd_ident);
402 silc_client_packet_send(cmd->client, cmd->conn->sock,
403 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
404 buffer->data, buffer->len, TRUE);
405 silc_buffer_free(buffer);
407 /* Register pending callback that will actually set the new nickname
408 if there were no errors returned by the server. */
409 silc_client_command_pending(conn, SILC_COMMAND_NICK,
410 cmd->conn->cmd_ident,
411 silc_client_command_destructor,
412 silc_client_command_nick_change,
413 silc_client_command_dup(cmd));
418 silc_client_command_free(cmd);
421 /* Command LIST. Lists channels on the current server. */
423 SILC_CLIENT_CMD_FUNC(list)
425 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
426 SilcClientConnection conn = cmd->conn;
427 SilcIDCacheEntry id_cache = NULL;
428 SilcChannelEntry channel;
429 SilcBuffer buffer, idp = NULL;
433 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
438 if (cmd->argc == 2) {
441 /* Get the Channel ID of the channel */
442 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
443 channel = (SilcChannelEntry)id_cache->context;
444 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
449 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
450 ++conn->cmd_ident, 0);
452 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
453 ++conn->cmd_ident, 1,
454 1, idp->data, idp->len);
456 silc_client_packet_send(cmd->client, cmd->conn->sock,
457 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
458 buffer->data, buffer->len, TRUE);
459 silc_buffer_free(buffer);
461 silc_buffer_free(idp);
463 /* Notify application */
467 silc_client_command_free(cmd);
470 /* Command TOPIC. Sets/shows topic on a channel. */
472 SILC_CLIENT_CMD_FUNC(topic)
474 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
475 SilcClientConnection conn = cmd->conn;
476 SilcIDCacheEntry id_cache = NULL;
477 SilcChannelEntry channel;
478 SilcBuffer buffer, idp;
482 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
487 if (cmd->argc < 2 || cmd->argc > 3) {
488 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
489 "Usage: /TOPIC <channel> [<topic>]");
494 if (cmd->argv[1][0] == '*') {
495 if (!conn->current_channel) {
496 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
497 "You are not on any channel");
501 name = conn->current_channel->channel_name;
506 if (!conn->current_channel) {
507 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
508 "You are not on that channel");
513 /* Get the Channel ID of the channel */
514 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
515 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
516 "You are not on that channel");
521 channel = (SilcChannelEntry)id_cache->context;
523 /* Send TOPIC command to the server */
524 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
526 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
527 ++conn->cmd_ident, 2,
528 1, idp->data, idp->len,
530 strlen(cmd->argv[2]));
532 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
533 ++conn->cmd_ident, 1,
534 1, idp->data, idp->len);
535 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
536 0, NULL, NULL, buffer->data, buffer->len, TRUE);
537 silc_buffer_free(buffer);
538 silc_buffer_free(idp);
540 /* Notify application */
544 silc_client_command_free(cmd);
547 /* Command INVITE. Invites specific client to join a channel. This is
548 also used to mange the invite list of the channel. */
550 SILC_CLIENT_CMD_FUNC(invite)
552 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
553 SilcClient client = cmd->client;
554 SilcClientConnection conn = cmd->conn;
555 SilcClientEntry client_entry = NULL;
556 SilcChannelEntry channel;
557 SilcBuffer buffer, clidp, chidp;
559 char *nickname = NULL, *name;
563 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
569 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
570 "Usage: /INVITE <channel> [<nickname>[@server>]"
571 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
576 if (cmd->argv[1][0] == '*') {
577 if (!conn->current_channel) {
578 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
579 "You are not on any channel");
584 channel = conn->current_channel;
588 channel = silc_client_get_channel(cmd->client, conn, name);
590 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
591 "You are on that channel");
597 /* Parse the typed nickname. */
598 if (cmd->argc == 3) {
599 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
600 if (client->internal->params->nickname_parse)
601 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
603 nickname = strdup(cmd->argv[2]);
605 /* Find client entry */
606 client_entry = silc_idlist_get_client(client, conn, nickname,
615 /* Client entry not found, it was requested thus mark this to be
617 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
619 silc_client_command_destructor,
620 silc_client_command_invite,
621 silc_client_command_dup(cmd));
626 invite = cmd->argv[2];
628 if (cmd->argv[2][0] == '+')
635 /* Send the command */
636 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
638 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
639 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
640 ++conn->cmd_ident, 3,
641 1, chidp->data, chidp->len,
642 2, clidp->data, clidp->len,
643 type, invite, invite ?
645 silc_buffer_free(clidp);
647 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
648 ++conn->cmd_ident, 2,
649 1, chidp->data, chidp->len,
650 type, invite, invite ?
654 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
655 0, NULL, NULL, buffer->data, buffer->len, TRUE);
656 silc_buffer_free(buffer);
657 silc_buffer_free(chidp);
659 /* Notify application */
664 silc_client_command_free(cmd);
669 SilcClientConnection conn;
672 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
674 QuitInternal q = (QuitInternal)context;
676 /* Close connection */
677 q->client->internal->ops->disconnect(q->client, q->conn);
678 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
683 /* Command QUIT. Closes connection with current server. */
685 SILC_CLIENT_CMD_FUNC(quit)
687 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
692 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
698 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
699 &cmd->argv[1], &cmd->argv_lens[1],
700 &cmd->argv_types[1], 0);
702 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
703 NULL, NULL, NULL, 0);
704 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
706 buffer->data, buffer->len, TRUE);
707 silc_buffer_free(buffer);
709 q = silc_calloc(1, sizeof(*q));
710 q->client = cmd->client;
713 /* Sleep for a while */
716 /* We quit the connection with little timeout */
717 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
718 silc_client_command_quit_cb, (void *)q,
719 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
721 /* Notify application */
725 silc_client_command_free(cmd);
728 /* Timeout callback to remove the killed client from cache */
730 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
732 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
733 SilcClient client = cmd->client;
734 SilcClientConnection conn = cmd->conn;
735 SilcClientEntry target;
736 char *nickname = NULL;
738 /* Parse the typed nickname. */
739 if (client->internal->params->nickname_parse)
740 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
742 nickname = strdup(cmd->argv[1]);
744 /* Get the target client */
745 target = silc_idlist_get_client(cmd->client, conn, nickname,
746 cmd->argv[1], FALSE);
748 silc_client_remove_from_channels(client, conn, target);
749 silc_client_del_client(client, conn, target);
753 silc_client_command_free(cmd);
756 /* Kill command's pending command callback to actually remove the killed
757 client from our local cache. */
759 SILC_CLIENT_CMD_FUNC(kill_remove)
761 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
762 SilcClientCommandReplyContext reply =
763 (SilcClientCommandReplyContext)context2;
764 SilcCommandStatus status;
766 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
767 if (status == SILC_STATUS_OK) {
768 /* Remove with timeout */
769 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
770 silc_client_command_kill_remove_later, context,
771 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
775 silc_client_command_free(cmd);
778 /* Command KILL. Router operator can use this command to remove an client
779 fromthe SILC Network. */
781 SILC_CLIENT_CMD_FUNC(kill)
783 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
784 SilcClient client = cmd->client;
785 SilcClientConnection conn = cmd->conn;
786 SilcBuffer buffer, idp;
787 SilcClientEntry target;
788 char *nickname = NULL;
791 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
797 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
798 "Usage: /KILL <nickname> [<comment>]");
803 /* Parse the typed nickname. */
804 if (client->internal->params->nickname_parse)
805 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
807 nickname = strdup(cmd->argv[1]);
809 /* Get the target client */
810 target = silc_idlist_get_client(cmd->client, conn, nickname,
820 /* Client entry not found, it was requested thus mark this to be
822 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
824 silc_client_command_destructor,
825 silc_client_command_kill,
826 silc_client_command_dup(cmd));
831 /* Send the KILL command to the server */
832 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
834 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
835 ++conn->cmd_ident, 1,
836 1, idp->data, idp->len);
838 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
839 ++conn->cmd_ident, 2,
840 1, idp->data, idp->len,
842 strlen(cmd->argv[2]));
843 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
844 0, NULL, NULL, buffer->data, buffer->len, TRUE);
845 silc_buffer_free(buffer);
846 silc_buffer_free(idp);
848 /* Notify application */
851 /* Register a pending callback that will actually remove the killed
852 client from our cache. */
853 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
854 NULL, silc_client_command_kill_remove,
855 silc_client_command_dup(cmd));
859 silc_client_command_free(cmd);
862 /* Command INFO. Request information about specific server. If specific
863 server is not provided the current server is used. */
865 SILC_CLIENT_CMD_FUNC(info)
867 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
868 SilcClientConnection conn = cmd->conn;
873 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
879 name = strdup(cmd->argv[1]);
881 /* Send the command */
883 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
884 1, name, strlen(name));
886 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
887 NULL, NULL, NULL, 0);
888 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
889 0, NULL, NULL, buffer->data, buffer->len, TRUE);
890 silc_buffer_free(buffer);
894 /* Notify application */
898 silc_client_command_free(cmd);
901 /* Command PING. Sends ping to server. This is used to test the
902 communication channel. */
904 SILC_CLIENT_CMD_FUNC(ping)
906 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
907 SilcClientConnection conn = cmd->conn;
913 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
918 /* Send the command */
919 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
920 1, conn->remote_id_data,
921 silc_id_get_len(conn->remote_id,
923 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
924 0, NULL, NULL, buffer->data, buffer->len, TRUE);
925 silc_buffer_free(buffer);
927 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
930 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
935 /* Start counting time */
936 for (i = 0; i < conn->ping_count; i++) {
937 if (conn->ping[i].dest_id == NULL) {
938 conn->ping[i].start_time = time(NULL);
939 conn->ping[i].dest_id = id;
940 conn->ping[i].dest_name = strdup(conn->remote_host);
944 if (i >= conn->ping_count) {
945 i = conn->ping_count;
946 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
947 conn->ping[i].start_time = time(NULL);
948 conn->ping[i].dest_id = id;
949 conn->ping[i].dest_name = strdup(conn->remote_host);
953 /* Notify application */
957 silc_client_command_free(cmd);
960 /* Command JOIN. Joins to a channel. */
962 SILC_CLIENT_CMD_FUNC(join)
964 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
965 SilcClientConnection conn = cmd->conn;
966 SilcIDCacheEntry id_cache = NULL;
967 SilcBuffer buffer, idp, auth = NULL;
968 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
972 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
982 /* See if we have joined to the requested channel already */
983 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
985 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
986 if (channel->on_channel)
990 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
992 if (cmd->argv_lens[1] > 256)
993 cmd->argv_lens[1] = 256;
997 for (i = 2; i < cmd->argc; i++) {
998 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc >= i + 1) {
999 cipher = cmd->argv[i + 1];
1001 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc >= i + 1) {
1002 hmac = cmd->argv[i + 1];
1004 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc >= i + 1) {
1005 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
1006 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1007 cmd->client->private_key,
1012 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1014 cmd->argv_lens[i + 1]);
1018 passphrase = cmd->argv[i];
1022 /* Send JOIN command to the server */
1024 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1025 1, name, strlen(name),
1026 2, idp->data, idp->len,
1028 passphrase ? strlen(passphrase) : 0,
1029 4, cipher, cipher ? strlen(cipher) : 0,
1030 5, hmac, hmac ? strlen(hmac) : 0,
1031 6, auth ? auth->data : NULL,
1032 auth ? auth->len : 0);
1033 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1034 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1035 silc_buffer_free(buffer);
1036 silc_buffer_free(idp);
1038 silc_buffer_free(auth);
1040 /* Notify application */
1044 silc_client_command_free(cmd);
1047 /* MOTD command. Requests motd from server. */
1049 SILC_CLIENT_CMD_FUNC(motd)
1051 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1052 SilcClientConnection conn = cmd->conn;
1056 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1061 if (cmd->argc < 1 || cmd->argc > 2) {
1062 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1063 "Usage: /MOTD [<server>]");
1068 /* Send TOPIC command to the server */
1070 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1071 1, conn->remote_host,
1072 strlen(conn->remote_host));
1074 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1077 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1078 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1079 silc_buffer_free(buffer);
1081 /* Notify application */
1085 silc_client_command_free(cmd);
1088 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1089 modes as client cannot set itself server/router operator privileges. */
1091 SILC_CLIENT_CMD_FUNC(umode)
1093 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1094 SilcClientConnection conn = cmd->conn;
1095 SilcBuffer buffer, idp;
1096 unsigned char *cp, modebuf[4];
1097 uint32 mode, add, len;
1101 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1106 if (cmd->argc < 2) {
1107 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1108 "Usage: /UMODE +|-<modes>");
1113 mode = conn->local_entry->mode;
1115 /* Are we adding or removing mode */
1116 if (cmd->argv[1][0] == '-')
1122 cp = cmd->argv[1] + 1;
1124 for (i = 0; i < len; i++) {
1129 mode |= SILC_UMODE_SERVER_OPERATOR;
1130 mode |= SILC_UMODE_ROUTER_OPERATOR;
1132 mode = SILC_UMODE_NONE;
1137 mode |= SILC_UMODE_SERVER_OPERATOR;
1139 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1143 mode |= SILC_UMODE_ROUTER_OPERATOR;
1145 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1149 mode |= SILC_UMODE_GONE;
1151 mode &= ~SILC_UMODE_GONE;
1160 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1161 SILC_PUT32_MSB(mode, modebuf);
1163 /* Send the command packet. We support sending only one mode at once
1164 that requires an argument. */
1166 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1167 1, idp->data, idp->len,
1168 2, modebuf, sizeof(modebuf));
1169 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1170 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1171 silc_buffer_free(buffer);
1172 silc_buffer_free(idp);
1174 /* Notify application */
1178 silc_client_command_free(cmd);
1181 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1182 can be set several at once. Those modes that require argument must be set
1183 separately (unless set with modes that does not require arguments). */
1185 SILC_CLIENT_CMD_FUNC(cmode)
1187 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1188 SilcClientConnection conn = cmd->conn;
1189 SilcChannelEntry channel;
1190 SilcBuffer buffer, chidp, auth = NULL;
1191 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1192 uint32 mode, add, type, len, arg_len = 0;
1196 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1201 if (cmd->argc < 3) {
1202 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1203 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1208 if (cmd->argv[1][0] == '*') {
1209 if (!conn->current_channel) {
1210 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1211 "You are not on any channel");
1216 channel = conn->current_channel;
1218 name = cmd->argv[1];
1220 channel = silc_client_get_channel(cmd->client, conn, name);
1222 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1223 "You are on that channel");
1229 mode = channel->mode;
1231 /* Are we adding or removing mode */
1232 if (cmd->argv[2][0] == '-')
1237 /* Argument type to be sent to server */
1241 cp = cmd->argv[2] + 1;
1243 for (i = 0; i < len; i++) {
1247 mode |= SILC_CHANNEL_MODE_PRIVATE;
1249 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1253 mode |= SILC_CHANNEL_MODE_SECRET;
1255 mode &= ~SILC_CHANNEL_MODE_SECRET;
1259 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1261 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1265 mode |= SILC_CHANNEL_MODE_INVITE;
1267 mode &= ~SILC_CHANNEL_MODE_INVITE;
1271 mode |= SILC_CHANNEL_MODE_TOPIC;
1273 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1278 mode |= SILC_CHANNEL_MODE_ULIMIT;
1280 if (cmd->argc < 4) {
1281 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1282 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1286 ll = atoi(cmd->argv[3]);
1287 SILC_PUT32_MSB(ll, tmp);
1291 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1296 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1298 if (cmd->argc < 4) {
1299 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1300 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1305 arg_len = cmd->argv_lens[3];
1307 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1312 mode |= SILC_CHANNEL_MODE_CIPHER;
1314 if (cmd->argc < 4) {
1315 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1316 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1321 arg_len = cmd->argv_lens[3];
1323 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1328 mode |= SILC_CHANNEL_MODE_HMAC;
1330 if (cmd->argc < 4) {
1331 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1332 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1337 arg_len = cmd->argv_lens[3];
1339 mode &= ~SILC_CHANNEL_MODE_HMAC;
1344 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1347 if (cmd->argc < 4) {
1348 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1349 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1354 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1355 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1356 cmd->client->private_key,
1361 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1362 cmd->argv[3], cmd->argv_lens[3]);
1366 arg_len = auth->len;
1368 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1378 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1379 SILC_PUT32_MSB(mode, modebuf);
1381 /* Send the command packet. We support sending only one mode at once
1382 that requires an argument. */
1385 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1386 1, chidp->data, chidp->len,
1387 2, modebuf, sizeof(modebuf),
1388 type, arg, arg_len);
1391 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1392 1, chidp->data, chidp->len,
1393 2, modebuf, sizeof(modebuf));
1396 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1397 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1398 silc_buffer_free(buffer);
1399 silc_buffer_free(chidp);
1401 silc_buffer_free(auth);
1403 /* Notify application */
1407 silc_client_command_free(cmd);
1410 /* CUMODE command. Changes client's mode on a channel. */
1412 SILC_CLIENT_CMD_FUNC(cumode)
1414 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1415 SilcClient client = cmd->client;
1416 SilcClientConnection conn = cmd->conn;
1417 SilcChannelEntry channel;
1418 SilcChannelUser chu;
1419 SilcClientEntry client_entry;
1420 SilcBuffer buffer, clidp, chidp, auth = NULL;
1421 unsigned char *name, *cp, modebuf[4];
1422 uint32 mode = 0, add, len;
1423 char *nickname = NULL;
1427 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1432 if (cmd->argc < 4) {
1433 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1434 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1439 if (cmd->argv[1][0] == '*') {
1440 if (!conn->current_channel) {
1441 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1442 "You are not on any channel");
1447 channel = conn->current_channel;
1449 name = cmd->argv[1];
1451 channel = silc_client_get_channel(cmd->client, conn, name);
1453 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1454 "You are on that channel");
1460 /* Parse the typed nickname. */
1461 if (client->internal->params->nickname_parse)
1462 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1464 nickname = strdup(cmd->argv[3]);
1466 /* Find client entry */
1467 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1468 cmd->argv[3], TRUE);
1469 if (!client_entry) {
1475 silc_free(nickname);
1477 /* Client entry not found, it was requested thus mark this to be
1479 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1481 silc_client_command_destructor,
1482 silc_client_command_cumode,
1483 silc_client_command_dup(cmd));
1488 /* Get the current mode */
1489 silc_list_start(channel->clients);
1490 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1491 if (chu->client == client_entry) {
1497 /* Are we adding or removing mode */
1498 if (cmd->argv[2][0] == '-')
1504 cp = cmd->argv[2] + 1;
1506 for (i = 0; i < len; i++) {
1510 mode |= SILC_CHANNEL_UMODE_CHANFO;
1511 mode |= SILC_CHANNEL_UMODE_CHANOP;
1513 mode = SILC_CHANNEL_UMODE_NONE;
1518 if (cmd->argc == 5) {
1519 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1520 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1521 cmd->client->private_key,
1526 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1527 cmd->argv[4], cmd->argv_lens[4]);
1530 mode |= SILC_CHANNEL_UMODE_CHANFO;
1532 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1537 mode |= SILC_CHANNEL_UMODE_CHANOP;
1539 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1548 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1549 SILC_PUT32_MSB(mode, modebuf);
1550 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1552 /* Send the command packet. We support sending only one mode at once
1553 that requires an argument. */
1554 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1556 1, chidp->data, chidp->len,
1558 3, clidp->data, clidp->len,
1559 4, auth ? auth->data : NULL,
1560 auth ? auth->len : 0);
1562 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1563 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1564 silc_buffer_free(buffer);
1565 silc_buffer_free(chidp);
1566 silc_buffer_free(clidp);
1568 silc_buffer_free(auth);
1570 /* Notify application */
1574 silc_free(nickname);
1575 silc_client_command_free(cmd);
1578 /* KICK command. Kicks a client out of channel. */
1580 SILC_CLIENT_CMD_FUNC(kick)
1582 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1583 SilcClient client = cmd->client;
1584 SilcClientConnection conn = cmd->conn;
1585 SilcIDCacheEntry id_cache = NULL;
1586 SilcChannelEntry channel;
1587 SilcBuffer buffer, idp, idp2;
1588 SilcClientEntry target;
1590 char *nickname = NULL;
1593 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1598 if (cmd->argc < 3) {
1599 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1600 "Usage: /KICK <channel> <nickname> [<comment>]");
1605 if (cmd->argv[1][0] == '*') {
1606 if (!conn->current_channel) {
1607 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1608 "You are not on any channel");
1612 name = conn->current_channel->channel_name;
1614 name = cmd->argv[1];
1617 if (!conn->current_channel) {
1618 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1619 "You are not on that channel");
1624 /* Get the Channel ID of the channel */
1625 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1626 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1627 "You are not on that channel");
1632 channel = (SilcChannelEntry)id_cache->context;
1634 /* Parse the typed nickname. */
1635 if (client->internal->params->nickname_parse)
1636 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1638 nickname = strdup(cmd->argv[2]);
1640 /* Get the target client */
1641 target = silc_idlist_get_client(cmd->client, conn, nickname,
1642 cmd->argv[2], FALSE);
1644 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1645 "No such client: %s",
1651 /* Send KICK command to the server */
1652 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1653 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1655 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1656 1, idp->data, idp->len,
1657 2, idp2->data, idp2->len);
1659 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1660 1, idp->data, idp->len,
1661 2, idp2->data, idp2->len,
1663 strlen(cmd->argv[3]));
1664 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1665 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1666 silc_buffer_free(buffer);
1667 silc_buffer_free(idp);
1668 silc_buffer_free(idp2);
1670 /* Notify application */
1674 silc_free(nickname);
1675 silc_client_command_free(cmd);
1678 static void silc_client_command_oper_send(unsigned char *data,
1679 uint32 data_len, void *context)
1681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1682 SilcClientConnection conn = cmd->conn;
1683 SilcBuffer buffer, auth;
1685 if (cmd->argc >= 3) {
1686 /* Encode the public key authentication payload */
1687 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1688 cmd->client->private_key,
1693 /* Encode the password authentication payload */
1694 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1698 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1700 strlen(cmd->argv[1]),
1701 2, auth->data, auth->len);
1702 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1703 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1705 silc_buffer_free(buffer);
1706 silc_buffer_free(auth);
1708 /* Notify application */
1712 /* OPER command. Used to obtain server operator privileges. */
1714 SILC_CLIENT_CMD_FUNC(oper)
1716 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1717 SilcClientConnection conn = cmd->conn;
1720 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1725 if (cmd->argc < 2) {
1726 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1727 "Usage: /OPER <username> [-pubkey]");
1732 if (cmd->argc < 3) {
1733 /* Get passphrase */
1734 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1735 silc_client_command_oper_send,
1740 silc_client_command_oper_send(NULL, 0, context);
1743 silc_client_command_free(cmd);
1746 static void silc_client_command_silcoper_send(unsigned char *data,
1747 uint32 data_len, void *context)
1749 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1750 SilcClientConnection conn = cmd->conn;
1751 SilcBuffer buffer, auth;
1753 if (cmd->argc >= 3) {
1754 /* Encode the public key authentication payload */
1755 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1756 cmd->client->private_key,
1761 /* Encode the password authentication payload */
1762 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1766 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1768 strlen(cmd->argv[1]),
1769 2, auth->data, auth->len);
1770 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1771 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1773 silc_buffer_free(buffer);
1774 silc_buffer_free(auth);
1776 /* Notify application */
1780 /* SILCOPER command. Used to obtain router operator privileges. */
1782 SILC_CLIENT_CMD_FUNC(silcoper)
1784 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1785 SilcClientConnection conn = cmd->conn;
1788 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1793 if (cmd->argc < 2) {
1794 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1795 "Usage: /SILCOPER <username> [-pubkey]");
1800 if (cmd->argc < 3) {
1801 /* Get passphrase */
1802 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1803 silc_client_command_silcoper_send,
1808 silc_client_command_silcoper_send(NULL, 0, context);
1811 silc_client_command_free(cmd);
1814 /* CONNECT command. Connects the server to another server. */
1816 SILC_CLIENT_CMD_FUNC(connect)
1818 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1819 SilcClientConnection conn = cmd->conn;
1821 unsigned char port[4];
1825 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1830 if (cmd->argc < 2) {
1831 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1832 "Usage: /CONNECT <server> [<port>]");
1837 if (cmd->argc == 3) {
1838 tmp = atoi(cmd->argv[2]);
1839 SILC_PUT32_MSB(tmp, port);
1843 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1845 strlen(cmd->argv[1]),
1848 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1850 strlen(cmd->argv[1]));
1851 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1852 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1853 silc_buffer_free(buffer);
1855 /* Notify application */
1859 silc_client_command_free(cmd);
1862 /* Command BAN. This is used to manage the ban list of the channel. */
1864 SILC_CLIENT_CMD_FUNC(ban)
1866 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1867 SilcClientConnection conn = cmd->conn;
1868 SilcChannelEntry channel;
1869 SilcBuffer buffer, chidp;
1871 char *name, *ban = NULL;
1874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1879 if (cmd->argc < 2) {
1880 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1881 "Usage: /BAN <channel> "
1882 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1887 if (cmd->argv[1][0] == '*') {
1888 if (!conn->current_channel) {
1889 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1890 "You are not on any channel");
1895 channel = conn->current_channel;
1897 name = cmd->argv[1];
1899 channel = silc_client_get_channel(cmd->client, conn, name);
1901 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1902 "You are on that channel");
1908 if (cmd->argc == 3) {
1909 if (cmd->argv[2][0] == '+')
1918 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1920 /* Send the command */
1922 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1923 1, chidp->data, chidp->len,
1924 type, ban, strlen(ban));
1926 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1927 1, chidp->data, chidp->len);
1929 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1930 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1931 silc_buffer_free(buffer);
1932 silc_buffer_free(chidp);
1934 /* Notify application */
1938 silc_client_command_free(cmd);
1941 /* CLOSE command. Close server connection to the remote server */
1943 SILC_CLIENT_CMD_FUNC(close)
1945 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1946 SilcClientConnection conn = cmd->conn;
1948 unsigned char port[4];
1952 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1957 if (cmd->argc < 2) {
1958 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1959 "Usage: /CLOSE <server> [<port>]");
1964 if (cmd->argc == 3) {
1965 tmp = atoi(cmd->argv[2]);
1966 SILC_PUT32_MSB(tmp, port);
1970 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1972 strlen(cmd->argv[1]),
1975 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1977 strlen(cmd->argv[1]));
1978 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1979 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1980 silc_buffer_free(buffer);
1982 /* Notify application */
1986 silc_client_command_free(cmd);
1989 /* SHUTDOWN command. Shutdowns the server. */
1991 SILC_CLIENT_CMD_FUNC(shutdown)
1993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1996 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2001 /* Send the command */
2002 silc_client_command_send(cmd->client, cmd->conn,
2003 SILC_COMMAND_SHUTDOWN, 0, 0);
2005 /* Notify application */
2009 silc_client_command_free(cmd);
2012 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2014 SILC_CLIENT_CMD_FUNC(leave)
2016 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2017 SilcClientConnection conn = cmd->conn;
2018 SilcIDCacheEntry id_cache = NULL;
2019 SilcChannelEntry channel;
2020 SilcBuffer buffer, idp;
2024 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2029 if (cmd->argc != 2) {
2030 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "Usage: /LEAVE <channel>");
2036 if (cmd->argv[1][0] == '*') {
2037 if (!conn->current_channel) {
2038 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2039 "You are not on any channel");
2043 name = conn->current_channel->channel_name;
2045 name = cmd->argv[1];
2048 /* Get the Channel ID of the channel */
2049 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2050 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2051 "You are not on that channel");
2056 channel = (SilcChannelEntry)id_cache->context;
2057 channel->on_channel = FALSE;
2059 /* Send LEAVE command to the server */
2060 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2061 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2062 1, idp->data, idp->len);
2063 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2064 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2065 silc_buffer_free(buffer);
2066 silc_buffer_free(idp);
2068 /* Notify application */
2071 if (conn->current_channel == channel)
2072 conn->current_channel = NULL;
2074 silc_client_del_channel(cmd->client, cmd->conn, channel);
2077 silc_client_command_free(cmd);
2080 /* Command USERS. Requests the USERS of the clients joined on requested
2083 SILC_CLIENT_CMD_FUNC(users)
2085 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2086 SilcClientConnection conn = cmd->conn;
2091 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2096 if (cmd->argc != 2) {
2097 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2098 "Usage: /USERS <channel>");
2103 if (cmd->argv[1][0] == '*') {
2104 if (!conn->current_channel) {
2105 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2106 "You are not on any channel");
2110 name = conn->current_channel->channel_name;
2112 name = cmd->argv[1];
2115 /* Send USERS command to the server */
2116 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2117 ++conn->cmd_ident, 1,
2118 2, name, strlen(name));
2119 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2120 NULL, 0, NULL, NULL, buffer->data,
2122 silc_buffer_free(buffer);
2124 /* Notify application */
2128 silc_client_command_free(cmd);
2131 /* Command GETKEY. Used to fetch remote client's public key. */
2133 SILC_CLIENT_CMD_FUNC(getkey)
2135 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2136 SilcClientConnection conn = cmd->conn;
2137 SilcClient client = cmd->client;
2138 SilcClientEntry client_entry = NULL;
2139 SilcServerEntry server_entry = NULL;
2140 char *nickname = NULL;
2141 SilcBuffer idp, buffer;
2144 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2149 if (cmd->argc < 2) {
2150 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2151 "Usage: /GETKEY <nickname or server name>");
2157 SilcClientCommandReplyContext reply =
2158 (SilcClientCommandReplyContext)context2;
2159 SilcCommandStatus status;
2160 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2161 SILC_GET16_MSB(status, tmp);
2163 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2164 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2165 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2167 silc_client_command_status_message(status));
2173 /* Parse the typed nickname. */
2174 if (client->internal->params->nickname_parse)
2175 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2177 nickname = strdup(cmd->argv[1]);
2179 /* Find client entry */
2180 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2182 if (!client_entry) {
2183 /* Check whether user requested server actually */
2184 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2186 if (!server_entry) {
2192 /* No. what ever user wants we don't have it, so resolve it. We
2193 will try to resolve both client and server, one of them is
2194 bound to be wrong. */
2196 /* This will send the IDENTIFY command */
2197 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2198 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2200 silc_client_command_destructor,
2201 silc_client_command_getkey,
2202 silc_client_command_dup(cmd));
2204 /* This sends the IDENTIFY command to resolve the server. */
2205 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
2206 silc_client_command_reply_identify_i, 0,
2208 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
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);
2241 /* Register a new command indicated by the `command' to the SILC client.
2242 The `name' is optional command name. If provided the command may be
2243 searched using the silc_client_command_find by that name. The
2244 `command_function' is the function to be called when the command is
2245 executed, and the `command_reply_function' is the function to be
2246 called after the server has sent reply back to the command.
2248 The `ident' is optional identifier for the command. If non-zero
2249 the `command_reply_function' for the command type `command' will be
2250 called only if the command reply sent by server includes the
2251 command identifier `ident'. Application usually does not need it
2252 and set it to zero value. */
2254 bool silc_client_command_register(SilcClient client,
2255 SilcCommand command,
2257 SilcCommandCb command_function,
2258 SilcCommandCb command_reply_function,
2262 SilcClientCommand cmd;
2264 cmd = silc_calloc(1, sizeof(*cmd));
2266 cmd->command = command_function;
2267 cmd->reply = command_reply_function;
2268 cmd->name = name ? strdup(name) : NULL;
2269 cmd->max_args = max_args;
2272 silc_list_add(client->internal->commands, cmd);
2277 /* Unregister a command indicated by the `command' with command function
2278 `command_function' and command reply function `command_reply_function'.
2279 Returns TRUE if the command was found and unregistered. */
2281 bool silc_client_command_unregister(SilcClient client,
2282 SilcCommand command,
2283 SilcCommandCb command_function,
2284 SilcCommandCb command_reply_function,
2287 SilcClientCommand cmd;
2289 silc_list_start(client->internal->commands);
2290 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2291 if (cmd->cmd == command && cmd->command == command_function &&
2292 cmd->reply == command_reply_function && cmd->ident == ident) {
2293 silc_list_del(client->internal->commands, cmd);
2294 silc_free(cmd->name);
2303 /* Register all default commands provided by the client library for the
2306 void silc_client_commands_register(SilcClient client)
2308 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2311 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2312 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2313 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2314 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2315 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2316 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2317 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2318 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2319 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2320 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2321 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2322 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2323 SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
2324 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2325 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2326 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2327 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2328 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2329 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2330 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2331 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2332 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2333 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2334 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2335 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2336 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2339 /* Unregister all commands. */
2341 void silc_client_commands_unregister(SilcClient client)
2343 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2344 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2345 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2346 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2347 SILC_CLIENT_CMDU(list, LIST, "LIST");
2348 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2349 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2350 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2351 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2352 SILC_CLIENT_CMDU(info, INFO, "INFO");
2353 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2354 SILC_CLIENT_CMDU(ping, PING, "PING");
2355 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2356 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2357 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2358 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2359 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2360 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2361 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2362 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2363 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2364 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2365 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2366 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2367 SILC_CLIENT_CMDU(users, USERS, "USERS");
2368 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2370 silc_list_uninit(client->internal->commands);