5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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 "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, use /SERVER to connect");
29 /* Command operation that is called at the end of all commands.
30 Usage: COMMAND(status); */
31 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
32 cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
34 /* Error to application. Usage: COMMAND_ERROR(status); */
35 #define COMMAND_ERROR(status) \
36 cmd->client->internal->ops->command(cmd->client, \
37 cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
39 #define SAY cmd->client->internal->ops->say
41 /* Generic function to send any command. The arguments must be sent already
42 encoded into correct form and in correct order. */
44 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
45 SilcCommand command, SilcUInt16 ident,
51 assert(client && conn);
55 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
56 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
57 NULL, 0, NULL, NULL, packet->data,
59 silc_buffer_free(packet);
62 /* Finds and returns a pointer to the command list. Return NULL if the
63 command is not found. */
65 SilcClientCommand silc_client_command_find(SilcClient client,
68 SilcClientCommand cmd;
72 silc_list_start(client->internal->commands);
73 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
74 if (cmd->name && !strcasecmp(cmd->name, name))
81 /* Executes a command */
83 bool silc_client_command_call(SilcClient client,
84 SilcClientConnection conn,
85 const char *command_line, ...)
89 unsigned char **argv = NULL;
90 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
91 SilcClientCommand cmd;
92 SilcClientCommandContext ctx;
98 va_start(va, command_line);
102 /* Get command name */
103 command_name = silc_memdup(command_line, strcspn(command_line, " "));
107 /* Find command by name */
108 cmd = silc_client_command_find(client, command_name);
110 silc_free(command_name);
114 /* Parse command line */
115 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
116 &argv_types, &argc, cmd->max_args);
118 silc_free(command_name);
120 arg = va_arg(va, char *);
124 /* Find command by name */
125 cmd = silc_client_command_find(client, arg);
130 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
131 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
132 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
133 argv[argc] = silc_memdup(arg, strlen(arg));
134 argv_lens[argc] = strlen(arg);
135 argv_types[argc] = argc;
137 arg = va_arg(va, char *);
141 /* Allocate command context. */
142 ctx = silc_client_command_alloc();
143 ctx->client = client;
148 ctx->argv_lens = argv_lens;
149 ctx->argv_types = argv_types;
151 /* Call the command */
152 cmd->command(ctx, NULL);
159 /* Add new pending command to be executed when reply to a command has been
160 received. The `reply_cmd' is the command that will call the `callback'
161 with `context' when reply has been received. It can be SILC_COMMAND_NONE
162 to match any command with the `ident'. If `ident' is non-zero
163 the `callback' will be executed when received reply with command
164 identifier `ident'. If there already exists pending command for the
165 specified command, ident, callback and context this function has no
168 void silc_client_command_pending(SilcClientConnection conn,
169 SilcCommand reply_cmd,
171 SilcCommandCb callback,
174 SilcClientCommandPending *reply;
177 reply = silc_calloc(1, sizeof(*reply));
178 reply->reply_cmd = reply_cmd;
179 reply->ident = ident;
180 reply->context = context;
181 reply->callback = callback;
182 silc_dlist_add(conn->internal->pending_commands, reply);
185 /* Deletes pending command by reply command type. */
187 void silc_client_command_pending_del(SilcClientConnection conn,
188 SilcCommand reply_cmd,
191 SilcClientCommandPending *r;
193 if (!conn->internal->pending_commands)
196 silc_dlist_start(conn->internal->pending_commands);
197 while ((r = silc_dlist_get(conn->internal->pending_commands))
199 if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
201 && r->ident == ident) {
202 silc_dlist_del(conn->internal->pending_commands, r);
208 /* Checks for pending commands and marks callbacks to be called from
209 the command reply function. */
211 SilcClientCommandPendingCallbacks
212 silc_client_command_pending_check(SilcClientConnection conn,
213 SilcClientCommandReplyContext ctx,
216 SilcUInt32 *callbacks_count)
218 SilcClientCommandPending *r;
219 SilcClientCommandPendingCallbacks callbacks = NULL;
222 silc_dlist_start(conn->internal->pending_commands);
223 while ((r = silc_dlist_get(conn->internal->pending_commands))
225 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
226 && r->ident == ident) {
227 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
228 callbacks[i].context = r->context;
229 callbacks[i].callback = r->callback;
230 r->reply_check = TRUE;
236 *callbacks_count = i;
240 /* Allocate Command Context */
242 SilcClientCommandContext silc_client_command_alloc(void)
244 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
249 /* Free command context and its internals */
251 void silc_client_command_free(SilcClientCommandContext ctx)
254 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
256 if (ctx->users < 1) {
259 for (i = 0; i < ctx->argc; i++)
260 silc_free(ctx->argv[i]);
261 silc_free(ctx->argv);
262 silc_free(ctx->argv_lens);
263 silc_free(ctx->argv_types);
268 /* Duplicate Command Context by adding reference counter. The context won't
269 be free'd untill it hits zero. */
271 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
274 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
279 /* Command WHOIS. This command is used to query information about
282 SILC_CLIENT_CMD_FUNC(whois)
284 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
285 SilcClientConnection conn = cmd->conn;
286 SilcBuffer buffer, attrs = NULL;
287 unsigned char count[4], *tmp = NULL;
290 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
291 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
295 /* Given without arguments fetches client's own information */
297 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
298 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
300 1, 4, buffer->data, buffer->len);
301 silc_buffer_free(buffer);
305 if (cmd->argc == 2) {
306 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
307 ++conn->cmd_ident, 1,
311 if (!strcasecmp(cmd->argv[2], "-details"))
312 attrs = silc_client_attributes_request(0);
314 if (!attrs || cmd->argc > 3) {
315 int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
316 SILC_PUT32_MSB(c, count);
320 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
321 ++conn->cmd_ident, 3,
322 1, cmd->argv[1], cmd->argv_lens[1],
323 2, tmp ? tmp : NULL, tmp ? 4 : 0,
324 3, attrs ? attrs->data : NULL,
325 attrs ? attrs->len : 0);
327 silc_client_packet_send(cmd->client, cmd->conn->sock,
328 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
329 buffer->data, buffer->len, TRUE);
330 silc_buffer_free(buffer);
332 /* Notify application */
333 COMMAND(SILC_STATUS_OK);
336 silc_client_command_free(cmd);
339 /* Command WHOWAS. This command is used to query history information about
340 specific user that used to exist in the network. */
342 SILC_CLIENT_CMD_FUNC(whowas)
344 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
345 SilcClientConnection conn = cmd->conn;
347 unsigned char count[4];
350 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
351 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
355 if (cmd->argc < 2 || cmd->argc > 3) {
356 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
357 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
358 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
359 SILC_STATUS_ERR_TOO_MANY_PARAMS));
363 if (cmd->argc == 2) {
364 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
365 ++conn->cmd_ident, 1,
369 int c = atoi(cmd->argv[2]);
370 memset(count, 0, sizeof(count));
371 SILC_PUT32_MSB(c, count);
372 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
373 ++conn->cmd_ident, 2,
374 1, cmd->argv[1], cmd->argv_lens[1],
375 2, count, sizeof(count));
377 silc_client_packet_send(cmd->client, cmd->conn->sock,
378 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
379 buffer->data, buffer->len, TRUE);
380 silc_buffer_free(buffer);
382 /* Notify application */
383 COMMAND(SILC_STATUS_OK);
386 silc_client_command_free(cmd);
389 /* Command IDENTIFY. This command is used to query information about
390 specific user, especially ID's.
392 NOTE: This command is used only internally by the client library
393 and application MUST NOT call this command directly. */
395 SILC_CLIENT_CMD_FUNC(identify)
397 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
398 SilcClientConnection conn = cmd->conn;
400 unsigned char count[4];
403 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
404 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
408 if (cmd->argc < 2 || cmd->argc > 3)
411 if (cmd->argc == 2) {
412 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
413 ++conn->cmd_ident, 1,
417 int c = atoi(cmd->argv[2]);
418 memset(count, 0, sizeof(count));
419 SILC_PUT32_MSB(c, count);
420 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
421 ++conn->cmd_ident, 2,
424 4, count, sizeof(count));
427 silc_client_packet_send(cmd->client, cmd->conn->sock,
428 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
429 buffer->data, buffer->len, TRUE);
430 silc_buffer_free(buffer);
433 silc_client_command_free(cmd);
436 /* Command NICK. Shows current nickname/sets new nickname on current
439 SILC_CLIENT_CMD_FUNC(nick)
441 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
442 SilcClientConnection conn = cmd->conn;
446 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
447 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
452 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
453 "Usage: /NICK <nickname>");
454 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
458 if (!strcmp(conn->nickname, cmd->argv[1]))
461 /* Show current nickname */
464 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
465 "Your nickname is %s on server %s",
466 conn->nickname, conn->remote_host);
468 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
469 "Your nickname is %s", conn->nickname);
472 COMMAND(SILC_STATUS_OK);
476 if (cmd->argv_lens[1] > 128)
477 cmd->argv_lens[1] = 128;
479 /* Send the NICK command */
480 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
484 ++cmd->conn->cmd_ident);
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);
491 silc_client_command_free(cmd);
494 /* Command LIST. Lists channels on the current server. */
496 SILC_CLIENT_CMD_FUNC(list)
498 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
499 SilcClientConnection conn = cmd->conn;
500 SilcIDCacheEntry id_cache = NULL;
501 SilcChannelEntry channel;
502 SilcBuffer buffer, idp = NULL;
506 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
507 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
511 if (cmd->argc == 2) {
514 /* Get the Channel ID of the channel */
515 if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
517 channel = (SilcChannelEntry)id_cache->context;
518 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
523 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
524 ++conn->cmd_ident, 0);
526 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
527 ++conn->cmd_ident, 1,
528 1, idp->data, idp->len);
530 silc_client_packet_send(cmd->client, cmd->conn->sock,
531 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
532 buffer->data, buffer->len, TRUE);
533 silc_buffer_free(buffer);
535 silc_buffer_free(idp);
537 /* Notify application */
538 COMMAND(SILC_STATUS_OK);
541 silc_client_command_free(cmd);
544 /* Command TOPIC. Sets/shows topic on a channel. */
546 SILC_CLIENT_CMD_FUNC(topic)
548 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
549 SilcClientConnection conn = cmd->conn;
550 SilcIDCacheEntry id_cache = NULL;
551 SilcChannelEntry channel;
552 SilcBuffer buffer, idp;
556 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
557 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
561 if (cmd->argc < 2 || cmd->argc > 3) {
562 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
563 "Usage: /TOPIC <channel> [<topic>]");
564 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
565 SILC_STATUS_ERR_TOO_MANY_PARAMS));
569 if (cmd->argv[1][0] == '*') {
570 if (!conn->current_channel) {
571 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
574 name = conn->current_channel->channel_name;
579 if (!conn->current_channel) {
580 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
584 /* Get the Channel ID of the channel */
585 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
587 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
591 channel = (SilcChannelEntry)id_cache->context;
593 /* Send TOPIC command to the server */
594 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
596 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
597 ++conn->cmd_ident, 2,
598 1, idp->data, idp->len,
600 strlen(cmd->argv[2]));
602 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
603 ++conn->cmd_ident, 1,
604 1, idp->data, idp->len);
605 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
606 0, NULL, NULL, buffer->data, buffer->len, TRUE);
607 silc_buffer_free(buffer);
608 silc_buffer_free(idp);
610 /* Notify application */
611 COMMAND(SILC_STATUS_OK);
614 silc_client_command_free(cmd);
617 /* Command INVITE. Invites specific client to join a channel. This is
618 also used to mange the invite list of the channel. */
620 SILC_CLIENT_CMD_FUNC(invite)
622 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
623 SilcClient client = cmd->client;
624 SilcClientConnection conn = cmd->conn;
625 SilcClientEntry client_entry = NULL;
626 SilcChannelEntry channel;
627 SilcBuffer buffer, clidp, chidp, args = NULL;
628 char *nickname = NULL, *name;
630 unsigned char action[1];
633 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
634 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
639 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
640 "Usage: /INVITE <channel> [<nickname>[@server>]"
641 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
642 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
646 if (cmd->argv[1][0] == '*') {
647 if (!conn->current_channel) {
648 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
652 channel = conn->current_channel;
656 channel = silc_client_get_channel(cmd->client, conn, name);
658 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
663 /* Parse the typed nickname. */
664 if (cmd->argc == 3) {
665 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
666 if (client->internal->params->nickname_parse)
667 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
669 nickname = strdup(cmd->argv[2]);
671 /* Find client entry */
672 client_entry = silc_idlist_get_client(client, conn, nickname,
676 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
680 /* Client entry not found, it was requested thus mark this to be
682 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
684 silc_client_command_invite,
685 silc_client_command_dup(cmd));
690 invite = cmd->argv[2];
692 if (cmd->argv[2][0] == '+')
700 args = silc_buffer_alloc_size(2);
701 silc_buffer_format(args,
702 SILC_STR_UI_SHORT(1),
704 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
707 /* Send the command */
708 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
710 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
711 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
712 ++conn->cmd_ident, 4,
713 1, chidp->data, chidp->len,
714 2, clidp->data, clidp->len,
715 3, args ? action : NULL,
717 4, args ? args->data : NULL,
718 args ? args->len : 0);
719 silc_buffer_free(clidp);
721 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
722 ++conn->cmd_ident, 3,
723 1, chidp->data, chidp->len,
724 3, args ? action : NULL,
726 4, args ? args->data : NULL,
727 args ? args->len : 0);
730 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
731 0, NULL, NULL, buffer->data, buffer->len, TRUE);
732 silc_buffer_free(buffer);
733 silc_buffer_free(chidp);
734 silc_buffer_free(args),
736 /* Notify application */
737 COMMAND(SILC_STATUS_OK);
741 silc_client_command_free(cmd);
746 SilcClientConnection conn;
749 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
751 QuitInternal q = (QuitInternal)context;
753 /* Close connection */
754 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
755 silc_client_close_connection(q->client, q->conn->sock->user_data);
760 /* Command QUIT. Closes connection with current server. */
762 SILC_CLIENT_CMD_FUNC(quit)
764 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
769 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
770 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
775 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
776 &cmd->argv[1], &cmd->argv_lens[1],
777 &cmd->argv_types[1], 0);
779 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
780 NULL, NULL, NULL, 0);
781 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
783 buffer->data, buffer->len, TRUE);
784 silc_buffer_free(buffer);
786 q = silc_calloc(1, sizeof(*q));
787 q->client = cmd->client;
790 /* Sleep for a while */
793 /* We quit the connection with little timeout */
794 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
795 silc_client_command_quit_cb, (void *)q,
796 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
798 /* Notify application */
799 COMMAND(SILC_STATUS_OK);
802 silc_client_command_free(cmd);
805 /* Timeout callback to remove the killed client from cache */
807 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
809 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
810 SilcClient client = cmd->client;
811 SilcClientConnection conn = cmd->conn;
812 SilcClientEntry target;
813 char *nickname = NULL;
815 /* Parse the typed nickname. */
816 if (client->internal->params->nickname_parse)
817 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
819 nickname = strdup(cmd->argv[1]);
821 /* Get the target client */
822 target = silc_idlist_get_client(cmd->client, conn, nickname,
823 cmd->argv[1], FALSE);
825 /* Remove the client from all channels and free it */
826 silc_client_del_client(client, conn, target);
829 silc_client_command_free(cmd);
832 /* Kill command's pending command callback to actually remove the killed
833 client from our local cache. */
835 SILC_CLIENT_CMD_FUNC(kill_remove)
837 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
838 SilcClientCommandReplyContext reply =
839 (SilcClientCommandReplyContext)context2;
842 silc_command_get_status(reply->payload, &status, NULL);
843 if (status == SILC_STATUS_OK) {
844 /* Remove with timeout */
845 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
846 silc_client_command_kill_remove_later, context,
847 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
851 silc_client_command_free(cmd);
854 /* Command KILL. Router operator can use this command to remove an client
855 fromthe SILC Network. */
857 SILC_CLIENT_CMD_FUNC(kill)
859 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
860 SilcClient client = cmd->client;
861 SilcClientConnection conn = cmd->conn;
862 SilcBuffer buffer, idp, auth = NULL;
863 SilcClientEntry target;
864 char *nickname = NULL, *comment = NULL;
867 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
868 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
873 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
874 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
875 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
879 /* Parse the typed nickname. */
880 if (client->internal->params->nickname_parse)
881 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
883 nickname = strdup(cmd->argv[1]);
885 /* Get the target client */
886 target = silc_idlist_get_client(cmd->client, conn, nickname,
890 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
894 /* Client entry not found, it was requested thus mark this to be
896 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
898 silc_client_command_kill,
899 silc_client_command_dup(cmd));
904 if (cmd->argc >= 3) {
905 if (strcasecmp(cmd->argv[2], "-pubkey"))
906 comment = cmd->argv[2];
908 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
909 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
910 /* Encode the public key authentication payload */
911 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
912 cmd->client->private_key,
915 target->id, SILC_ID_CLIENT);
919 /* Send the KILL command to the server */
920 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
922 silc_command_payload_encode_va(SILC_COMMAND_KILL,
923 ++conn->cmd_ident, 3,
924 1, idp->data, idp->len,
925 2, comment, comment ? strlen(comment) : 0,
926 3, auth ? auth->data : NULL,
927 auth ? auth->len : 0);
928 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
929 0, NULL, NULL, buffer->data, buffer->len, TRUE);
930 silc_buffer_free(buffer);
931 silc_buffer_free(idp);
932 silc_buffer_free(auth);
934 /* Notify application */
935 COMMAND(SILC_STATUS_OK);
937 /* Register a pending callback that will actually remove the killed
938 client from our cache. */
939 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
940 silc_client_command_kill_remove,
941 silc_client_command_dup(cmd));
945 silc_client_command_free(cmd);
948 /* Command INFO. Request information about specific server. If specific
949 server is not provided the current server is used. */
951 SILC_CLIENT_CMD_FUNC(info)
953 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
954 SilcClientConnection conn = cmd->conn;
959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
960 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
965 name = strdup(cmd->argv[1]);
967 /* Send the command */
969 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
970 1, name, strlen(name));
972 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
973 NULL, NULL, NULL, 0);
974 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
975 0, NULL, NULL, buffer->data, buffer->len, TRUE);
976 silc_buffer_free(buffer);
980 /* Notify application */
981 COMMAND(SILC_STATUS_OK);
984 silc_client_command_free(cmd);
987 /* Command STATS. Shows server and network statistics. */
989 SILC_CLIENT_CMD_FUNC(stats)
991 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
992 SilcClientConnection conn = cmd->conn;
993 SilcBuffer buffer, idp = NULL;
996 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
997 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1001 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1003 /* Send the command */
1004 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1005 ++conn->cmd_ident, 1,
1006 SILC_ID_SERVER, idp->data, idp->len);
1007 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1008 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1009 silc_buffer_free(buffer);
1010 silc_buffer_free(idp);
1012 /* Notify application */
1013 COMMAND(SILC_STATUS_OK);
1016 silc_client_command_free(cmd);
1019 /* Command PING. Sends ping to server. This is used to test the
1020 communication channel. */
1022 SILC_CLIENT_CMD_FUNC(ping)
1024 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1025 SilcClientConnection conn = cmd->conn;
1026 SilcBuffer buffer, idp;
1031 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1032 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1036 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1038 /* Send the command */
1039 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1040 1, idp->data, idp->len);
1041 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1042 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1043 silc_buffer_free(buffer);
1044 silc_buffer_free(idp);
1046 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1049 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1050 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1054 /* Start counting time */
1055 for (i = 0; i < conn->internal->ping_count; i++) {
1056 if (conn->internal->ping[i].dest_id == NULL) {
1057 conn->internal->ping[i].start_time = time(NULL);
1058 conn->internal->ping[i].dest_id = id;
1059 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1063 if (i >= conn->internal->ping_count) {
1064 i = conn->internal->ping_count;
1065 conn->internal->ping =
1066 silc_realloc(conn->internal->ping,
1067 sizeof(*conn->internal->ping) * (i + 1));
1068 conn->internal->ping[i].start_time = time(NULL);
1069 conn->internal->ping[i].dest_id = id;
1070 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1071 conn->internal->ping_count++;
1074 /* Notify application */
1075 COMMAND(SILC_STATUS_OK);
1078 silc_client_command_free(cmd);
1081 /* Command JOIN. Joins to a channel. */
1083 SILC_CLIENT_CMD_FUNC(join)
1085 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1086 SilcClientConnection conn = cmd->conn;
1087 SilcChannelEntry channel;
1088 SilcBuffer buffer, idp, auth = NULL;
1089 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1090 int i, passphrase_len = 0;
1093 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1094 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1098 if (cmd->argc < 2) {
1099 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1103 /* See if we have joined to the requested channel already */
1104 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1105 if (channel && silc_client_on_channel(channel, conn->local_entry))
1108 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1110 if (cmd->argv_lens[1] > 256)
1111 cmd->argv_lens[1] = 256;
1113 name = cmd->argv[1];
1115 for (i = 2; i < cmd->argc; i++) {
1116 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1117 cipher = cmd->argv[i + 1];
1119 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1120 hmac = cmd->argv[i + 1];
1122 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1123 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1124 cmd->client->private_key,
1126 cmd->client->sha1hash,
1131 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1132 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1133 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1134 cmd->argv_lens[i], 0);
1135 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1136 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1137 0, pu8, passphrase_len);
1140 passphrase = strdup(cmd->argv[i]);
1141 passphrase_len = cmd->argv_lens[i];
1146 /* Send JOIN command to the server */
1148 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1149 1, name, strlen(name),
1150 2, idp->data, idp->len,
1151 3, passphrase, passphrase_len,
1152 4, cipher, cipher ? strlen(cipher) : 0,
1153 5, hmac, hmac ? strlen(hmac) : 0,
1154 6, auth ? auth->data : NULL,
1155 auth ? auth->len : 0);
1156 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1157 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1158 silc_buffer_free(buffer);
1159 silc_buffer_free(idp);
1161 silc_buffer_free(auth);
1162 silc_free(passphrase);
1164 /* Notify application */
1165 COMMAND(SILC_STATUS_OK);
1168 silc_client_command_free(cmd);
1171 /* MOTD command. Requests motd from server. */
1173 SILC_CLIENT_CMD_FUNC(motd)
1175 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1176 SilcClientConnection conn = cmd->conn;
1180 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1181 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1185 if (cmd->argc < 1 || cmd->argc > 2) {
1186 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1187 "Usage: /MOTD [<server>]");
1188 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1189 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1193 /* Send TOPIC command to the server */
1195 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1196 1, conn->remote_host,
1197 strlen(conn->remote_host));
1199 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1202 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1203 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1204 silc_buffer_free(buffer);
1206 /* Notify application */
1207 COMMAND(SILC_STATUS_OK);
1210 silc_client_command_free(cmd);
1213 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1214 modes as client cannot set itself server/router operator privileges. */
1216 SILC_CLIENT_CMD_FUNC(umode)
1218 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1219 SilcClientConnection conn = cmd->conn;
1220 SilcBuffer buffer, idp;
1221 unsigned char *cp, modebuf[4];
1222 SilcUInt32 mode, add, len;
1226 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1227 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1231 if (cmd->argc < 2) {
1232 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1233 "Usage: /UMODE +|-<modes>");
1234 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1238 mode = conn->local_entry->mode;
1240 /* Are we adding or removing mode */
1241 if (cmd->argv[1][0] == '-')
1247 cp = cmd->argv[1] + 1;
1249 for (i = 0; i < len; i++) {
1254 mode |= SILC_UMODE_SERVER_OPERATOR;
1255 mode |= SILC_UMODE_ROUTER_OPERATOR;
1256 mode |= SILC_UMODE_GONE;
1257 mode |= SILC_UMODE_INDISPOSED;
1258 mode |= SILC_UMODE_BUSY;
1259 mode |= SILC_UMODE_PAGE;
1260 mode |= SILC_UMODE_HYPER;
1261 mode |= SILC_UMODE_ROBOT;
1262 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1263 mode |= SILC_UMODE_REJECT_WATCHING;
1265 mode = SILC_UMODE_NONE;
1270 mode |= SILC_UMODE_SERVER_OPERATOR;
1272 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1276 mode |= SILC_UMODE_ROUTER_OPERATOR;
1278 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1282 mode |= SILC_UMODE_GONE;
1284 mode &= ~SILC_UMODE_GONE;
1288 mode |= SILC_UMODE_INDISPOSED;
1290 mode &= ~SILC_UMODE_INDISPOSED;
1294 mode |= SILC_UMODE_BUSY;
1296 mode &= ~SILC_UMODE_BUSY;
1300 mode |= SILC_UMODE_PAGE;
1302 mode &= ~SILC_UMODE_PAGE;
1306 mode |= SILC_UMODE_HYPER;
1308 mode &= ~SILC_UMODE_HYPER;
1312 mode |= SILC_UMODE_ROBOT;
1314 mode &= ~SILC_UMODE_ROBOT;
1318 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1320 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1324 mode |= SILC_UMODE_REJECT_WATCHING;
1326 mode &= ~SILC_UMODE_REJECT_WATCHING;
1330 mode |= SILC_UMODE_BLOCK_INVITE;
1332 mode &= ~SILC_UMODE_BLOCK_INVITE;
1335 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1341 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1342 SILC_PUT32_MSB(mode, modebuf);
1344 /* Send the command packet. We support sending only one mode at once
1345 that requires an argument. */
1347 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1348 1, idp->data, idp->len,
1349 2, modebuf, sizeof(modebuf));
1350 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1351 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1352 silc_buffer_free(buffer);
1353 silc_buffer_free(idp);
1355 /* Notify application */
1356 COMMAND(SILC_STATUS_OK);
1359 silc_client_command_free(cmd);
1362 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1363 can be set several at once. Those modes that require argument must be set
1364 separately (unless set with modes that does not require arguments). */
1366 SILC_CLIENT_CMD_FUNC(cmode)
1368 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1369 SilcClientConnection conn = cmd->conn;
1370 SilcChannelEntry channel;
1371 SilcBuffer buffer, chidp, auth = NULL;
1372 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1373 SilcUInt32 mode, add, type, len, arg_len = 0;
1377 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1378 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1382 if (cmd->argc < 3) {
1383 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1384 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1385 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1389 if (cmd->argv[1][0] == '*') {
1390 if (!conn->current_channel) {
1391 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1395 channel = conn->current_channel;
1397 name = cmd->argv[1];
1399 channel = silc_client_get_channel(cmd->client, conn, name);
1401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1406 mode = channel->mode;
1408 /* Are we adding or removing mode */
1409 if (cmd->argv[2][0] == '-')
1414 /* Argument type to be sent to server */
1418 cp = cmd->argv[2] + 1;
1420 for (i = 0; i < len; i++) {
1424 mode |= SILC_CHANNEL_MODE_PRIVATE;
1426 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1430 mode |= SILC_CHANNEL_MODE_SECRET;
1432 mode &= ~SILC_CHANNEL_MODE_SECRET;
1436 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1438 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1442 mode |= SILC_CHANNEL_MODE_INVITE;
1444 mode &= ~SILC_CHANNEL_MODE_INVITE;
1448 mode |= SILC_CHANNEL_MODE_TOPIC;
1450 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1454 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1456 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1460 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1462 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1467 mode |= SILC_CHANNEL_MODE_ULIMIT;
1469 if (cmd->argc < 4) {
1470 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1471 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1472 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1475 ll = atoi(cmd->argv[3]);
1476 SILC_PUT32_MSB(ll, tmp);
1480 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1485 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1487 if (cmd->argc < 4) {
1488 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1489 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1490 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1494 arg_len = cmd->argv_lens[3];
1496 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1501 mode |= SILC_CHANNEL_MODE_CIPHER;
1503 if (cmd->argc < 4) {
1504 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1505 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1510 arg_len = cmd->argv_lens[3];
1512 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1517 mode |= SILC_CHANNEL_MODE_HMAC;
1519 if (cmd->argc < 4) {
1520 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1521 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1522 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1526 arg_len = cmd->argv_lens[3];
1528 mode &= ~SILC_CHANNEL_MODE_HMAC;
1533 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1535 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1536 cmd->client->private_key,
1538 cmd->client->sha1hash,
1542 arg_len = auth->len;
1544 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1548 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1554 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1555 SILC_PUT32_MSB(mode, modebuf);
1557 /* Send the command packet. We support sending only one mode at once
1558 that requires an argument. */
1561 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1562 1, chidp->data, chidp->len,
1563 2, modebuf, sizeof(modebuf),
1564 type, arg, arg_len);
1567 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1568 1, chidp->data, chidp->len,
1569 2, modebuf, sizeof(modebuf));
1572 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1573 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1574 silc_buffer_free(buffer);
1575 silc_buffer_free(chidp);
1577 silc_buffer_free(auth);
1579 /* Notify application */
1580 COMMAND(SILC_STATUS_OK);
1583 silc_client_command_free(cmd);
1586 /* CUMODE command. Changes client's mode on a channel. */
1588 SILC_CLIENT_CMD_FUNC(cumode)
1590 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1591 SilcClient client = cmd->client;
1592 SilcClientConnection conn = cmd->conn;
1593 SilcChannelEntry channel;
1594 SilcChannelUser chu;
1595 SilcClientEntry client_entry;
1596 SilcBuffer buffer, clidp, chidp, auth = NULL;
1597 unsigned char *name, *cp, modebuf[4];
1598 SilcUInt32 mode = 0, add, len;
1599 char *nickname = NULL;
1603 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1604 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1608 if (cmd->argc < 4) {
1609 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1610 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1611 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1615 if (cmd->argv[1][0] == '*') {
1616 if (!conn->current_channel) {
1617 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1621 channel = conn->current_channel;
1623 name = cmd->argv[1];
1625 channel = silc_client_get_channel(cmd->client, conn, name);
1627 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1632 /* Parse the typed nickname. */
1633 if (client->internal->params->nickname_parse)
1634 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1636 nickname = strdup(cmd->argv[3]);
1638 /* Find client entry */
1639 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1640 cmd->argv[3], TRUE);
1641 if (!client_entry) {
1643 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1647 /* Client entry not found, it was requested thus mark this to be
1649 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1651 silc_client_command_cumode,
1652 silc_client_command_dup(cmd));
1657 /* Get the current mode */
1658 chu = silc_client_on_channel(channel, client_entry);
1662 /* Are we adding or removing mode */
1663 if (cmd->argv[2][0] == '-')
1669 cp = cmd->argv[2] + 1;
1671 for (i = 0; i < len; i++) {
1675 mode |= SILC_CHANNEL_UMODE_CHANFO;
1676 mode |= SILC_CHANNEL_UMODE_CHANOP;
1677 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1678 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1679 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1681 mode = SILC_CHANNEL_UMODE_NONE;
1686 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1687 cmd->client->private_key,
1689 cmd->client->sha1hash,
1692 mode |= SILC_CHANNEL_UMODE_CHANFO;
1694 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1699 mode |= SILC_CHANNEL_UMODE_CHANOP;
1701 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1705 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1707 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1711 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1713 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1717 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1719 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1723 mode |= SILC_CHANNEL_UMODE_QUIET;
1725 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1728 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1734 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1735 SILC_PUT32_MSB(mode, modebuf);
1736 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1738 /* Send the command packet. We support sending only one mode at once
1739 that requires an argument. */
1740 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1742 1, chidp->data, chidp->len,
1744 3, clidp->data, clidp->len,
1745 4, auth ? auth->data : NULL,
1746 auth ? auth->len : 0);
1748 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1749 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1750 silc_buffer_free(buffer);
1751 silc_buffer_free(chidp);
1752 silc_buffer_free(clidp);
1754 silc_buffer_free(auth);
1756 /* Notify application */
1757 COMMAND(SILC_STATUS_OK);
1760 silc_free(nickname);
1761 silc_client_command_free(cmd);
1764 /* KICK command. Kicks a client out of channel. */
1766 SILC_CLIENT_CMD_FUNC(kick)
1768 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1769 SilcClient client = cmd->client;
1770 SilcClientConnection conn = cmd->conn;
1771 SilcIDCacheEntry id_cache = NULL;
1772 SilcChannelEntry channel;
1773 SilcBuffer buffer, idp, idp2;
1774 SilcClientEntry target;
1776 char *nickname = NULL;
1779 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1780 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1784 if (cmd->argc < 3) {
1785 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1786 "Usage: /KICK <channel> <nickname> [<comment>]");
1787 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1791 if (cmd->argv[1][0] == '*') {
1792 if (!conn->current_channel) {
1793 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1796 name = conn->current_channel->channel_name;
1798 name = cmd->argv[1];
1801 if (!conn->current_channel) {
1802 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1806 /* Get the Channel ID of the channel */
1807 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1809 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1813 channel = (SilcChannelEntry)id_cache->context;
1815 /* Parse the typed nickname. */
1816 if (client->internal->params->nickname_parse)
1817 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1819 nickname = strdup(cmd->argv[2]);
1821 /* Get the target client */
1822 target = silc_idlist_get_client(cmd->client, conn, nickname,
1823 cmd->argv[2], FALSE);
1825 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1826 "No such client: %s", cmd->argv[2]);
1827 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1831 /* Send KICK command to the server */
1832 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1833 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1835 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1836 1, idp->data, idp->len,
1837 2, idp2->data, idp2->len);
1839 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1840 1, idp->data, idp->len,
1841 2, idp2->data, idp2->len,
1843 strlen(cmd->argv[3]));
1844 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1845 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1846 silc_buffer_free(buffer);
1847 silc_buffer_free(idp);
1848 silc_buffer_free(idp2);
1850 /* Notify application */
1851 COMMAND(SILC_STATUS_OK);
1854 silc_free(nickname);
1855 silc_client_command_free(cmd);
1858 static void silc_client_command_oper_send(unsigned char *data,
1859 SilcUInt32 data_len, void *context)
1861 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1862 SilcClientConnection conn = cmd->conn;
1863 SilcBuffer buffer, auth;
1865 if (cmd->argc >= 3) {
1866 /* Encode the public key authentication payload */
1867 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1868 cmd->client->private_key,
1870 conn->internal->hash,
1874 /* Encode the password authentication payload */
1875 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1879 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1881 strlen(cmd->argv[1]),
1882 2, auth ? auth->data : NULL,
1883 auth ? auth->len : 0);
1884 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1885 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1887 silc_buffer_free(buffer);
1888 silc_buffer_free(auth);
1890 /* Notify application */
1891 COMMAND(SILC_STATUS_OK);
1894 /* OPER command. Used to obtain server operator privileges. */
1896 SILC_CLIENT_CMD_FUNC(oper)
1898 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1899 SilcClientConnection conn = cmd->conn;
1902 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1903 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1907 if (cmd->argc < 2) {
1908 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1909 "Usage: /OPER <username> [-pubkey]");
1910 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1914 if (cmd->argc < 3) {
1915 /* Get passphrase */
1916 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1917 silc_client_command_oper_send,
1922 silc_client_command_oper_send(NULL, 0, context);
1925 silc_client_command_free(cmd);
1928 static void silc_client_command_silcoper_send(unsigned char *data,
1929 SilcUInt32 data_len,
1932 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1933 SilcClientConnection conn = cmd->conn;
1934 SilcBuffer buffer, auth;
1936 if (cmd->argc >= 3) {
1937 /* Encode the public key authentication payload */
1938 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1939 cmd->client->private_key,
1941 conn->internal->hash,
1945 /* Encode the password authentication payload */
1946 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1950 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1952 strlen(cmd->argv[1]),
1953 2, auth ? auth->data : NULL,
1954 auth ? auth->len : 0);
1955 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1956 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1958 silc_buffer_free(buffer);
1959 silc_buffer_free(auth);
1961 /* Notify application */
1962 COMMAND(SILC_STATUS_OK);
1965 /* SILCOPER command. Used to obtain router operator privileges. */
1967 SILC_CLIENT_CMD_FUNC(silcoper)
1969 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1970 SilcClientConnection conn = cmd->conn;
1973 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1974 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1978 if (cmd->argc < 2) {
1979 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1980 "Usage: /SILCOPER <username> [-pubkey]");
1981 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1985 if (cmd->argc < 3) {
1986 /* Get passphrase */
1987 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1988 silc_client_command_silcoper_send,
1993 silc_client_command_silcoper_send(NULL, 0, context);
1996 silc_client_command_free(cmd);
1999 /* Command BAN. This is used to manage the ban list of the channel. */
2001 SILC_CLIENT_CMD_FUNC(ban)
2003 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2004 SilcClientConnection conn = cmd->conn;
2005 SilcChannelEntry channel;
2006 SilcBuffer buffer, chidp, args = NULL;
2007 char *name, *ban = NULL;
2008 unsigned char action[1];
2011 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2012 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2016 if (cmd->argc < 2) {
2017 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2018 "Usage: /BAN <channel> "
2019 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2020 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2024 if (cmd->argv[1][0] == '*') {
2025 if (!conn->current_channel) {
2026 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2030 channel = conn->current_channel;
2032 name = cmd->argv[1];
2034 channel = silc_client_get_channel(cmd->client, conn, name);
2036 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2041 if (cmd->argc == 3) {
2042 if (cmd->argv[2][0] == '+')
2052 args = silc_buffer_alloc_size(2);
2053 silc_buffer_format(args,
2054 SILC_STR_UI_SHORT(1),
2056 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2059 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2061 /* Send the command */
2062 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2063 ++conn->cmd_ident, 3,
2064 1, chidp->data, chidp->len,
2065 2, args ? action : NULL,
2067 3, args ? args->data : NULL,
2068 args ? args->len : 0);
2069 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2070 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2071 silc_buffer_free(buffer);
2072 silc_buffer_free(chidp);
2073 silc_buffer_free(args);
2075 /* Notify application */
2076 COMMAND(SILC_STATUS_OK);
2079 silc_client_command_free(cmd);
2082 /* Command DETACH. This is used to detach from the server */
2084 SILC_CLIENT_CMD_FUNC(detach)
2086 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2087 SilcClientConnection conn = cmd->conn;
2091 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2092 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2096 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2097 ++conn->cmd_ident, 0);
2098 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2099 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2100 silc_buffer_free(buffer);
2102 /* Notify application */
2103 COMMAND(SILC_STATUS_OK);
2106 silc_client_command_free(cmd);
2109 /* Command WATCH. */
2111 SILC_CLIENT_CMD_FUNC(watch)
2113 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2114 SilcClientConnection conn = cmd->conn;
2115 SilcBuffer buffer, idp = NULL;
2119 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2120 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2124 if (cmd->argc < 3) {
2125 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2129 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2131 if (!strcasecmp(cmd->argv[1], "-add")) {
2133 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2136 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2140 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2141 ++conn->cmd_ident, 2,
2142 1, idp->data, idp->len,
2145 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2146 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2147 silc_buffer_free(buffer);
2149 /* Notify application */
2150 COMMAND(SILC_STATUS_OK);
2154 silc_buffer_free(idp);
2155 silc_client_command_free(cmd);
2158 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2160 SILC_CLIENT_CMD_FUNC(leave)
2162 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2163 SilcClientConnection conn = cmd->conn;
2164 SilcChannelEntry channel;
2165 SilcChannelUser chu;
2166 SilcBuffer buffer, idp;
2170 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2171 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2175 if (cmd->argc != 2) {
2176 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2177 "Usage: /LEAVE <channel>");
2178 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2182 if (cmd->argv[1][0] == '*') {
2183 if (!conn->current_channel) {
2184 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2187 name = conn->current_channel->channel_name;
2189 name = cmd->argv[1];
2192 /* Get the channel entry */
2193 channel = silc_client_get_channel(cmd->client, conn, name);
2195 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2199 /* Remove us from channel */
2200 chu = silc_client_on_channel(channel, conn->local_entry);
2202 silc_hash_table_del(chu->client->channels, chu->channel);
2203 silc_hash_table_del(chu->channel->user_list, chu->client);
2207 /* Send LEAVE command to the server */
2208 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2209 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2210 1, idp->data, idp->len);
2211 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2212 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2213 silc_buffer_free(buffer);
2214 silc_buffer_free(idp);
2216 /* Notify application */
2217 COMMAND(SILC_STATUS_OK);
2219 if (conn->current_channel == channel)
2220 conn->current_channel = NULL;
2222 silc_client_del_channel(cmd->client, cmd->conn, channel);
2225 silc_client_command_free(cmd);
2228 /* Command USERS. Requests the USERS of the clients joined on requested
2231 SILC_CLIENT_CMD_FUNC(users)
2233 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2234 SilcClientConnection conn = cmd->conn;
2239 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2240 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2244 if (cmd->argc != 2) {
2245 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2246 "Usage: /USERS <channel>");
2247 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2251 if (cmd->argv[1][0] == '*') {
2252 if (!conn->current_channel) {
2253 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2256 name = conn->current_channel->channel_name;
2258 name = cmd->argv[1];
2261 /* Send USERS command to the server */
2262 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2263 ++conn->cmd_ident, 1,
2264 2, name, strlen(name));
2265 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2266 NULL, 0, NULL, NULL, buffer->data,
2268 silc_buffer_free(buffer);
2270 /* Notify application */
2271 COMMAND(SILC_STATUS_OK);
2274 silc_client_command_free(cmd);
2277 /* Command GETKEY. Used to fetch remote client's public key. */
2279 SILC_CLIENT_CMD_FUNC(getkey)
2281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2282 SilcClientConnection conn = cmd->conn;
2283 SilcClient client = cmd->client;
2284 SilcClientEntry client_entry = NULL;
2285 SilcServerEntry server_entry = NULL;
2286 char *nickname = NULL;
2287 SilcBuffer idp, buffer;
2289 SILC_LOG_DEBUG(("Start"));
2292 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2293 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2297 if (cmd->argc < 2) {
2298 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2299 "Usage: /GETKEY <nickname or server name>");
2300 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2304 /* Parse the typed nickname. */
2305 if (client->internal->params->nickname_parse)
2306 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2308 nickname = strdup(cmd->argv[1]);
2310 /* Find client entry */
2311 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2313 if (!client_entry) {
2314 /* Check whether user requested server actually */
2315 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2317 if (!server_entry) {
2318 /* No. what ever user wants we don't have it, so resolve it. We
2319 will first try to resolve the client, and if that fails then
2320 we'll try to resolve the server. */
2322 if (!cmd->pending) {
2323 /* This will send the IDENTIFY command for nickname */
2324 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2325 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2327 silc_client_command_getkey,
2328 silc_client_command_dup(cmd));
2332 SilcClientCommandReplyContext reply =
2333 (SilcClientCommandReplyContext)context2;
2336 /* If nickname was not found, then resolve the server. */
2337 silc_command_get_status(reply->payload, NULL, &error);
2338 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2339 /* This sends the IDENTIFY command to resolve the server. */
2340 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2342 silc_client_command_reply_identify_i, 0,
2344 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2346 2, cmd->argv[1], cmd->argv_lens[1]);
2347 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2349 silc_client_command_getkey,
2350 silc_client_command_dup(cmd));
2354 /* If server was not found, then we've resolved both nickname and
2355 server and did not find anybody. */
2356 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2357 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2358 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2359 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2360 silc_get_status_message(error));
2361 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2365 COMMAND_ERROR(error);
2370 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2372 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2375 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2376 1, idp->data, idp->len);
2377 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2378 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2379 silc_buffer_free(buffer);
2380 silc_buffer_free(idp);
2382 /* Notify application */
2383 COMMAND(SILC_STATUS_OK);
2386 silc_free(nickname);
2387 silc_client_command_free(cmd);
2390 /* Register a new command indicated by the `command' to the SILC client.
2391 The `name' is optional command name. If provided the command may be
2392 searched using the silc_client_command_find by that name. The
2393 `command_function' is the function to be called when the command is
2394 executed, and the `command_reply_function' is the function to be
2395 called after the server has sent reply back to the command.
2397 The `ident' is optional identifier for the command. If non-zero
2398 the `command_reply_function' for the command type `command' will be
2399 called only if the command reply sent by server includes the
2400 command identifier `ident'. Application usually does not need it
2401 and set it to zero value. */
2403 bool silc_client_command_register(SilcClient client,
2404 SilcCommand command,
2406 SilcCommandCb command_function,
2407 SilcCommandCb command_reply_function,
2411 SilcClientCommand cmd;
2413 cmd = silc_calloc(1, sizeof(*cmd));
2415 cmd->command = command_function;
2416 cmd->reply = command_reply_function;
2417 cmd->name = name ? strdup(name) : NULL;
2418 cmd->max_args = max_args;
2421 silc_list_add(client->internal->commands, cmd);
2426 /* Unregister a command indicated by the `command' with command function
2427 `command_function' and command reply function `command_reply_function'.
2428 Returns TRUE if the command was found and unregistered. */
2430 bool silc_client_command_unregister(SilcClient client,
2431 SilcCommand command,
2432 SilcCommandCb command_function,
2433 SilcCommandCb command_reply_function,
2436 SilcClientCommand cmd;
2438 silc_list_start(client->internal->commands);
2439 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2440 if (cmd->cmd == command && cmd->command == command_function &&
2441 cmd->reply == command_reply_function && cmd->ident == ident) {
2442 silc_list_del(client->internal->commands, cmd);
2443 silc_free(cmd->name);
2452 /* Private range commands, specific to this implementation (and compatible
2453 with SILC Server). */
2455 /* CONNECT command. Connects the server to another server. */
2457 SILC_CLIENT_CMD_FUNC(connect)
2459 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2460 SilcClientConnection conn = cmd->conn;
2462 unsigned char port[4];
2466 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2467 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2471 if (cmd->argc < 2) {
2472 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2473 "Usage: /CONNECT <server> [<port>]");
2474 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2478 if (cmd->argc == 3) {
2479 tmp = atoi(cmd->argv[2]);
2480 SILC_PUT32_MSB(tmp, port);
2484 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2486 strlen(cmd->argv[1]),
2489 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2491 strlen(cmd->argv[1]));
2492 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2493 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2494 silc_buffer_free(buffer);
2496 /* Notify application */
2497 COMMAND(SILC_STATUS_OK);
2500 silc_client_command_free(cmd);
2504 /* CLOSE command. Close server connection to the remote server */
2506 SILC_CLIENT_CMD_FUNC(close)
2508 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2509 SilcClientConnection conn = cmd->conn;
2511 unsigned char port[4];
2515 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2516 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2520 if (cmd->argc < 2) {
2521 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2522 "Usage: /CLOSE <server> [<port>]");
2523 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2527 if (cmd->argc == 3) {
2528 tmp = atoi(cmd->argv[2]);
2529 SILC_PUT32_MSB(tmp, port);
2533 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2535 strlen(cmd->argv[1]),
2538 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2540 strlen(cmd->argv[1]));
2541 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2542 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2543 silc_buffer_free(buffer);
2545 /* Notify application */
2546 COMMAND(SILC_STATUS_OK);
2549 silc_client_command_free(cmd);
2552 /* SHUTDOWN command. Shutdowns the server. */
2554 SILC_CLIENT_CMD_FUNC(shutdown)
2556 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2559 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2560 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2564 /* Send the command */
2565 silc_client_command_send(cmd->client, cmd->conn,
2566 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2568 /* Notify application */
2569 COMMAND(SILC_STATUS_OK);
2572 silc_client_command_free(cmd);
2575 /* Register all default commands provided by the client library for the
2578 void silc_client_commands_register(SilcClient client)
2580 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2583 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2584 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2585 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2586 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2587 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2588 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2589 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2590 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2591 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2592 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2593 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2594 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2595 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2596 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2597 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2598 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2599 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2600 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2601 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2602 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2603 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2604 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2605 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2606 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2607 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2608 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2610 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2611 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2612 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2615 /* Unregister all commands. */
2617 void silc_client_commands_unregister(SilcClient client)
2619 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2620 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2621 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2622 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2623 SILC_CLIENT_CMDU(list, LIST, "LIST");
2624 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2625 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2626 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2627 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2628 SILC_CLIENT_CMDU(info, INFO, "INFO");
2629 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2630 SILC_CLIENT_CMDU(ping, PING, "PING");
2631 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2632 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2633 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2634 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2635 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2636 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2637 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2638 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2639 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2640 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2641 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2642 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2643 SILC_CLIENT_CMDU(users, USERS, "USERS");
2644 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2646 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2647 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2648 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2651 /**** Client side incoming command handling **********************************/
2653 void silc_client_command_process_whois(SilcClient client,
2654 SilcSocketConnection sock,
2655 SilcCommandPayload payload,
2656 SilcArgumentPayload args);
2658 /* Client is able to receive some command packets even though they are
2659 special case. Server may send WHOIS command to the client to retrieve
2660 Requested Attributes information for WHOIS query the server is
2661 processing. This function currently handles only the WHOIS command,
2662 but if in the future for commands may arrive then this can be made
2663 to support other commands too. */
2665 void silc_client_command_process(SilcClient client,
2666 SilcSocketConnection sock,
2667 SilcPacketContext *packet)
2669 SilcCommandPayload payload;
2670 SilcCommand command;
2671 SilcArgumentPayload args;
2673 /* Get command payload from packet */
2674 payload = silc_command_payload_parse(packet->buffer->data,
2675 packet->buffer->len);
2677 /* Silently ignore bad reply packet */
2678 SILC_LOG_DEBUG(("Bad command packet"));
2683 args = silc_command_get_args(payload);
2685 /* Get the command */
2686 command = silc_command_get(payload);
2689 case SILC_COMMAND_WHOIS:
2690 /* Ignore everything if requested by application */
2691 if (client->internal->params->ignore_requested_attributes)
2694 silc_client_command_process_whois(client, sock, payload, args);
2701 silc_command_payload_free(payload);
2704 void silc_client_command_process_whois(SilcClient client,
2705 SilcSocketConnection sock,
2706 SilcCommandPayload payload,
2707 SilcArgumentPayload args)
2712 SilcBuffer buffer, packet;
2714 SILC_LOG_DEBUG(("Received WHOIS command"));
2716 /* Try to take the Requested Attributes */
2717 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2721 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2725 /* Process requested attributes */
2726 buffer = silc_client_attributes_process(client, sock, attrs);
2728 silc_attribute_payload_list_free(attrs);
2732 /* Send the attributes back */
2734 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2736 silc_command_get_ident(payload),
2737 1, 11, buffer->data, buffer->len);
2738 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2739 NULL, 0, NULL, NULL, packet->data,
2741 silc_buffer_free(packet);
2742 silc_buffer_free(buffer);