5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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 (silc_utf8_strcasecmp(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 SilcChannelEntry channel;
551 SilcBuffer buffer, idp = NULL;
554 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
555 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
559 if (cmd->argc == 2) {
560 /* Get the Channel ID of the channel */
561 channel = silc_client_get_channel(cmd->client, cmd->conn, cmd->argv[1]);
563 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
567 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
568 ++conn->cmd_ident, 0);
570 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
571 ++conn->cmd_ident, 1,
572 1, idp->data, idp->len);
574 silc_client_packet_send(cmd->client, cmd->conn->sock,
575 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
576 buffer->data, buffer->len, TRUE);
577 silc_buffer_free(buffer);
579 silc_buffer_free(idp);
581 /* Notify application */
582 COMMAND(SILC_STATUS_OK);
585 silc_client_command_free(cmd);
588 /* Command TOPIC. Sets/shows topic on a channel. */
590 SILC_CLIENT_CMD_FUNC(topic)
592 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
593 SilcClientConnection conn = cmd->conn;
594 SilcChannelEntry channel;
595 SilcBuffer buffer, idp;
599 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
600 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
604 if (cmd->argc < 2 || cmd->argc > 3) {
605 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
606 "Usage: /TOPIC <channel> [<topic>]");
607 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
608 SILC_STATUS_ERR_TOO_MANY_PARAMS));
612 if (cmd->argv[1][0] == '*') {
613 if (!conn->current_channel) {
614 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
617 name = conn->current_channel->channel_name;
622 if (!conn->current_channel) {
623 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
627 /* Get the Channel ID of the channel */
628 channel = silc_client_get_channel(cmd->client, conn, name);
630 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
634 /* Send TOPIC command to the server */
635 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
637 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
638 ++conn->cmd_ident, 2,
639 1, idp->data, idp->len,
641 strlen(cmd->argv[2]));
643 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
644 ++conn->cmd_ident, 1,
645 1, idp->data, idp->len);
646 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
647 0, NULL, NULL, buffer->data, buffer->len, TRUE);
648 silc_buffer_free(buffer);
649 silc_buffer_free(idp);
651 /* Notify application */
652 COMMAND(SILC_STATUS_OK);
655 silc_client_command_free(cmd);
658 /* Command INVITE. Invites specific client to join a channel. This is
659 also used to mange the invite list of the channel. */
661 SILC_CLIENT_CMD_FUNC(invite)
663 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
664 SilcClient client = cmd->client;
665 SilcClientConnection conn = cmd->conn;
666 SilcClientEntry client_entry = NULL;
667 SilcChannelEntry channel;
668 SilcBuffer buffer, clidp, chidp, args = NULL;
669 SilcPublicKey pubkey = NULL;
670 char *nickname = NULL, *name;
672 unsigned char action[1];
675 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
676 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
681 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
682 "Usage: /INVITE <channel> [<nickname>[@server>]"
683 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
684 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
688 if (cmd->argv[1][0] == '*') {
689 if (!conn->current_channel) {
690 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
694 channel = conn->current_channel;
698 channel = silc_client_get_channel(cmd->client, conn, name);
700 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
705 /* Parse the typed nickname. */
706 if (cmd->argc == 3) {
707 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
708 if (client->internal->params->nickname_parse)
709 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
711 nickname = strdup(cmd->argv[2]);
713 /* Find client entry */
714 client_entry = silc_idlist_get_client(client, conn, nickname,
718 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
722 /* Client entry not found, it was requested thus mark this to be
724 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
726 silc_client_command_invite,
727 silc_client_command_dup(cmd));
732 if (cmd->argv[2][0] == '+')
737 /* Check if it is public key file to be added to invite list */
738 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
740 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
742 invite = cmd->argv[2];
749 args = silc_buffer_alloc_size(2);
750 silc_buffer_format(args,
751 SILC_STR_UI_SHORT(1),
754 chidp = silc_pkcs_public_key_payload_encode(pubkey);
755 args = silc_argument_payload_encode_one(args, chidp->data,
757 silc_buffer_free(chidp);
758 silc_pkcs_public_key_free(pubkey);
760 args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1);
764 /* Send the command */
765 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
767 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
768 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
769 ++conn->cmd_ident, 4,
770 1, chidp->data, chidp->len,
771 2, clidp->data, clidp->len,
772 3, args ? action : NULL,
774 4, args ? args->data : NULL,
775 args ? args->len : 0);
776 silc_buffer_free(clidp);
778 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
779 ++conn->cmd_ident, 3,
780 1, chidp->data, chidp->len,
781 3, args ? action : NULL,
783 4, args ? args->data : NULL,
784 args ? args->len : 0);
787 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
788 0, NULL, NULL, buffer->data, buffer->len, TRUE);
789 silc_buffer_free(buffer);
790 silc_buffer_free(chidp);
791 silc_buffer_free(args);
793 /* Notify application */
794 COMMAND(SILC_STATUS_OK);
798 silc_client_command_free(cmd);
803 SilcClientConnection conn;
806 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
808 QuitInternal q = (QuitInternal)context;
810 /* Close connection */
811 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
812 silc_client_close_connection(q->client, q->conn->sock->user_data);
817 /* Command QUIT. Closes connection with current server. */
819 SILC_CLIENT_CMD_FUNC(quit)
821 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
826 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
827 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
832 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
833 &cmd->argv[1], &cmd->argv_lens[1],
835 ++cmd->conn->cmd_ident);
837 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
839 ++cmd->conn->cmd_ident);
840 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
842 buffer->data, buffer->len, TRUE);
843 silc_buffer_free(buffer);
845 q = silc_calloc(1, sizeof(*q));
846 q->client = cmd->client;
849 /* Sleep for a while */
852 /* We quit the connection with little timeout */
853 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
854 silc_client_command_quit_cb, (void *)q,
855 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
857 /* Notify application */
858 COMMAND(SILC_STATUS_OK);
861 silc_client_command_free(cmd);
864 /* Timeout callback to remove the killed client from cache */
866 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
868 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
869 SilcClient client = cmd->client;
870 SilcClientConnection conn = cmd->conn;
871 SilcClientEntry target;
872 char *nickname = NULL;
874 /* Parse the typed nickname. */
875 if (client->internal->params->nickname_parse)
876 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
878 nickname = strdup(cmd->argv[1]);
880 /* Get the target client */
881 target = silc_idlist_get_client(cmd->client, conn, nickname,
882 cmd->argv[1], FALSE);
884 /* Remove the client from all channels and free it */
885 silc_client_del_client(client, conn, target);
888 silc_client_command_free(cmd);
891 /* Kill command's pending command callback to actually remove the killed
892 client from our local cache. */
894 SILC_CLIENT_CMD_FUNC(kill_remove)
896 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
897 SilcClientCommandReplyContext reply =
898 (SilcClientCommandReplyContext)context2;
901 silc_command_get_status(reply->payload, &status, NULL);
902 if (status == SILC_STATUS_OK) {
903 /* Remove with timeout */
904 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
905 silc_client_command_kill_remove_later, context,
906 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
910 silc_client_command_free(cmd);
913 /* Command KILL. Router operator can use this command to remove an client
914 fromthe SILC Network. */
916 SILC_CLIENT_CMD_FUNC(kill)
918 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
919 SilcClient client = cmd->client;
920 SilcClientConnection conn = cmd->conn;
921 SilcBuffer buffer, idp, auth = NULL;
922 SilcClientEntry target;
923 char *nickname = NULL, *comment = NULL;
926 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
927 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
932 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
933 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
934 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
938 /* Parse the typed nickname. */
939 if (client->internal->params->nickname_parse)
940 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
942 nickname = strdup(cmd->argv[1]);
944 /* Get the target client */
945 target = silc_idlist_get_client(cmd->client, conn, nickname,
949 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
953 /* Client entry not found, it was requested thus mark this to be
955 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
957 silc_client_command_kill,
958 silc_client_command_dup(cmd));
963 if (cmd->argc >= 3) {
964 if (strcasecmp(cmd->argv[2], "-pubkey"))
965 comment = cmd->argv[2];
967 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
968 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
969 /* Encode the public key authentication payload */
970 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
971 cmd->client->private_key,
974 target->id, SILC_ID_CLIENT);
978 /* Send the KILL command to the server */
979 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
981 silc_command_payload_encode_va(SILC_COMMAND_KILL,
982 ++conn->cmd_ident, 3,
983 1, idp->data, idp->len,
984 2, comment, comment ? strlen(comment) : 0,
985 3, auth ? auth->data : NULL,
986 auth ? auth->len : 0);
987 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
988 0, NULL, NULL, buffer->data, buffer->len, TRUE);
989 silc_buffer_free(buffer);
990 silc_buffer_free(idp);
991 silc_buffer_free(auth);
993 /* Notify application */
994 COMMAND(SILC_STATUS_OK);
996 /* Register a pending callback that will actually remove the killed
997 client from our cache. */
998 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
999 silc_client_command_kill_remove,
1000 silc_client_command_dup(cmd));
1003 silc_free(nickname);
1004 silc_client_command_free(cmd);
1007 /* Command INFO. Request information about specific server. If specific
1008 server is not provided the current server is used. */
1010 SILC_CLIENT_CMD_FUNC(info)
1012 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1013 SilcClientConnection conn = cmd->conn;
1018 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1019 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1024 name = strdup(cmd->argv[1]);
1026 /* Send the command */
1028 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO,
1029 ++conn->cmd_ident, 1,
1030 1, name, strlen(name));
1032 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
1033 NULL, NULL, NULL, ++conn->cmd_ident);
1034 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1035 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1036 silc_buffer_free(buffer);
1040 /* Notify application */
1041 COMMAND(SILC_STATUS_OK);
1044 silc_client_command_free(cmd);
1047 /* Command STATS. Shows server and network statistics. */
1049 SILC_CLIENT_CMD_FUNC(stats)
1051 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1052 SilcClientConnection conn = cmd->conn;
1053 SilcBuffer buffer, idp = NULL;
1056 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1057 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1061 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1063 /* Send the command */
1064 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1065 ++conn->cmd_ident, 1,
1066 SILC_ID_SERVER, idp->data, idp->len);
1067 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1068 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1069 silc_buffer_free(buffer);
1070 silc_buffer_free(idp);
1072 /* Notify application */
1073 COMMAND(SILC_STATUS_OK);
1076 silc_client_command_free(cmd);
1079 /* Command PING. Sends ping to server. This is used to test the
1080 communication channel. */
1082 SILC_CLIENT_CMD_FUNC(ping)
1084 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1085 SilcClientConnection conn = cmd->conn;
1086 SilcBuffer buffer, idp;
1091 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1092 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1096 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1098 /* Send the command */
1099 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING,
1100 ++conn->cmd_ident, 1,
1101 1, idp->data, idp->len);
1102 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1103 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1104 silc_buffer_free(buffer);
1105 silc_buffer_free(idp);
1107 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1110 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1111 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1115 /* Start counting time */
1116 for (i = 0; i < conn->internal->ping_count; i++) {
1117 if (conn->internal->ping[i].dest_id == NULL) {
1118 conn->internal->ping[i].start_time = time(NULL);
1119 conn->internal->ping[i].dest_id = id;
1120 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1124 if (i >= conn->internal->ping_count) {
1125 i = conn->internal->ping_count;
1126 conn->internal->ping =
1127 silc_realloc(conn->internal->ping,
1128 sizeof(*conn->internal->ping) * (i + 1));
1129 conn->internal->ping[i].start_time = time(NULL);
1130 conn->internal->ping[i].dest_id = id;
1131 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1132 conn->internal->ping_count++;
1135 /* Notify application */
1136 COMMAND(SILC_STATUS_OK);
1139 silc_client_command_free(cmd);
1142 /* Command JOIN. Joins to a channel. */
1144 SILC_CLIENT_CMD_FUNC(join)
1146 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1147 SilcClientConnection conn = cmd->conn;
1148 SilcChannelEntry channel;
1149 SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
1150 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1151 int i, passphrase_len = 0;
1154 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1155 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1159 if (cmd->argc < 2) {
1160 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1164 /* See if we have joined to the requested channel already */
1165 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1166 if (channel && silc_client_on_channel(channel, conn->local_entry))
1169 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1171 if (cmd->argv_lens[1] > 256)
1172 cmd->argv_lens[1] = 256;
1174 name = cmd->argv[1];
1176 for (i = 2; i < cmd->argc; i++) {
1177 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1178 cipher = cmd->argv[i + 1];
1180 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1181 hmac = cmd->argv[i + 1];
1183 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1184 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1185 cmd->client->private_key,
1187 cmd->client->sha1hash,
1190 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1191 SilcPublicKey pubkey = cmd->client->public_key;
1192 SilcPrivateKey privkey = cmd->client->private_key;
1193 unsigned char *pk, pkhash[20], *pubdata;
1196 if (cmd->argc >= i + 3) {
1198 if (cmd->argc >= i + 4) {
1199 pass = cmd->argv[i + 3];
1202 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1203 NULL, &pubkey, &privkey)) {
1204 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1205 "Could not load key pair, check your arguments");
1206 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1212 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1213 silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
1215 pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
1216 memcpy(pubdata, pkhash, 20);
1217 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1219 cmd->client->sha1hash,
1222 memset(pubdata, 0, 128);
1225 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1226 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1227 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1228 cmd->argv_lens[i], 0);
1229 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1230 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1231 0, pu8, passphrase_len);
1234 passphrase = strdup(cmd->argv[i]);
1235 passphrase_len = cmd->argv_lens[i];
1240 /* Send JOIN command to the server */
1242 silc_command_payload_encode_va(SILC_COMMAND_JOIN, ++conn->cmd_ident, 7,
1243 1, name, strlen(name),
1244 2, idp->data, idp->len,
1245 3, passphrase, passphrase_len,
1246 4, cipher, cipher ? strlen(cipher) : 0,
1247 5, hmac, hmac ? strlen(hmac) : 0,
1248 6, auth ? auth->data : NULL,
1249 auth ? auth->len : 0,
1250 7, cauth ? cauth->data : NULL,
1251 cauth ? cauth->len : 0);
1252 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1253 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1254 silc_buffer_free(buffer);
1255 silc_buffer_free(idp);
1256 silc_buffer_free(auth);
1257 silc_buffer_free(cauth);
1259 memset(passphrase, 0, strlen(passphrase));
1260 silc_free(passphrase);
1262 /* Notify application */
1263 COMMAND(SILC_STATUS_OK);
1266 silc_client_command_free(cmd);
1269 /* MOTD command. Requests motd from server. */
1271 SILC_CLIENT_CMD_FUNC(motd)
1273 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1274 SilcClientConnection conn = cmd->conn;
1278 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1279 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1283 if (cmd->argc < 1 || cmd->argc > 2) {
1284 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1285 "Usage: /MOTD [<server>]");
1286 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1287 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1291 /* Send TOPIC command to the server */
1293 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
1294 ++conn->cmd_ident, 1,
1295 1, conn->remote_host,
1296 strlen(conn->remote_host));
1298 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
1299 ++conn->cmd_ident, 1,
1302 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1303 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1304 silc_buffer_free(buffer);
1306 /* Notify application */
1307 COMMAND(SILC_STATUS_OK);
1310 silc_client_command_free(cmd);
1313 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1314 modes as client cannot set itself server/router operator privileges. */
1316 SILC_CLIENT_CMD_FUNC(umode)
1318 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1319 SilcClientConnection conn = cmd->conn;
1320 SilcBuffer buffer, idp;
1321 unsigned char *cp, modebuf[4];
1322 SilcUInt32 mode, add, len;
1326 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1327 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1331 if (cmd->argc < 2) {
1332 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1333 "Usage: /UMODE +|-<modes>");
1334 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1338 mode = conn->local_entry->mode;
1340 /* Are we adding or removing mode */
1341 if (cmd->argv[1][0] == '-')
1347 cp = cmd->argv[1] + 1;
1349 for (i = 0; i < len; i++) {
1354 mode |= SILC_UMODE_SERVER_OPERATOR;
1355 mode |= SILC_UMODE_ROUTER_OPERATOR;
1356 mode |= SILC_UMODE_GONE;
1357 mode |= SILC_UMODE_INDISPOSED;
1358 mode |= SILC_UMODE_BUSY;
1359 mode |= SILC_UMODE_PAGE;
1360 mode |= SILC_UMODE_HYPER;
1361 mode |= SILC_UMODE_ROBOT;
1362 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1363 mode |= SILC_UMODE_REJECT_WATCHING;
1365 mode = SILC_UMODE_NONE;
1370 mode |= SILC_UMODE_SERVER_OPERATOR;
1372 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1376 mode |= SILC_UMODE_ROUTER_OPERATOR;
1378 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1382 mode |= SILC_UMODE_GONE;
1384 mode &= ~SILC_UMODE_GONE;
1388 mode |= SILC_UMODE_INDISPOSED;
1390 mode &= ~SILC_UMODE_INDISPOSED;
1394 mode |= SILC_UMODE_BUSY;
1396 mode &= ~SILC_UMODE_BUSY;
1400 mode |= SILC_UMODE_PAGE;
1402 mode &= ~SILC_UMODE_PAGE;
1406 mode |= SILC_UMODE_HYPER;
1408 mode &= ~SILC_UMODE_HYPER;
1412 mode |= SILC_UMODE_ROBOT;
1414 mode &= ~SILC_UMODE_ROBOT;
1418 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1420 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1424 mode |= SILC_UMODE_REJECT_WATCHING;
1426 mode &= ~SILC_UMODE_REJECT_WATCHING;
1430 mode |= SILC_UMODE_BLOCK_INVITE;
1432 mode &= ~SILC_UMODE_BLOCK_INVITE;
1435 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1441 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1442 SILC_PUT32_MSB(mode, modebuf);
1444 /* Send the command packet. We support sending only one mode at once
1445 that requires an argument. */
1447 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1448 1, idp->data, idp->len,
1449 2, modebuf, sizeof(modebuf));
1450 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1451 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1452 silc_buffer_free(buffer);
1453 silc_buffer_free(idp);
1455 /* Notify application */
1456 COMMAND(SILC_STATUS_OK);
1459 silc_client_command_free(cmd);
1462 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1463 can be set several at once. Those modes that require argument must be set
1464 separately (unless set with modes that does not require arguments). */
1466 SILC_CLIENT_CMD_FUNC(cmode)
1468 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1469 SilcClientConnection conn = cmd->conn;
1470 SilcChannelEntry channel;
1471 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1472 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1473 SilcUInt32 mode, add, type, len, arg_len = 0;
1477 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1478 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1482 if (cmd->argc < 3) {
1483 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1484 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1485 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1489 if (cmd->argv[1][0] == '*') {
1490 if (!conn->current_channel) {
1491 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1495 channel = conn->current_channel;
1497 name = cmd->argv[1];
1499 channel = silc_client_get_channel(cmd->client, conn, name);
1501 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1506 mode = channel->mode;
1508 /* Are we adding or removing mode */
1509 if (cmd->argv[2][0] == '-')
1514 /* Argument type to be sent to server */
1518 cp = cmd->argv[2] + 1;
1520 for (i = 0; i < len; i++) {
1524 mode |= SILC_CHANNEL_MODE_PRIVATE;
1526 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1530 mode |= SILC_CHANNEL_MODE_SECRET;
1532 mode &= ~SILC_CHANNEL_MODE_SECRET;
1536 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1538 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1542 mode |= SILC_CHANNEL_MODE_INVITE;
1544 mode &= ~SILC_CHANNEL_MODE_INVITE;
1548 mode |= SILC_CHANNEL_MODE_TOPIC;
1550 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1554 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1556 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1560 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1562 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1567 mode |= SILC_CHANNEL_MODE_ULIMIT;
1569 if (cmd->argc < 4) {
1570 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1571 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1572 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1575 ll = atoi(cmd->argv[3]);
1576 SILC_PUT32_MSB(ll, tmp);
1580 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1585 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1587 if (cmd->argc < 4) {
1588 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1589 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1590 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1594 arg_len = cmd->argv_lens[3];
1596 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1601 mode |= SILC_CHANNEL_MODE_CIPHER;
1603 if (cmd->argc < 4) {
1604 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1605 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1606 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1610 arg_len = cmd->argv_lens[3];
1612 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1617 mode |= SILC_CHANNEL_MODE_HMAC;
1619 if (cmd->argc < 4) {
1620 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1621 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1622 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1626 arg_len = cmd->argv_lens[3];
1628 mode &= ~SILC_CHANNEL_MODE_HMAC;
1633 SilcPublicKey pubkey = cmd->client->public_key;
1634 SilcPrivateKey privkey = cmd->client->private_key;
1636 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1639 if (cmd->argc >= 5) {
1642 pass = cmd->argv[5];
1643 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1644 NULL, &pubkey, &privkey)) {
1645 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1646 "Could not load key pair, check your arguments");
1647 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1652 pk = silc_pkcs_public_key_payload_encode(pubkey);
1653 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1655 cmd->client->sha1hash,
1659 arg_len = auth->len;
1661 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1668 SilcPublicKey chpk = NULL;
1670 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1673 if (cmd->argc == 3) {
1674 /* Send empty command to receive the public key list. */
1675 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1676 silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
1677 0, 1, 1, chidp->data, chidp->len);
1678 silc_buffer_free(chidp);
1680 /* Notify application */
1681 COMMAND(SILC_STATUS_OK);
1685 if (cmd->argc >= 4) {
1686 auth = silc_buffer_alloc_size(2);
1687 silc_buffer_format(auth,
1688 SILC_STR_UI_SHORT(cmd->argc - 3),
1692 for (k = 3; k < cmd->argc; k++) {
1693 if (cmd->argv[k][0] == '+')
1695 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1696 SILC_PKCS_FILE_PEM))
1697 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1698 SILC_PKCS_FILE_BIN)) {
1699 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1700 "Could not load public key %s, check the filename",
1702 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1703 silc_buffer_free(auth);
1708 pk = silc_pkcs_public_key_payload_encode(chpk);
1709 auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
1710 chadd ? 0x00 : 0x01);
1711 silc_pkcs_public_key_free(chpk);
1712 silc_buffer_free(pk);
1718 arg_len = auth->len;
1720 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1724 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1730 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1731 SILC_PUT32_MSB(mode, modebuf);
1733 /* Send the command packet. We support sending only one mode at once
1734 that requires an argument. */
1737 silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 4,
1738 1, chidp->data, chidp->len,
1739 2, modebuf, sizeof(modebuf),
1741 8, pk ? pk->data : NULL,
1745 silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 2,
1746 1, chidp->data, chidp->len,
1747 2, modebuf, sizeof(modebuf));
1750 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1751 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1752 silc_buffer_free(buffer);
1753 silc_buffer_free(chidp);
1754 silc_buffer_free(auth);
1755 silc_buffer_free(pk);
1757 /* Notify application */
1758 COMMAND(SILC_STATUS_OK);
1761 silc_client_command_free(cmd);
1764 /* CUMODE command. Changes client's mode on a channel. */
1766 SILC_CLIENT_CMD_FUNC(cumode)
1768 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1769 SilcClient client = cmd->client;
1770 SilcClientConnection conn = cmd->conn;
1771 SilcChannelEntry channel;
1772 SilcChannelUser chu;
1773 SilcClientEntry client_entry;
1774 SilcBuffer buffer, clidp, chidp, auth = NULL;
1775 unsigned char *name, *cp, modebuf[4];
1776 SilcUInt32 mode = 0, add, len;
1777 char *nickname = NULL;
1781 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1782 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1786 if (cmd->argc < 4) {
1787 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1788 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1789 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1793 if (cmd->argv[1][0] == '*') {
1794 if (!conn->current_channel) {
1795 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1799 channel = conn->current_channel;
1801 name = cmd->argv[1];
1803 channel = silc_client_get_channel(cmd->client, conn, name);
1805 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1810 /* Parse the typed nickname. */
1811 if (client->internal->params->nickname_parse)
1812 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1814 nickname = strdup(cmd->argv[3]);
1816 /* Find client entry */
1817 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1818 cmd->argv[3], TRUE);
1819 if (!client_entry) {
1821 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1825 /* Client entry not found, it was requested thus mark this to be
1827 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1829 silc_client_command_cumode,
1830 silc_client_command_dup(cmd));
1835 /* Get the current mode */
1836 chu = silc_client_on_channel(channel, client_entry);
1840 /* Are we adding or removing mode */
1841 if (cmd->argv[2][0] == '-')
1847 cp = cmd->argv[2] + 1;
1849 for (i = 0; i < len; i++) {
1853 mode |= SILC_CHANNEL_UMODE_CHANFO;
1854 mode |= SILC_CHANNEL_UMODE_CHANOP;
1855 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1856 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1857 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1859 mode = SILC_CHANNEL_UMODE_NONE;
1864 SilcPublicKey pubkey = cmd->client->public_key;
1865 SilcPrivateKey privkey = cmd->client->private_key;
1867 if (cmd->argc >= 6) {
1870 pass = cmd->argv[6];
1871 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1872 NULL, &pubkey, &privkey)) {
1873 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1874 "Could not load key pair, check your arguments");
1875 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1880 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1882 cmd->client->sha1hash,
1885 mode |= SILC_CHANNEL_UMODE_CHANFO;
1887 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1892 mode |= SILC_CHANNEL_UMODE_CHANOP;
1894 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1898 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1900 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1904 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1906 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1910 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1912 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1916 mode |= SILC_CHANNEL_UMODE_QUIET;
1918 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1921 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1927 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1928 SILC_PUT32_MSB(mode, modebuf);
1929 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1931 /* Send the command packet. We support sending only one mode at once
1932 that requires an argument. */
1933 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE,
1936 1, chidp->data, chidp->len,
1938 3, clidp->data, clidp->len,
1939 4, auth ? auth->data : NULL,
1940 auth ? auth->len : 0);
1942 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1943 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1944 silc_buffer_free(buffer);
1945 silc_buffer_free(chidp);
1946 silc_buffer_free(clidp);
1948 silc_buffer_free(auth);
1950 /* Notify application */
1951 COMMAND(SILC_STATUS_OK);
1954 silc_free(nickname);
1955 silc_client_command_free(cmd);
1958 /* KICK command. Kicks a client out of channel. */
1960 SILC_CLIENT_CMD_FUNC(kick)
1962 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1963 SilcClient client = cmd->client;
1964 SilcClientConnection conn = cmd->conn;
1965 SilcChannelEntry channel;
1966 SilcBuffer buffer, idp, idp2;
1967 SilcClientEntry target;
1969 char *nickname = NULL;
1972 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1973 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1977 if (cmd->argc < 3) {
1978 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1979 "Usage: /KICK <channel> <nickname> [<comment>]");
1980 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1984 if (cmd->argv[1][0] == '*') {
1985 if (!conn->current_channel) {
1986 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1989 name = conn->current_channel->channel_name;
1991 name = cmd->argv[1];
1994 if (!conn->current_channel) {
1995 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1999 /* Get the Channel ID of the channel */
2000 channel = silc_client_get_channel(cmd->client, conn, name);
2002 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2006 /* Parse the typed nickname. */
2007 if (client->internal->params->nickname_parse)
2008 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2010 nickname = strdup(cmd->argv[2]);
2012 /* Get the target client */
2013 target = silc_idlist_get_client(cmd->client, conn, nickname,
2014 cmd->argv[2], FALSE);
2016 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2017 "No such client: %s", cmd->argv[2]);
2018 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2022 /* Send KICK command to the server */
2023 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2024 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
2026 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
2027 ++conn->cmd_ident, 2,
2028 1, idp->data, idp->len,
2029 2, idp2->data, idp2->len);
2031 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
2032 ++conn->cmd_ident, 3,
2033 1, idp->data, idp->len,
2034 2, idp2->data, idp2->len,
2036 strlen(cmd->argv[3]));
2037 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2038 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2039 silc_buffer_free(buffer);
2040 silc_buffer_free(idp);
2041 silc_buffer_free(idp2);
2043 /* Notify application */
2044 COMMAND(SILC_STATUS_OK);
2047 silc_free(nickname);
2048 silc_client_command_free(cmd);
2051 static void silc_client_command_oper_send(unsigned char *data,
2052 SilcUInt32 data_len, void *context)
2054 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2055 SilcClientConnection conn = cmd->conn;
2056 SilcBuffer buffer, auth;
2058 if (cmd->argc >= 3) {
2059 /* Encode the public key authentication payload */
2060 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2061 cmd->client->private_key,
2063 conn->internal->hash,
2067 /* Encode the password authentication payload */
2068 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2072 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER,
2073 ++conn->cmd_ident, 2,
2075 strlen(cmd->argv[1]),
2076 2, auth ? auth->data : NULL,
2077 auth ? auth->len : 0);
2078 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2079 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2081 silc_buffer_free(buffer);
2082 silc_buffer_clear(auth);
2083 silc_buffer_free(auth);
2085 /* Notify application */
2086 COMMAND(SILC_STATUS_OK);
2089 /* OPER command. Used to obtain server operator privileges. */
2091 SILC_CLIENT_CMD_FUNC(oper)
2093 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2094 SilcClientConnection conn = cmd->conn;
2097 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2098 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2102 if (cmd->argc < 2) {
2103 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2104 "Usage: /OPER <username> [-pubkey]");
2105 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2109 if (cmd->argc < 3) {
2110 /* Get passphrase */
2111 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2112 silc_client_command_oper_send,
2117 silc_client_command_oper_send(NULL, 0, context);
2120 silc_client_command_free(cmd);
2123 static void silc_client_command_silcoper_send(unsigned char *data,
2124 SilcUInt32 data_len,
2127 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2128 SilcClientConnection conn = cmd->conn;
2129 SilcBuffer buffer, auth;
2131 if (cmd->argc >= 3) {
2132 /* Encode the public key authentication payload */
2133 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2134 cmd->client->private_key,
2136 conn->internal->hash,
2140 /* Encode the password authentication payload */
2141 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2145 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER,
2146 ++conn->cmd_ident, 2,
2148 strlen(cmd->argv[1]),
2149 2, auth ? auth->data : NULL,
2150 auth ? auth->len : 0);
2151 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2152 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2154 silc_buffer_free(buffer);
2155 silc_buffer_clear(auth);
2156 silc_buffer_free(auth);
2158 /* Notify application */
2159 COMMAND(SILC_STATUS_OK);
2162 /* SILCOPER command. Used to obtain router operator privileges. */
2164 SILC_CLIENT_CMD_FUNC(silcoper)
2166 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2167 SilcClientConnection conn = cmd->conn;
2170 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2171 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2175 if (cmd->argc < 2) {
2176 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2177 "Usage: /SILCOPER <username> [-pubkey]");
2178 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2182 if (cmd->argc < 3) {
2183 /* Get passphrase */
2184 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2185 silc_client_command_silcoper_send,
2190 silc_client_command_silcoper_send(NULL, 0, context);
2193 silc_client_command_free(cmd);
2196 /* Command BAN. This is used to manage the ban list of the channel. */
2198 SILC_CLIENT_CMD_FUNC(ban)
2200 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2201 SilcClientConnection conn = cmd->conn;
2202 SilcChannelEntry channel;
2203 SilcBuffer buffer, chidp, args = NULL;
2204 char *name, *ban = NULL;
2205 unsigned char action[1];
2206 SilcPublicKey pubkey = NULL;
2209 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2210 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2214 if (cmd->argc < 2) {
2215 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2216 "Usage: /BAN <channel> "
2217 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2218 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2222 if (cmd->argv[1][0] == '*') {
2223 if (!conn->current_channel) {
2224 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2228 channel = conn->current_channel;
2230 name = cmd->argv[1];
2232 channel = silc_client_get_channel(cmd->client, conn, name);
2234 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2239 if (cmd->argc == 3) {
2240 if (cmd->argv[2][0] == '+')
2245 /* Check if it is public key file to be added to invite list */
2246 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2247 SILC_PKCS_FILE_PEM))
2248 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2249 SILC_PKCS_FILE_BIN);
2256 args = silc_buffer_alloc_size(2);
2257 silc_buffer_format(args,
2258 SILC_STR_UI_SHORT(1),
2261 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2262 args = silc_argument_payload_encode_one(args, chidp->data,
2264 silc_buffer_free(chidp);
2265 silc_pkcs_public_key_free(pubkey);
2267 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2271 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2273 /* Send the command */
2274 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2275 ++conn->cmd_ident, 3,
2276 1, chidp->data, chidp->len,
2277 2, args ? action : NULL,
2279 3, args ? args->data : NULL,
2280 args ? args->len : 0);
2281 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2282 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2283 silc_buffer_free(buffer);
2284 silc_buffer_free(chidp);
2285 silc_buffer_free(args);
2287 /* Notify application */
2288 COMMAND(SILC_STATUS_OK);
2291 silc_client_command_free(cmd);
2294 /* Command DETACH. This is used to detach from the server */
2296 SILC_CLIENT_CMD_FUNC(detach)
2298 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2299 SilcClientConnection conn = cmd->conn;
2303 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2304 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2308 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2309 ++conn->cmd_ident, 0);
2310 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2311 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2312 silc_buffer_free(buffer);
2314 /* Notify application */
2315 COMMAND(SILC_STATUS_OK);
2318 silc_client_command_free(cmd);
2321 /* Command WATCH. */
2323 SILC_CLIENT_CMD_FUNC(watch)
2325 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2326 SilcClientConnection conn = cmd->conn;
2327 SilcBuffer buffer, idp = NULL, args = NULL;
2329 const char *pubkey = NULL;
2330 bool pubkey_add = TRUE;
2333 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2334 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2338 if (cmd->argc < 3) {
2339 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2343 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2345 if (!strcasecmp(cmd->argv[1], "-add")) {
2347 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2349 } else if (!strcasecmp(cmd->argv[1], "-pubkey") && cmd->argc >= 3) {
2351 pubkey = cmd->argv[2] + 1;
2352 if (cmd->argv[2][0] == '-')
2355 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2362 if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) {
2363 if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) {
2364 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2365 "Could not load public key %s, check the filename",
2367 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2372 args = silc_buffer_alloc_size(2);
2373 silc_buffer_format(args,
2374 SILC_STR_UI_SHORT(1),
2376 buffer = silc_pkcs_public_key_payload_encode(pk);
2377 args = silc_argument_payload_encode_one(args, buffer->data, buffer->len,
2378 pubkey_add ? 0x00 : 0x01);
2379 silc_buffer_free(buffer);
2380 silc_pkcs_public_key_free(pk);
2383 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2384 ++conn->cmd_ident, 2,
2385 1, idp->data, idp->len,
2387 pubkey ? args->data : cmd->argv[2],
2388 pubkey ? args->len :
2390 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2391 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2392 silc_buffer_free(buffer);
2393 silc_buffer_free(args);
2395 /* Notify application */
2396 COMMAND(SILC_STATUS_OK);
2400 silc_buffer_free(idp);
2401 silc_client_command_free(cmd);
2404 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2406 SILC_CLIENT_CMD_FUNC(leave)
2408 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2409 SilcClientConnection conn = cmd->conn;
2410 SilcChannelEntry channel;
2411 SilcBuffer buffer, idp;
2415 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2416 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2420 if (cmd->argc != 2) {
2421 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2422 "Usage: /LEAVE <channel>");
2423 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2427 if (cmd->argv[1][0] == '*') {
2428 if (!conn->current_channel) {
2429 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2432 name = conn->current_channel->channel_name;
2434 name = cmd->argv[1];
2437 /* Get the channel entry */
2438 channel = silc_client_get_channel(cmd->client, conn, name);
2440 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2444 /* Send LEAVE command to the server */
2445 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2446 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE,
2447 ++conn->cmd_ident, 1,
2448 1, idp->data, idp->len);
2449 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2450 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2451 silc_buffer_free(buffer);
2452 silc_buffer_free(idp);
2454 /* Notify application */
2455 COMMAND(SILC_STATUS_OK);
2457 if (conn->current_channel == channel)
2458 conn->current_channel = NULL;
2461 silc_client_command_free(cmd);
2464 /* Command USERS. Requests the USERS of the clients joined on requested
2467 SILC_CLIENT_CMD_FUNC(users)
2469 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2470 SilcClientConnection conn = cmd->conn;
2475 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2476 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2480 if (cmd->argc != 2) {
2481 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2482 "Usage: /USERS <channel>");
2483 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2487 if (cmd->argv[1][0] == '*') {
2488 if (!conn->current_channel) {
2489 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2492 name = conn->current_channel->channel_name;
2494 name = cmd->argv[1];
2497 /* Send USERS command to the server */
2498 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2499 ++conn->cmd_ident, 1,
2500 2, name, strlen(name));
2501 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2502 NULL, 0, NULL, NULL, buffer->data,
2504 silc_buffer_free(buffer);
2506 /* Notify application */
2507 COMMAND(SILC_STATUS_OK);
2510 silc_client_command_free(cmd);
2513 /* Command GETKEY. Used to fetch remote client's public key. */
2515 SILC_CLIENT_CMD_FUNC(getkey)
2517 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2518 SilcClientConnection conn = cmd->conn;
2519 SilcClient client = cmd->client;
2520 SilcClientEntry client_entry = NULL;
2521 SilcServerEntry server_entry = NULL;
2522 char *nickname = NULL;
2523 SilcBuffer idp, buffer;
2525 SILC_LOG_DEBUG(("Start"));
2528 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2529 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2533 if (cmd->argc < 2) {
2534 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2535 "Usage: /GETKEY <nickname or server name>");
2536 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2540 /* Parse the typed nickname. */
2541 if (client->internal->params->nickname_parse)
2542 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2544 nickname = strdup(cmd->argv[1]);
2546 /* Find client entry */
2547 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2549 if (!client_entry) {
2550 /* Check whether user requested server actually */
2551 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2553 if (!server_entry) {
2554 /* No. what ever user wants we don't have it, so resolve it. We
2555 will first try to resolve the client, and if that fails then
2556 we'll try to resolve the server. */
2558 if (!cmd->pending) {
2559 /* This will send the IDENTIFY command for nickname */
2560 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2561 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2563 silc_client_command_getkey,
2564 silc_client_command_dup(cmd));
2568 SilcClientCommandReplyContext reply =
2569 (SilcClientCommandReplyContext)context2;
2572 /* If nickname was not found, then resolve the server. */
2573 silc_command_get_status(reply->payload, NULL, &error);
2574 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2575 /* This sends the IDENTIFY command to resolve the server. */
2576 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2578 silc_client_command_reply_identify_i, 0,
2580 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2582 2, cmd->argv[1], cmd->argv_lens[1]);
2583 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2585 silc_client_command_getkey,
2586 silc_client_command_dup(cmd));
2590 /* If server was not found, then we've resolved both nickname and
2591 server and did not find anybody. */
2592 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2593 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2594 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2595 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2596 silc_get_status_message(error));
2597 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2601 COMMAND_ERROR(error);
2606 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2608 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2611 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY,
2612 ++conn->cmd_ident, 1,
2613 1, idp->data, idp->len);
2614 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2615 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2616 silc_buffer_free(buffer);
2617 silc_buffer_free(idp);
2619 /* Notify application */
2620 COMMAND(SILC_STATUS_OK);
2623 silc_free(nickname);
2624 silc_client_command_free(cmd);
2627 /* Register a new command indicated by the `command' to the SILC client.
2628 The `name' is optional command name. If provided the command may be
2629 searched using the silc_client_command_find by that name. The
2630 `command_function' is the function to be called when the command is
2631 executed, and the `command_reply_function' is the function to be
2632 called after the server has sent reply back to the command.
2634 The `ident' is optional identifier for the command. If non-zero
2635 the `command_reply_function' for the command type `command' will be
2636 called only if the command reply sent by server includes the
2637 command identifier `ident'. Application usually does not need it
2638 and set it to zero value. */
2640 bool silc_client_command_register(SilcClient client,
2641 SilcCommand command,
2643 SilcCommandCb command_function,
2644 SilcCommandCb command_reply_function,
2648 SilcClientCommand cmd;
2650 cmd = silc_calloc(1, sizeof(*cmd));
2652 cmd->command = command_function;
2653 cmd->reply = command_reply_function;
2654 cmd->name = name ? strdup(name) : NULL;
2655 cmd->max_args = max_args;
2658 silc_list_add(client->internal->commands, cmd);
2663 /* Unregister a command indicated by the `command' with command function
2664 `command_function' and command reply function `command_reply_function'.
2665 Returns TRUE if the command was found and unregistered. */
2667 bool silc_client_command_unregister(SilcClient client,
2668 SilcCommand command,
2669 SilcCommandCb command_function,
2670 SilcCommandCb command_reply_function,
2673 SilcClientCommand cmd;
2675 silc_list_start(client->internal->commands);
2676 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2677 if (cmd->cmd == command && cmd->command == command_function &&
2678 cmd->reply == command_reply_function && cmd->ident == ident) {
2679 silc_list_del(client->internal->commands, cmd);
2680 silc_free(cmd->name);
2689 /* Private range commands, specific to this implementation (and compatible
2690 with SILC Server). */
2692 /* CONNECT command. Connects the server to another server. */
2694 SILC_CLIENT_CMD_FUNC(connect)
2696 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2697 SilcClientConnection conn = cmd->conn;
2699 unsigned char port[4];
2703 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2704 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2708 if (cmd->argc < 2) {
2709 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2710 "Usage: /CONNECT <server> [<port>]");
2711 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2715 if (cmd->argc == 3) {
2716 tmp = atoi(cmd->argv[2]);
2717 SILC_PUT32_MSB(tmp, port);
2721 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
2722 ++conn->cmd_ident, 2,
2724 strlen(cmd->argv[1]),
2727 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
2728 ++conn->cmd_ident, 1,
2730 strlen(cmd->argv[1]));
2731 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2732 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2733 silc_buffer_free(buffer);
2735 /* Notify application */
2736 COMMAND(SILC_STATUS_OK);
2739 silc_client_command_free(cmd);
2743 /* CLOSE command. Close server connection to the remote server */
2745 SILC_CLIENT_CMD_FUNC(close)
2747 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2748 SilcClientConnection conn = cmd->conn;
2750 unsigned char port[4];
2754 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2755 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2759 if (cmd->argc < 2) {
2760 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2761 "Usage: /CLOSE <server> [<port>]");
2762 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2766 if (cmd->argc == 3) {
2767 tmp = atoi(cmd->argv[2]);
2768 SILC_PUT32_MSB(tmp, port);
2772 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
2773 ++conn->cmd_ident, 2,
2775 strlen(cmd->argv[1]),
2778 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
2779 ++conn->cmd_ident, 1,
2781 strlen(cmd->argv[1]));
2782 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2783 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2784 silc_buffer_free(buffer);
2786 /* Notify application */
2787 COMMAND(SILC_STATUS_OK);
2790 silc_client_command_free(cmd);
2793 /* SHUTDOWN command. Shutdowns the server. */
2795 SILC_CLIENT_CMD_FUNC(shutdown)
2797 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2800 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2801 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2805 /* Send the command */
2806 silc_client_command_send(cmd->client, cmd->conn,
2807 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2809 /* Notify application */
2810 COMMAND(SILC_STATUS_OK);
2813 silc_client_command_free(cmd);
2816 /* Register all default commands provided by the client library for the
2819 void silc_client_commands_register(SilcClient client)
2821 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2824 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2825 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2826 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2827 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2828 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2829 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2830 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2831 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2832 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2833 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2834 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2835 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2836 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2837 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2838 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2839 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2840 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2841 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2842 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2843 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2844 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2845 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2846 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2847 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2848 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2849 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2851 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2852 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2853 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2856 /* Unregister all commands. */
2858 void silc_client_commands_unregister(SilcClient client)
2860 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2861 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2862 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2863 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2864 SILC_CLIENT_CMDU(list, LIST, "LIST");
2865 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2866 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2867 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2868 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2869 SILC_CLIENT_CMDU(info, INFO, "INFO");
2870 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2871 SILC_CLIENT_CMDU(ping, PING, "PING");
2872 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2873 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2874 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2875 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2876 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2877 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2878 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2879 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2880 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2881 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2882 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2883 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2884 SILC_CLIENT_CMDU(users, USERS, "USERS");
2885 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2887 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2888 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2889 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2892 /**** Client side incoming command handling **********************************/
2894 void silc_client_command_process_whois(SilcClient client,
2895 SilcSocketConnection sock,
2896 SilcCommandPayload payload,
2897 SilcArgumentPayload args);
2899 /* Client is able to receive some command packets even though they are
2900 special case. Server may send WHOIS command to the client to retrieve
2901 Requested Attributes information for WHOIS query the server is
2902 processing. This function currently handles only the WHOIS command,
2903 but if in the future for commands may arrive then this can be made
2904 to support other commands too. */
2906 void silc_client_command_process(SilcClient client,
2907 SilcSocketConnection sock,
2908 SilcPacketContext *packet)
2910 SilcCommandPayload payload;
2911 SilcCommand command;
2912 SilcArgumentPayload args;
2914 /* Get command payload from packet */
2915 payload = silc_command_payload_parse(packet->buffer->data,
2916 packet->buffer->len);
2918 /* Silently ignore bad reply packet */
2919 SILC_LOG_DEBUG(("Bad command packet"));
2924 args = silc_command_get_args(payload);
2926 /* Get the command */
2927 command = silc_command_get(payload);
2930 case SILC_COMMAND_WHOIS:
2931 /* Ignore everything if requested by application */
2932 if (client->internal->params->ignore_requested_attributes)
2935 silc_client_command_process_whois(client, sock, payload, args);
2942 silc_command_payload_free(payload);
2945 void silc_client_command_process_whois(SilcClient client,
2946 SilcSocketConnection sock,
2947 SilcCommandPayload payload,
2948 SilcArgumentPayload args)
2953 SilcBuffer buffer, packet;
2955 SILC_LOG_DEBUG(("Received WHOIS command"));
2957 /* Try to take the Requested Attributes */
2958 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2962 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2966 /* Process requested attributes */
2967 buffer = silc_client_attributes_process(client, sock, attrs);
2969 silc_attribute_payload_list_free(attrs);
2973 /* Send the attributes back */
2975 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2977 silc_command_get_ident(payload),
2978 1, 11, buffer->data, buffer->len);
2979 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2980 NULL, 0, NULL, NULL, packet->data,
2982 silc_buffer_free(packet);
2983 silc_buffer_free(buffer);