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 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;
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,
1147 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1148 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1149 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1150 cmd->argv_lens[i], 0);
1151 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1152 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1153 0, pu8, passphrase_len);
1156 passphrase = strdup(cmd->argv[i]);
1157 passphrase_len = cmd->argv_lens[i];
1162 /* Send JOIN command to the server */
1164 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1165 1, name, strlen(name),
1166 2, idp->data, idp->len,
1167 3, passphrase, passphrase_len,
1168 4, cipher, cipher ? strlen(cipher) : 0,
1169 5, hmac, hmac ? strlen(hmac) : 0,
1170 6, auth ? auth->data : NULL,
1171 auth ? auth->len : 0);
1172 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1173 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1174 silc_buffer_free(buffer);
1175 silc_buffer_free(idp);
1177 silc_buffer_free(auth);
1179 memset(passphrase, 0, strlen(passphrase));
1180 silc_free(passphrase);
1182 /* Notify application */
1183 COMMAND(SILC_STATUS_OK);
1186 silc_client_command_free(cmd);
1189 /* MOTD command. Requests motd from server. */
1191 SILC_CLIENT_CMD_FUNC(motd)
1193 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1194 SilcClientConnection conn = cmd->conn;
1198 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1199 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1203 if (cmd->argc < 1 || cmd->argc > 2) {
1204 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1205 "Usage: /MOTD [<server>]");
1206 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1207 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1211 /* Send TOPIC command to the server */
1213 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1214 1, conn->remote_host,
1215 strlen(conn->remote_host));
1217 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1220 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1221 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1222 silc_buffer_free(buffer);
1224 /* Notify application */
1225 COMMAND(SILC_STATUS_OK);
1228 silc_client_command_free(cmd);
1231 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1232 modes as client cannot set itself server/router operator privileges. */
1234 SILC_CLIENT_CMD_FUNC(umode)
1236 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1237 SilcClientConnection conn = cmd->conn;
1238 SilcBuffer buffer, idp;
1239 unsigned char *cp, modebuf[4];
1240 SilcUInt32 mode, add, len;
1244 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1245 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1249 if (cmd->argc < 2) {
1250 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1251 "Usage: /UMODE +|-<modes>");
1252 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1256 mode = conn->local_entry->mode;
1258 /* Are we adding or removing mode */
1259 if (cmd->argv[1][0] == '-')
1265 cp = cmd->argv[1] + 1;
1267 for (i = 0; i < len; i++) {
1272 mode |= SILC_UMODE_SERVER_OPERATOR;
1273 mode |= SILC_UMODE_ROUTER_OPERATOR;
1274 mode |= SILC_UMODE_GONE;
1275 mode |= SILC_UMODE_INDISPOSED;
1276 mode |= SILC_UMODE_BUSY;
1277 mode |= SILC_UMODE_PAGE;
1278 mode |= SILC_UMODE_HYPER;
1279 mode |= SILC_UMODE_ROBOT;
1280 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1281 mode |= SILC_UMODE_REJECT_WATCHING;
1283 mode = SILC_UMODE_NONE;
1288 mode |= SILC_UMODE_SERVER_OPERATOR;
1290 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1294 mode |= SILC_UMODE_ROUTER_OPERATOR;
1296 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1300 mode |= SILC_UMODE_GONE;
1302 mode &= ~SILC_UMODE_GONE;
1306 mode |= SILC_UMODE_INDISPOSED;
1308 mode &= ~SILC_UMODE_INDISPOSED;
1312 mode |= SILC_UMODE_BUSY;
1314 mode &= ~SILC_UMODE_BUSY;
1318 mode |= SILC_UMODE_PAGE;
1320 mode &= ~SILC_UMODE_PAGE;
1324 mode |= SILC_UMODE_HYPER;
1326 mode &= ~SILC_UMODE_HYPER;
1330 mode |= SILC_UMODE_ROBOT;
1332 mode &= ~SILC_UMODE_ROBOT;
1336 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1338 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1342 mode |= SILC_UMODE_REJECT_WATCHING;
1344 mode &= ~SILC_UMODE_REJECT_WATCHING;
1348 mode |= SILC_UMODE_BLOCK_INVITE;
1350 mode &= ~SILC_UMODE_BLOCK_INVITE;
1353 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1359 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1360 SILC_PUT32_MSB(mode, modebuf);
1362 /* Send the command packet. We support sending only one mode at once
1363 that requires an argument. */
1365 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1366 1, idp->data, idp->len,
1367 2, modebuf, sizeof(modebuf));
1368 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1369 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1370 silc_buffer_free(buffer);
1371 silc_buffer_free(idp);
1373 /* Notify application */
1374 COMMAND(SILC_STATUS_OK);
1377 silc_client_command_free(cmd);
1380 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1381 can be set several at once. Those modes that require argument must be set
1382 separately (unless set with modes that does not require arguments). */
1384 SILC_CLIENT_CMD_FUNC(cmode)
1386 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1387 SilcClientConnection conn = cmd->conn;
1388 SilcChannelEntry channel;
1389 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1390 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1391 SilcUInt32 mode, add, type, len, arg_len = 0;
1395 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1396 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1400 if (cmd->argc < 3) {
1401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1402 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1407 if (cmd->argv[1][0] == '*') {
1408 if (!conn->current_channel) {
1409 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1413 channel = conn->current_channel;
1415 name = cmd->argv[1];
1417 channel = silc_client_get_channel(cmd->client, conn, name);
1419 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1424 mode = channel->mode;
1426 /* Are we adding or removing mode */
1427 if (cmd->argv[2][0] == '-')
1432 /* Argument type to be sent to server */
1436 cp = cmd->argv[2] + 1;
1438 for (i = 0; i < len; i++) {
1442 mode |= SILC_CHANNEL_MODE_PRIVATE;
1444 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1448 mode |= SILC_CHANNEL_MODE_SECRET;
1450 mode &= ~SILC_CHANNEL_MODE_SECRET;
1454 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1456 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1460 mode |= SILC_CHANNEL_MODE_INVITE;
1462 mode &= ~SILC_CHANNEL_MODE_INVITE;
1466 mode |= SILC_CHANNEL_MODE_TOPIC;
1468 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1472 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1474 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1478 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1480 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1485 mode |= SILC_CHANNEL_MODE_ULIMIT;
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);
1493 ll = atoi(cmd->argv[3]);
1494 SILC_PUT32_MSB(ll, tmp);
1498 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1503 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1505 if (cmd->argc < 4) {
1506 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1507 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1508 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1512 arg_len = cmd->argv_lens[3];
1514 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1519 mode |= SILC_CHANNEL_MODE_CIPHER;
1521 if (cmd->argc < 4) {
1522 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1523 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1524 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1528 arg_len = cmd->argv_lens[3];
1530 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1535 mode |= SILC_CHANNEL_MODE_HMAC;
1537 if (cmd->argc < 4) {
1538 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1539 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1540 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1544 arg_len = cmd->argv_lens[3];
1546 mode &= ~SILC_CHANNEL_MODE_HMAC;
1551 SilcPublicKey pubkey = cmd->client->public_key;
1552 SilcPrivateKey privkey = cmd->client->private_key;
1554 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1557 if (cmd->argc >= 5) {
1560 pass = cmd->argv[5];
1561 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1562 NULL, &pubkey, &privkey)) {
1563 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1564 "Could not load key pair, check your arguments");
1565 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1570 pk = silc_pkcs_public_key_payload_encode(pubkey);
1571 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1573 cmd->client->sha1hash,
1577 arg_len = auth->len;
1579 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1583 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1589 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1590 SILC_PUT32_MSB(mode, modebuf);
1592 /* Send the command packet. We support sending only one mode at once
1593 that requires an argument. */
1596 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
1597 1, chidp->data, chidp->len,
1598 2, modebuf, sizeof(modebuf),
1600 8, pk ? pk->data : NULL,
1604 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1605 1, chidp->data, chidp->len,
1606 2, modebuf, sizeof(modebuf));
1609 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1610 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1611 silc_buffer_free(buffer);
1612 silc_buffer_free(chidp);
1613 silc_buffer_free(auth);
1614 silc_buffer_free(pk);
1616 /* Notify application */
1617 COMMAND(SILC_STATUS_OK);
1620 silc_client_command_free(cmd);
1623 /* CUMODE command. Changes client's mode on a channel. */
1625 SILC_CLIENT_CMD_FUNC(cumode)
1627 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1628 SilcClient client = cmd->client;
1629 SilcClientConnection conn = cmd->conn;
1630 SilcChannelEntry channel;
1631 SilcChannelUser chu;
1632 SilcClientEntry client_entry;
1633 SilcBuffer buffer, clidp, chidp, auth = NULL;
1634 unsigned char *name, *cp, modebuf[4];
1635 SilcUInt32 mode = 0, add, len;
1636 char *nickname = NULL;
1640 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1641 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1645 if (cmd->argc < 4) {
1646 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1647 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1648 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1652 if (cmd->argv[1][0] == '*') {
1653 if (!conn->current_channel) {
1654 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1658 channel = conn->current_channel;
1660 name = cmd->argv[1];
1662 channel = silc_client_get_channel(cmd->client, conn, name);
1664 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1669 /* Parse the typed nickname. */
1670 if (client->internal->params->nickname_parse)
1671 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1673 nickname = strdup(cmd->argv[3]);
1675 /* Find client entry */
1676 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1677 cmd->argv[3], TRUE);
1678 if (!client_entry) {
1680 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1684 /* Client entry not found, it was requested thus mark this to be
1686 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1688 silc_client_command_cumode,
1689 silc_client_command_dup(cmd));
1694 /* Get the current mode */
1695 chu = silc_client_on_channel(channel, client_entry);
1699 /* Are we adding or removing mode */
1700 if (cmd->argv[2][0] == '-')
1706 cp = cmd->argv[2] + 1;
1708 for (i = 0; i < len; i++) {
1712 mode |= SILC_CHANNEL_UMODE_CHANFO;
1713 mode |= SILC_CHANNEL_UMODE_CHANOP;
1714 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1715 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1716 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1718 mode = SILC_CHANNEL_UMODE_NONE;
1723 SilcPublicKey pubkey = cmd->client->public_key;
1724 SilcPrivateKey privkey = cmd->client->private_key;
1726 if (cmd->argc >= 6) {
1729 pass = cmd->argv[6];
1730 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1731 NULL, &pubkey, &privkey)) {
1732 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1733 "Could not load key pair, check your arguments");
1734 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1739 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1741 cmd->client->sha1hash,
1744 mode |= SILC_CHANNEL_UMODE_CHANFO;
1746 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1751 mode |= SILC_CHANNEL_UMODE_CHANOP;
1753 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1757 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1759 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1763 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1765 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1769 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1771 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1775 mode |= SILC_CHANNEL_UMODE_QUIET;
1777 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1780 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1786 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1787 SILC_PUT32_MSB(mode, modebuf);
1788 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1790 /* Send the command packet. We support sending only one mode at once
1791 that requires an argument. */
1792 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1794 1, chidp->data, chidp->len,
1796 3, clidp->data, clidp->len,
1797 4, auth ? auth->data : NULL,
1798 auth ? auth->len : 0);
1800 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1801 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1802 silc_buffer_free(buffer);
1803 silc_buffer_free(chidp);
1804 silc_buffer_free(clidp);
1806 silc_buffer_free(auth);
1808 /* Notify application */
1809 COMMAND(SILC_STATUS_OK);
1812 silc_free(nickname);
1813 silc_client_command_free(cmd);
1816 /* KICK command. Kicks a client out of channel. */
1818 SILC_CLIENT_CMD_FUNC(kick)
1820 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1821 SilcClient client = cmd->client;
1822 SilcClientConnection conn = cmd->conn;
1823 SilcIDCacheEntry id_cache = NULL;
1824 SilcChannelEntry channel;
1825 SilcBuffer buffer, idp, idp2;
1826 SilcClientEntry target;
1828 char *nickname = NULL;
1831 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1832 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1836 if (cmd->argc < 3) {
1837 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1838 "Usage: /KICK <channel> <nickname> [<comment>]");
1839 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1843 if (cmd->argv[1][0] == '*') {
1844 if (!conn->current_channel) {
1845 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1848 name = conn->current_channel->channel_name;
1850 name = cmd->argv[1];
1853 if (!conn->current_channel) {
1854 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1858 /* Get the Channel ID of the channel */
1859 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1861 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1865 channel = (SilcChannelEntry)id_cache->context;
1867 /* Parse the typed nickname. */
1868 if (client->internal->params->nickname_parse)
1869 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1871 nickname = strdup(cmd->argv[2]);
1873 /* Get the target client */
1874 target = silc_idlist_get_client(cmd->client, conn, nickname,
1875 cmd->argv[2], FALSE);
1877 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1878 "No such client: %s", cmd->argv[2]);
1879 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1883 /* Send KICK command to the server */
1884 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1885 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1887 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1888 1, idp->data, idp->len,
1889 2, idp2->data, idp2->len);
1891 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1892 1, idp->data, idp->len,
1893 2, idp2->data, idp2->len,
1895 strlen(cmd->argv[3]));
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(idp);
1900 silc_buffer_free(idp2);
1902 /* Notify application */
1903 COMMAND(SILC_STATUS_OK);
1906 silc_free(nickname);
1907 silc_client_command_free(cmd);
1910 static void silc_client_command_oper_send(unsigned char *data,
1911 SilcUInt32 data_len, void *context)
1913 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1914 SilcClientConnection conn = cmd->conn;
1915 SilcBuffer buffer, auth;
1917 if (cmd->argc >= 3) {
1918 /* Encode the public key authentication payload */
1919 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1920 cmd->client->private_key,
1922 conn->internal->hash,
1926 /* Encode the password authentication payload */
1927 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1931 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1933 strlen(cmd->argv[1]),
1934 2, auth ? auth->data : NULL,
1935 auth ? auth->len : 0);
1936 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1937 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1939 silc_buffer_free(buffer);
1940 silc_buffer_clear(auth);
1941 silc_buffer_free(auth);
1943 /* Notify application */
1944 COMMAND(SILC_STATUS_OK);
1947 /* OPER command. Used to obtain server operator privileges. */
1949 SILC_CLIENT_CMD_FUNC(oper)
1951 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1952 SilcClientConnection conn = cmd->conn;
1955 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1956 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1960 if (cmd->argc < 2) {
1961 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1962 "Usage: /OPER <username> [-pubkey]");
1963 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1967 if (cmd->argc < 3) {
1968 /* Get passphrase */
1969 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1970 silc_client_command_oper_send,
1975 silc_client_command_oper_send(NULL, 0, context);
1978 silc_client_command_free(cmd);
1981 static void silc_client_command_silcoper_send(unsigned char *data,
1982 SilcUInt32 data_len,
1985 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1986 SilcClientConnection conn = cmd->conn;
1987 SilcBuffer buffer, auth;
1989 if (cmd->argc >= 3) {
1990 /* Encode the public key authentication payload */
1991 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1992 cmd->client->private_key,
1994 conn->internal->hash,
1998 /* Encode the password authentication payload */
1999 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2003 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
2005 strlen(cmd->argv[1]),
2006 2, auth ? auth->data : NULL,
2007 auth ? auth->len : 0);
2008 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2009 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2011 silc_buffer_free(buffer);
2012 silc_buffer_clear(auth);
2013 silc_buffer_free(auth);
2015 /* Notify application */
2016 COMMAND(SILC_STATUS_OK);
2019 /* SILCOPER command. Used to obtain router operator privileges. */
2021 SILC_CLIENT_CMD_FUNC(silcoper)
2023 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2024 SilcClientConnection conn = cmd->conn;
2027 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2028 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2032 if (cmd->argc < 2) {
2033 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2034 "Usage: /SILCOPER <username> [-pubkey]");
2035 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2039 if (cmd->argc < 3) {
2040 /* Get passphrase */
2041 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2042 silc_client_command_silcoper_send,
2047 silc_client_command_silcoper_send(NULL, 0, context);
2050 silc_client_command_free(cmd);
2053 /* Command BAN. This is used to manage the ban list of the channel. */
2055 SILC_CLIENT_CMD_FUNC(ban)
2057 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2058 SilcClientConnection conn = cmd->conn;
2059 SilcChannelEntry channel;
2060 SilcBuffer buffer, chidp, args = NULL;
2061 char *name, *ban = NULL;
2062 unsigned char action[1];
2063 SilcPublicKey pubkey = NULL;
2066 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2067 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2071 if (cmd->argc < 2) {
2072 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2073 "Usage: /BAN <channel> "
2074 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2075 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2079 if (cmd->argv[1][0] == '*') {
2080 if (!conn->current_channel) {
2081 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2085 channel = conn->current_channel;
2087 name = cmd->argv[1];
2089 channel = silc_client_get_channel(cmd->client, conn, name);
2091 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2096 if (cmd->argc == 3) {
2097 if (cmd->argv[2][0] == '+')
2102 /* Check if it is public key file to be added to invite list */
2103 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2104 SILC_PKCS_FILE_PEM))
2105 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2106 SILC_PKCS_FILE_BIN);
2113 args = silc_buffer_alloc_size(2);
2114 silc_buffer_format(args,
2115 SILC_STR_UI_SHORT(1),
2118 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2119 args = silc_argument_payload_encode_one(args, chidp->data,
2121 silc_buffer_free(chidp);
2122 silc_pkcs_public_key_free(pubkey);
2124 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2128 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2130 /* Send the command */
2131 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2132 ++conn->cmd_ident, 3,
2133 1, chidp->data, chidp->len,
2134 2, args ? action : NULL,
2136 3, args ? args->data : NULL,
2137 args ? args->len : 0);
2138 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2139 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2140 silc_buffer_free(buffer);
2141 silc_buffer_free(chidp);
2142 silc_buffer_free(args);
2144 /* Notify application */
2145 COMMAND(SILC_STATUS_OK);
2148 silc_client_command_free(cmd);
2151 /* Command DETACH. This is used to detach from the server */
2153 SILC_CLIENT_CMD_FUNC(detach)
2155 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2156 SilcClientConnection conn = cmd->conn;
2160 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2161 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2165 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2166 ++conn->cmd_ident, 0);
2167 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2168 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2169 silc_buffer_free(buffer);
2171 /* Notify application */
2172 COMMAND(SILC_STATUS_OK);
2175 silc_client_command_free(cmd);
2178 /* Command WATCH. */
2180 SILC_CLIENT_CMD_FUNC(watch)
2182 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2183 SilcClientConnection conn = cmd->conn;
2184 SilcBuffer buffer, idp = NULL;
2188 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2189 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2193 if (cmd->argc < 3) {
2194 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2198 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2200 if (!strcasecmp(cmd->argv[1], "-add")) {
2202 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2205 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2209 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2210 ++conn->cmd_ident, 2,
2211 1, idp->data, idp->len,
2214 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2215 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2216 silc_buffer_free(buffer);
2218 /* Notify application */
2219 COMMAND(SILC_STATUS_OK);
2223 silc_buffer_free(idp);
2224 silc_client_command_free(cmd);
2227 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2229 SILC_CLIENT_CMD_FUNC(leave)
2231 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2232 SilcClientConnection conn = cmd->conn;
2233 SilcChannelEntry channel;
2234 SilcChannelUser chu;
2235 SilcBuffer buffer, idp;
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: /LEAVE <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 /* Get the channel entry */
2262 channel = silc_client_get_channel(cmd->client, conn, name);
2264 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2268 /* Remove us from channel */
2269 chu = silc_client_on_channel(channel, conn->local_entry);
2271 silc_hash_table_del(chu->client->channels, chu->channel);
2272 silc_hash_table_del(chu->channel->user_list, chu->client);
2276 /* Send LEAVE command to the server */
2277 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2278 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2279 1, idp->data, idp->len);
2280 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2281 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2282 silc_buffer_free(buffer);
2283 silc_buffer_free(idp);
2285 /* Notify application */
2286 COMMAND(SILC_STATUS_OK);
2288 if (conn->current_channel == channel)
2289 conn->current_channel = NULL;
2291 silc_client_del_channel(cmd->client, cmd->conn, channel);
2294 silc_client_command_free(cmd);
2297 /* Command USERS. Requests the USERS of the clients joined on requested
2300 SILC_CLIENT_CMD_FUNC(users)
2302 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2303 SilcClientConnection conn = cmd->conn;
2308 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2309 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2313 if (cmd->argc != 2) {
2314 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2315 "Usage: /USERS <channel>");
2316 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2320 if (cmd->argv[1][0] == '*') {
2321 if (!conn->current_channel) {
2322 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2325 name = conn->current_channel->channel_name;
2327 name = cmd->argv[1];
2330 /* Send USERS command to the server */
2331 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2332 ++conn->cmd_ident, 1,
2333 2, name, strlen(name));
2334 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2335 NULL, 0, NULL, NULL, buffer->data,
2337 silc_buffer_free(buffer);
2339 /* Notify application */
2340 COMMAND(SILC_STATUS_OK);
2343 silc_client_command_free(cmd);
2346 /* Command GETKEY. Used to fetch remote client's public key. */
2348 SILC_CLIENT_CMD_FUNC(getkey)
2350 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2351 SilcClientConnection conn = cmd->conn;
2352 SilcClient client = cmd->client;
2353 SilcClientEntry client_entry = NULL;
2354 SilcServerEntry server_entry = NULL;
2355 char *nickname = NULL;
2356 SilcBuffer idp, buffer;
2358 SILC_LOG_DEBUG(("Start"));
2361 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2362 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2366 if (cmd->argc < 2) {
2367 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2368 "Usage: /GETKEY <nickname or server name>");
2369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2373 /* Parse the typed nickname. */
2374 if (client->internal->params->nickname_parse)
2375 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2377 nickname = strdup(cmd->argv[1]);
2379 /* Find client entry */
2380 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2382 if (!client_entry) {
2383 /* Check whether user requested server actually */
2384 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2386 if (!server_entry) {
2387 /* No. what ever user wants we don't have it, so resolve it. We
2388 will first try to resolve the client, and if that fails then
2389 we'll try to resolve the server. */
2391 if (!cmd->pending) {
2392 /* This will send the IDENTIFY command for nickname */
2393 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2394 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2396 silc_client_command_getkey,
2397 silc_client_command_dup(cmd));
2401 SilcClientCommandReplyContext reply =
2402 (SilcClientCommandReplyContext)context2;
2405 /* If nickname was not found, then resolve the server. */
2406 silc_command_get_status(reply->payload, NULL, &error);
2407 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2408 /* This sends the IDENTIFY command to resolve the server. */
2409 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2411 silc_client_command_reply_identify_i, 0,
2413 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2415 2, cmd->argv[1], cmd->argv_lens[1]);
2416 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2418 silc_client_command_getkey,
2419 silc_client_command_dup(cmd));
2423 /* If server was not found, then we've resolved both nickname and
2424 server and did not find anybody. */
2425 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2426 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2427 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2428 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2429 silc_get_status_message(error));
2430 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2434 COMMAND_ERROR(error);
2439 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2441 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2444 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2445 1, idp->data, idp->len);
2446 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2447 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2448 silc_buffer_free(buffer);
2449 silc_buffer_free(idp);
2451 /* Notify application */
2452 COMMAND(SILC_STATUS_OK);
2455 silc_free(nickname);
2456 silc_client_command_free(cmd);
2459 /* Register a new command indicated by the `command' to the SILC client.
2460 The `name' is optional command name. If provided the command may be
2461 searched using the silc_client_command_find by that name. The
2462 `command_function' is the function to be called when the command is
2463 executed, and the `command_reply_function' is the function to be
2464 called after the server has sent reply back to the command.
2466 The `ident' is optional identifier for the command. If non-zero
2467 the `command_reply_function' for the command type `command' will be
2468 called only if the command reply sent by server includes the
2469 command identifier `ident'. Application usually does not need it
2470 and set it to zero value. */
2472 bool silc_client_command_register(SilcClient client,
2473 SilcCommand command,
2475 SilcCommandCb command_function,
2476 SilcCommandCb command_reply_function,
2480 SilcClientCommand cmd;
2482 cmd = silc_calloc(1, sizeof(*cmd));
2484 cmd->command = command_function;
2485 cmd->reply = command_reply_function;
2486 cmd->name = name ? strdup(name) : NULL;
2487 cmd->max_args = max_args;
2490 silc_list_add(client->internal->commands, cmd);
2495 /* Unregister a command indicated by the `command' with command function
2496 `command_function' and command reply function `command_reply_function'.
2497 Returns TRUE if the command was found and unregistered. */
2499 bool silc_client_command_unregister(SilcClient client,
2500 SilcCommand command,
2501 SilcCommandCb command_function,
2502 SilcCommandCb command_reply_function,
2505 SilcClientCommand cmd;
2507 silc_list_start(client->internal->commands);
2508 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2509 if (cmd->cmd == command && cmd->command == command_function &&
2510 cmd->reply == command_reply_function && cmd->ident == ident) {
2511 silc_list_del(client->internal->commands, cmd);
2512 silc_free(cmd->name);
2521 /* Private range commands, specific to this implementation (and compatible
2522 with SILC Server). */
2524 /* CONNECT command. Connects the server to another server. */
2526 SILC_CLIENT_CMD_FUNC(connect)
2528 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2529 SilcClientConnection conn = cmd->conn;
2531 unsigned char port[4];
2535 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2536 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2540 if (cmd->argc < 2) {
2541 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2542 "Usage: /CONNECT <server> [<port>]");
2543 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2547 if (cmd->argc == 3) {
2548 tmp = atoi(cmd->argv[2]);
2549 SILC_PUT32_MSB(tmp, port);
2553 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2555 strlen(cmd->argv[1]),
2558 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2560 strlen(cmd->argv[1]));
2561 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2562 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2563 silc_buffer_free(buffer);
2565 /* Notify application */
2566 COMMAND(SILC_STATUS_OK);
2569 silc_client_command_free(cmd);
2573 /* CLOSE command. Close server connection to the remote server */
2575 SILC_CLIENT_CMD_FUNC(close)
2577 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2578 SilcClientConnection conn = cmd->conn;
2580 unsigned char port[4];
2584 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2585 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2589 if (cmd->argc < 2) {
2590 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2591 "Usage: /CLOSE <server> [<port>]");
2592 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2596 if (cmd->argc == 3) {
2597 tmp = atoi(cmd->argv[2]);
2598 SILC_PUT32_MSB(tmp, port);
2602 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2604 strlen(cmd->argv[1]),
2607 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2609 strlen(cmd->argv[1]));
2610 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2611 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2612 silc_buffer_free(buffer);
2614 /* Notify application */
2615 COMMAND(SILC_STATUS_OK);
2618 silc_client_command_free(cmd);
2621 /* SHUTDOWN command. Shutdowns the server. */
2623 SILC_CLIENT_CMD_FUNC(shutdown)
2625 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2628 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2629 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2633 /* Send the command */
2634 silc_client_command_send(cmd->client, cmd->conn,
2635 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2637 /* Notify application */
2638 COMMAND(SILC_STATUS_OK);
2641 silc_client_command_free(cmd);
2644 /* Register all default commands provided by the client library for the
2647 void silc_client_commands_register(SilcClient client)
2649 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2652 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2653 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2654 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2655 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2656 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2657 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2658 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2659 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2660 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2661 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2662 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2663 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2664 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2665 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2666 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2667 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2668 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2669 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2670 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2671 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2672 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2673 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2674 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2675 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2676 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2677 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2679 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2680 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2681 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2684 /* Unregister all commands. */
2686 void silc_client_commands_unregister(SilcClient client)
2688 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2689 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2690 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2691 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2692 SILC_CLIENT_CMDU(list, LIST, "LIST");
2693 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2694 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2695 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2696 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2697 SILC_CLIENT_CMDU(info, INFO, "INFO");
2698 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2699 SILC_CLIENT_CMDU(ping, PING, "PING");
2700 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2701 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2702 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2703 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2704 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2705 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2706 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2707 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2708 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2709 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2710 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2711 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2712 SILC_CLIENT_CMDU(users, USERS, "USERS");
2713 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2715 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2716 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2717 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2720 /**** Client side incoming command handling **********************************/
2722 void silc_client_command_process_whois(SilcClient client,
2723 SilcSocketConnection sock,
2724 SilcCommandPayload payload,
2725 SilcArgumentPayload args);
2727 /* Client is able to receive some command packets even though they are
2728 special case. Server may send WHOIS command to the client to retrieve
2729 Requested Attributes information for WHOIS query the server is
2730 processing. This function currently handles only the WHOIS command,
2731 but if in the future for commands may arrive then this can be made
2732 to support other commands too. */
2734 void silc_client_command_process(SilcClient client,
2735 SilcSocketConnection sock,
2736 SilcPacketContext *packet)
2738 SilcCommandPayload payload;
2739 SilcCommand command;
2740 SilcArgumentPayload args;
2742 /* Get command payload from packet */
2743 payload = silc_command_payload_parse(packet->buffer->data,
2744 packet->buffer->len);
2746 /* Silently ignore bad reply packet */
2747 SILC_LOG_DEBUG(("Bad command packet"));
2752 args = silc_command_get_args(payload);
2754 /* Get the command */
2755 command = silc_command_get(payload);
2758 case SILC_COMMAND_WHOIS:
2759 /* Ignore everything if requested by application */
2760 if (client->internal->params->ignore_requested_attributes)
2763 silc_client_command_process_whois(client, sock, payload, args);
2770 silc_command_payload_free(payload);
2773 void silc_client_command_process_whois(SilcClient client,
2774 SilcSocketConnection sock,
2775 SilcCommandPayload payload,
2776 SilcArgumentPayload args)
2781 SilcBuffer buffer, packet;
2783 SILC_LOG_DEBUG(("Received WHOIS command"));
2785 /* Try to take the Requested Attributes */
2786 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2790 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2794 /* Process requested attributes */
2795 buffer = silc_client_attributes_process(client, sock, attrs);
2797 silc_attribute_payload_list_free(attrs);
2801 /* Send the attributes back */
2803 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2805 silc_command_get_ident(payload),
2806 1, 11, buffer->data, buffer->len);
2807 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2808 NULL, 0, NULL, NULL, packet->data,
2810 silc_buffer_free(packet);
2811 silc_buffer_free(buffer);