5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2004 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, please connect to server");
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;
289 bool details = FALSE, nick = FALSE;
290 unsigned char *pubkey = NULL;
293 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
294 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
298 /* Given without arguments fetches client's own information */
300 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
301 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
303 1, 4, buffer->data, buffer->len);
304 silc_buffer_free(buffer);
308 for (i = 1; i < cmd->argc; i++) {
309 if (!strcasecmp(cmd->argv[i], "-details")) {
311 } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
312 pubkey = cmd->argv[i + 1];
315 /* We assume that the first parameter is the nickname, if it isn't
316 -details or -pubkey. The last parameter should always be the count */
319 } else if (i == cmd->argc - 1) {
320 int c = atoi(cmd->argv[i]);
321 SILC_PUT32_MSB(c, count);
328 /* if pubkey is set, add all attributes to the
329 attrs buffer, except public key */
331 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
332 SILC_ATTRIBUTE_SERVICE,
333 SILC_ATTRIBUTE_STATUS_MOOD,
334 SILC_ATTRIBUTE_STATUS_FREETEXT,
335 SILC_ATTRIBUTE_STATUS_MESSAGE,
336 SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
337 SILC_ATTRIBUTE_PREFERRED_CONTACT,
338 SILC_ATTRIBUTE_TIMEZONE,
339 SILC_ATTRIBUTE_GEOLOCATION,
340 SILC_ATTRIBUTE_DEVICE_INFO, 0);
342 attrs = silc_client_attributes_request(0);
347 SilcAttributeObjPk obj;
350 if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) {
351 if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) {
352 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
353 "Could not load public key %s, check the filename",
355 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
360 obj.type = "silc-rsa";
361 obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
363 attrs = silc_attribute_payload_encode(attrs,
364 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
365 SILC_ATTRIBUTE_FLAG_VALID,
369 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
370 ++conn->cmd_ident, 3,
371 1, nick ? cmd->argv[1] : NULL,
372 nick ? cmd->argv_lens[1] : 0,
373 2, tmp ? tmp : NULL, tmp ? 4 : 0,
374 3, attrs ? attrs->data : NULL,
375 attrs ? attrs->len : 0);
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 WHOWAS. This command is used to query history information about
390 specific user that used to exist in the network. */
392 SILC_CLIENT_CMD_FUNC(whowas)
394 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
395 SilcClientConnection conn = cmd->conn;
397 unsigned char count[4];
400 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
405 if (cmd->argc < 2 || cmd->argc > 3) {
406 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
407 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
408 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
409 SILC_STATUS_ERR_TOO_MANY_PARAMS));
413 if (cmd->argc == 2) {
414 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
415 ++conn->cmd_ident, 1,
419 int c = atoi(cmd->argv[2]);
420 memset(count, 0, sizeof(count));
421 SILC_PUT32_MSB(c, count);
422 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
423 ++conn->cmd_ident, 2,
424 1, cmd->argv[1], cmd->argv_lens[1],
425 2, 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);
432 /* Notify application */
433 COMMAND(SILC_STATUS_OK);
436 silc_client_command_free(cmd);
439 /* Command IDENTIFY. This command is used to query information about
440 specific user, especially ID's.
442 NOTE: This command is used only internally by the client library
443 and application MUST NOT call this command directly. */
445 SILC_CLIENT_CMD_FUNC(identify)
447 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
448 SilcClientConnection conn = cmd->conn;
450 unsigned char count[4];
453 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
454 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
458 if (cmd->argc < 2 || cmd->argc > 3)
461 if (cmd->argc == 2) {
462 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
463 ++conn->cmd_ident, 1,
467 int c = atoi(cmd->argv[2]);
468 memset(count, 0, sizeof(count));
469 SILC_PUT32_MSB(c, count);
470 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
471 ++conn->cmd_ident, 2,
474 4, count, sizeof(count));
477 silc_client_packet_send(cmd->client, cmd->conn->sock,
478 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
479 buffer->data, buffer->len, TRUE);
480 silc_buffer_free(buffer);
483 silc_client_command_free(cmd);
486 /* Command NICK. Shows current nickname/sets new nickname on current
489 SILC_CLIENT_CMD_FUNC(nick)
491 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
492 SilcClientConnection conn = cmd->conn;
496 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
502 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
503 "Usage: /NICK <nickname>");
504 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
508 if (!strcmp(conn->nickname, cmd->argv[1]))
511 /* Show current nickname */
514 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
515 "Your nickname is %s on server %s",
516 conn->nickname, conn->remote_host);
518 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
519 "Your nickname is %s", conn->nickname);
522 COMMAND(SILC_STATUS_OK);
526 if (cmd->argv_lens[1] > 128)
527 cmd->argv_lens[1] = 128;
529 /* Send the NICK command */
530 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
534 ++cmd->conn->cmd_ident);
535 silc_client_packet_send(cmd->client, cmd->conn->sock,
536 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
537 buffer->data, buffer->len, TRUE);
538 silc_buffer_free(buffer);
541 silc_client_command_free(cmd);
544 /* Command LIST. Lists channels on the current server. */
546 SILC_CLIENT_CMD_FUNC(list)
548 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
549 SilcClientConnection conn = cmd->conn;
550 SilcIDCacheEntry id_cache = NULL;
551 SilcChannelEntry channel;
552 SilcBuffer buffer, idp = NULL;
556 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
557 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
561 if (cmd->argc == 2) {
564 /* Get the Channel ID of the channel */
565 if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
567 channel = (SilcChannelEntry)id_cache->context;
568 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
573 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
574 ++conn->cmd_ident, 0);
576 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
577 ++conn->cmd_ident, 1,
578 1, idp->data, idp->len);
580 silc_client_packet_send(cmd->client, cmd->conn->sock,
581 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
582 buffer->data, buffer->len, TRUE);
583 silc_buffer_free(buffer);
585 silc_buffer_free(idp);
587 /* Notify application */
588 COMMAND(SILC_STATUS_OK);
591 silc_client_command_free(cmd);
594 /* Command TOPIC. Sets/shows topic on a channel. */
596 SILC_CLIENT_CMD_FUNC(topic)
598 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
599 SilcClientConnection conn = cmd->conn;
600 SilcIDCacheEntry id_cache = NULL;
601 SilcChannelEntry channel;
602 SilcBuffer buffer, idp;
606 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
607 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
611 if (cmd->argc < 2 || cmd->argc > 3) {
612 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
613 "Usage: /TOPIC <channel> [<topic>]");
614 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
615 SILC_STATUS_ERR_TOO_MANY_PARAMS));
619 if (cmd->argv[1][0] == '*') {
620 if (!conn->current_channel) {
621 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
624 name = conn->current_channel->channel_name;
629 if (!conn->current_channel) {
630 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
634 /* Get the Channel ID of the channel */
635 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
637 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
641 channel = (SilcChannelEntry)id_cache->context;
643 /* Send TOPIC command to the server */
644 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
646 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
647 ++conn->cmd_ident, 2,
648 1, idp->data, idp->len,
650 strlen(cmd->argv[2]));
652 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
653 ++conn->cmd_ident, 1,
654 1, idp->data, idp->len);
655 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
656 0, NULL, NULL, buffer->data, buffer->len, TRUE);
657 silc_buffer_free(buffer);
658 silc_buffer_free(idp);
660 /* Notify application */
661 COMMAND(SILC_STATUS_OK);
664 silc_client_command_free(cmd);
667 /* Command INVITE. Invites specific client to join a channel. This is
668 also used to mange the invite list of the channel. */
670 SILC_CLIENT_CMD_FUNC(invite)
672 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
673 SilcClient client = cmd->client;
674 SilcClientConnection conn = cmd->conn;
675 SilcClientEntry client_entry = NULL;
676 SilcChannelEntry channel;
677 SilcBuffer buffer, clidp, chidp, args = NULL;
678 SilcPublicKey pubkey = NULL;
679 char *nickname = NULL, *name;
681 unsigned char action[1];
684 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
685 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
690 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
691 "Usage: /INVITE <channel> [<nickname>[@server>]"
692 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
693 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
697 if (cmd->argv[1][0] == '*') {
698 if (!conn->current_channel) {
699 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
703 channel = conn->current_channel;
707 channel = silc_client_get_channel(cmd->client, conn, name);
709 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
714 /* Parse the typed nickname. */
715 if (cmd->argc == 3) {
716 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
717 if (client->internal->params->nickname_parse)
718 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
720 nickname = strdup(cmd->argv[2]);
722 /* Find client entry */
723 client_entry = silc_idlist_get_client(client, conn, nickname,
727 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
731 /* Client entry not found, it was requested thus mark this to be
733 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
735 silc_client_command_invite,
736 silc_client_command_dup(cmd));
741 if (cmd->argv[2][0] == '+')
746 /* Check if it is public key file to be added to invite list */
747 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
749 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
751 invite = cmd->argv[2];
758 args = silc_buffer_alloc_size(2);
759 silc_buffer_format(args,
760 SILC_STR_UI_SHORT(1),
763 chidp = silc_pkcs_public_key_payload_encode(pubkey);
764 args = silc_argument_payload_encode_one(args, chidp->data,
766 silc_buffer_free(chidp);
767 silc_pkcs_public_key_free(pubkey);
769 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
773 /* Send the command */
774 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
776 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
777 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
778 ++conn->cmd_ident, 4,
779 1, chidp->data, chidp->len,
780 2, clidp->data, clidp->len,
781 3, args ? action : NULL,
783 4, args ? args->data : NULL,
784 args ? args->len : 0);
785 silc_buffer_free(clidp);
787 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
788 ++conn->cmd_ident, 3,
789 1, chidp->data, chidp->len,
790 3, args ? action : NULL,
792 4, args ? args->data : NULL,
793 args ? args->len : 0);
796 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
797 0, NULL, NULL, buffer->data, buffer->len, TRUE);
798 silc_buffer_free(buffer);
799 silc_buffer_free(chidp);
800 silc_buffer_free(args);
802 /* Notify application */
803 COMMAND(SILC_STATUS_OK);
807 silc_client_command_free(cmd);
812 SilcClientConnection conn;
815 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
817 QuitInternal q = (QuitInternal)context;
819 /* Close connection */
820 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
821 silc_client_close_connection(q->client, q->conn->sock->user_data);
826 /* Command QUIT. Closes connection with current server. */
828 SILC_CLIENT_CMD_FUNC(quit)
830 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
835 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
836 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
841 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
842 &cmd->argv[1], &cmd->argv_lens[1],
844 ++cmd->conn->cmd_ident);
846 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
848 ++cmd->conn->cmd_ident);
849 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
851 buffer->data, buffer->len, TRUE);
852 silc_buffer_free(buffer);
854 q = silc_calloc(1, sizeof(*q));
855 q->client = cmd->client;
858 /* Sleep for a while */
861 /* We quit the connection with little timeout */
862 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
863 silc_client_command_quit_cb, (void *)q,
864 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
866 /* Notify application */
867 COMMAND(SILC_STATUS_OK);
870 silc_client_command_free(cmd);
873 /* Timeout callback to remove the killed client from cache */
875 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
877 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
878 SilcClient client = cmd->client;
879 SilcClientConnection conn = cmd->conn;
880 SilcClientEntry target;
881 char *nickname = NULL;
883 /* Parse the typed nickname. */
884 if (client->internal->params->nickname_parse)
885 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
887 nickname = strdup(cmd->argv[1]);
889 /* Get the target client */
890 target = silc_idlist_get_client(cmd->client, conn, nickname,
891 cmd->argv[1], FALSE);
893 /* Remove the client from all channels and free it */
894 silc_client_del_client(client, conn, target);
897 silc_client_command_free(cmd);
900 /* Kill command's pending command callback to actually remove the killed
901 client from our local cache. */
903 SILC_CLIENT_CMD_FUNC(kill_remove)
905 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
906 SilcClientCommandReplyContext reply =
907 (SilcClientCommandReplyContext)context2;
910 silc_command_get_status(reply->payload, &status, NULL);
911 if (status == SILC_STATUS_OK) {
912 /* Remove with timeout */
913 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
914 silc_client_command_kill_remove_later, context,
915 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
919 silc_client_command_free(cmd);
922 /* Command KILL. Router operator can use this command to remove an client
923 fromthe SILC Network. */
925 SILC_CLIENT_CMD_FUNC(kill)
927 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
928 SilcClient client = cmd->client;
929 SilcClientConnection conn = cmd->conn;
930 SilcBuffer buffer, idp, auth = NULL;
931 SilcClientEntry target;
932 char *nickname = NULL, *comment = NULL;
935 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
936 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
941 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
942 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
947 /* Parse the typed nickname. */
948 if (client->internal->params->nickname_parse)
949 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
951 nickname = strdup(cmd->argv[1]);
953 /* Get the target client */
954 target = silc_idlist_get_client(cmd->client, conn, nickname,
958 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
962 /* Client entry not found, it was requested thus mark this to be
964 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
966 silc_client_command_kill,
967 silc_client_command_dup(cmd));
972 if (cmd->argc >= 3) {
973 if (strcasecmp(cmd->argv[2], "-pubkey"))
974 comment = cmd->argv[2];
976 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
977 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
978 /* Encode the public key authentication payload */
979 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
980 cmd->client->private_key,
983 target->id, SILC_ID_CLIENT);
987 /* Send the KILL command to the server */
988 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
990 silc_command_payload_encode_va(SILC_COMMAND_KILL,
991 ++conn->cmd_ident, 3,
992 1, idp->data, idp->len,
993 2, comment, comment ? strlen(comment) : 0,
994 3, auth ? auth->data : NULL,
995 auth ? auth->len : 0);
996 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
997 0, NULL, NULL, buffer->data, buffer->len, TRUE);
998 silc_buffer_free(buffer);
999 silc_buffer_free(idp);
1000 silc_buffer_free(auth);
1002 /* Notify application */
1003 COMMAND(SILC_STATUS_OK);
1005 /* Register a pending callback that will actually remove the killed
1006 client from our cache. */
1007 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
1008 silc_client_command_kill_remove,
1009 silc_client_command_dup(cmd));
1012 silc_free(nickname);
1013 silc_client_command_free(cmd);
1016 /* Command INFO. Request information about specific server. If specific
1017 server is not provided the current server is used. */
1019 SILC_CLIENT_CMD_FUNC(info)
1021 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1022 SilcClientConnection conn = cmd->conn;
1027 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1028 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1033 name = strdup(cmd->argv[1]);
1035 /* Send the command */
1037 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO,
1038 ++conn->cmd_ident, 1,
1039 1, name, strlen(name));
1041 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
1042 NULL, NULL, NULL, ++conn->cmd_ident);
1043 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1044 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1045 silc_buffer_free(buffer);
1049 /* Notify application */
1050 COMMAND(SILC_STATUS_OK);
1053 silc_client_command_free(cmd);
1056 /* Command STATS. Shows server and network statistics. */
1058 SILC_CLIENT_CMD_FUNC(stats)
1060 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1061 SilcClientConnection conn = cmd->conn;
1062 SilcBuffer buffer, idp = NULL;
1065 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1066 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1070 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1072 /* Send the command */
1073 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1074 ++conn->cmd_ident, 1,
1075 SILC_ID_SERVER, idp->data, idp->len);
1076 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1077 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1078 silc_buffer_free(buffer);
1079 silc_buffer_free(idp);
1081 /* Notify application */
1082 COMMAND(SILC_STATUS_OK);
1085 silc_client_command_free(cmd);
1088 /* Command PING. Sends ping to server. This is used to test the
1089 communication channel. */
1091 SILC_CLIENT_CMD_FUNC(ping)
1093 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1094 SilcClientConnection conn = cmd->conn;
1095 SilcBuffer buffer, idp;
1100 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1101 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1105 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1107 /* Send the command */
1108 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING,
1109 ++conn->cmd_ident, 1,
1110 1, idp->data, idp->len);
1111 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1112 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1113 silc_buffer_free(buffer);
1114 silc_buffer_free(idp);
1116 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1119 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1120 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1124 /* Start counting time */
1125 for (i = 0; i < conn->internal->ping_count; i++) {
1126 if (conn->internal->ping[i].dest_id == NULL) {
1127 conn->internal->ping[i].start_time = time(NULL);
1128 conn->internal->ping[i].dest_id = id;
1129 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1133 if (i >= conn->internal->ping_count) {
1134 i = conn->internal->ping_count;
1135 conn->internal->ping =
1136 silc_realloc(conn->internal->ping,
1137 sizeof(*conn->internal->ping) * (i + 1));
1138 conn->internal->ping[i].start_time = time(NULL);
1139 conn->internal->ping[i].dest_id = id;
1140 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1141 conn->internal->ping_count++;
1144 /* Notify application */
1145 COMMAND(SILC_STATUS_OK);
1148 silc_client_command_free(cmd);
1151 /* Command JOIN. Joins to a channel. */
1153 SILC_CLIENT_CMD_FUNC(join)
1155 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1156 SilcClientConnection conn = cmd->conn;
1157 SilcChannelEntry channel;
1158 SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
1159 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1160 int i, passphrase_len = 0;
1163 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1164 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1168 if (cmd->argc < 2) {
1169 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1173 /* See if we have joined to the requested channel already */
1174 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1175 if (channel && silc_client_on_channel(channel, conn->local_entry))
1178 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1180 if (cmd->argv_lens[1] > 256)
1181 cmd->argv_lens[1] = 256;
1183 name = cmd->argv[1];
1185 for (i = 2; i < cmd->argc; i++) {
1186 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1187 cipher = cmd->argv[i + 1];
1189 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1190 hmac = cmd->argv[i + 1];
1192 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1193 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1194 cmd->client->private_key,
1196 cmd->client->sha1hash,
1199 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1200 SilcPublicKey pubkey = cmd->client->public_key;
1201 SilcPrivateKey privkey = cmd->client->private_key;
1202 unsigned char *pk, pkhash[20], *pubdata;
1205 if (cmd->argc >= i + 3) {
1207 if (cmd->argc >= i + 4) {
1208 pass = cmd->argv[i + 3];
1211 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1212 NULL, &pubkey, &privkey)) {
1213 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1214 "Could not load key pair, check your arguments");
1215 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1221 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1222 silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
1224 pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
1225 memcpy(pubdata, pkhash, 20);
1226 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1228 cmd->client->sha1hash,
1231 memset(pubdata, 0, 128);
1234 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1235 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1236 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1237 cmd->argv_lens[i], 0);
1238 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1239 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1240 0, pu8, passphrase_len);
1243 passphrase = strdup(cmd->argv[i]);
1244 passphrase_len = cmd->argv_lens[i];
1249 /* Send JOIN command to the server */
1251 silc_command_payload_encode_va(SILC_COMMAND_JOIN, ++conn->cmd_ident, 7,
1252 1, name, strlen(name),
1253 2, idp->data, idp->len,
1254 3, passphrase, passphrase_len,
1255 4, cipher, cipher ? strlen(cipher) : 0,
1256 5, hmac, hmac ? strlen(hmac) : 0,
1257 6, auth ? auth->data : NULL,
1258 auth ? auth->len : 0,
1259 7, cauth ? cauth->data : NULL,
1260 cauth ? cauth->len : 0);
1261 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1262 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1263 silc_buffer_free(buffer);
1264 silc_buffer_free(idp);
1265 silc_buffer_free(auth);
1266 silc_buffer_free(cauth);
1268 memset(passphrase, 0, strlen(passphrase));
1269 silc_free(passphrase);
1271 /* Notify application */
1272 COMMAND(SILC_STATUS_OK);
1275 silc_client_command_free(cmd);
1278 /* MOTD command. Requests motd from server. */
1280 SILC_CLIENT_CMD_FUNC(motd)
1282 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1283 SilcClientConnection conn = cmd->conn;
1287 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1288 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1292 if (cmd->argc < 1 || cmd->argc > 2) {
1293 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1294 "Usage: /MOTD [<server>]");
1295 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1296 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1300 /* Send TOPIC command to the server */
1302 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
1303 ++conn->cmd_ident, 1,
1304 1, conn->remote_host,
1305 strlen(conn->remote_host));
1307 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
1308 ++conn->cmd_ident, 1,
1311 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1312 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1313 silc_buffer_free(buffer);
1315 /* Notify application */
1316 COMMAND(SILC_STATUS_OK);
1319 silc_client_command_free(cmd);
1322 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1323 modes as client cannot set itself server/router operator privileges. */
1325 SILC_CLIENT_CMD_FUNC(umode)
1327 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1328 SilcClientConnection conn = cmd->conn;
1329 SilcBuffer buffer, idp;
1330 unsigned char *cp, modebuf[4];
1331 SilcUInt32 mode, add, len;
1335 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1336 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1340 if (cmd->argc < 2) {
1341 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1342 "Usage: /UMODE +|-<modes>");
1343 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1347 mode = conn->local_entry->mode;
1349 /* Are we adding or removing mode */
1350 if (cmd->argv[1][0] == '-')
1356 cp = cmd->argv[1] + 1;
1358 for (i = 0; i < len; i++) {
1363 mode |= SILC_UMODE_SERVER_OPERATOR;
1364 mode |= SILC_UMODE_ROUTER_OPERATOR;
1365 mode |= SILC_UMODE_GONE;
1366 mode |= SILC_UMODE_INDISPOSED;
1367 mode |= SILC_UMODE_BUSY;
1368 mode |= SILC_UMODE_PAGE;
1369 mode |= SILC_UMODE_HYPER;
1370 mode |= SILC_UMODE_ROBOT;
1371 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1372 mode |= SILC_UMODE_REJECT_WATCHING;
1374 mode = SILC_UMODE_NONE;
1379 mode |= SILC_UMODE_SERVER_OPERATOR;
1381 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1385 mode |= SILC_UMODE_ROUTER_OPERATOR;
1387 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1391 mode |= SILC_UMODE_GONE;
1393 mode &= ~SILC_UMODE_GONE;
1397 mode |= SILC_UMODE_INDISPOSED;
1399 mode &= ~SILC_UMODE_INDISPOSED;
1403 mode |= SILC_UMODE_BUSY;
1405 mode &= ~SILC_UMODE_BUSY;
1409 mode |= SILC_UMODE_PAGE;
1411 mode &= ~SILC_UMODE_PAGE;
1415 mode |= SILC_UMODE_HYPER;
1417 mode &= ~SILC_UMODE_HYPER;
1421 mode |= SILC_UMODE_ROBOT;
1423 mode &= ~SILC_UMODE_ROBOT;
1427 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1429 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1433 mode |= SILC_UMODE_REJECT_WATCHING;
1435 mode &= ~SILC_UMODE_REJECT_WATCHING;
1439 mode |= SILC_UMODE_BLOCK_INVITE;
1441 mode &= ~SILC_UMODE_BLOCK_INVITE;
1444 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1450 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1451 SILC_PUT32_MSB(mode, modebuf);
1453 /* Send the command packet. We support sending only one mode at once
1454 that requires an argument. */
1456 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1457 1, idp->data, idp->len,
1458 2, modebuf, sizeof(modebuf));
1459 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1460 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1461 silc_buffer_free(buffer);
1462 silc_buffer_free(idp);
1464 /* Notify application */
1465 COMMAND(SILC_STATUS_OK);
1468 silc_client_command_free(cmd);
1471 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1472 can be set several at once. Those modes that require argument must be set
1473 separately (unless set with modes that does not require arguments). */
1475 SILC_CLIENT_CMD_FUNC(cmode)
1477 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1478 SilcClientConnection conn = cmd->conn;
1479 SilcChannelEntry channel;
1480 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1481 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1482 SilcUInt32 mode, add, type, len, arg_len = 0;
1486 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1487 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1491 if (cmd->argc < 3) {
1492 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1493 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1494 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1498 if (cmd->argv[1][0] == '*') {
1499 if (!conn->current_channel) {
1500 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1504 channel = conn->current_channel;
1506 name = cmd->argv[1];
1508 channel = silc_client_get_channel(cmd->client, conn, name);
1510 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1515 mode = channel->mode;
1517 /* Are we adding or removing mode */
1518 if (cmd->argv[2][0] == '-')
1523 /* Argument type to be sent to server */
1527 cp = cmd->argv[2] + 1;
1529 for (i = 0; i < len; i++) {
1533 mode |= SILC_CHANNEL_MODE_PRIVATE;
1535 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1539 mode |= SILC_CHANNEL_MODE_SECRET;
1541 mode &= ~SILC_CHANNEL_MODE_SECRET;
1545 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1547 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1551 mode |= SILC_CHANNEL_MODE_INVITE;
1553 mode &= ~SILC_CHANNEL_MODE_INVITE;
1557 mode |= SILC_CHANNEL_MODE_TOPIC;
1559 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1563 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1565 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1569 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1571 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1576 mode |= SILC_CHANNEL_MODE_ULIMIT;
1578 if (cmd->argc < 4) {
1579 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1580 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1581 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1584 ll = atoi(cmd->argv[3]);
1585 SILC_PUT32_MSB(ll, tmp);
1589 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1594 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1596 if (cmd->argc < 4) {
1597 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1598 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1599 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1603 arg_len = cmd->argv_lens[3];
1605 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1610 mode |= SILC_CHANNEL_MODE_CIPHER;
1612 if (cmd->argc < 4) {
1613 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1614 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1615 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1619 arg_len = cmd->argv_lens[3];
1621 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1626 mode |= SILC_CHANNEL_MODE_HMAC;
1628 if (cmd->argc < 4) {
1629 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1630 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1631 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1635 arg_len = cmd->argv_lens[3];
1637 mode &= ~SILC_CHANNEL_MODE_HMAC;
1642 SilcPublicKey pubkey = cmd->client->public_key;
1643 SilcPrivateKey privkey = cmd->client->private_key;
1645 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1648 if (cmd->argc >= 5) {
1651 pass = cmd->argv[5];
1652 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1653 NULL, &pubkey, &privkey)) {
1654 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1655 "Could not load key pair, check your arguments");
1656 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1661 pk = silc_pkcs_public_key_payload_encode(pubkey);
1662 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1664 cmd->client->sha1hash,
1668 arg_len = auth->len;
1670 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1677 SilcPublicKey chpk = NULL;
1679 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1682 if (cmd->argc == 3) {
1683 /* Send empty command to receive the public key list. */
1684 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1685 silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
1686 0, 1, 1, chidp->data, chidp->len);
1687 silc_buffer_free(chidp);
1689 /* Notify application */
1690 COMMAND(SILC_STATUS_OK);
1694 if (cmd->argc >= 4) {
1695 auth = silc_buffer_alloc_size(2);
1696 silc_buffer_format(auth,
1697 SILC_STR_UI_SHORT(cmd->argc - 3),
1701 for (k = 3; k < cmd->argc; k++) {
1702 if (cmd->argv[k][0] == '+')
1704 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1705 SILC_PKCS_FILE_PEM))
1706 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1707 SILC_PKCS_FILE_BIN)) {
1708 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1709 "Could not load public key %s, check the filename",
1711 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1712 silc_buffer_free(auth);
1717 pk = silc_pkcs_public_key_payload_encode(chpk);
1718 auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
1719 chadd ? 0x00 : 0x01);
1720 silc_pkcs_public_key_free(chpk);
1721 silc_buffer_free(pk);
1727 arg_len = auth->len;
1729 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1733 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1739 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1740 SILC_PUT32_MSB(mode, modebuf);
1742 /* Send the command packet. We support sending only one mode at once
1743 that requires an argument. */
1746 silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 4,
1747 1, chidp->data, chidp->len,
1748 2, modebuf, sizeof(modebuf),
1750 8, pk ? pk->data : NULL,
1754 silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 2,
1755 1, chidp->data, chidp->len,
1756 2, modebuf, sizeof(modebuf));
1759 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1760 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1761 silc_buffer_free(buffer);
1762 silc_buffer_free(chidp);
1763 silc_buffer_free(auth);
1764 silc_buffer_free(pk);
1766 /* Notify application */
1767 COMMAND(SILC_STATUS_OK);
1770 silc_client_command_free(cmd);
1773 /* CUMODE command. Changes client's mode on a channel. */
1775 SILC_CLIENT_CMD_FUNC(cumode)
1777 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1778 SilcClient client = cmd->client;
1779 SilcClientConnection conn = cmd->conn;
1780 SilcChannelEntry channel;
1781 SilcChannelUser chu;
1782 SilcClientEntry client_entry;
1783 SilcBuffer buffer, clidp, chidp, auth = NULL;
1784 unsigned char *name, *cp, modebuf[4];
1785 SilcUInt32 mode = 0, add, len;
1786 char *nickname = NULL;
1790 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1791 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1795 if (cmd->argc < 4) {
1796 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1797 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1798 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1802 if (cmd->argv[1][0] == '*') {
1803 if (!conn->current_channel) {
1804 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1808 channel = conn->current_channel;
1810 name = cmd->argv[1];
1812 channel = silc_client_get_channel(cmd->client, conn, name);
1814 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1819 /* Parse the typed nickname. */
1820 if (client->internal->params->nickname_parse)
1821 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1823 nickname = strdup(cmd->argv[3]);
1825 /* Find client entry */
1826 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1827 cmd->argv[3], TRUE);
1828 if (!client_entry) {
1830 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1834 /* Client entry not found, it was requested thus mark this to be
1836 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1838 silc_client_command_cumode,
1839 silc_client_command_dup(cmd));
1844 /* Get the current mode */
1845 chu = silc_client_on_channel(channel, client_entry);
1849 /* Are we adding or removing mode */
1850 if (cmd->argv[2][0] == '-')
1856 cp = cmd->argv[2] + 1;
1858 for (i = 0; i < len; i++) {
1862 mode |= SILC_CHANNEL_UMODE_CHANFO;
1863 mode |= SILC_CHANNEL_UMODE_CHANOP;
1864 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1865 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1866 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1868 mode = SILC_CHANNEL_UMODE_NONE;
1873 SilcPublicKey pubkey = cmd->client->public_key;
1874 SilcPrivateKey privkey = cmd->client->private_key;
1876 if (cmd->argc >= 6) {
1879 pass = cmd->argv[6];
1880 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1881 NULL, &pubkey, &privkey)) {
1882 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1883 "Could not load key pair, check your arguments");
1884 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1889 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1891 cmd->client->sha1hash,
1894 mode |= SILC_CHANNEL_UMODE_CHANFO;
1896 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1901 mode |= SILC_CHANNEL_UMODE_CHANOP;
1903 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1907 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1909 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1913 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1915 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1919 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1921 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1925 mode |= SILC_CHANNEL_UMODE_QUIET;
1927 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1930 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1936 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1937 SILC_PUT32_MSB(mode, modebuf);
1938 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1940 /* Send the command packet. We support sending only one mode at once
1941 that requires an argument. */
1942 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE,
1945 1, chidp->data, chidp->len,
1947 3, clidp->data, clidp->len,
1948 4, auth ? auth->data : NULL,
1949 auth ? auth->len : 0);
1951 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1952 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1953 silc_buffer_free(buffer);
1954 silc_buffer_free(chidp);
1955 silc_buffer_free(clidp);
1957 silc_buffer_free(auth);
1959 /* Notify application */
1960 COMMAND(SILC_STATUS_OK);
1963 silc_free(nickname);
1964 silc_client_command_free(cmd);
1967 /* KICK command. Kicks a client out of channel. */
1969 SILC_CLIENT_CMD_FUNC(kick)
1971 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1972 SilcClient client = cmd->client;
1973 SilcClientConnection conn = cmd->conn;
1974 SilcIDCacheEntry id_cache = NULL;
1975 SilcChannelEntry channel;
1976 SilcBuffer buffer, idp, idp2;
1977 SilcClientEntry target;
1979 char *nickname = NULL;
1982 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1983 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1987 if (cmd->argc < 3) {
1988 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1989 "Usage: /KICK <channel> <nickname> [<comment>]");
1990 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1994 if (cmd->argv[1][0] == '*') {
1995 if (!conn->current_channel) {
1996 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1999 name = conn->current_channel->channel_name;
2001 name = cmd->argv[1];
2004 if (!conn->current_channel) {
2005 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2009 /* Get the Channel ID of the channel */
2010 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
2012 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2016 channel = (SilcChannelEntry)id_cache->context;
2018 /* Parse the typed nickname. */
2019 if (client->internal->params->nickname_parse)
2020 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2022 nickname = strdup(cmd->argv[2]);
2024 /* Get the target client */
2025 target = silc_idlist_get_client(cmd->client, conn, nickname,
2026 cmd->argv[2], FALSE);
2028 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2029 "No such client: %s", cmd->argv[2]);
2030 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2034 /* Send KICK command to the server */
2035 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2036 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
2038 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
2039 ++conn->cmd_ident, 2,
2040 1, idp->data, idp->len,
2041 2, idp2->data, idp2->len);
2043 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
2044 ++conn->cmd_ident, 3,
2045 1, idp->data, idp->len,
2046 2, idp2->data, idp2->len,
2048 strlen(cmd->argv[3]));
2049 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2050 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2051 silc_buffer_free(buffer);
2052 silc_buffer_free(idp);
2053 silc_buffer_free(idp2);
2055 /* Notify application */
2056 COMMAND(SILC_STATUS_OK);
2059 silc_free(nickname);
2060 silc_client_command_free(cmd);
2063 static void silc_client_command_oper_send(unsigned char *data,
2064 SilcUInt32 data_len, void *context)
2066 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2067 SilcClientConnection conn = cmd->conn;
2068 SilcBuffer buffer, auth;
2070 if (cmd->argc >= 3) {
2071 /* Encode the public key authentication payload */
2072 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2073 cmd->client->private_key,
2075 conn->internal->hash,
2079 /* Encode the password authentication payload */
2080 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2084 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER,
2085 ++conn->cmd_ident, 2,
2087 strlen(cmd->argv[1]),
2088 2, auth ? auth->data : NULL,
2089 auth ? auth->len : 0);
2090 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2091 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2093 silc_buffer_free(buffer);
2094 silc_buffer_clear(auth);
2095 silc_buffer_free(auth);
2097 /* Notify application */
2098 COMMAND(SILC_STATUS_OK);
2101 /* OPER command. Used to obtain server operator privileges. */
2103 SILC_CLIENT_CMD_FUNC(oper)
2105 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2106 SilcClientConnection conn = cmd->conn;
2109 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2110 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2114 if (cmd->argc < 2) {
2115 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2116 "Usage: /OPER <username> [-pubkey]");
2117 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2121 if (cmd->argc < 3) {
2122 /* Get passphrase */
2123 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2124 silc_client_command_oper_send,
2129 silc_client_command_oper_send(NULL, 0, context);
2132 silc_client_command_free(cmd);
2135 static void silc_client_command_silcoper_send(unsigned char *data,
2136 SilcUInt32 data_len,
2139 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2140 SilcClientConnection conn = cmd->conn;
2141 SilcBuffer buffer, auth;
2143 if (cmd->argc >= 3) {
2144 /* Encode the public key authentication payload */
2145 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2146 cmd->client->private_key,
2148 conn->internal->hash,
2152 /* Encode the password authentication payload */
2153 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2157 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER,
2158 ++conn->cmd_ident, 2,
2160 strlen(cmd->argv[1]),
2161 2, auth ? auth->data : NULL,
2162 auth ? auth->len : 0);
2163 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2164 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2166 silc_buffer_free(buffer);
2167 silc_buffer_clear(auth);
2168 silc_buffer_free(auth);
2170 /* Notify application */
2171 COMMAND(SILC_STATUS_OK);
2174 /* SILCOPER command. Used to obtain router operator privileges. */
2176 SILC_CLIENT_CMD_FUNC(silcoper)
2178 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2179 SilcClientConnection conn = cmd->conn;
2182 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2183 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2187 if (cmd->argc < 2) {
2188 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2189 "Usage: /SILCOPER <username> [-pubkey]");
2190 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2194 if (cmd->argc < 3) {
2195 /* Get passphrase */
2196 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2197 silc_client_command_silcoper_send,
2202 silc_client_command_silcoper_send(NULL, 0, context);
2205 silc_client_command_free(cmd);
2208 /* Command BAN. This is used to manage the ban list of the channel. */
2210 SILC_CLIENT_CMD_FUNC(ban)
2212 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2213 SilcClientConnection conn = cmd->conn;
2214 SilcChannelEntry channel;
2215 SilcBuffer buffer, chidp, args = NULL;
2216 char *name, *ban = NULL;
2217 unsigned char action[1];
2218 SilcPublicKey pubkey = NULL;
2221 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2222 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2226 if (cmd->argc < 2) {
2227 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2228 "Usage: /BAN <channel> "
2229 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2230 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2234 if (cmd->argv[1][0] == '*') {
2235 if (!conn->current_channel) {
2236 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2240 channel = conn->current_channel;
2242 name = cmd->argv[1];
2244 channel = silc_client_get_channel(cmd->client, conn, name);
2246 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2251 if (cmd->argc == 3) {
2252 if (cmd->argv[2][0] == '+')
2257 /* Check if it is public key file to be added to invite list */
2258 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2259 SILC_PKCS_FILE_PEM))
2260 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2261 SILC_PKCS_FILE_BIN);
2268 args = silc_buffer_alloc_size(2);
2269 silc_buffer_format(args,
2270 SILC_STR_UI_SHORT(1),
2273 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2274 args = silc_argument_payload_encode_one(args, chidp->data,
2276 silc_buffer_free(chidp);
2277 silc_pkcs_public_key_free(pubkey);
2279 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2283 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2285 /* Send the command */
2286 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2287 ++conn->cmd_ident, 3,
2288 1, chidp->data, chidp->len,
2289 2, args ? action : NULL,
2291 3, args ? args->data : NULL,
2292 args ? args->len : 0);
2293 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2294 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2295 silc_buffer_free(buffer);
2296 silc_buffer_free(chidp);
2297 silc_buffer_free(args);
2299 /* Notify application */
2300 COMMAND(SILC_STATUS_OK);
2303 silc_client_command_free(cmd);
2306 /* Command DETACH. This is used to detach from the server */
2308 SILC_CLIENT_CMD_FUNC(detach)
2310 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2311 SilcClientConnection conn = cmd->conn;
2315 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2316 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2320 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2321 ++conn->cmd_ident, 0);
2322 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2323 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2324 silc_buffer_free(buffer);
2326 /* Notify application */
2327 COMMAND(SILC_STATUS_OK);
2330 silc_client_command_free(cmd);
2333 /* Command WATCH. */
2335 SILC_CLIENT_CMD_FUNC(watch)
2337 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2338 SilcClientConnection conn = cmd->conn;
2339 SilcBuffer buffer, idp = NULL, args = NULL;
2341 const char *pubkey = NULL;
2342 bool pubkey_add = TRUE;
2345 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2346 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2350 if (cmd->argc < 3) {
2351 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2355 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2357 if (!strcasecmp(cmd->argv[1], "-add")) {
2359 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2361 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2363 pubkey = cmd->argv[2] + 1;
2364 if (cmd->argv[2][0] == '-')
2367 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2374 if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) {
2375 if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) {
2376 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2377 "Could not load public key %s, check the filename",
2379 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2384 args = silc_buffer_alloc_size(2);
2385 silc_buffer_format(args,
2386 SILC_STR_UI_SHORT(1),
2388 buffer = silc_pkcs_public_key_payload_encode(pk);
2389 args = silc_argument_payload_encode_one(args, buffer->data, buffer->len,
2390 pubkey_add ? 0x00 : 0x01);
2391 silc_buffer_free(buffer);
2392 silc_pkcs_public_key_free(pk);
2395 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2396 ++conn->cmd_ident, 2,
2397 1, idp->data, idp->len,
2399 pubkey ? args->data : cmd->argv[2],
2400 pubkey ? args->len :
2402 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2403 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2404 silc_buffer_free(buffer);
2405 silc_buffer_free(args);
2407 /* Notify application */
2408 COMMAND(SILC_STATUS_OK);
2412 silc_buffer_free(idp);
2413 silc_client_command_free(cmd);
2416 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2418 SILC_CLIENT_CMD_FUNC(leave)
2420 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2421 SilcClientConnection conn = cmd->conn;
2422 SilcChannelEntry channel;
2423 SilcBuffer buffer, idp;
2427 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2428 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2432 if (cmd->argc != 2) {
2433 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2434 "Usage: /LEAVE <channel>");
2435 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2439 if (cmd->argv[1][0] == '*') {
2440 if (!conn->current_channel) {
2441 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2444 name = conn->current_channel->channel_name;
2446 name = cmd->argv[1];
2449 /* Get the channel entry */
2450 channel = silc_client_get_channel(cmd->client, conn, name);
2452 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2456 /* Send LEAVE command to the server */
2457 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2458 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE,
2459 ++conn->cmd_ident, 1,
2460 1, idp->data, idp->len);
2461 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2462 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2463 silc_buffer_free(buffer);
2464 silc_buffer_free(idp);
2466 /* Notify application */
2467 COMMAND(SILC_STATUS_OK);
2469 if (conn->current_channel == channel)
2470 conn->current_channel = NULL;
2473 silc_client_command_free(cmd);
2476 /* Command USERS. Requests the USERS of the clients joined on requested
2479 SILC_CLIENT_CMD_FUNC(users)
2481 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2482 SilcClientConnection conn = cmd->conn;
2487 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2488 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2492 if (cmd->argc != 2) {
2493 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2494 "Usage: /USERS <channel>");
2495 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2499 if (cmd->argv[1][0] == '*') {
2500 if (!conn->current_channel) {
2501 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2504 name = conn->current_channel->channel_name;
2506 name = cmd->argv[1];
2509 /* Send USERS command to the server */
2510 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2511 ++conn->cmd_ident, 1,
2512 2, name, strlen(name));
2513 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2514 NULL, 0, NULL, NULL, buffer->data,
2516 silc_buffer_free(buffer);
2518 /* Notify application */
2519 COMMAND(SILC_STATUS_OK);
2522 silc_client_command_free(cmd);
2525 /* Command GETKEY. Used to fetch remote client's public key. */
2527 SILC_CLIENT_CMD_FUNC(getkey)
2529 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2530 SilcClientConnection conn = cmd->conn;
2531 SilcClient client = cmd->client;
2532 SilcClientEntry client_entry = NULL;
2533 SilcServerEntry server_entry = NULL;
2534 char *nickname = NULL;
2535 SilcBuffer idp, buffer;
2537 SILC_LOG_DEBUG(("Start"));
2540 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2541 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2545 if (cmd->argc < 2) {
2546 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2547 "Usage: /GETKEY <nickname or server name>");
2548 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2552 /* Parse the typed nickname. */
2553 if (client->internal->params->nickname_parse)
2554 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2556 nickname = strdup(cmd->argv[1]);
2558 /* Find client entry */
2559 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2561 if (!client_entry) {
2562 /* Check whether user requested server actually */
2563 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2565 if (!server_entry) {
2566 /* No. what ever user wants we don't have it, so resolve it. We
2567 will first try to resolve the client, and if that fails then
2568 we'll try to resolve the server. */
2570 if (!cmd->pending) {
2571 /* This will send the IDENTIFY command for nickname */
2572 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2573 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2575 silc_client_command_getkey,
2576 silc_client_command_dup(cmd));
2580 SilcClientCommandReplyContext reply =
2581 (SilcClientCommandReplyContext)context2;
2584 /* If nickname was not found, then resolve the server. */
2585 silc_command_get_status(reply->payload, NULL, &error);
2586 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2587 /* This sends the IDENTIFY command to resolve the server. */
2588 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2590 silc_client_command_reply_identify_i, 0,
2592 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2594 2, cmd->argv[1], cmd->argv_lens[1]);
2595 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2597 silc_client_command_getkey,
2598 silc_client_command_dup(cmd));
2602 /* If server was not found, then we've resolved both nickname and
2603 server and did not find anybody. */
2604 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2605 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2606 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2607 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2608 silc_get_status_message(error));
2609 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2613 COMMAND_ERROR(error);
2618 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2620 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2623 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY,
2624 ++conn->cmd_ident, 1,
2625 1, idp->data, idp->len);
2626 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2627 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2628 silc_buffer_free(buffer);
2629 silc_buffer_free(idp);
2631 /* Notify application */
2632 COMMAND(SILC_STATUS_OK);
2635 silc_free(nickname);
2636 silc_client_command_free(cmd);
2639 /* Register a new command indicated by the `command' to the SILC client.
2640 The `name' is optional command name. If provided the command may be
2641 searched using the silc_client_command_find by that name. The
2642 `command_function' is the function to be called when the command is
2643 executed, and the `command_reply_function' is the function to be
2644 called after the server has sent reply back to the command.
2646 The `ident' is optional identifier for the command. If non-zero
2647 the `command_reply_function' for the command type `command' will be
2648 called only if the command reply sent by server includes the
2649 command identifier `ident'. Application usually does not need it
2650 and set it to zero value. */
2652 bool silc_client_command_register(SilcClient client,
2653 SilcCommand command,
2655 SilcCommandCb command_function,
2656 SilcCommandCb command_reply_function,
2660 SilcClientCommand cmd;
2662 cmd = silc_calloc(1, sizeof(*cmd));
2664 cmd->command = command_function;
2665 cmd->reply = command_reply_function;
2666 cmd->name = name ? strdup(name) : NULL;
2667 cmd->max_args = max_args;
2670 silc_list_add(client->internal->commands, cmd);
2675 /* Unregister a command indicated by the `command' with command function
2676 `command_function' and command reply function `command_reply_function'.
2677 Returns TRUE if the command was found and unregistered. */
2679 bool silc_client_command_unregister(SilcClient client,
2680 SilcCommand command,
2681 SilcCommandCb command_function,
2682 SilcCommandCb command_reply_function,
2685 SilcClientCommand cmd;
2687 silc_list_start(client->internal->commands);
2688 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2689 if (cmd->cmd == command && cmd->command == command_function &&
2690 cmd->reply == command_reply_function && cmd->ident == ident) {
2691 silc_list_del(client->internal->commands, cmd);
2692 silc_free(cmd->name);
2701 /* Private range commands, specific to this implementation (and compatible
2702 with SILC Server). */
2704 /* CONNECT command. Connects the server to another server. */
2706 SILC_CLIENT_CMD_FUNC(connect)
2708 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2709 SilcClientConnection conn = cmd->conn;
2711 unsigned char port[4];
2715 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2716 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2720 if (cmd->argc < 2) {
2721 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2722 "Usage: /CONNECT <server> [<port>]");
2723 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2727 if (cmd->argc == 3) {
2728 tmp = atoi(cmd->argv[2]);
2729 SILC_PUT32_MSB(tmp, port);
2733 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
2734 ++conn->cmd_ident, 2,
2736 strlen(cmd->argv[1]),
2739 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
2740 ++conn->cmd_ident, 1,
2742 strlen(cmd->argv[1]));
2743 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2744 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2745 silc_buffer_free(buffer);
2747 /* Notify application */
2748 COMMAND(SILC_STATUS_OK);
2751 silc_client_command_free(cmd);
2755 /* CLOSE command. Close server connection to the remote server */
2757 SILC_CLIENT_CMD_FUNC(close)
2759 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2760 SilcClientConnection conn = cmd->conn;
2762 unsigned char port[4];
2766 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2767 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2771 if (cmd->argc < 2) {
2772 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2773 "Usage: /CLOSE <server> [<port>]");
2774 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2778 if (cmd->argc == 3) {
2779 tmp = atoi(cmd->argv[2]);
2780 SILC_PUT32_MSB(tmp, port);
2784 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
2785 ++conn->cmd_ident, 2,
2787 strlen(cmd->argv[1]),
2790 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
2791 ++conn->cmd_ident, 1,
2793 strlen(cmd->argv[1]));
2794 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2795 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2796 silc_buffer_free(buffer);
2798 /* Notify application */
2799 COMMAND(SILC_STATUS_OK);
2802 silc_client_command_free(cmd);
2805 /* SHUTDOWN command. Shutdowns the server. */
2807 SILC_CLIENT_CMD_FUNC(shutdown)
2809 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2812 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2813 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2817 /* Send the command */
2818 silc_client_command_send(cmd->client, cmd->conn,
2819 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2821 /* Notify application */
2822 COMMAND(SILC_STATUS_OK);
2825 silc_client_command_free(cmd);
2828 /* Register all default commands provided by the client library for the
2831 void silc_client_commands_register(SilcClient client)
2833 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2836 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2837 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2838 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2839 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2840 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2841 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2842 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2843 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2844 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2845 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2846 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2847 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2848 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2849 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2850 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2851 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2852 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2853 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2854 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2855 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2856 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2857 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2858 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2859 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2860 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2861 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2863 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2864 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2865 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2868 /* Unregister all commands. */
2870 void silc_client_commands_unregister(SilcClient client)
2872 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2873 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2874 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2875 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2876 SILC_CLIENT_CMDU(list, LIST, "LIST");
2877 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2878 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2879 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2880 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2881 SILC_CLIENT_CMDU(info, INFO, "INFO");
2882 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2883 SILC_CLIENT_CMDU(ping, PING, "PING");
2884 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2885 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2886 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2887 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2888 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2889 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2890 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2891 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2892 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2893 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2894 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2895 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2896 SILC_CLIENT_CMDU(users, USERS, "USERS");
2897 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2899 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2900 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2901 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2904 /**** Client side incoming command handling **********************************/
2906 void silc_client_command_process_whois(SilcClient client,
2907 SilcSocketConnection sock,
2908 SilcCommandPayload payload,
2909 SilcArgumentPayload args);
2911 /* Client is able to receive some command packets even though they are
2912 special case. Server may send WHOIS command to the client to retrieve
2913 Requested Attributes information for WHOIS query the server is
2914 processing. This function currently handles only the WHOIS command,
2915 but if in the future for commands may arrive then this can be made
2916 to support other commands too. */
2918 void silc_client_command_process(SilcClient client,
2919 SilcSocketConnection sock,
2920 SilcPacketContext *packet)
2922 SilcCommandPayload payload;
2923 SilcCommand command;
2924 SilcArgumentPayload args;
2926 /* Get command payload from packet */
2927 payload = silc_command_payload_parse(packet->buffer->data,
2928 packet->buffer->len);
2930 /* Silently ignore bad reply packet */
2931 SILC_LOG_DEBUG(("Bad command packet"));
2936 args = silc_command_get_args(payload);
2938 /* Get the command */
2939 command = silc_command_get(payload);
2942 case SILC_COMMAND_WHOIS:
2943 /* Ignore everything if requested by application */
2944 if (client->internal->params->ignore_requested_attributes)
2947 silc_client_command_process_whois(client, sock, payload, args);
2954 silc_command_payload_free(payload);
2957 void silc_client_command_process_whois(SilcClient client,
2958 SilcSocketConnection sock,
2959 SilcCommandPayload payload,
2960 SilcArgumentPayload args)
2965 SilcBuffer buffer, packet;
2967 SILC_LOG_DEBUG(("Received WHOIS command"));
2969 /* Try to take the Requested Attributes */
2970 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2974 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2978 /* Process requested attributes */
2979 buffer = silc_client_attributes_process(client, sock, attrs);
2981 silc_attribute_payload_list_free(attrs);
2985 /* Send the attributes back */
2987 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2989 silc_command_get_ident(payload),
2990 1, 11, buffer->data, buffer->len);
2991 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2992 NULL, 0, NULL, NULL, packet->data,
2994 silc_buffer_free(packet);
2995 silc_buffer_free(buffer);