5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 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 SilcPublicKey pubkey = NULL;
629 char *nickname = NULL, *name;
631 unsigned char action[1];
634 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
635 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
640 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
641 "Usage: /INVITE <channel> [<nickname>[@server>]"
642 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
643 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
647 if (cmd->argv[1][0] == '*') {
648 if (!conn->current_channel) {
649 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
653 channel = conn->current_channel;
657 channel = silc_client_get_channel(cmd->client, conn, name);
659 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
664 /* Parse the typed nickname. */
665 if (cmd->argc == 3) {
666 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
667 if (client->internal->params->nickname_parse)
668 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
670 nickname = strdup(cmd->argv[2]);
672 /* Find client entry */
673 client_entry = silc_idlist_get_client(client, conn, nickname,
677 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
681 /* Client entry not found, it was requested thus mark this to be
683 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
685 silc_client_command_invite,
686 silc_client_command_dup(cmd));
691 if (cmd->argv[2][0] == '+')
696 /* Check if it is public key file to be added to invite list */
697 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
699 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
701 invite = cmd->argv[2];
708 args = silc_buffer_alloc_size(2);
709 silc_buffer_format(args,
710 SILC_STR_UI_SHORT(1),
713 chidp = silc_pkcs_public_key_payload_encode(pubkey);
714 args = silc_argument_payload_encode_one(args, chidp->data,
716 silc_buffer_free(chidp);
717 silc_pkcs_public_key_free(pubkey);
719 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
723 /* Send the command */
724 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
726 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
727 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
728 ++conn->cmd_ident, 4,
729 1, chidp->data, chidp->len,
730 2, clidp->data, clidp->len,
731 3, args ? action : NULL,
733 4, args ? args->data : NULL,
734 args ? args->len : 0);
735 silc_buffer_free(clidp);
737 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
738 ++conn->cmd_ident, 3,
739 1, chidp->data, chidp->len,
740 3, args ? action : NULL,
742 4, args ? args->data : NULL,
743 args ? args->len : 0);
746 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
747 0, NULL, NULL, buffer->data, buffer->len, TRUE);
748 silc_buffer_free(buffer);
749 silc_buffer_free(chidp);
750 silc_buffer_free(args),
752 /* Notify application */
753 COMMAND(SILC_STATUS_OK);
757 silc_client_command_free(cmd);
762 SilcClientConnection conn;
765 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
767 QuitInternal q = (QuitInternal)context;
769 /* Close connection */
770 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
771 silc_client_close_connection(q->client, q->conn->sock->user_data);
776 /* Command QUIT. Closes connection with current server. */
778 SILC_CLIENT_CMD_FUNC(quit)
780 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
785 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
786 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
791 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
792 &cmd->argv[1], &cmd->argv_lens[1],
793 &cmd->argv_types[1], 0);
795 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
796 NULL, NULL, NULL, 0);
797 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
799 buffer->data, buffer->len, TRUE);
800 silc_buffer_free(buffer);
802 q = silc_calloc(1, sizeof(*q));
803 q->client = cmd->client;
806 /* Sleep for a while */
809 /* We quit the connection with little timeout */
810 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
811 silc_client_command_quit_cb, (void *)q,
812 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
814 /* Notify application */
815 COMMAND(SILC_STATUS_OK);
818 silc_client_command_free(cmd);
821 /* Timeout callback to remove the killed client from cache */
823 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
825 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
826 SilcClient client = cmd->client;
827 SilcClientConnection conn = cmd->conn;
828 SilcClientEntry target;
829 char *nickname = NULL;
831 /* Parse the typed nickname. */
832 if (client->internal->params->nickname_parse)
833 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
835 nickname = strdup(cmd->argv[1]);
837 /* Get the target client */
838 target = silc_idlist_get_client(cmd->client, conn, nickname,
839 cmd->argv[1], FALSE);
841 /* Remove the client from all channels and free it */
842 silc_client_del_client(client, conn, target);
845 silc_client_command_free(cmd);
848 /* Kill command's pending command callback to actually remove the killed
849 client from our local cache. */
851 SILC_CLIENT_CMD_FUNC(kill_remove)
853 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
854 SilcClientCommandReplyContext reply =
855 (SilcClientCommandReplyContext)context2;
858 silc_command_get_status(reply->payload, &status, NULL);
859 if (status == SILC_STATUS_OK) {
860 /* Remove with timeout */
861 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
862 silc_client_command_kill_remove_later, context,
863 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
867 silc_client_command_free(cmd);
870 /* Command KILL. Router operator can use this command to remove an client
871 fromthe SILC Network. */
873 SILC_CLIENT_CMD_FUNC(kill)
875 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
876 SilcClient client = cmd->client;
877 SilcClientConnection conn = cmd->conn;
878 SilcBuffer buffer, idp, auth = NULL;
879 SilcClientEntry target;
880 char *nickname = NULL, *comment = NULL;
883 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
884 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
889 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
890 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
891 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
895 /* Parse the typed nickname. */
896 if (client->internal->params->nickname_parse)
897 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
899 nickname = strdup(cmd->argv[1]);
901 /* Get the target client */
902 target = silc_idlist_get_client(cmd->client, conn, nickname,
906 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
910 /* Client entry not found, it was requested thus mark this to be
912 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
914 silc_client_command_kill,
915 silc_client_command_dup(cmd));
920 if (cmd->argc >= 3) {
921 if (strcasecmp(cmd->argv[2], "-pubkey"))
922 comment = cmd->argv[2];
924 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
925 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
926 /* Encode the public key authentication payload */
927 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
928 cmd->client->private_key,
931 target->id, SILC_ID_CLIENT);
935 /* Send the KILL command to the server */
936 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
938 silc_command_payload_encode_va(SILC_COMMAND_KILL,
939 ++conn->cmd_ident, 3,
940 1, idp->data, idp->len,
941 2, comment, comment ? strlen(comment) : 0,
942 3, auth ? auth->data : NULL,
943 auth ? auth->len : 0);
944 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
945 0, NULL, NULL, buffer->data, buffer->len, TRUE);
946 silc_buffer_free(buffer);
947 silc_buffer_free(idp);
948 silc_buffer_free(auth);
950 /* Notify application */
951 COMMAND(SILC_STATUS_OK);
953 /* Register a pending callback that will actually remove the killed
954 client from our cache. */
955 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
956 silc_client_command_kill_remove,
957 silc_client_command_dup(cmd));
961 silc_client_command_free(cmd);
964 /* Command INFO. Request information about specific server. If specific
965 server is not provided the current server is used. */
967 SILC_CLIENT_CMD_FUNC(info)
969 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
970 SilcClientConnection conn = cmd->conn;
975 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
976 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
981 name = strdup(cmd->argv[1]);
983 /* Send the command */
985 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
986 1, name, strlen(name));
988 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
989 NULL, NULL, NULL, 0);
990 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
991 0, NULL, NULL, buffer->data, buffer->len, TRUE);
992 silc_buffer_free(buffer);
996 /* Notify application */
997 COMMAND(SILC_STATUS_OK);
1000 silc_client_command_free(cmd);
1003 /* Command STATS. Shows server and network statistics. */
1005 SILC_CLIENT_CMD_FUNC(stats)
1007 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1008 SilcClientConnection conn = cmd->conn;
1009 SilcBuffer buffer, idp = NULL;
1012 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1013 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1017 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1019 /* Send the command */
1020 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1021 ++conn->cmd_ident, 1,
1022 SILC_ID_SERVER, idp->data, idp->len);
1023 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1024 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1025 silc_buffer_free(buffer);
1026 silc_buffer_free(idp);
1028 /* Notify application */
1029 COMMAND(SILC_STATUS_OK);
1032 silc_client_command_free(cmd);
1035 /* Command PING. Sends ping to server. This is used to test the
1036 communication channel. */
1038 SILC_CLIENT_CMD_FUNC(ping)
1040 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1041 SilcClientConnection conn = cmd->conn;
1042 SilcBuffer buffer, idp;
1047 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1048 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1052 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1054 /* Send the command */
1055 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1056 1, idp->data, idp->len);
1057 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1058 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1059 silc_buffer_free(buffer);
1060 silc_buffer_free(idp);
1062 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1065 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1066 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1070 /* Start counting time */
1071 for (i = 0; i < conn->internal->ping_count; i++) {
1072 if (conn->internal->ping[i].dest_id == NULL) {
1073 conn->internal->ping[i].start_time = time(NULL);
1074 conn->internal->ping[i].dest_id = id;
1075 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1079 if (i >= conn->internal->ping_count) {
1080 i = conn->internal->ping_count;
1081 conn->internal->ping =
1082 silc_realloc(conn->internal->ping,
1083 sizeof(*conn->internal->ping) * (i + 1));
1084 conn->internal->ping[i].start_time = time(NULL);
1085 conn->internal->ping[i].dest_id = id;
1086 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1087 conn->internal->ping_count++;
1090 /* Notify application */
1091 COMMAND(SILC_STATUS_OK);
1094 silc_client_command_free(cmd);
1097 /* Command JOIN. Joins to a channel. */
1099 SILC_CLIENT_CMD_FUNC(join)
1101 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1102 SilcClientConnection conn = cmd->conn;
1103 SilcChannelEntry channel;
1104 SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
1105 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1106 int i, passphrase_len = 0;
1109 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1110 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1114 if (cmd->argc < 2) {
1115 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1119 /* See if we have joined to the requested channel already */
1120 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1121 if (channel && silc_client_on_channel(channel, conn->local_entry))
1124 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1126 if (cmd->argv_lens[1] > 256)
1127 cmd->argv_lens[1] = 256;
1129 name = cmd->argv[1];
1131 for (i = 2; i < cmd->argc; i++) {
1132 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1133 cipher = cmd->argv[i + 1];
1135 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1136 hmac = cmd->argv[i + 1];
1138 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1139 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1140 cmd->client->private_key,
1142 cmd->client->sha1hash,
1146 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1147 SilcPublicKey pubkey = cmd->client->public_key;
1148 SilcPrivateKey privkey = cmd->client->private_key;
1149 unsigned char *pk, pkhash[20], *pubdata;
1152 if (cmd->argc >= i + 3) {
1154 if (cmd->argc >= i + 4) {
1155 pass = cmd->argv[i + 3];
1158 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1159 NULL, &pubkey, &privkey)) {
1160 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1161 "Could not load key pair, check your arguments");
1162 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1168 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1169 silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
1171 pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
1172 memcpy(pubdata, pkhash, 20);
1173 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1175 cmd->client->sha1hash,
1178 memset(pubdata, 0, 128);
1182 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1183 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1184 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1185 cmd->argv_lens[i], 0);
1186 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1187 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1188 0, pu8, passphrase_len);
1191 passphrase = strdup(cmd->argv[i]);
1192 passphrase_len = cmd->argv_lens[i];
1197 /* Send JOIN command to the server */
1199 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 7,
1200 1, name, strlen(name),
1201 2, idp->data, idp->len,
1202 3, passphrase, passphrase_len,
1203 4, cipher, cipher ? strlen(cipher) : 0,
1204 5, hmac, hmac ? strlen(hmac) : 0,
1205 6, auth ? auth->data : NULL,
1206 auth ? auth->len : 0,
1207 7, cauth ? cauth->data : NULL,
1208 cauth ? cauth->len : 0);
1209 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1210 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1211 silc_buffer_free(buffer);
1212 silc_buffer_free(idp);
1213 silc_buffer_free(auth);
1214 silc_buffer_free(cauth);
1216 memset(passphrase, 0, strlen(passphrase));
1217 silc_free(passphrase);
1219 /* Notify application */
1220 COMMAND(SILC_STATUS_OK);
1223 silc_client_command_free(cmd);
1226 /* MOTD command. Requests motd from server. */
1228 SILC_CLIENT_CMD_FUNC(motd)
1230 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1231 SilcClientConnection conn = cmd->conn;
1235 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1236 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1240 if (cmd->argc < 1 || cmd->argc > 2) {
1241 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1242 "Usage: /MOTD [<server>]");
1243 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1244 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1248 /* Send TOPIC command to the server */
1250 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1251 1, conn->remote_host,
1252 strlen(conn->remote_host));
1254 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1257 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1258 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1259 silc_buffer_free(buffer);
1261 /* Notify application */
1262 COMMAND(SILC_STATUS_OK);
1265 silc_client_command_free(cmd);
1268 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1269 modes as client cannot set itself server/router operator privileges. */
1271 SILC_CLIENT_CMD_FUNC(umode)
1273 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1274 SilcClientConnection conn = cmd->conn;
1275 SilcBuffer buffer, idp;
1276 unsigned char *cp, modebuf[4];
1277 SilcUInt32 mode, add, len;
1281 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1282 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1286 if (cmd->argc < 2) {
1287 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1288 "Usage: /UMODE +|-<modes>");
1289 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1293 mode = conn->local_entry->mode;
1295 /* Are we adding or removing mode */
1296 if (cmd->argv[1][0] == '-')
1302 cp = cmd->argv[1] + 1;
1304 for (i = 0; i < len; i++) {
1309 mode |= SILC_UMODE_SERVER_OPERATOR;
1310 mode |= SILC_UMODE_ROUTER_OPERATOR;
1311 mode |= SILC_UMODE_GONE;
1312 mode |= SILC_UMODE_INDISPOSED;
1313 mode |= SILC_UMODE_BUSY;
1314 mode |= SILC_UMODE_PAGE;
1315 mode |= SILC_UMODE_HYPER;
1316 mode |= SILC_UMODE_ROBOT;
1317 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1318 mode |= SILC_UMODE_REJECT_WATCHING;
1320 mode = SILC_UMODE_NONE;
1325 mode |= SILC_UMODE_SERVER_OPERATOR;
1327 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1331 mode |= SILC_UMODE_ROUTER_OPERATOR;
1333 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1337 mode |= SILC_UMODE_GONE;
1339 mode &= ~SILC_UMODE_GONE;
1343 mode |= SILC_UMODE_INDISPOSED;
1345 mode &= ~SILC_UMODE_INDISPOSED;
1349 mode |= SILC_UMODE_BUSY;
1351 mode &= ~SILC_UMODE_BUSY;
1355 mode |= SILC_UMODE_PAGE;
1357 mode &= ~SILC_UMODE_PAGE;
1361 mode |= SILC_UMODE_HYPER;
1363 mode &= ~SILC_UMODE_HYPER;
1367 mode |= SILC_UMODE_ROBOT;
1369 mode &= ~SILC_UMODE_ROBOT;
1373 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1375 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1379 mode |= SILC_UMODE_REJECT_WATCHING;
1381 mode &= ~SILC_UMODE_REJECT_WATCHING;
1385 mode |= SILC_UMODE_BLOCK_INVITE;
1387 mode &= ~SILC_UMODE_BLOCK_INVITE;
1390 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1396 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1397 SILC_PUT32_MSB(mode, modebuf);
1399 /* Send the command packet. We support sending only one mode at once
1400 that requires an argument. */
1402 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1403 1, idp->data, idp->len,
1404 2, modebuf, sizeof(modebuf));
1405 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1406 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1407 silc_buffer_free(buffer);
1408 silc_buffer_free(idp);
1410 /* Notify application */
1411 COMMAND(SILC_STATUS_OK);
1414 silc_client_command_free(cmd);
1417 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1418 can be set several at once. Those modes that require argument must be set
1419 separately (unless set with modes that does not require arguments). */
1421 SILC_CLIENT_CMD_FUNC(cmode)
1423 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1424 SilcClientConnection conn = cmd->conn;
1425 SilcChannelEntry channel;
1426 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1427 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1428 SilcUInt32 mode, add, type, len, arg_len = 0;
1432 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1433 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1437 if (cmd->argc < 3) {
1438 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1439 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1440 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1444 if (cmd->argv[1][0] == '*') {
1445 if (!conn->current_channel) {
1446 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1450 channel = conn->current_channel;
1452 name = cmd->argv[1];
1454 channel = silc_client_get_channel(cmd->client, conn, name);
1456 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1461 mode = channel->mode;
1463 /* Are we adding or removing mode */
1464 if (cmd->argv[2][0] == '-')
1469 /* Argument type to be sent to server */
1473 cp = cmd->argv[2] + 1;
1475 for (i = 0; i < len; i++) {
1479 mode |= SILC_CHANNEL_MODE_PRIVATE;
1481 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1485 mode |= SILC_CHANNEL_MODE_SECRET;
1487 mode &= ~SILC_CHANNEL_MODE_SECRET;
1491 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1493 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1497 mode |= SILC_CHANNEL_MODE_INVITE;
1499 mode &= ~SILC_CHANNEL_MODE_INVITE;
1503 mode |= SILC_CHANNEL_MODE_TOPIC;
1505 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1509 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1511 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1515 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1517 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1522 mode |= SILC_CHANNEL_MODE_ULIMIT;
1524 if (cmd->argc < 4) {
1525 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1526 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1527 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1530 ll = atoi(cmd->argv[3]);
1531 SILC_PUT32_MSB(ll, tmp);
1535 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1540 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1542 if (cmd->argc < 4) {
1543 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1544 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1545 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1549 arg_len = cmd->argv_lens[3];
1551 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1556 mode |= SILC_CHANNEL_MODE_CIPHER;
1558 if (cmd->argc < 4) {
1559 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1560 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1561 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1565 arg_len = cmd->argv_lens[3];
1567 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1572 mode |= SILC_CHANNEL_MODE_HMAC;
1574 if (cmd->argc < 4) {
1575 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1576 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1577 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1581 arg_len = cmd->argv_lens[3];
1583 mode &= ~SILC_CHANNEL_MODE_HMAC;
1588 SilcPublicKey pubkey = cmd->client->public_key;
1589 SilcPrivateKey privkey = cmd->client->private_key;
1591 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1594 if (cmd->argc >= 5) {
1597 pass = cmd->argv[5];
1598 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1599 NULL, &pubkey, &privkey)) {
1600 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1601 "Could not load key pair, check your arguments");
1602 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1607 pk = silc_pkcs_public_key_payload_encode(pubkey);
1608 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1610 cmd->client->sha1hash,
1614 arg_len = auth->len;
1616 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1623 SilcPublicKey chpk = NULL;
1625 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1628 if (cmd->argc == 3) {
1629 /* Send empty command to receive the public key list. */
1630 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1631 silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
1632 0, 1, 1, chidp->data, chidp->len);
1633 silc_buffer_free(chidp);
1635 /* Notify application */
1636 COMMAND(SILC_STATUS_OK);
1640 if (cmd->argc >= 4) {
1641 auth = silc_buffer_alloc_size(2);
1642 silc_buffer_format(auth,
1643 SILC_STR_UI_SHORT(cmd->argc - 3),
1647 for (k = 3; k < cmd->argc; k++) {
1648 if (cmd->argv[k][0] == '+')
1650 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1651 SILC_PKCS_FILE_PEM))
1652 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1653 SILC_PKCS_FILE_BIN)) {
1654 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1655 "Could not load public key %s, check the filename",
1657 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1658 silc_buffer_free(auth);
1663 pk = silc_pkcs_public_key_payload_encode(chpk);
1664 auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
1665 chadd ? 0x00 : 0x01);
1666 silc_pkcs_public_key_free(chpk);
1667 silc_buffer_free(pk);
1673 arg_len = auth->len;
1675 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1679 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1685 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1686 SILC_PUT32_MSB(mode, modebuf);
1688 /* Send the command packet. We support sending only one mode at once
1689 that requires an argument. */
1692 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
1693 1, chidp->data, chidp->len,
1694 2, modebuf, sizeof(modebuf),
1696 8, pk ? pk->data : NULL,
1700 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1701 1, chidp->data, chidp->len,
1702 2, modebuf, sizeof(modebuf));
1705 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1706 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1707 silc_buffer_free(buffer);
1708 silc_buffer_free(chidp);
1709 silc_buffer_free(auth);
1710 silc_buffer_free(pk);
1712 /* Notify application */
1713 COMMAND(SILC_STATUS_OK);
1716 silc_client_command_free(cmd);
1719 /* CUMODE command. Changes client's mode on a channel. */
1721 SILC_CLIENT_CMD_FUNC(cumode)
1723 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1724 SilcClient client = cmd->client;
1725 SilcClientConnection conn = cmd->conn;
1726 SilcChannelEntry channel;
1727 SilcChannelUser chu;
1728 SilcClientEntry client_entry;
1729 SilcBuffer buffer, clidp, chidp, auth = NULL;
1730 unsigned char *name, *cp, modebuf[4];
1731 SilcUInt32 mode = 0, add, len;
1732 char *nickname = NULL;
1736 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1737 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1741 if (cmd->argc < 4) {
1742 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1743 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1744 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1748 if (cmd->argv[1][0] == '*') {
1749 if (!conn->current_channel) {
1750 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1754 channel = conn->current_channel;
1756 name = cmd->argv[1];
1758 channel = silc_client_get_channel(cmd->client, conn, name);
1760 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1765 /* Parse the typed nickname. */
1766 if (client->internal->params->nickname_parse)
1767 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1769 nickname = strdup(cmd->argv[3]);
1771 /* Find client entry */
1772 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1773 cmd->argv[3], TRUE);
1774 if (!client_entry) {
1776 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1780 /* Client entry not found, it was requested thus mark this to be
1782 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1784 silc_client_command_cumode,
1785 silc_client_command_dup(cmd));
1790 /* Get the current mode */
1791 chu = silc_client_on_channel(channel, client_entry);
1795 /* Are we adding or removing mode */
1796 if (cmd->argv[2][0] == '-')
1802 cp = cmd->argv[2] + 1;
1804 for (i = 0; i < len; i++) {
1808 mode |= SILC_CHANNEL_UMODE_CHANFO;
1809 mode |= SILC_CHANNEL_UMODE_CHANOP;
1810 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1811 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1812 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1814 mode = SILC_CHANNEL_UMODE_NONE;
1819 SilcPublicKey pubkey = cmd->client->public_key;
1820 SilcPrivateKey privkey = cmd->client->private_key;
1822 if (cmd->argc >= 6) {
1825 pass = cmd->argv[6];
1826 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1827 NULL, &pubkey, &privkey)) {
1828 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1829 "Could not load key pair, check your arguments");
1830 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1835 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1837 cmd->client->sha1hash,
1840 mode |= SILC_CHANNEL_UMODE_CHANFO;
1842 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1847 mode |= SILC_CHANNEL_UMODE_CHANOP;
1849 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1853 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1855 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1859 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1861 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1865 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1867 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1871 mode |= SILC_CHANNEL_UMODE_QUIET;
1873 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1876 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1882 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1883 SILC_PUT32_MSB(mode, modebuf);
1884 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1886 /* Send the command packet. We support sending only one mode at once
1887 that requires an argument. */
1888 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1890 1, chidp->data, chidp->len,
1892 3, clidp->data, clidp->len,
1893 4, auth ? auth->data : NULL,
1894 auth ? auth->len : 0);
1896 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1897 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1898 silc_buffer_free(buffer);
1899 silc_buffer_free(chidp);
1900 silc_buffer_free(clidp);
1902 silc_buffer_free(auth);
1904 /* Notify application */
1905 COMMAND(SILC_STATUS_OK);
1908 silc_free(nickname);
1909 silc_client_command_free(cmd);
1912 /* KICK command. Kicks a client out of channel. */
1914 SILC_CLIENT_CMD_FUNC(kick)
1916 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1917 SilcClient client = cmd->client;
1918 SilcClientConnection conn = cmd->conn;
1919 SilcIDCacheEntry id_cache = NULL;
1920 SilcChannelEntry channel;
1921 SilcBuffer buffer, idp, idp2;
1922 SilcClientEntry target;
1924 char *nickname = NULL;
1927 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1928 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1932 if (cmd->argc < 3) {
1933 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1934 "Usage: /KICK <channel> <nickname> [<comment>]");
1935 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1939 if (cmd->argv[1][0] == '*') {
1940 if (!conn->current_channel) {
1941 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1944 name = conn->current_channel->channel_name;
1946 name = cmd->argv[1];
1949 if (!conn->current_channel) {
1950 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1954 /* Get the Channel ID of the channel */
1955 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1957 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1961 channel = (SilcChannelEntry)id_cache->context;
1963 /* Parse the typed nickname. */
1964 if (client->internal->params->nickname_parse)
1965 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1967 nickname = strdup(cmd->argv[2]);
1969 /* Get the target client */
1970 target = silc_idlist_get_client(cmd->client, conn, nickname,
1971 cmd->argv[2], FALSE);
1973 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1974 "No such client: %s", cmd->argv[2]);
1975 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1979 /* Send KICK command to the server */
1980 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1981 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1983 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1984 1, idp->data, idp->len,
1985 2, idp2->data, idp2->len);
1987 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1988 1, idp->data, idp->len,
1989 2, idp2->data, idp2->len,
1991 strlen(cmd->argv[3]));
1992 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1993 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1994 silc_buffer_free(buffer);
1995 silc_buffer_free(idp);
1996 silc_buffer_free(idp2);
1998 /* Notify application */
1999 COMMAND(SILC_STATUS_OK);
2002 silc_free(nickname);
2003 silc_client_command_free(cmd);
2006 static void silc_client_command_oper_send(unsigned char *data,
2007 SilcUInt32 data_len, void *context)
2009 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2010 SilcClientConnection conn = cmd->conn;
2011 SilcBuffer buffer, auth;
2013 if (cmd->argc >= 3) {
2014 /* Encode the public key authentication payload */
2015 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2016 cmd->client->private_key,
2018 conn->internal->hash,
2022 /* Encode the password authentication payload */
2023 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2027 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
2029 strlen(cmd->argv[1]),
2030 2, auth ? auth->data : NULL,
2031 auth ? auth->len : 0);
2032 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2033 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2035 silc_buffer_free(buffer);
2036 silc_buffer_clear(auth);
2037 silc_buffer_free(auth);
2039 /* Notify application */
2040 COMMAND(SILC_STATUS_OK);
2043 /* OPER command. Used to obtain server operator privileges. */
2045 SILC_CLIENT_CMD_FUNC(oper)
2047 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2048 SilcClientConnection conn = cmd->conn;
2051 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2052 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2056 if (cmd->argc < 2) {
2057 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2058 "Usage: /OPER <username> [-pubkey]");
2059 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2063 if (cmd->argc < 3) {
2064 /* Get passphrase */
2065 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2066 silc_client_command_oper_send,
2071 silc_client_command_oper_send(NULL, 0, context);
2074 silc_client_command_free(cmd);
2077 static void silc_client_command_silcoper_send(unsigned char *data,
2078 SilcUInt32 data_len,
2081 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2082 SilcClientConnection conn = cmd->conn;
2083 SilcBuffer buffer, auth;
2085 if (cmd->argc >= 3) {
2086 /* Encode the public key authentication payload */
2087 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2088 cmd->client->private_key,
2090 conn->internal->hash,
2094 /* Encode the password authentication payload */
2095 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2099 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
2101 strlen(cmd->argv[1]),
2102 2, auth ? auth->data : NULL,
2103 auth ? auth->len : 0);
2104 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2105 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2107 silc_buffer_free(buffer);
2108 silc_buffer_clear(auth);
2109 silc_buffer_free(auth);
2111 /* Notify application */
2112 COMMAND(SILC_STATUS_OK);
2115 /* SILCOPER command. Used to obtain router operator privileges. */
2117 SILC_CLIENT_CMD_FUNC(silcoper)
2119 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2120 SilcClientConnection conn = cmd->conn;
2123 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2124 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2128 if (cmd->argc < 2) {
2129 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2130 "Usage: /SILCOPER <username> [-pubkey]");
2131 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2135 if (cmd->argc < 3) {
2136 /* Get passphrase */
2137 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2138 silc_client_command_silcoper_send,
2143 silc_client_command_silcoper_send(NULL, 0, context);
2146 silc_client_command_free(cmd);
2149 /* Command BAN. This is used to manage the ban list of the channel. */
2151 SILC_CLIENT_CMD_FUNC(ban)
2153 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2154 SilcClientConnection conn = cmd->conn;
2155 SilcChannelEntry channel;
2156 SilcBuffer buffer, chidp, args = NULL;
2157 char *name, *ban = NULL;
2158 unsigned char action[1];
2159 SilcPublicKey pubkey = NULL;
2162 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2163 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2167 if (cmd->argc < 2) {
2168 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2169 "Usage: /BAN <channel> "
2170 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2171 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2175 if (cmd->argv[1][0] == '*') {
2176 if (!conn->current_channel) {
2177 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2181 channel = conn->current_channel;
2183 name = cmd->argv[1];
2185 channel = silc_client_get_channel(cmd->client, conn, name);
2187 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2192 if (cmd->argc == 3) {
2193 if (cmd->argv[2][0] == '+')
2198 /* Check if it is public key file to be added to invite list */
2199 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2200 SILC_PKCS_FILE_PEM))
2201 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2202 SILC_PKCS_FILE_BIN);
2209 args = silc_buffer_alloc_size(2);
2210 silc_buffer_format(args,
2211 SILC_STR_UI_SHORT(1),
2214 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2215 args = silc_argument_payload_encode_one(args, chidp->data,
2217 silc_buffer_free(chidp);
2218 silc_pkcs_public_key_free(pubkey);
2220 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2224 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2226 /* Send the command */
2227 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2228 ++conn->cmd_ident, 3,
2229 1, chidp->data, chidp->len,
2230 2, args ? action : NULL,
2232 3, args ? args->data : NULL,
2233 args ? args->len : 0);
2234 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2235 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2236 silc_buffer_free(buffer);
2237 silc_buffer_free(chidp);
2238 silc_buffer_free(args);
2240 /* Notify application */
2241 COMMAND(SILC_STATUS_OK);
2244 silc_client_command_free(cmd);
2247 /* Command DETACH. This is used to detach from the server */
2249 SILC_CLIENT_CMD_FUNC(detach)
2251 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2252 SilcClientConnection conn = cmd->conn;
2256 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2257 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2261 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2262 ++conn->cmd_ident, 0);
2263 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2264 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2265 silc_buffer_free(buffer);
2267 /* Notify application */
2268 COMMAND(SILC_STATUS_OK);
2271 silc_client_command_free(cmd);
2274 /* Command WATCH. */
2276 SILC_CLIENT_CMD_FUNC(watch)
2278 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2279 SilcClientConnection conn = cmd->conn;
2280 SilcBuffer buffer, idp = NULL;
2284 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2285 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2289 if (cmd->argc < 3) {
2290 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2294 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2296 if (!strcasecmp(cmd->argv[1], "-add")) {
2298 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2301 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2305 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2306 ++conn->cmd_ident, 2,
2307 1, idp->data, idp->len,
2310 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2311 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2312 silc_buffer_free(buffer);
2314 /* Notify application */
2315 COMMAND(SILC_STATUS_OK);
2319 silc_buffer_free(idp);
2320 silc_client_command_free(cmd);
2323 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2325 SILC_CLIENT_CMD_FUNC(leave)
2327 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2328 SilcClientConnection conn = cmd->conn;
2329 SilcChannelEntry channel;
2330 SilcBuffer buffer, idp;
2334 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2335 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2339 if (cmd->argc != 2) {
2340 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2341 "Usage: /LEAVE <channel>");
2342 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2346 if (cmd->argv[1][0] == '*') {
2347 if (!conn->current_channel) {
2348 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2351 name = conn->current_channel->channel_name;
2353 name = cmd->argv[1];
2356 /* Get the channel entry */
2357 channel = silc_client_get_channel(cmd->client, conn, name);
2359 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2363 /* Send LEAVE command to the server */
2364 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2365 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2366 1, idp->data, idp->len);
2367 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2368 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2369 silc_buffer_free(buffer);
2370 silc_buffer_free(idp);
2372 /* Notify application */
2373 COMMAND(SILC_STATUS_OK);
2375 if (conn->current_channel == channel)
2376 conn->current_channel = NULL;
2379 silc_client_command_free(cmd);
2382 /* Command USERS. Requests the USERS of the clients joined on requested
2385 SILC_CLIENT_CMD_FUNC(users)
2387 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2388 SilcClientConnection conn = cmd->conn;
2393 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2394 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2398 if (cmd->argc != 2) {
2399 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2400 "Usage: /USERS <channel>");
2401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2405 if (cmd->argv[1][0] == '*') {
2406 if (!conn->current_channel) {
2407 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2410 name = conn->current_channel->channel_name;
2412 name = cmd->argv[1];
2415 /* Send USERS command to the server */
2416 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2417 ++conn->cmd_ident, 1,
2418 2, name, strlen(name));
2419 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2420 NULL, 0, NULL, NULL, buffer->data,
2422 silc_buffer_free(buffer);
2424 /* Notify application */
2425 COMMAND(SILC_STATUS_OK);
2428 silc_client_command_free(cmd);
2431 /* Command GETKEY. Used to fetch remote client's public key. */
2433 SILC_CLIENT_CMD_FUNC(getkey)
2435 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2436 SilcClientConnection conn = cmd->conn;
2437 SilcClient client = cmd->client;
2438 SilcClientEntry client_entry = NULL;
2439 SilcServerEntry server_entry = NULL;
2440 char *nickname = NULL;
2441 SilcBuffer idp, buffer;
2443 SILC_LOG_DEBUG(("Start"));
2446 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2447 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2451 if (cmd->argc < 2) {
2452 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2453 "Usage: /GETKEY <nickname or server name>");
2454 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2458 /* Parse the typed nickname. */
2459 if (client->internal->params->nickname_parse)
2460 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2462 nickname = strdup(cmd->argv[1]);
2464 /* Find client entry */
2465 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2467 if (!client_entry) {
2468 /* Check whether user requested server actually */
2469 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2471 if (!server_entry) {
2472 /* No. what ever user wants we don't have it, so resolve it. We
2473 will first try to resolve the client, and if that fails then
2474 we'll try to resolve the server. */
2476 if (!cmd->pending) {
2477 /* This will send the IDENTIFY command for nickname */
2478 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2479 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2481 silc_client_command_getkey,
2482 silc_client_command_dup(cmd));
2486 SilcClientCommandReplyContext reply =
2487 (SilcClientCommandReplyContext)context2;
2490 /* If nickname was not found, then resolve the server. */
2491 silc_command_get_status(reply->payload, NULL, &error);
2492 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2493 /* This sends the IDENTIFY command to resolve the server. */
2494 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2496 silc_client_command_reply_identify_i, 0,
2498 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2500 2, cmd->argv[1], cmd->argv_lens[1]);
2501 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2503 silc_client_command_getkey,
2504 silc_client_command_dup(cmd));
2508 /* If server was not found, then we've resolved both nickname and
2509 server and did not find anybody. */
2510 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2511 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2512 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2513 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2514 silc_get_status_message(error));
2515 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2519 COMMAND_ERROR(error);
2524 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2526 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2529 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2530 1, idp->data, idp->len);
2531 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2532 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2533 silc_buffer_free(buffer);
2534 silc_buffer_free(idp);
2536 /* Notify application */
2537 COMMAND(SILC_STATUS_OK);
2540 silc_free(nickname);
2541 silc_client_command_free(cmd);
2544 /* Register a new command indicated by the `command' to the SILC client.
2545 The `name' is optional command name. If provided the command may be
2546 searched using the silc_client_command_find by that name. The
2547 `command_function' is the function to be called when the command is
2548 executed, and the `command_reply_function' is the function to be
2549 called after the server has sent reply back to the command.
2551 The `ident' is optional identifier for the command. If non-zero
2552 the `command_reply_function' for the command type `command' will be
2553 called only if the command reply sent by server includes the
2554 command identifier `ident'. Application usually does not need it
2555 and set it to zero value. */
2557 bool silc_client_command_register(SilcClient client,
2558 SilcCommand command,
2560 SilcCommandCb command_function,
2561 SilcCommandCb command_reply_function,
2565 SilcClientCommand cmd;
2567 cmd = silc_calloc(1, sizeof(*cmd));
2569 cmd->command = command_function;
2570 cmd->reply = command_reply_function;
2571 cmd->name = name ? strdup(name) : NULL;
2572 cmd->max_args = max_args;
2575 silc_list_add(client->internal->commands, cmd);
2580 /* Unregister a command indicated by the `command' with command function
2581 `command_function' and command reply function `command_reply_function'.
2582 Returns TRUE if the command was found and unregistered. */
2584 bool silc_client_command_unregister(SilcClient client,
2585 SilcCommand command,
2586 SilcCommandCb command_function,
2587 SilcCommandCb command_reply_function,
2590 SilcClientCommand cmd;
2592 silc_list_start(client->internal->commands);
2593 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2594 if (cmd->cmd == command && cmd->command == command_function &&
2595 cmd->reply == command_reply_function && cmd->ident == ident) {
2596 silc_list_del(client->internal->commands, cmd);
2597 silc_free(cmd->name);
2606 /* Private range commands, specific to this implementation (and compatible
2607 with SILC Server). */
2609 /* CONNECT command. Connects the server to another server. */
2611 SILC_CLIENT_CMD_FUNC(connect)
2613 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2614 SilcClientConnection conn = cmd->conn;
2616 unsigned char port[4];
2620 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2621 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2625 if (cmd->argc < 2) {
2626 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2627 "Usage: /CONNECT <server> [<port>]");
2628 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2632 if (cmd->argc == 3) {
2633 tmp = atoi(cmd->argv[2]);
2634 SILC_PUT32_MSB(tmp, port);
2638 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2640 strlen(cmd->argv[1]),
2643 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2645 strlen(cmd->argv[1]));
2646 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2647 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2648 silc_buffer_free(buffer);
2650 /* Notify application */
2651 COMMAND(SILC_STATUS_OK);
2654 silc_client_command_free(cmd);
2658 /* CLOSE command. Close server connection to the remote server */
2660 SILC_CLIENT_CMD_FUNC(close)
2662 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2663 SilcClientConnection conn = cmd->conn;
2665 unsigned char port[4];
2669 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2670 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2674 if (cmd->argc < 2) {
2675 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2676 "Usage: /CLOSE <server> [<port>]");
2677 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2681 if (cmd->argc == 3) {
2682 tmp = atoi(cmd->argv[2]);
2683 SILC_PUT32_MSB(tmp, port);
2687 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2689 strlen(cmd->argv[1]),
2692 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2694 strlen(cmd->argv[1]));
2695 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2696 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2697 silc_buffer_free(buffer);
2699 /* Notify application */
2700 COMMAND(SILC_STATUS_OK);
2703 silc_client_command_free(cmd);
2706 /* SHUTDOWN command. Shutdowns the server. */
2708 SILC_CLIENT_CMD_FUNC(shutdown)
2710 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2713 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2714 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2718 /* Send the command */
2719 silc_client_command_send(cmd->client, cmd->conn,
2720 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2722 /* Notify application */
2723 COMMAND(SILC_STATUS_OK);
2726 silc_client_command_free(cmd);
2729 /* Register all default commands provided by the client library for the
2732 void silc_client_commands_register(SilcClient client)
2734 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2737 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2738 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2739 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2740 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2741 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2742 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2743 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2744 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2745 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2746 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2747 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2748 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2749 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2750 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2751 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2752 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2753 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2754 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2755 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2756 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2757 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2758 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2759 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2760 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2761 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2762 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2764 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2765 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2766 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2769 /* Unregister all commands. */
2771 void silc_client_commands_unregister(SilcClient client)
2773 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2774 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2775 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2776 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2777 SILC_CLIENT_CMDU(list, LIST, "LIST");
2778 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2779 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2780 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2781 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2782 SILC_CLIENT_CMDU(info, INFO, "INFO");
2783 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2784 SILC_CLIENT_CMDU(ping, PING, "PING");
2785 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2786 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2787 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2788 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2789 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2790 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2791 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2792 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2793 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2794 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2795 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2796 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2797 SILC_CLIENT_CMDU(users, USERS, "USERS");
2798 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2800 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2801 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2802 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2805 /**** Client side incoming command handling **********************************/
2807 void silc_client_command_process_whois(SilcClient client,
2808 SilcSocketConnection sock,
2809 SilcCommandPayload payload,
2810 SilcArgumentPayload args);
2812 /* Client is able to receive some command packets even though they are
2813 special case. Server may send WHOIS command to the client to retrieve
2814 Requested Attributes information for WHOIS query the server is
2815 processing. This function currently handles only the WHOIS command,
2816 but if in the future for commands may arrive then this can be made
2817 to support other commands too. */
2819 void silc_client_command_process(SilcClient client,
2820 SilcSocketConnection sock,
2821 SilcPacketContext *packet)
2823 SilcCommandPayload payload;
2824 SilcCommand command;
2825 SilcArgumentPayload args;
2827 /* Get command payload from packet */
2828 payload = silc_command_payload_parse(packet->buffer->data,
2829 packet->buffer->len);
2831 /* Silently ignore bad reply packet */
2832 SILC_LOG_DEBUG(("Bad command packet"));
2837 args = silc_command_get_args(payload);
2839 /* Get the command */
2840 command = silc_command_get(payload);
2843 case SILC_COMMAND_WHOIS:
2844 /* Ignore everything if requested by application */
2845 if (client->internal->params->ignore_requested_attributes)
2848 silc_client_command_process_whois(client, sock, payload, args);
2855 silc_command_payload_free(payload);
2858 void silc_client_command_process_whois(SilcClient client,
2859 SilcSocketConnection sock,
2860 SilcCommandPayload payload,
2861 SilcArgumentPayload args)
2866 SilcBuffer buffer, packet;
2868 SILC_LOG_DEBUG(("Received WHOIS command"));
2870 /* Try to take the Requested Attributes */
2871 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2875 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2879 /* Process requested attributes */
2880 buffer = silc_client_attributes_process(client, sock, attrs);
2882 silc_attribute_payload_list_free(attrs);
2886 /* Send the attributes back */
2888 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2890 silc_command_get_ident(payload),
2891 1, 11, buffer->data, buffer->len);
2892 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2893 NULL, 0, NULL, NULL, packet->data,
2895 silc_buffer_free(packet);
2896 silc_buffer_free(buffer);