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);
1178 silc_free(passphrase);
1180 /* Notify application */
1181 COMMAND(SILC_STATUS_OK);
1184 silc_client_command_free(cmd);
1187 /* MOTD command. Requests motd from server. */
1189 SILC_CLIENT_CMD_FUNC(motd)
1191 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1192 SilcClientConnection conn = cmd->conn;
1196 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1197 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1201 if (cmd->argc < 1 || cmd->argc > 2) {
1202 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1203 "Usage: /MOTD [<server>]");
1204 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1205 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1209 /* Send TOPIC command to the server */
1211 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1212 1, conn->remote_host,
1213 strlen(conn->remote_host));
1215 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1218 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1219 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1220 silc_buffer_free(buffer);
1222 /* Notify application */
1223 COMMAND(SILC_STATUS_OK);
1226 silc_client_command_free(cmd);
1229 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1230 modes as client cannot set itself server/router operator privileges. */
1232 SILC_CLIENT_CMD_FUNC(umode)
1234 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1235 SilcClientConnection conn = cmd->conn;
1236 SilcBuffer buffer, idp;
1237 unsigned char *cp, modebuf[4];
1238 SilcUInt32 mode, add, len;
1242 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1243 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1247 if (cmd->argc < 2) {
1248 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1249 "Usage: /UMODE +|-<modes>");
1250 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1254 mode = conn->local_entry->mode;
1256 /* Are we adding or removing mode */
1257 if (cmd->argv[1][0] == '-')
1263 cp = cmd->argv[1] + 1;
1265 for (i = 0; i < len; i++) {
1270 mode |= SILC_UMODE_SERVER_OPERATOR;
1271 mode |= SILC_UMODE_ROUTER_OPERATOR;
1272 mode |= SILC_UMODE_GONE;
1273 mode |= SILC_UMODE_INDISPOSED;
1274 mode |= SILC_UMODE_BUSY;
1275 mode |= SILC_UMODE_PAGE;
1276 mode |= SILC_UMODE_HYPER;
1277 mode |= SILC_UMODE_ROBOT;
1278 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1279 mode |= SILC_UMODE_REJECT_WATCHING;
1281 mode = SILC_UMODE_NONE;
1286 mode |= SILC_UMODE_SERVER_OPERATOR;
1288 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1292 mode |= SILC_UMODE_ROUTER_OPERATOR;
1294 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1298 mode |= SILC_UMODE_GONE;
1300 mode &= ~SILC_UMODE_GONE;
1304 mode |= SILC_UMODE_INDISPOSED;
1306 mode &= ~SILC_UMODE_INDISPOSED;
1310 mode |= SILC_UMODE_BUSY;
1312 mode &= ~SILC_UMODE_BUSY;
1316 mode |= SILC_UMODE_PAGE;
1318 mode &= ~SILC_UMODE_PAGE;
1322 mode |= SILC_UMODE_HYPER;
1324 mode &= ~SILC_UMODE_HYPER;
1328 mode |= SILC_UMODE_ROBOT;
1330 mode &= ~SILC_UMODE_ROBOT;
1334 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1336 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1340 mode |= SILC_UMODE_REJECT_WATCHING;
1342 mode &= ~SILC_UMODE_REJECT_WATCHING;
1346 mode |= SILC_UMODE_BLOCK_INVITE;
1348 mode &= ~SILC_UMODE_BLOCK_INVITE;
1351 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1357 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1358 SILC_PUT32_MSB(mode, modebuf);
1360 /* Send the command packet. We support sending only one mode at once
1361 that requires an argument. */
1363 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1364 1, idp->data, idp->len,
1365 2, modebuf, sizeof(modebuf));
1366 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1367 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1368 silc_buffer_free(buffer);
1369 silc_buffer_free(idp);
1371 /* Notify application */
1372 COMMAND(SILC_STATUS_OK);
1375 silc_client_command_free(cmd);
1378 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1379 can be set several at once. Those modes that require argument must be set
1380 separately (unless set with modes that does not require arguments). */
1382 SILC_CLIENT_CMD_FUNC(cmode)
1384 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1385 SilcClientConnection conn = cmd->conn;
1386 SilcChannelEntry channel;
1387 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1388 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1389 SilcUInt32 mode, add, type, len, arg_len = 0;
1393 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1394 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1398 if (cmd->argc < 3) {
1399 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1400 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1405 if (cmd->argv[1][0] == '*') {
1406 if (!conn->current_channel) {
1407 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1411 channel = conn->current_channel;
1413 name = cmd->argv[1];
1415 channel = silc_client_get_channel(cmd->client, conn, name);
1417 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1422 mode = channel->mode;
1424 /* Are we adding or removing mode */
1425 if (cmd->argv[2][0] == '-')
1430 /* Argument type to be sent to server */
1434 cp = cmd->argv[2] + 1;
1436 for (i = 0; i < len; i++) {
1440 mode |= SILC_CHANNEL_MODE_PRIVATE;
1442 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1446 mode |= SILC_CHANNEL_MODE_SECRET;
1448 mode &= ~SILC_CHANNEL_MODE_SECRET;
1452 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1454 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1458 mode |= SILC_CHANNEL_MODE_INVITE;
1460 mode &= ~SILC_CHANNEL_MODE_INVITE;
1464 mode |= SILC_CHANNEL_MODE_TOPIC;
1466 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1470 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1472 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1476 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1478 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1483 mode |= SILC_CHANNEL_MODE_ULIMIT;
1485 if (cmd->argc < 4) {
1486 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1487 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1488 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1491 ll = atoi(cmd->argv[3]);
1492 SILC_PUT32_MSB(ll, tmp);
1496 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1501 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1503 if (cmd->argc < 4) {
1504 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1505 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1510 arg_len = cmd->argv_lens[3];
1512 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1517 mode |= SILC_CHANNEL_MODE_CIPHER;
1519 if (cmd->argc < 4) {
1520 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1521 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1522 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1526 arg_len = cmd->argv_lens[3];
1528 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1533 mode |= SILC_CHANNEL_MODE_HMAC;
1535 if (cmd->argc < 4) {
1536 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1537 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1538 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1542 arg_len = cmd->argv_lens[3];
1544 mode &= ~SILC_CHANNEL_MODE_HMAC;
1549 SilcPublicKey pubkey = cmd->client->public_key;
1550 SilcPrivateKey privkey = cmd->client->private_key;
1552 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1555 if (cmd->argc >= 5) {
1558 pass = cmd->argv[5];
1559 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1560 NULL, &pubkey, &privkey)) {
1561 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1562 "Could not load key pair, check your arguments");
1563 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1568 pk = silc_pkcs_public_key_payload_encode(pubkey);
1569 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1571 cmd->client->sha1hash,
1575 arg_len = auth->len;
1577 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1581 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1587 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1588 SILC_PUT32_MSB(mode, modebuf);
1590 /* Send the command packet. We support sending only one mode at once
1591 that requires an argument. */
1594 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
1595 1, chidp->data, chidp->len,
1596 2, modebuf, sizeof(modebuf),
1598 8, pk ? pk->data : NULL,
1602 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1603 1, chidp->data, chidp->len,
1604 2, modebuf, sizeof(modebuf));
1607 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1608 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1609 silc_buffer_free(buffer);
1610 silc_buffer_free(chidp);
1611 silc_buffer_free(auth);
1612 silc_buffer_free(pk);
1614 /* Notify application */
1615 COMMAND(SILC_STATUS_OK);
1618 silc_client_command_free(cmd);
1621 /* CUMODE command. Changes client's mode on a channel. */
1623 SILC_CLIENT_CMD_FUNC(cumode)
1625 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1626 SilcClient client = cmd->client;
1627 SilcClientConnection conn = cmd->conn;
1628 SilcChannelEntry channel;
1629 SilcChannelUser chu;
1630 SilcClientEntry client_entry;
1631 SilcBuffer buffer, clidp, chidp, auth = NULL;
1632 unsigned char *name, *cp, modebuf[4];
1633 SilcUInt32 mode = 0, add, len;
1634 char *nickname = NULL;
1638 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1639 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1643 if (cmd->argc < 4) {
1644 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1645 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1646 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1650 if (cmd->argv[1][0] == '*') {
1651 if (!conn->current_channel) {
1652 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1656 channel = conn->current_channel;
1658 name = cmd->argv[1];
1660 channel = silc_client_get_channel(cmd->client, conn, name);
1662 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1667 /* Parse the typed nickname. */
1668 if (client->internal->params->nickname_parse)
1669 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1671 nickname = strdup(cmd->argv[3]);
1673 /* Find client entry */
1674 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1675 cmd->argv[3], TRUE);
1676 if (!client_entry) {
1678 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1682 /* Client entry not found, it was requested thus mark this to be
1684 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1686 silc_client_command_cumode,
1687 silc_client_command_dup(cmd));
1692 /* Get the current mode */
1693 chu = silc_client_on_channel(channel, client_entry);
1697 /* Are we adding or removing mode */
1698 if (cmd->argv[2][0] == '-')
1704 cp = cmd->argv[2] + 1;
1706 for (i = 0; i < len; i++) {
1710 mode |= SILC_CHANNEL_UMODE_CHANFO;
1711 mode |= SILC_CHANNEL_UMODE_CHANOP;
1712 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1713 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1714 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1716 mode = SILC_CHANNEL_UMODE_NONE;
1721 SilcPublicKey pubkey = cmd->client->public_key;
1722 SilcPrivateKey privkey = cmd->client->private_key;
1724 if (cmd->argc >= 6) {
1727 pass = cmd->argv[6];
1728 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1729 NULL, &pubkey, &privkey)) {
1730 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1731 "Could not load key pair, check your arguments");
1732 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1737 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1739 cmd->client->sha1hash,
1742 mode |= SILC_CHANNEL_UMODE_CHANFO;
1744 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1749 mode |= SILC_CHANNEL_UMODE_CHANOP;
1751 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1755 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1757 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1761 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1763 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1767 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1769 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1773 mode |= SILC_CHANNEL_UMODE_QUIET;
1775 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1778 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1784 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1785 SILC_PUT32_MSB(mode, modebuf);
1786 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1788 /* Send the command packet. We support sending only one mode at once
1789 that requires an argument. */
1790 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1792 1, chidp->data, chidp->len,
1794 3, clidp->data, clidp->len,
1795 4, auth ? auth->data : NULL,
1796 auth ? auth->len : 0);
1798 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1799 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1800 silc_buffer_free(buffer);
1801 silc_buffer_free(chidp);
1802 silc_buffer_free(clidp);
1804 silc_buffer_free(auth);
1806 /* Notify application */
1807 COMMAND(SILC_STATUS_OK);
1810 silc_free(nickname);
1811 silc_client_command_free(cmd);
1814 /* KICK command. Kicks a client out of channel. */
1816 SILC_CLIENT_CMD_FUNC(kick)
1818 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1819 SilcClient client = cmd->client;
1820 SilcClientConnection conn = cmd->conn;
1821 SilcIDCacheEntry id_cache = NULL;
1822 SilcChannelEntry channel;
1823 SilcBuffer buffer, idp, idp2;
1824 SilcClientEntry target;
1826 char *nickname = NULL;
1829 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1830 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1834 if (cmd->argc < 3) {
1835 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1836 "Usage: /KICK <channel> <nickname> [<comment>]");
1837 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1841 if (cmd->argv[1][0] == '*') {
1842 if (!conn->current_channel) {
1843 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1846 name = conn->current_channel->channel_name;
1848 name = cmd->argv[1];
1851 if (!conn->current_channel) {
1852 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1856 /* Get the Channel ID of the channel */
1857 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1859 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1863 channel = (SilcChannelEntry)id_cache->context;
1865 /* Parse the typed nickname. */
1866 if (client->internal->params->nickname_parse)
1867 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1869 nickname = strdup(cmd->argv[2]);
1871 /* Get the target client */
1872 target = silc_idlist_get_client(cmd->client, conn, nickname,
1873 cmd->argv[2], FALSE);
1875 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1876 "No such client: %s", cmd->argv[2]);
1877 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1881 /* Send KICK command to the server */
1882 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1883 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1885 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1886 1, idp->data, idp->len,
1887 2, idp2->data, idp2->len);
1889 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1890 1, idp->data, idp->len,
1891 2, idp2->data, idp2->len,
1893 strlen(cmd->argv[3]));
1894 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1895 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1896 silc_buffer_free(buffer);
1897 silc_buffer_free(idp);
1898 silc_buffer_free(idp2);
1900 /* Notify application */
1901 COMMAND(SILC_STATUS_OK);
1904 silc_free(nickname);
1905 silc_client_command_free(cmd);
1908 static void silc_client_command_oper_send(unsigned char *data,
1909 SilcUInt32 data_len, void *context)
1911 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1912 SilcClientConnection conn = cmd->conn;
1913 SilcBuffer buffer, auth;
1915 if (cmd->argc >= 3) {
1916 /* Encode the public key authentication payload */
1917 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1918 cmd->client->private_key,
1920 conn->internal->hash,
1924 /* Encode the password authentication payload */
1925 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1929 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1931 strlen(cmd->argv[1]),
1932 2, auth ? auth->data : NULL,
1933 auth ? auth->len : 0);
1934 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1935 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1937 silc_buffer_free(buffer);
1938 silc_buffer_free(auth);
1940 /* Notify application */
1941 COMMAND(SILC_STATUS_OK);
1944 /* OPER command. Used to obtain server operator privileges. */
1946 SILC_CLIENT_CMD_FUNC(oper)
1948 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1949 SilcClientConnection conn = cmd->conn;
1952 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1953 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1957 if (cmd->argc < 2) {
1958 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1959 "Usage: /OPER <username> [-pubkey]");
1960 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1964 if (cmd->argc < 3) {
1965 /* Get passphrase */
1966 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1967 silc_client_command_oper_send,
1972 silc_client_command_oper_send(NULL, 0, context);
1975 silc_client_command_free(cmd);
1978 static void silc_client_command_silcoper_send(unsigned char *data,
1979 SilcUInt32 data_len,
1982 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1983 SilcClientConnection conn = cmd->conn;
1984 SilcBuffer buffer, auth;
1986 if (cmd->argc >= 3) {
1987 /* Encode the public key authentication payload */
1988 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1989 cmd->client->private_key,
1991 conn->internal->hash,
1995 /* Encode the password authentication payload */
1996 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2000 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
2002 strlen(cmd->argv[1]),
2003 2, auth ? auth->data : NULL,
2004 auth ? auth->len : 0);
2005 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2006 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2008 silc_buffer_free(buffer);
2009 silc_buffer_free(auth);
2011 /* Notify application */
2012 COMMAND(SILC_STATUS_OK);
2015 /* SILCOPER command. Used to obtain router operator privileges. */
2017 SILC_CLIENT_CMD_FUNC(silcoper)
2019 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2020 SilcClientConnection conn = cmd->conn;
2023 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2024 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2028 if (cmd->argc < 2) {
2029 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2030 "Usage: /SILCOPER <username> [-pubkey]");
2031 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2035 if (cmd->argc < 3) {
2036 /* Get passphrase */
2037 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2038 silc_client_command_silcoper_send,
2043 silc_client_command_silcoper_send(NULL, 0, context);
2046 silc_client_command_free(cmd);
2049 /* Command BAN. This is used to manage the ban list of the channel. */
2051 SILC_CLIENT_CMD_FUNC(ban)
2053 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2054 SilcClientConnection conn = cmd->conn;
2055 SilcChannelEntry channel;
2056 SilcBuffer buffer, chidp, args = NULL;
2057 char *name, *ban = NULL;
2058 unsigned char action[1];
2059 SilcPublicKey pubkey = NULL;
2062 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2063 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2067 if (cmd->argc < 2) {
2068 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2069 "Usage: /BAN <channel> "
2070 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2071 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2075 if (cmd->argv[1][0] == '*') {
2076 if (!conn->current_channel) {
2077 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2081 channel = conn->current_channel;
2083 name = cmd->argv[1];
2085 channel = silc_client_get_channel(cmd->client, conn, name);
2087 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2092 if (cmd->argc == 3) {
2093 if (cmd->argv[2][0] == '+')
2098 /* Check if it is public key file to be added to invite list */
2099 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2100 SILC_PKCS_FILE_PEM))
2101 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2102 SILC_PKCS_FILE_BIN);
2109 args = silc_buffer_alloc_size(2);
2110 silc_buffer_format(args,
2111 SILC_STR_UI_SHORT(1),
2114 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2115 args = silc_argument_payload_encode_one(args, chidp->data,
2117 silc_buffer_free(chidp);
2118 silc_pkcs_public_key_free(pubkey);
2120 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2124 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2126 /* Send the command */
2127 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2128 ++conn->cmd_ident, 3,
2129 1, chidp->data, chidp->len,
2130 2, args ? action : NULL,
2132 3, args ? args->data : NULL,
2133 args ? args->len : 0);
2134 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2135 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2136 silc_buffer_free(buffer);
2137 silc_buffer_free(chidp);
2138 silc_buffer_free(args);
2140 /* Notify application */
2141 COMMAND(SILC_STATUS_OK);
2144 silc_client_command_free(cmd);
2147 /* Command DETACH. This is used to detach from the server */
2149 SILC_CLIENT_CMD_FUNC(detach)
2151 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2152 SilcClientConnection conn = cmd->conn;
2156 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2157 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2161 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2162 ++conn->cmd_ident, 0);
2163 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2164 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2165 silc_buffer_free(buffer);
2167 /* Notify application */
2168 COMMAND(SILC_STATUS_OK);
2171 silc_client_command_free(cmd);
2174 /* Command WATCH. */
2176 SILC_CLIENT_CMD_FUNC(watch)
2178 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2179 SilcClientConnection conn = cmd->conn;
2180 SilcBuffer buffer, idp = NULL;
2184 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2185 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2189 if (cmd->argc < 3) {
2190 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2194 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2196 if (!strcasecmp(cmd->argv[1], "-add")) {
2198 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2201 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2205 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2206 ++conn->cmd_ident, 2,
2207 1, idp->data, idp->len,
2210 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2211 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2212 silc_buffer_free(buffer);
2214 /* Notify application */
2215 COMMAND(SILC_STATUS_OK);
2219 silc_buffer_free(idp);
2220 silc_client_command_free(cmd);
2223 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2225 SILC_CLIENT_CMD_FUNC(leave)
2227 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2228 SilcClientConnection conn = cmd->conn;
2229 SilcChannelEntry channel;
2230 SilcChannelUser chu;
2231 SilcBuffer buffer, idp;
2235 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2236 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2240 if (cmd->argc != 2) {
2241 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2242 "Usage: /LEAVE <channel>");
2243 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2247 if (cmd->argv[1][0] == '*') {
2248 if (!conn->current_channel) {
2249 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2252 name = conn->current_channel->channel_name;
2254 name = cmd->argv[1];
2257 /* Get the channel entry */
2258 channel = silc_client_get_channel(cmd->client, conn, name);
2260 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2264 /* Remove us from channel */
2265 chu = silc_client_on_channel(channel, conn->local_entry);
2267 silc_hash_table_del(chu->client->channels, chu->channel);
2268 silc_hash_table_del(chu->channel->user_list, chu->client);
2272 /* Send LEAVE command to the server */
2273 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2274 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2275 1, idp->data, idp->len);
2276 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2277 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2278 silc_buffer_free(buffer);
2279 silc_buffer_free(idp);
2281 /* Notify application */
2282 COMMAND(SILC_STATUS_OK);
2284 if (conn->current_channel == channel)
2285 conn->current_channel = NULL;
2287 silc_client_del_channel(cmd->client, cmd->conn, channel);
2290 silc_client_command_free(cmd);
2293 /* Command USERS. Requests the USERS of the clients joined on requested
2296 SILC_CLIENT_CMD_FUNC(users)
2298 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2299 SilcClientConnection conn = cmd->conn;
2304 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2305 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2309 if (cmd->argc != 2) {
2310 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2311 "Usage: /USERS <channel>");
2312 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2316 if (cmd->argv[1][0] == '*') {
2317 if (!conn->current_channel) {
2318 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2321 name = conn->current_channel->channel_name;
2323 name = cmd->argv[1];
2326 /* Send USERS command to the server */
2327 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2328 ++conn->cmd_ident, 1,
2329 2, name, strlen(name));
2330 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2331 NULL, 0, NULL, NULL, buffer->data,
2333 silc_buffer_free(buffer);
2335 /* Notify application */
2336 COMMAND(SILC_STATUS_OK);
2339 silc_client_command_free(cmd);
2342 /* Command GETKEY. Used to fetch remote client's public key. */
2344 SILC_CLIENT_CMD_FUNC(getkey)
2346 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2347 SilcClientConnection conn = cmd->conn;
2348 SilcClient client = cmd->client;
2349 SilcClientEntry client_entry = NULL;
2350 SilcServerEntry server_entry = NULL;
2351 char *nickname = NULL;
2352 SilcBuffer idp, buffer;
2354 SILC_LOG_DEBUG(("Start"));
2357 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2358 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2362 if (cmd->argc < 2) {
2363 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2364 "Usage: /GETKEY <nickname or server name>");
2365 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2369 /* Parse the typed nickname. */
2370 if (client->internal->params->nickname_parse)
2371 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2373 nickname = strdup(cmd->argv[1]);
2375 /* Find client entry */
2376 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2378 if (!client_entry) {
2379 /* Check whether user requested server actually */
2380 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2382 if (!server_entry) {
2383 /* No. what ever user wants we don't have it, so resolve it. We
2384 will first try to resolve the client, and if that fails then
2385 we'll try to resolve the server. */
2387 if (!cmd->pending) {
2388 /* This will send the IDENTIFY command for nickname */
2389 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2390 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2392 silc_client_command_getkey,
2393 silc_client_command_dup(cmd));
2397 SilcClientCommandReplyContext reply =
2398 (SilcClientCommandReplyContext)context2;
2401 /* If nickname was not found, then resolve the server. */
2402 silc_command_get_status(reply->payload, NULL, &error);
2403 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2404 /* This sends the IDENTIFY command to resolve the server. */
2405 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2407 silc_client_command_reply_identify_i, 0,
2409 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2411 2, cmd->argv[1], cmd->argv_lens[1]);
2412 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2414 silc_client_command_getkey,
2415 silc_client_command_dup(cmd));
2419 /* If server was not found, then we've resolved both nickname and
2420 server and did not find anybody. */
2421 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2422 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2423 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2424 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2425 silc_get_status_message(error));
2426 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2430 COMMAND_ERROR(error);
2435 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2437 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2440 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2441 1, idp->data, idp->len);
2442 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2443 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2444 silc_buffer_free(buffer);
2445 silc_buffer_free(idp);
2447 /* Notify application */
2448 COMMAND(SILC_STATUS_OK);
2451 silc_free(nickname);
2452 silc_client_command_free(cmd);
2455 /* Register a new command indicated by the `command' to the SILC client.
2456 The `name' is optional command name. If provided the command may be
2457 searched using the silc_client_command_find by that name. The
2458 `command_function' is the function to be called when the command is
2459 executed, and the `command_reply_function' is the function to be
2460 called after the server has sent reply back to the command.
2462 The `ident' is optional identifier for the command. If non-zero
2463 the `command_reply_function' for the command type `command' will be
2464 called only if the command reply sent by server includes the
2465 command identifier `ident'. Application usually does not need it
2466 and set it to zero value. */
2468 bool silc_client_command_register(SilcClient client,
2469 SilcCommand command,
2471 SilcCommandCb command_function,
2472 SilcCommandCb command_reply_function,
2476 SilcClientCommand cmd;
2478 cmd = silc_calloc(1, sizeof(*cmd));
2480 cmd->command = command_function;
2481 cmd->reply = command_reply_function;
2482 cmd->name = name ? strdup(name) : NULL;
2483 cmd->max_args = max_args;
2486 silc_list_add(client->internal->commands, cmd);
2491 /* Unregister a command indicated by the `command' with command function
2492 `command_function' and command reply function `command_reply_function'.
2493 Returns TRUE if the command was found and unregistered. */
2495 bool silc_client_command_unregister(SilcClient client,
2496 SilcCommand command,
2497 SilcCommandCb command_function,
2498 SilcCommandCb command_reply_function,
2501 SilcClientCommand cmd;
2503 silc_list_start(client->internal->commands);
2504 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2505 if (cmd->cmd == command && cmd->command == command_function &&
2506 cmd->reply == command_reply_function && cmd->ident == ident) {
2507 silc_list_del(client->internal->commands, cmd);
2508 silc_free(cmd->name);
2517 /* Private range commands, specific to this implementation (and compatible
2518 with SILC Server). */
2520 /* CONNECT command. Connects the server to another server. */
2522 SILC_CLIENT_CMD_FUNC(connect)
2524 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2525 SilcClientConnection conn = cmd->conn;
2527 unsigned char port[4];
2531 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2532 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2536 if (cmd->argc < 2) {
2537 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2538 "Usage: /CONNECT <server> [<port>]");
2539 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2543 if (cmd->argc == 3) {
2544 tmp = atoi(cmd->argv[2]);
2545 SILC_PUT32_MSB(tmp, port);
2549 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2551 strlen(cmd->argv[1]),
2554 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2556 strlen(cmd->argv[1]));
2557 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2558 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2559 silc_buffer_free(buffer);
2561 /* Notify application */
2562 COMMAND(SILC_STATUS_OK);
2565 silc_client_command_free(cmd);
2569 /* CLOSE command. Close server connection to the remote server */
2571 SILC_CLIENT_CMD_FUNC(close)
2573 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2574 SilcClientConnection conn = cmd->conn;
2576 unsigned char port[4];
2580 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2581 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2585 if (cmd->argc < 2) {
2586 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2587 "Usage: /CLOSE <server> [<port>]");
2588 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2592 if (cmd->argc == 3) {
2593 tmp = atoi(cmd->argv[2]);
2594 SILC_PUT32_MSB(tmp, port);
2598 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2600 strlen(cmd->argv[1]),
2603 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2605 strlen(cmd->argv[1]));
2606 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2607 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2608 silc_buffer_free(buffer);
2610 /* Notify application */
2611 COMMAND(SILC_STATUS_OK);
2614 silc_client_command_free(cmd);
2617 /* SHUTDOWN command. Shutdowns the server. */
2619 SILC_CLIENT_CMD_FUNC(shutdown)
2621 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2624 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2625 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2629 /* Send the command */
2630 silc_client_command_send(cmd->client, cmd->conn,
2631 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2633 /* Notify application */
2634 COMMAND(SILC_STATUS_OK);
2637 silc_client_command_free(cmd);
2640 /* Register all default commands provided by the client library for the
2643 void silc_client_commands_register(SilcClient client)
2645 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2648 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2649 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2650 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2651 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2652 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2653 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2654 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2655 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2656 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2657 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2658 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2659 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2660 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2661 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2662 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2663 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2664 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2665 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2666 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2667 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2668 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2669 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2670 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2671 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2672 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2673 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2675 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2676 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2677 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2680 /* Unregister all commands. */
2682 void silc_client_commands_unregister(SilcClient client)
2684 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2685 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2686 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2687 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2688 SILC_CLIENT_CMDU(list, LIST, "LIST");
2689 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2690 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2691 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2692 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2693 SILC_CLIENT_CMDU(info, INFO, "INFO");
2694 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2695 SILC_CLIENT_CMDU(ping, PING, "PING");
2696 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2697 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2698 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2699 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2700 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2701 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2702 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2703 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2704 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2705 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2706 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2707 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2708 SILC_CLIENT_CMDU(users, USERS, "USERS");
2709 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2711 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2712 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2713 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2716 /**** Client side incoming command handling **********************************/
2718 void silc_client_command_process_whois(SilcClient client,
2719 SilcSocketConnection sock,
2720 SilcCommandPayload payload,
2721 SilcArgumentPayload args);
2723 /* Client is able to receive some command packets even though they are
2724 special case. Server may send WHOIS command to the client to retrieve
2725 Requested Attributes information for WHOIS query the server is
2726 processing. This function currently handles only the WHOIS command,
2727 but if in the future for commands may arrive then this can be made
2728 to support other commands too. */
2730 void silc_client_command_process(SilcClient client,
2731 SilcSocketConnection sock,
2732 SilcPacketContext *packet)
2734 SilcCommandPayload payload;
2735 SilcCommand command;
2736 SilcArgumentPayload args;
2738 /* Get command payload from packet */
2739 payload = silc_command_payload_parse(packet->buffer->data,
2740 packet->buffer->len);
2742 /* Silently ignore bad reply packet */
2743 SILC_LOG_DEBUG(("Bad command packet"));
2748 args = silc_command_get_args(payload);
2750 /* Get the command */
2751 command = silc_command_get(payload);
2754 case SILC_COMMAND_WHOIS:
2755 /* Ignore everything if requested by application */
2756 if (client->internal->params->ignore_requested_attributes)
2759 silc_client_command_process_whois(client, sock, payload, args);
2766 silc_command_payload_free(payload);
2769 void silc_client_command_process_whois(SilcClient client,
2770 SilcSocketConnection sock,
2771 SilcCommandPayload payload,
2772 SilcArgumentPayload args)
2777 SilcBuffer buffer, packet;
2779 SILC_LOG_DEBUG(("Received WHOIS command"));
2781 /* Try to take the Requested Attributes */
2782 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2786 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2790 /* Process requested attributes */
2791 buffer = silc_client_attributes_process(client, sock, attrs);
2793 silc_attribute_payload_list_free(attrs);
2797 /* Send the attributes back */
2799 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2801 silc_command_get_ident(payload),
2802 1, 11, buffer->data, buffer->len);
2803 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2804 NULL, 0, NULL, NULL, packet->data,
2806 silc_buffer_free(packet);
2807 silc_buffer_free(buffer);