5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, 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],
843 &cmd->argv_types[1], 0);
845 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
846 NULL, NULL, NULL, 0);
847 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
849 buffer->data, buffer->len, TRUE);
850 silc_buffer_free(buffer);
852 q = silc_calloc(1, sizeof(*q));
853 q->client = cmd->client;
856 /* Sleep for a while */
859 /* We quit the connection with little timeout */
860 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
861 silc_client_command_quit_cb, (void *)q,
862 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
864 /* Notify application */
865 COMMAND(SILC_STATUS_OK);
868 silc_client_command_free(cmd);
871 /* Timeout callback to remove the killed client from cache */
873 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
875 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
876 SilcClient client = cmd->client;
877 SilcClientConnection conn = cmd->conn;
878 SilcClientEntry target;
879 char *nickname = NULL;
881 /* Parse the typed nickname. */
882 if (client->internal->params->nickname_parse)
883 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
885 nickname = strdup(cmd->argv[1]);
887 /* Get the target client */
888 target = silc_idlist_get_client(cmd->client, conn, nickname,
889 cmd->argv[1], FALSE);
891 /* Remove the client from all channels and free it */
892 silc_client_del_client(client, conn, target);
895 silc_client_command_free(cmd);
898 /* Kill command's pending command callback to actually remove the killed
899 client from our local cache. */
901 SILC_CLIENT_CMD_FUNC(kill_remove)
903 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
904 SilcClientCommandReplyContext reply =
905 (SilcClientCommandReplyContext)context2;
908 silc_command_get_status(reply->payload, &status, NULL);
909 if (status == SILC_STATUS_OK) {
910 /* Remove with timeout */
911 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
912 silc_client_command_kill_remove_later, context,
913 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
917 silc_client_command_free(cmd);
920 /* Command KILL. Router operator can use this command to remove an client
921 fromthe SILC Network. */
923 SILC_CLIENT_CMD_FUNC(kill)
925 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
926 SilcClient client = cmd->client;
927 SilcClientConnection conn = cmd->conn;
928 SilcBuffer buffer, idp, auth = NULL;
929 SilcClientEntry target;
930 char *nickname = NULL, *comment = NULL;
933 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
934 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
939 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
940 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
941 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
945 /* Parse the typed nickname. */
946 if (client->internal->params->nickname_parse)
947 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
949 nickname = strdup(cmd->argv[1]);
951 /* Get the target client */
952 target = silc_idlist_get_client(cmd->client, conn, nickname,
956 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
960 /* Client entry not found, it was requested thus mark this to be
962 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
964 silc_client_command_kill,
965 silc_client_command_dup(cmd));
970 if (cmd->argc >= 3) {
971 if (strcasecmp(cmd->argv[2], "-pubkey"))
972 comment = cmd->argv[2];
974 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
975 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
976 /* Encode the public key authentication payload */
977 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
978 cmd->client->private_key,
981 target->id, SILC_ID_CLIENT);
985 /* Send the KILL command to the server */
986 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
988 silc_command_payload_encode_va(SILC_COMMAND_KILL,
989 ++conn->cmd_ident, 3,
990 1, idp->data, idp->len,
991 2, comment, comment ? strlen(comment) : 0,
992 3, auth ? auth->data : NULL,
993 auth ? auth->len : 0);
994 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
995 0, NULL, NULL, buffer->data, buffer->len, TRUE);
996 silc_buffer_free(buffer);
997 silc_buffer_free(idp);
998 silc_buffer_free(auth);
1000 /* Notify application */
1001 COMMAND(SILC_STATUS_OK);
1003 /* Register a pending callback that will actually remove the killed
1004 client from our cache. */
1005 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
1006 silc_client_command_kill_remove,
1007 silc_client_command_dup(cmd));
1010 silc_free(nickname);
1011 silc_client_command_free(cmd);
1014 /* Command INFO. Request information about specific server. If specific
1015 server is not provided the current server is used. */
1017 SILC_CLIENT_CMD_FUNC(info)
1019 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1020 SilcClientConnection conn = cmd->conn;
1025 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1026 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1031 name = strdup(cmd->argv[1]);
1033 /* Send the command */
1035 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
1036 1, name, strlen(name));
1038 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
1039 NULL, NULL, NULL, 0);
1040 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1041 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1042 silc_buffer_free(buffer);
1046 /* Notify application */
1047 COMMAND(SILC_STATUS_OK);
1050 silc_client_command_free(cmd);
1053 /* Command STATS. Shows server and network statistics. */
1055 SILC_CLIENT_CMD_FUNC(stats)
1057 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1058 SilcClientConnection conn = cmd->conn;
1059 SilcBuffer buffer, idp = NULL;
1062 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1063 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1067 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1069 /* Send the command */
1070 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1071 ++conn->cmd_ident, 1,
1072 SILC_ID_SERVER, idp->data, idp->len);
1073 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1074 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1075 silc_buffer_free(buffer);
1076 silc_buffer_free(idp);
1078 /* Notify application */
1079 COMMAND(SILC_STATUS_OK);
1082 silc_client_command_free(cmd);
1085 /* Command PING. Sends ping to server. This is used to test the
1086 communication channel. */
1088 SILC_CLIENT_CMD_FUNC(ping)
1090 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1091 SilcClientConnection conn = cmd->conn;
1092 SilcBuffer buffer, idp;
1097 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1098 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1102 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1104 /* Send the command */
1105 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1106 1, idp->data, idp->len);
1107 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1108 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1109 silc_buffer_free(buffer);
1110 silc_buffer_free(idp);
1112 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1115 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1116 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1120 /* Start counting time */
1121 for (i = 0; i < conn->internal->ping_count; i++) {
1122 if (conn->internal->ping[i].dest_id == NULL) {
1123 conn->internal->ping[i].start_time = time(NULL);
1124 conn->internal->ping[i].dest_id = id;
1125 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1129 if (i >= conn->internal->ping_count) {
1130 i = conn->internal->ping_count;
1131 conn->internal->ping =
1132 silc_realloc(conn->internal->ping,
1133 sizeof(*conn->internal->ping) * (i + 1));
1134 conn->internal->ping[i].start_time = time(NULL);
1135 conn->internal->ping[i].dest_id = id;
1136 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1137 conn->internal->ping_count++;
1140 /* Notify application */
1141 COMMAND(SILC_STATUS_OK);
1144 silc_client_command_free(cmd);
1147 /* Command JOIN. Joins to a channel. */
1149 SILC_CLIENT_CMD_FUNC(join)
1151 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1152 SilcClientConnection conn = cmd->conn;
1153 SilcChannelEntry channel;
1154 SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
1155 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1156 int i, passphrase_len = 0;
1159 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1160 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1164 if (cmd->argc < 2) {
1165 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1169 /* See if we have joined to the requested channel already */
1170 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1171 if (channel && silc_client_on_channel(channel, conn->local_entry))
1174 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1176 if (cmd->argv_lens[1] > 256)
1177 cmd->argv_lens[1] = 256;
1179 name = cmd->argv[1];
1181 for (i = 2; i < cmd->argc; i++) {
1182 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1183 cipher = cmd->argv[i + 1];
1185 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1186 hmac = cmd->argv[i + 1];
1188 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1189 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1190 cmd->client->private_key,
1192 cmd->client->sha1hash,
1196 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1197 SilcPublicKey pubkey = cmd->client->public_key;
1198 SilcPrivateKey privkey = cmd->client->private_key;
1199 unsigned char *pk, pkhash[20], *pubdata;
1202 if (cmd->argc >= i + 3) {
1204 if (cmd->argc >= i + 4) {
1205 pass = cmd->argv[i + 3];
1208 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1209 NULL, &pubkey, &privkey)) {
1210 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1211 "Could not load key pair, check your arguments");
1212 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1218 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1219 silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
1221 pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
1222 memcpy(pubdata, pkhash, 20);
1223 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1225 cmd->client->sha1hash,
1228 memset(pubdata, 0, 128);
1232 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1233 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1234 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1235 cmd->argv_lens[i], 0);
1236 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1237 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1238 0, pu8, passphrase_len);
1241 passphrase = strdup(cmd->argv[i]);
1242 passphrase_len = cmd->argv_lens[i];
1247 /* Send JOIN command to the server */
1249 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 7,
1250 1, name, strlen(name),
1251 2, idp->data, idp->len,
1252 3, passphrase, passphrase_len,
1253 4, cipher, cipher ? strlen(cipher) : 0,
1254 5, hmac, hmac ? strlen(hmac) : 0,
1255 6, auth ? auth->data : NULL,
1256 auth ? auth->len : 0,
1257 7, cauth ? cauth->data : NULL,
1258 cauth ? cauth->len : 0);
1259 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1260 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1261 silc_buffer_free(buffer);
1262 silc_buffer_free(idp);
1263 silc_buffer_free(auth);
1264 silc_buffer_free(cauth);
1266 memset(passphrase, 0, strlen(passphrase));
1267 silc_free(passphrase);
1269 /* Notify application */
1270 COMMAND(SILC_STATUS_OK);
1273 silc_client_command_free(cmd);
1276 /* MOTD command. Requests motd from server. */
1278 SILC_CLIENT_CMD_FUNC(motd)
1280 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1281 SilcClientConnection conn = cmd->conn;
1285 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1286 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1290 if (cmd->argc < 1 || cmd->argc > 2) {
1291 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1292 "Usage: /MOTD [<server>]");
1293 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1294 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1298 /* Send TOPIC command to the server */
1300 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1301 1, conn->remote_host,
1302 strlen(conn->remote_host));
1304 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1307 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1308 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1309 silc_buffer_free(buffer);
1311 /* Notify application */
1312 COMMAND(SILC_STATUS_OK);
1315 silc_client_command_free(cmd);
1318 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1319 modes as client cannot set itself server/router operator privileges. */
1321 SILC_CLIENT_CMD_FUNC(umode)
1323 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1324 SilcClientConnection conn = cmd->conn;
1325 SilcBuffer buffer, idp;
1326 unsigned char *cp, modebuf[4];
1327 SilcUInt32 mode, add, len;
1331 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1332 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1336 if (cmd->argc < 2) {
1337 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1338 "Usage: /UMODE +|-<modes>");
1339 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1343 mode = conn->local_entry->mode;
1345 /* Are we adding or removing mode */
1346 if (cmd->argv[1][0] == '-')
1352 cp = cmd->argv[1] + 1;
1354 for (i = 0; i < len; i++) {
1359 mode |= SILC_UMODE_SERVER_OPERATOR;
1360 mode |= SILC_UMODE_ROUTER_OPERATOR;
1361 mode |= SILC_UMODE_GONE;
1362 mode |= SILC_UMODE_INDISPOSED;
1363 mode |= SILC_UMODE_BUSY;
1364 mode |= SILC_UMODE_PAGE;
1365 mode |= SILC_UMODE_HYPER;
1366 mode |= SILC_UMODE_ROBOT;
1367 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1368 mode |= SILC_UMODE_REJECT_WATCHING;
1370 mode = SILC_UMODE_NONE;
1375 mode |= SILC_UMODE_SERVER_OPERATOR;
1377 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1381 mode |= SILC_UMODE_ROUTER_OPERATOR;
1383 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1387 mode |= SILC_UMODE_GONE;
1389 mode &= ~SILC_UMODE_GONE;
1393 mode |= SILC_UMODE_INDISPOSED;
1395 mode &= ~SILC_UMODE_INDISPOSED;
1399 mode |= SILC_UMODE_BUSY;
1401 mode &= ~SILC_UMODE_BUSY;
1405 mode |= SILC_UMODE_PAGE;
1407 mode &= ~SILC_UMODE_PAGE;
1411 mode |= SILC_UMODE_HYPER;
1413 mode &= ~SILC_UMODE_HYPER;
1417 mode |= SILC_UMODE_ROBOT;
1419 mode &= ~SILC_UMODE_ROBOT;
1423 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1425 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1429 mode |= SILC_UMODE_REJECT_WATCHING;
1431 mode &= ~SILC_UMODE_REJECT_WATCHING;
1435 mode |= SILC_UMODE_BLOCK_INVITE;
1437 mode &= ~SILC_UMODE_BLOCK_INVITE;
1440 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1446 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1447 SILC_PUT32_MSB(mode, modebuf);
1449 /* Send the command packet. We support sending only one mode at once
1450 that requires an argument. */
1452 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1453 1, idp->data, idp->len,
1454 2, modebuf, sizeof(modebuf));
1455 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1456 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1457 silc_buffer_free(buffer);
1458 silc_buffer_free(idp);
1460 /* Notify application */
1461 COMMAND(SILC_STATUS_OK);
1464 silc_client_command_free(cmd);
1467 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1468 can be set several at once. Those modes that require argument must be set
1469 separately (unless set with modes that does not require arguments). */
1471 SILC_CLIENT_CMD_FUNC(cmode)
1473 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1474 SilcClientConnection conn = cmd->conn;
1475 SilcChannelEntry channel;
1476 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1477 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1478 SilcUInt32 mode, add, type, len, arg_len = 0;
1482 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1483 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1487 if (cmd->argc < 3) {
1488 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1489 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1490 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1494 if (cmd->argv[1][0] == '*') {
1495 if (!conn->current_channel) {
1496 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1500 channel = conn->current_channel;
1502 name = cmd->argv[1];
1504 channel = silc_client_get_channel(cmd->client, conn, name);
1506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1511 mode = channel->mode;
1513 /* Are we adding or removing mode */
1514 if (cmd->argv[2][0] == '-')
1519 /* Argument type to be sent to server */
1523 cp = cmd->argv[2] + 1;
1525 for (i = 0; i < len; i++) {
1529 mode |= SILC_CHANNEL_MODE_PRIVATE;
1531 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1535 mode |= SILC_CHANNEL_MODE_SECRET;
1537 mode &= ~SILC_CHANNEL_MODE_SECRET;
1541 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1543 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1547 mode |= SILC_CHANNEL_MODE_INVITE;
1549 mode &= ~SILC_CHANNEL_MODE_INVITE;
1553 mode |= SILC_CHANNEL_MODE_TOPIC;
1555 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1559 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1561 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1565 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1567 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1572 mode |= SILC_CHANNEL_MODE_ULIMIT;
1574 if (cmd->argc < 4) {
1575 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1576 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1577 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1580 ll = atoi(cmd->argv[3]);
1581 SILC_PUT32_MSB(ll, tmp);
1585 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1590 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1592 if (cmd->argc < 4) {
1593 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1594 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1595 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1599 arg_len = cmd->argv_lens[3];
1601 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1606 mode |= SILC_CHANNEL_MODE_CIPHER;
1608 if (cmd->argc < 4) {
1609 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1610 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1611 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1615 arg_len = cmd->argv_lens[3];
1617 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1622 mode |= SILC_CHANNEL_MODE_HMAC;
1624 if (cmd->argc < 4) {
1625 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1626 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1627 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1631 arg_len = cmd->argv_lens[3];
1633 mode &= ~SILC_CHANNEL_MODE_HMAC;
1638 SilcPublicKey pubkey = cmd->client->public_key;
1639 SilcPrivateKey privkey = cmd->client->private_key;
1641 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1644 if (cmd->argc >= 5) {
1647 pass = cmd->argv[5];
1648 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1649 NULL, &pubkey, &privkey)) {
1650 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1651 "Could not load key pair, check your arguments");
1652 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1657 pk = silc_pkcs_public_key_payload_encode(pubkey);
1658 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1660 cmd->client->sha1hash,
1664 arg_len = auth->len;
1666 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1673 SilcPublicKey chpk = NULL;
1675 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1678 if (cmd->argc == 3) {
1679 /* Send empty command to receive the public key list. */
1680 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1681 silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
1682 0, 1, 1, chidp->data, chidp->len);
1683 silc_buffer_free(chidp);
1685 /* Notify application */
1686 COMMAND(SILC_STATUS_OK);
1690 if (cmd->argc >= 4) {
1691 auth = silc_buffer_alloc_size(2);
1692 silc_buffer_format(auth,
1693 SILC_STR_UI_SHORT(cmd->argc - 3),
1697 for (k = 3; k < cmd->argc; k++) {
1698 if (cmd->argv[k][0] == '+')
1700 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1701 SILC_PKCS_FILE_PEM))
1702 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1703 SILC_PKCS_FILE_BIN)) {
1704 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1705 "Could not load public key %s, check the filename",
1707 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1708 silc_buffer_free(auth);
1713 pk = silc_pkcs_public_key_payload_encode(chpk);
1714 auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
1715 chadd ? 0x00 : 0x01);
1716 silc_pkcs_public_key_free(chpk);
1717 silc_buffer_free(pk);
1723 arg_len = auth->len;
1725 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1729 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1735 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1736 SILC_PUT32_MSB(mode, modebuf);
1738 /* Send the command packet. We support sending only one mode at once
1739 that requires an argument. */
1742 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
1743 1, chidp->data, chidp->len,
1744 2, modebuf, sizeof(modebuf),
1746 8, pk ? pk->data : NULL,
1750 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1751 1, chidp->data, chidp->len,
1752 2, modebuf, sizeof(modebuf));
1755 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1756 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1757 silc_buffer_free(buffer);
1758 silc_buffer_free(chidp);
1759 silc_buffer_free(auth);
1760 silc_buffer_free(pk);
1762 /* Notify application */
1763 COMMAND(SILC_STATUS_OK);
1766 silc_client_command_free(cmd);
1769 /* CUMODE command. Changes client's mode on a channel. */
1771 SILC_CLIENT_CMD_FUNC(cumode)
1773 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1774 SilcClient client = cmd->client;
1775 SilcClientConnection conn = cmd->conn;
1776 SilcChannelEntry channel;
1777 SilcChannelUser chu;
1778 SilcClientEntry client_entry;
1779 SilcBuffer buffer, clidp, chidp, auth = NULL;
1780 unsigned char *name, *cp, modebuf[4];
1781 SilcUInt32 mode = 0, add, len;
1782 char *nickname = NULL;
1786 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1787 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1791 if (cmd->argc < 4) {
1792 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1793 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1794 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1798 if (cmd->argv[1][0] == '*') {
1799 if (!conn->current_channel) {
1800 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1804 channel = conn->current_channel;
1806 name = cmd->argv[1];
1808 channel = silc_client_get_channel(cmd->client, conn, name);
1810 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1815 /* Parse the typed nickname. */
1816 if (client->internal->params->nickname_parse)
1817 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1819 nickname = strdup(cmd->argv[3]);
1821 /* Find client entry */
1822 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1823 cmd->argv[3], TRUE);
1824 if (!client_entry) {
1826 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1830 /* Client entry not found, it was requested thus mark this to be
1832 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1834 silc_client_command_cumode,
1835 silc_client_command_dup(cmd));
1840 /* Get the current mode */
1841 chu = silc_client_on_channel(channel, client_entry);
1845 /* Are we adding or removing mode */
1846 if (cmd->argv[2][0] == '-')
1852 cp = cmd->argv[2] + 1;
1854 for (i = 0; i < len; i++) {
1858 mode |= SILC_CHANNEL_UMODE_CHANFO;
1859 mode |= SILC_CHANNEL_UMODE_CHANOP;
1860 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1861 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1862 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1864 mode = SILC_CHANNEL_UMODE_NONE;
1869 SilcPublicKey pubkey = cmd->client->public_key;
1870 SilcPrivateKey privkey = cmd->client->private_key;
1872 if (cmd->argc >= 6) {
1875 pass = cmd->argv[6];
1876 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1877 NULL, &pubkey, &privkey)) {
1878 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1879 "Could not load key pair, check your arguments");
1880 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1885 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1887 cmd->client->sha1hash,
1890 mode |= SILC_CHANNEL_UMODE_CHANFO;
1892 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1897 mode |= SILC_CHANNEL_UMODE_CHANOP;
1899 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1903 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1905 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1909 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1911 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1915 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1917 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1921 mode |= SILC_CHANNEL_UMODE_QUIET;
1923 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1926 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1932 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1933 SILC_PUT32_MSB(mode, modebuf);
1934 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1936 /* Send the command packet. We support sending only one mode at once
1937 that requires an argument. */
1938 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1940 1, chidp->data, chidp->len,
1942 3, clidp->data, clidp->len,
1943 4, auth ? auth->data : NULL,
1944 auth ? auth->len : 0);
1946 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1947 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1948 silc_buffer_free(buffer);
1949 silc_buffer_free(chidp);
1950 silc_buffer_free(clidp);
1952 silc_buffer_free(auth);
1954 /* Notify application */
1955 COMMAND(SILC_STATUS_OK);
1958 silc_free(nickname);
1959 silc_client_command_free(cmd);
1962 /* KICK command. Kicks a client out of channel. */
1964 SILC_CLIENT_CMD_FUNC(kick)
1966 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1967 SilcClient client = cmd->client;
1968 SilcClientConnection conn = cmd->conn;
1969 SilcIDCacheEntry id_cache = NULL;
1970 SilcChannelEntry channel;
1971 SilcBuffer buffer, idp, idp2;
1972 SilcClientEntry target;
1974 char *nickname = NULL;
1977 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1978 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1982 if (cmd->argc < 3) {
1983 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1984 "Usage: /KICK <channel> <nickname> [<comment>]");
1985 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1989 if (cmd->argv[1][0] == '*') {
1990 if (!conn->current_channel) {
1991 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1994 name = conn->current_channel->channel_name;
1996 name = cmd->argv[1];
1999 if (!conn->current_channel) {
2000 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2004 /* Get the Channel ID of the channel */
2005 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
2007 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2011 channel = (SilcChannelEntry)id_cache->context;
2013 /* Parse the typed nickname. */
2014 if (client->internal->params->nickname_parse)
2015 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2017 nickname = strdup(cmd->argv[2]);
2019 /* Get the target client */
2020 target = silc_idlist_get_client(cmd->client, conn, nickname,
2021 cmd->argv[2], FALSE);
2023 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2024 "No such client: %s", cmd->argv[2]);
2025 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2029 /* Send KICK command to the server */
2030 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2031 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
2033 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
2034 1, idp->data, idp->len,
2035 2, idp2->data, idp2->len);
2037 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
2038 1, idp->data, idp->len,
2039 2, idp2->data, idp2->len,
2041 strlen(cmd->argv[3]));
2042 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2043 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2044 silc_buffer_free(buffer);
2045 silc_buffer_free(idp);
2046 silc_buffer_free(idp2);
2048 /* Notify application */
2049 COMMAND(SILC_STATUS_OK);
2052 silc_free(nickname);
2053 silc_client_command_free(cmd);
2056 static void silc_client_command_oper_send(unsigned char *data,
2057 SilcUInt32 data_len, void *context)
2059 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2060 SilcClientConnection conn = cmd->conn;
2061 SilcBuffer buffer, auth;
2063 if (cmd->argc >= 3) {
2064 /* Encode the public key authentication payload */
2065 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2066 cmd->client->private_key,
2068 conn->internal->hash,
2072 /* Encode the password authentication payload */
2073 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2077 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
2079 strlen(cmd->argv[1]),
2080 2, auth ? auth->data : NULL,
2081 auth ? auth->len : 0);
2082 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2083 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2085 silc_buffer_free(buffer);
2086 silc_buffer_clear(auth);
2087 silc_buffer_free(auth);
2089 /* Notify application */
2090 COMMAND(SILC_STATUS_OK);
2093 /* OPER command. Used to obtain server operator privileges. */
2095 SILC_CLIENT_CMD_FUNC(oper)
2097 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2098 SilcClientConnection conn = cmd->conn;
2101 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2102 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2106 if (cmd->argc < 2) {
2107 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2108 "Usage: /OPER <username> [-pubkey]");
2109 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2113 if (cmd->argc < 3) {
2114 /* Get passphrase */
2115 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2116 silc_client_command_oper_send,
2121 silc_client_command_oper_send(NULL, 0, context);
2124 silc_client_command_free(cmd);
2127 static void silc_client_command_silcoper_send(unsigned char *data,
2128 SilcUInt32 data_len,
2131 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2132 SilcClientConnection conn = cmd->conn;
2133 SilcBuffer buffer, auth;
2135 if (cmd->argc >= 3) {
2136 /* Encode the public key authentication payload */
2137 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2138 cmd->client->private_key,
2140 conn->internal->hash,
2144 /* Encode the password authentication payload */
2145 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2149 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
2151 strlen(cmd->argv[1]),
2152 2, auth ? auth->data : NULL,
2153 auth ? auth->len : 0);
2154 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2155 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2157 silc_buffer_free(buffer);
2158 silc_buffer_clear(auth);
2159 silc_buffer_free(auth);
2161 /* Notify application */
2162 COMMAND(SILC_STATUS_OK);
2165 /* SILCOPER command. Used to obtain router operator privileges. */
2167 SILC_CLIENT_CMD_FUNC(silcoper)
2169 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2170 SilcClientConnection conn = cmd->conn;
2173 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2174 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2178 if (cmd->argc < 2) {
2179 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2180 "Usage: /SILCOPER <username> [-pubkey]");
2181 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2185 if (cmd->argc < 3) {
2186 /* Get passphrase */
2187 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2188 silc_client_command_silcoper_send,
2193 silc_client_command_silcoper_send(NULL, 0, context);
2196 silc_client_command_free(cmd);
2199 /* Command BAN. This is used to manage the ban list of the channel. */
2201 SILC_CLIENT_CMD_FUNC(ban)
2203 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2204 SilcClientConnection conn = cmd->conn;
2205 SilcChannelEntry channel;
2206 SilcBuffer buffer, chidp, args = NULL;
2207 char *name, *ban = NULL;
2208 unsigned char action[1];
2209 SilcPublicKey pubkey = NULL;
2212 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2213 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2217 if (cmd->argc < 2) {
2218 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2219 "Usage: /BAN <channel> "
2220 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2221 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2225 if (cmd->argv[1][0] == '*') {
2226 if (!conn->current_channel) {
2227 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2231 channel = conn->current_channel;
2233 name = cmd->argv[1];
2235 channel = silc_client_get_channel(cmd->client, conn, name);
2237 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2242 if (cmd->argc == 3) {
2243 if (cmd->argv[2][0] == '+')
2248 /* Check if it is public key file to be added to invite list */
2249 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2250 SILC_PKCS_FILE_PEM))
2251 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2252 SILC_PKCS_FILE_BIN);
2259 args = silc_buffer_alloc_size(2);
2260 silc_buffer_format(args,
2261 SILC_STR_UI_SHORT(1),
2264 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2265 args = silc_argument_payload_encode_one(args, chidp->data,
2267 silc_buffer_free(chidp);
2268 silc_pkcs_public_key_free(pubkey);
2270 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2274 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2276 /* Send the command */
2277 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2278 ++conn->cmd_ident, 3,
2279 1, chidp->data, chidp->len,
2280 2, args ? action : NULL,
2282 3, args ? args->data : NULL,
2283 args ? args->len : 0);
2284 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2285 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2286 silc_buffer_free(buffer);
2287 silc_buffer_free(chidp);
2288 silc_buffer_free(args);
2290 /* Notify application */
2291 COMMAND(SILC_STATUS_OK);
2294 silc_client_command_free(cmd);
2297 /* Command DETACH. This is used to detach from the server */
2299 SILC_CLIENT_CMD_FUNC(detach)
2301 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2302 SilcClientConnection conn = cmd->conn;
2306 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2307 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2311 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2312 ++conn->cmd_ident, 0);
2313 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2314 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2315 silc_buffer_free(buffer);
2317 /* Notify application */
2318 COMMAND(SILC_STATUS_OK);
2321 silc_client_command_free(cmd);
2324 /* Command WATCH. */
2326 SILC_CLIENT_CMD_FUNC(watch)
2328 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2329 SilcClientConnection conn = cmd->conn;
2330 SilcBuffer buffer, idp = NULL;
2334 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2335 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2339 if (cmd->argc < 3) {
2340 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2344 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2346 if (!strcasecmp(cmd->argv[1], "-add")) {
2348 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2351 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2355 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2356 ++conn->cmd_ident, 2,
2357 1, idp->data, idp->len,
2360 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2361 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2362 silc_buffer_free(buffer);
2364 /* Notify application */
2365 COMMAND(SILC_STATUS_OK);
2369 silc_buffer_free(idp);
2370 silc_client_command_free(cmd);
2373 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2375 SILC_CLIENT_CMD_FUNC(leave)
2377 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2378 SilcClientConnection conn = cmd->conn;
2379 SilcChannelEntry channel;
2380 SilcBuffer buffer, idp;
2384 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2385 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2389 if (cmd->argc != 2) {
2390 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2391 "Usage: /LEAVE <channel>");
2392 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2396 if (cmd->argv[1][0] == '*') {
2397 if (!conn->current_channel) {
2398 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2401 name = conn->current_channel->channel_name;
2403 name = cmd->argv[1];
2406 /* Get the channel entry */
2407 channel = silc_client_get_channel(cmd->client, conn, name);
2409 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2413 /* Send LEAVE command to the server */
2414 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2415 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2416 1, idp->data, idp->len);
2417 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2418 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2419 silc_buffer_free(buffer);
2420 silc_buffer_free(idp);
2422 /* Notify application */
2423 COMMAND(SILC_STATUS_OK);
2425 if (conn->current_channel == channel)
2426 conn->current_channel = NULL;
2429 silc_client_command_free(cmd);
2432 /* Command USERS. Requests the USERS of the clients joined on requested
2435 SILC_CLIENT_CMD_FUNC(users)
2437 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2438 SilcClientConnection conn = cmd->conn;
2443 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2444 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2448 if (cmd->argc != 2) {
2449 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2450 "Usage: /USERS <channel>");
2451 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2455 if (cmd->argv[1][0] == '*') {
2456 if (!conn->current_channel) {
2457 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2460 name = conn->current_channel->channel_name;
2462 name = cmd->argv[1];
2465 /* Send USERS command to the server */
2466 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2467 ++conn->cmd_ident, 1,
2468 2, name, strlen(name));
2469 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2470 NULL, 0, NULL, NULL, buffer->data,
2472 silc_buffer_free(buffer);
2474 /* Notify application */
2475 COMMAND(SILC_STATUS_OK);
2478 silc_client_command_free(cmd);
2481 /* Command GETKEY. Used to fetch remote client's public key. */
2483 SILC_CLIENT_CMD_FUNC(getkey)
2485 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2486 SilcClientConnection conn = cmd->conn;
2487 SilcClient client = cmd->client;
2488 SilcClientEntry client_entry = NULL;
2489 SilcServerEntry server_entry = NULL;
2490 char *nickname = NULL;
2491 SilcBuffer idp, buffer;
2493 SILC_LOG_DEBUG(("Start"));
2496 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2501 if (cmd->argc < 2) {
2502 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2503 "Usage: /GETKEY <nickname or server name>");
2504 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2508 /* Parse the typed nickname. */
2509 if (client->internal->params->nickname_parse)
2510 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2512 nickname = strdup(cmd->argv[1]);
2514 /* Find client entry */
2515 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2517 if (!client_entry) {
2518 /* Check whether user requested server actually */
2519 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2521 if (!server_entry) {
2522 /* No. what ever user wants we don't have it, so resolve it. We
2523 will first try to resolve the client, and if that fails then
2524 we'll try to resolve the server. */
2526 if (!cmd->pending) {
2527 /* This will send the IDENTIFY command for nickname */
2528 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2529 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2531 silc_client_command_getkey,
2532 silc_client_command_dup(cmd));
2536 SilcClientCommandReplyContext reply =
2537 (SilcClientCommandReplyContext)context2;
2540 /* If nickname was not found, then resolve the server. */
2541 silc_command_get_status(reply->payload, NULL, &error);
2542 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2543 /* This sends the IDENTIFY command to resolve the server. */
2544 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2546 silc_client_command_reply_identify_i, 0,
2548 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2550 2, cmd->argv[1], cmd->argv_lens[1]);
2551 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2553 silc_client_command_getkey,
2554 silc_client_command_dup(cmd));
2558 /* If server was not found, then we've resolved both nickname and
2559 server and did not find anybody. */
2560 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2561 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2562 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2563 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2564 silc_get_status_message(error));
2565 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2569 COMMAND_ERROR(error);
2574 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2576 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2579 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2580 1, idp->data, idp->len);
2581 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2582 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2583 silc_buffer_free(buffer);
2584 silc_buffer_free(idp);
2586 /* Notify application */
2587 COMMAND(SILC_STATUS_OK);
2590 silc_free(nickname);
2591 silc_client_command_free(cmd);
2594 /* Register a new command indicated by the `command' to the SILC client.
2595 The `name' is optional command name. If provided the command may be
2596 searched using the silc_client_command_find by that name. The
2597 `command_function' is the function to be called when the command is
2598 executed, and the `command_reply_function' is the function to be
2599 called after the server has sent reply back to the command.
2601 The `ident' is optional identifier for the command. If non-zero
2602 the `command_reply_function' for the command type `command' will be
2603 called only if the command reply sent by server includes the
2604 command identifier `ident'. Application usually does not need it
2605 and set it to zero value. */
2607 bool silc_client_command_register(SilcClient client,
2608 SilcCommand command,
2610 SilcCommandCb command_function,
2611 SilcCommandCb command_reply_function,
2615 SilcClientCommand cmd;
2617 cmd = silc_calloc(1, sizeof(*cmd));
2619 cmd->command = command_function;
2620 cmd->reply = command_reply_function;
2621 cmd->name = name ? strdup(name) : NULL;
2622 cmd->max_args = max_args;
2625 silc_list_add(client->internal->commands, cmd);
2630 /* Unregister a command indicated by the `command' with command function
2631 `command_function' and command reply function `command_reply_function'.
2632 Returns TRUE if the command was found and unregistered. */
2634 bool silc_client_command_unregister(SilcClient client,
2635 SilcCommand command,
2636 SilcCommandCb command_function,
2637 SilcCommandCb command_reply_function,
2640 SilcClientCommand cmd;
2642 silc_list_start(client->internal->commands);
2643 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2644 if (cmd->cmd == command && cmd->command == command_function &&
2645 cmd->reply == command_reply_function && cmd->ident == ident) {
2646 silc_list_del(client->internal->commands, cmd);
2647 silc_free(cmd->name);
2656 /* Private range commands, specific to this implementation (and compatible
2657 with SILC Server). */
2659 /* CONNECT command. Connects the server to another server. */
2661 SILC_CLIENT_CMD_FUNC(connect)
2663 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2664 SilcClientConnection conn = cmd->conn;
2666 unsigned char port[4];
2670 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2671 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2675 if (cmd->argc < 2) {
2676 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2677 "Usage: /CONNECT <server> [<port>]");
2678 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2682 if (cmd->argc == 3) {
2683 tmp = atoi(cmd->argv[2]);
2684 SILC_PUT32_MSB(tmp, port);
2688 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2690 strlen(cmd->argv[1]),
2693 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2695 strlen(cmd->argv[1]));
2696 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2697 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2698 silc_buffer_free(buffer);
2700 /* Notify application */
2701 COMMAND(SILC_STATUS_OK);
2704 silc_client_command_free(cmd);
2708 /* CLOSE command. Close server connection to the remote server */
2710 SILC_CLIENT_CMD_FUNC(close)
2712 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2713 SilcClientConnection conn = cmd->conn;
2715 unsigned char port[4];
2719 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2720 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2724 if (cmd->argc < 2) {
2725 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2726 "Usage: /CLOSE <server> [<port>]");
2727 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2731 if (cmd->argc == 3) {
2732 tmp = atoi(cmd->argv[2]);
2733 SILC_PUT32_MSB(tmp, port);
2737 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2739 strlen(cmd->argv[1]),
2742 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2744 strlen(cmd->argv[1]));
2745 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2746 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2747 silc_buffer_free(buffer);
2749 /* Notify application */
2750 COMMAND(SILC_STATUS_OK);
2753 silc_client_command_free(cmd);
2756 /* SHUTDOWN command. Shutdowns the server. */
2758 SILC_CLIENT_CMD_FUNC(shutdown)
2760 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2763 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2764 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2768 /* Send the command */
2769 silc_client_command_send(cmd->client, cmd->conn,
2770 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2772 /* Notify application */
2773 COMMAND(SILC_STATUS_OK);
2776 silc_client_command_free(cmd);
2779 /* Register all default commands provided by the client library for the
2782 void silc_client_commands_register(SilcClient client)
2784 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2787 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2788 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2789 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2790 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2791 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2792 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2793 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2794 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2795 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2796 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2797 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2798 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2799 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2800 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2801 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2802 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2803 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2804 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2805 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2806 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2807 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2808 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2809 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2810 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2811 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2812 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2814 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2815 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2816 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2819 /* Unregister all commands. */
2821 void silc_client_commands_unregister(SilcClient client)
2823 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2824 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2825 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2826 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2827 SILC_CLIENT_CMDU(list, LIST, "LIST");
2828 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2829 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2830 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2831 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2832 SILC_CLIENT_CMDU(info, INFO, "INFO");
2833 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2834 SILC_CLIENT_CMDU(ping, PING, "PING");
2835 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2836 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2837 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2838 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2839 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2840 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2841 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2842 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2843 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2844 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2845 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2846 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2847 SILC_CLIENT_CMDU(users, USERS, "USERS");
2848 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2850 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2851 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2852 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2855 /**** Client side incoming command handling **********************************/
2857 void silc_client_command_process_whois(SilcClient client,
2858 SilcSocketConnection sock,
2859 SilcCommandPayload payload,
2860 SilcArgumentPayload args);
2862 /* Client is able to receive some command packets even though they are
2863 special case. Server may send WHOIS command to the client to retrieve
2864 Requested Attributes information for WHOIS query the server is
2865 processing. This function currently handles only the WHOIS command,
2866 but if in the future for commands may arrive then this can be made
2867 to support other commands too. */
2869 void silc_client_command_process(SilcClient client,
2870 SilcSocketConnection sock,
2871 SilcPacketContext *packet)
2873 SilcCommandPayload payload;
2874 SilcCommand command;
2875 SilcArgumentPayload args;
2877 /* Get command payload from packet */
2878 payload = silc_command_payload_parse(packet->buffer->data,
2879 packet->buffer->len);
2881 /* Silently ignore bad reply packet */
2882 SILC_LOG_DEBUG(("Bad command packet"));
2887 args = silc_command_get_args(payload);
2889 /* Get the command */
2890 command = silc_command_get(payload);
2893 case SILC_COMMAND_WHOIS:
2894 /* Ignore everything if requested by application */
2895 if (client->internal->params->ignore_requested_attributes)
2898 silc_client_command_process_whois(client, sock, payload, args);
2905 silc_command_payload_free(payload);
2908 void silc_client_command_process_whois(SilcClient client,
2909 SilcSocketConnection sock,
2910 SilcCommandPayload payload,
2911 SilcArgumentPayload args)
2916 SilcBuffer buffer, packet;
2918 SILC_LOG_DEBUG(("Received WHOIS command"));
2920 /* Try to take the Requested Attributes */
2921 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2925 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2929 /* Process requested attributes */
2930 buffer = silc_client_attributes_process(client, sock, attrs);
2932 silc_attribute_payload_list_free(attrs);
2936 /* Send the attributes back */
2938 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2940 silc_command_get_ident(payload),
2941 1, 11, buffer->data, buffer->len);
2942 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2943 NULL, 0, NULL, NULL, packet->data,
2945 silc_buffer_free(packet);
2946 silc_buffer_free(buffer);