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],
844 ++cmd->conn->cmd_ident);
846 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
848 ++cmd->conn->cmd_ident);
849 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
851 buffer->data, buffer->len, TRUE);
852 silc_buffer_free(buffer);
854 q = silc_calloc(1, sizeof(*q));
855 q->client = cmd->client;
858 /* Sleep for a while */
861 /* We quit the connection with little timeout */
862 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
863 silc_client_command_quit_cb, (void *)q,
864 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
866 /* Notify application */
867 COMMAND(SILC_STATUS_OK);
870 silc_client_command_free(cmd);
873 /* Timeout callback to remove the killed client from cache */
875 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
877 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
878 SilcClient client = cmd->client;
879 SilcClientConnection conn = cmd->conn;
880 SilcClientEntry target;
881 char *nickname = NULL;
883 /* Parse the typed nickname. */
884 if (client->internal->params->nickname_parse)
885 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
887 nickname = strdup(cmd->argv[1]);
889 /* Get the target client */
890 target = silc_idlist_get_client(cmd->client, conn, nickname,
891 cmd->argv[1], FALSE);
893 /* Remove the client from all channels and free it */
894 silc_client_del_client(client, conn, target);
897 silc_client_command_free(cmd);
900 /* Kill command's pending command callback to actually remove the killed
901 client from our local cache. */
903 SILC_CLIENT_CMD_FUNC(kill_remove)
905 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
906 SilcClientCommandReplyContext reply =
907 (SilcClientCommandReplyContext)context2;
910 silc_command_get_status(reply->payload, &status, NULL);
911 if (status == SILC_STATUS_OK) {
912 /* Remove with timeout */
913 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
914 silc_client_command_kill_remove_later, context,
915 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
919 silc_client_command_free(cmd);
922 /* Command KILL. Router operator can use this command to remove an client
923 fromthe SILC Network. */
925 SILC_CLIENT_CMD_FUNC(kill)
927 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
928 SilcClient client = cmd->client;
929 SilcClientConnection conn = cmd->conn;
930 SilcBuffer buffer, idp, auth = NULL;
931 SilcClientEntry target;
932 char *nickname = NULL, *comment = NULL;
935 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
936 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
941 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
942 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
947 /* Parse the typed nickname. */
948 if (client->internal->params->nickname_parse)
949 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
951 nickname = strdup(cmd->argv[1]);
953 /* Get the target client */
954 target = silc_idlist_get_client(cmd->client, conn, nickname,
958 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
962 /* Client entry not found, it was requested thus mark this to be
964 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
966 silc_client_command_kill,
967 silc_client_command_dup(cmd));
972 if (cmd->argc >= 3) {
973 if (strcasecmp(cmd->argv[2], "-pubkey"))
974 comment = cmd->argv[2];
976 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
977 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
978 /* Encode the public key authentication payload */
979 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
980 cmd->client->private_key,
983 target->id, SILC_ID_CLIENT);
987 /* Send the KILL command to the server */
988 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
990 silc_command_payload_encode_va(SILC_COMMAND_KILL,
991 ++conn->cmd_ident, 3,
992 1, idp->data, idp->len,
993 2, comment, comment ? strlen(comment) : 0,
994 3, auth ? auth->data : NULL,
995 auth ? auth->len : 0);
996 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
997 0, NULL, NULL, buffer->data, buffer->len, TRUE);
998 silc_buffer_free(buffer);
999 silc_buffer_free(idp);
1000 silc_buffer_free(auth);
1002 /* Notify application */
1003 COMMAND(SILC_STATUS_OK);
1005 /* Register a pending callback that will actually remove the killed
1006 client from our cache. */
1007 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
1008 silc_client_command_kill_remove,
1009 silc_client_command_dup(cmd));
1012 silc_free(nickname);
1013 silc_client_command_free(cmd);
1016 /* Command INFO. Request information about specific server. If specific
1017 server is not provided the current server is used. */
1019 SILC_CLIENT_CMD_FUNC(info)
1021 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1022 SilcClientConnection conn = cmd->conn;
1027 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1028 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1033 name = strdup(cmd->argv[1]);
1035 /* Send the command */
1037 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO,
1038 ++conn->cmd_ident, 1,
1039 1, name, strlen(name));
1041 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
1042 NULL, NULL, NULL, ++conn->cmd_ident);
1043 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1044 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1045 silc_buffer_free(buffer);
1049 /* Notify application */
1050 COMMAND(SILC_STATUS_OK);
1053 silc_client_command_free(cmd);
1056 /* Command STATS. Shows server and network statistics. */
1058 SILC_CLIENT_CMD_FUNC(stats)
1060 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1061 SilcClientConnection conn = cmd->conn;
1062 SilcBuffer buffer, idp = NULL;
1065 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1066 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1070 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1072 /* Send the command */
1073 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1074 ++conn->cmd_ident, 1,
1075 SILC_ID_SERVER, idp->data, idp->len);
1076 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1077 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1078 silc_buffer_free(buffer);
1079 silc_buffer_free(idp);
1081 /* Notify application */
1082 COMMAND(SILC_STATUS_OK);
1085 silc_client_command_free(cmd);
1088 /* Command PING. Sends ping to server. This is used to test the
1089 communication channel. */
1091 SILC_CLIENT_CMD_FUNC(ping)
1093 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1094 SilcClientConnection conn = cmd->conn;
1095 SilcBuffer buffer, idp;
1100 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1101 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1105 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1107 /* Send the command */
1108 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING,
1109 ++conn->cmd_ident, 1,
1110 1, idp->data, idp->len);
1111 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1112 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1113 silc_buffer_free(buffer);
1114 silc_buffer_free(idp);
1116 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1119 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1120 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1124 /* Start counting time */
1125 for (i = 0; i < conn->internal->ping_count; i++) {
1126 if (conn->internal->ping[i].dest_id == NULL) {
1127 conn->internal->ping[i].start_time = time(NULL);
1128 conn->internal->ping[i].dest_id = id;
1129 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1133 if (i >= conn->internal->ping_count) {
1134 i = conn->internal->ping_count;
1135 conn->internal->ping =
1136 silc_realloc(conn->internal->ping,
1137 sizeof(*conn->internal->ping) * (i + 1));
1138 conn->internal->ping[i].start_time = time(NULL);
1139 conn->internal->ping[i].dest_id = id;
1140 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1141 conn->internal->ping_count++;
1144 /* Notify application */
1145 COMMAND(SILC_STATUS_OK);
1148 silc_client_command_free(cmd);
1151 /* Command JOIN. Joins to a channel. */
1153 SILC_CLIENT_CMD_FUNC(join)
1155 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1156 SilcClientConnection conn = cmd->conn;
1157 SilcChannelEntry channel;
1158 SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
1159 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1160 int i, passphrase_len = 0;
1163 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1164 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1168 if (cmd->argc < 2) {
1169 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1173 /* See if we have joined to the requested channel already */
1174 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1175 if (channel && silc_client_on_channel(channel, conn->local_entry))
1178 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1180 if (cmd->argv_lens[1] > 256)
1181 cmd->argv_lens[1] = 256;
1183 name = cmd->argv[1];
1185 for (i = 2; i < cmd->argc; i++) {
1186 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1187 cipher = cmd->argv[i + 1];
1189 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1190 hmac = cmd->argv[i + 1];
1192 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1193 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1194 cmd->client->private_key,
1196 cmd->client->sha1hash,
1200 } else if (!strcasecmp(cmd->argv[i], "-auth")) {
1201 SilcPublicKey pubkey = cmd->client->public_key;
1202 SilcPrivateKey privkey = cmd->client->private_key;
1203 unsigned char *pk, pkhash[20], *pubdata;
1206 if (cmd->argc >= i + 3) {
1208 if (cmd->argc >= i + 4) {
1209 pass = cmd->argv[i + 3];
1212 if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
1213 NULL, &pubkey, &privkey)) {
1214 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1215 "Could not load key pair, check your arguments");
1216 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1222 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
1223 silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
1225 pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
1226 memcpy(pubdata, pkhash, 20);
1227 cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
1229 cmd->client->sha1hash,
1232 memset(pubdata, 0, 128);
1236 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1237 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1238 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1239 cmd->argv_lens[i], 0);
1240 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1241 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1242 0, pu8, passphrase_len);
1245 passphrase = strdup(cmd->argv[i]);
1246 passphrase_len = cmd->argv_lens[i];
1251 /* Send JOIN command to the server */
1253 silc_command_payload_encode_va(SILC_COMMAND_JOIN, ++conn->cmd_ident, 7,
1254 1, name, strlen(name),
1255 2, idp->data, idp->len,
1256 3, passphrase, passphrase_len,
1257 4, cipher, cipher ? strlen(cipher) : 0,
1258 5, hmac, hmac ? strlen(hmac) : 0,
1259 6, auth ? auth->data : NULL,
1260 auth ? auth->len : 0,
1261 7, cauth ? cauth->data : NULL,
1262 cauth ? cauth->len : 0);
1263 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1264 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1265 silc_buffer_free(buffer);
1266 silc_buffer_free(idp);
1267 silc_buffer_free(auth);
1268 silc_buffer_free(cauth);
1270 memset(passphrase, 0, strlen(passphrase));
1271 silc_free(passphrase);
1273 /* Notify application */
1274 COMMAND(SILC_STATUS_OK);
1277 silc_client_command_free(cmd);
1280 /* MOTD command. Requests motd from server. */
1282 SILC_CLIENT_CMD_FUNC(motd)
1284 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1285 SilcClientConnection conn = cmd->conn;
1289 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1290 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1294 if (cmd->argc < 1 || cmd->argc > 2) {
1295 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1296 "Usage: /MOTD [<server>]");
1297 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1298 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1302 /* Send TOPIC command to the server */
1304 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
1305 ++conn->cmd_ident, 1,
1306 1, conn->remote_host,
1307 strlen(conn->remote_host));
1309 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
1310 ++conn->cmd_ident, 1,
1313 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1314 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1315 silc_buffer_free(buffer);
1317 /* Notify application */
1318 COMMAND(SILC_STATUS_OK);
1321 silc_client_command_free(cmd);
1324 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1325 modes as client cannot set itself server/router operator privileges. */
1327 SILC_CLIENT_CMD_FUNC(umode)
1329 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1330 SilcClientConnection conn = cmd->conn;
1331 SilcBuffer buffer, idp;
1332 unsigned char *cp, modebuf[4];
1333 SilcUInt32 mode, add, len;
1337 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1338 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1342 if (cmd->argc < 2) {
1343 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1344 "Usage: /UMODE +|-<modes>");
1345 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1349 mode = conn->local_entry->mode;
1351 /* Are we adding or removing mode */
1352 if (cmd->argv[1][0] == '-')
1358 cp = cmd->argv[1] + 1;
1360 for (i = 0; i < len; i++) {
1365 mode |= SILC_UMODE_SERVER_OPERATOR;
1366 mode |= SILC_UMODE_ROUTER_OPERATOR;
1367 mode |= SILC_UMODE_GONE;
1368 mode |= SILC_UMODE_INDISPOSED;
1369 mode |= SILC_UMODE_BUSY;
1370 mode |= SILC_UMODE_PAGE;
1371 mode |= SILC_UMODE_HYPER;
1372 mode |= SILC_UMODE_ROBOT;
1373 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1374 mode |= SILC_UMODE_REJECT_WATCHING;
1376 mode = SILC_UMODE_NONE;
1381 mode |= SILC_UMODE_SERVER_OPERATOR;
1383 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1387 mode |= SILC_UMODE_ROUTER_OPERATOR;
1389 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1393 mode |= SILC_UMODE_GONE;
1395 mode &= ~SILC_UMODE_GONE;
1399 mode |= SILC_UMODE_INDISPOSED;
1401 mode &= ~SILC_UMODE_INDISPOSED;
1405 mode |= SILC_UMODE_BUSY;
1407 mode &= ~SILC_UMODE_BUSY;
1411 mode |= SILC_UMODE_PAGE;
1413 mode &= ~SILC_UMODE_PAGE;
1417 mode |= SILC_UMODE_HYPER;
1419 mode &= ~SILC_UMODE_HYPER;
1423 mode |= SILC_UMODE_ROBOT;
1425 mode &= ~SILC_UMODE_ROBOT;
1429 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1431 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1435 mode |= SILC_UMODE_REJECT_WATCHING;
1437 mode &= ~SILC_UMODE_REJECT_WATCHING;
1441 mode |= SILC_UMODE_BLOCK_INVITE;
1443 mode &= ~SILC_UMODE_BLOCK_INVITE;
1446 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1452 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1453 SILC_PUT32_MSB(mode, modebuf);
1455 /* Send the command packet. We support sending only one mode at once
1456 that requires an argument. */
1458 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1459 1, idp->data, idp->len,
1460 2, modebuf, sizeof(modebuf));
1461 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1462 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1463 silc_buffer_free(buffer);
1464 silc_buffer_free(idp);
1466 /* Notify application */
1467 COMMAND(SILC_STATUS_OK);
1470 silc_client_command_free(cmd);
1473 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1474 can be set several at once. Those modes that require argument must be set
1475 separately (unless set with modes that does not require arguments). */
1477 SILC_CLIENT_CMD_FUNC(cmode)
1479 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1480 SilcClientConnection conn = cmd->conn;
1481 SilcChannelEntry channel;
1482 SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
1483 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1484 SilcUInt32 mode, add, type, len, arg_len = 0;
1488 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1489 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1493 if (cmd->argc < 3) {
1494 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1495 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1496 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1500 if (cmd->argv[1][0] == '*') {
1501 if (!conn->current_channel) {
1502 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1506 channel = conn->current_channel;
1508 name = cmd->argv[1];
1510 channel = silc_client_get_channel(cmd->client, conn, name);
1512 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1517 mode = channel->mode;
1519 /* Are we adding or removing mode */
1520 if (cmd->argv[2][0] == '-')
1525 /* Argument type to be sent to server */
1529 cp = cmd->argv[2] + 1;
1531 for (i = 0; i < len; i++) {
1535 mode |= SILC_CHANNEL_MODE_PRIVATE;
1537 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1541 mode |= SILC_CHANNEL_MODE_SECRET;
1543 mode &= ~SILC_CHANNEL_MODE_SECRET;
1547 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1549 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1553 mode |= SILC_CHANNEL_MODE_INVITE;
1555 mode &= ~SILC_CHANNEL_MODE_INVITE;
1559 mode |= SILC_CHANNEL_MODE_TOPIC;
1561 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1565 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1567 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1571 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1573 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1578 mode |= SILC_CHANNEL_MODE_ULIMIT;
1580 if (cmd->argc < 4) {
1581 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1582 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1583 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1586 ll = atoi(cmd->argv[3]);
1587 SILC_PUT32_MSB(ll, tmp);
1591 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1596 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1598 if (cmd->argc < 4) {
1599 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1600 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1601 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1605 arg_len = cmd->argv_lens[3];
1607 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1612 mode |= SILC_CHANNEL_MODE_CIPHER;
1614 if (cmd->argc < 4) {
1615 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1616 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1617 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1621 arg_len = cmd->argv_lens[3];
1623 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1628 mode |= SILC_CHANNEL_MODE_HMAC;
1630 if (cmd->argc < 4) {
1631 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1632 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1633 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1637 arg_len = cmd->argv_lens[3];
1639 mode &= ~SILC_CHANNEL_MODE_HMAC;
1644 SilcPublicKey pubkey = cmd->client->public_key;
1645 SilcPrivateKey privkey = cmd->client->private_key;
1647 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1650 if (cmd->argc >= 5) {
1653 pass = cmd->argv[5];
1654 if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
1655 NULL, &pubkey, &privkey)) {
1656 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1657 "Could not load key pair, check your arguments");
1658 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1663 pk = silc_pkcs_public_key_payload_encode(pubkey);
1664 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1666 cmd->client->sha1hash,
1670 arg_len = auth->len;
1672 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1679 SilcPublicKey chpk = NULL;
1681 mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
1684 if (cmd->argc == 3) {
1685 /* Send empty command to receive the public key list. */
1686 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1687 silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
1688 0, 1, 1, chidp->data, chidp->len);
1689 silc_buffer_free(chidp);
1691 /* Notify application */
1692 COMMAND(SILC_STATUS_OK);
1696 if (cmd->argc >= 4) {
1697 auth = silc_buffer_alloc_size(2);
1698 silc_buffer_format(auth,
1699 SILC_STR_UI_SHORT(cmd->argc - 3),
1703 for (k = 3; k < cmd->argc; k++) {
1704 if (cmd->argv[k][0] == '+')
1706 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1707 SILC_PKCS_FILE_PEM))
1708 if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
1709 SILC_PKCS_FILE_BIN)) {
1710 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1711 "Could not load public key %s, check the filename",
1713 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1714 silc_buffer_free(auth);
1719 pk = silc_pkcs_public_key_payload_encode(chpk);
1720 auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
1721 chadd ? 0x00 : 0x01);
1722 silc_pkcs_public_key_free(chpk);
1723 silc_buffer_free(pk);
1729 arg_len = auth->len;
1731 mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
1735 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1741 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1742 SILC_PUT32_MSB(mode, modebuf);
1744 /* Send the command packet. We support sending only one mode at once
1745 that requires an argument. */
1748 silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 4,
1749 1, chidp->data, chidp->len,
1750 2, modebuf, sizeof(modebuf),
1752 8, pk ? pk->data : NULL,
1756 silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 2,
1757 1, chidp->data, chidp->len,
1758 2, modebuf, sizeof(modebuf));
1761 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1762 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1763 silc_buffer_free(buffer);
1764 silc_buffer_free(chidp);
1765 silc_buffer_free(auth);
1766 silc_buffer_free(pk);
1768 /* Notify application */
1769 COMMAND(SILC_STATUS_OK);
1772 silc_client_command_free(cmd);
1775 /* CUMODE command. Changes client's mode on a channel. */
1777 SILC_CLIENT_CMD_FUNC(cumode)
1779 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1780 SilcClient client = cmd->client;
1781 SilcClientConnection conn = cmd->conn;
1782 SilcChannelEntry channel;
1783 SilcChannelUser chu;
1784 SilcClientEntry client_entry;
1785 SilcBuffer buffer, clidp, chidp, auth = NULL;
1786 unsigned char *name, *cp, modebuf[4];
1787 SilcUInt32 mode = 0, add, len;
1788 char *nickname = NULL;
1792 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1793 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1797 if (cmd->argc < 4) {
1798 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1799 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1800 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1804 if (cmd->argv[1][0] == '*') {
1805 if (!conn->current_channel) {
1806 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1810 channel = conn->current_channel;
1812 name = cmd->argv[1];
1814 channel = silc_client_get_channel(cmd->client, conn, name);
1816 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1821 /* Parse the typed nickname. */
1822 if (client->internal->params->nickname_parse)
1823 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1825 nickname = strdup(cmd->argv[3]);
1827 /* Find client entry */
1828 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1829 cmd->argv[3], TRUE);
1830 if (!client_entry) {
1832 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1836 /* Client entry not found, it was requested thus mark this to be
1838 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1840 silc_client_command_cumode,
1841 silc_client_command_dup(cmd));
1846 /* Get the current mode */
1847 chu = silc_client_on_channel(channel, client_entry);
1851 /* Are we adding or removing mode */
1852 if (cmd->argv[2][0] == '-')
1858 cp = cmd->argv[2] + 1;
1860 for (i = 0; i < len; i++) {
1864 mode |= SILC_CHANNEL_UMODE_CHANFO;
1865 mode |= SILC_CHANNEL_UMODE_CHANOP;
1866 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1867 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1868 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1870 mode = SILC_CHANNEL_UMODE_NONE;
1875 SilcPublicKey pubkey = cmd->client->public_key;
1876 SilcPrivateKey privkey = cmd->client->private_key;
1878 if (cmd->argc >= 6) {
1881 pass = cmd->argv[6];
1882 if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
1883 NULL, &pubkey, &privkey)) {
1884 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1885 "Could not load key pair, check your arguments");
1886 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1891 auth = silc_auth_public_key_auth_generate(pubkey, privkey,
1893 cmd->client->sha1hash,
1896 mode |= SILC_CHANNEL_UMODE_CHANFO;
1898 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1903 mode |= SILC_CHANNEL_UMODE_CHANOP;
1905 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1909 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1911 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1915 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1917 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1921 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1923 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1927 mode |= SILC_CHANNEL_UMODE_QUIET;
1929 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1932 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1938 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1939 SILC_PUT32_MSB(mode, modebuf);
1940 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1942 /* Send the command packet. We support sending only one mode at once
1943 that requires an argument. */
1944 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE,
1947 1, chidp->data, chidp->len,
1949 3, clidp->data, clidp->len,
1950 4, auth ? auth->data : NULL,
1951 auth ? auth->len : 0);
1953 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1954 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1955 silc_buffer_free(buffer);
1956 silc_buffer_free(chidp);
1957 silc_buffer_free(clidp);
1959 silc_buffer_free(auth);
1961 /* Notify application */
1962 COMMAND(SILC_STATUS_OK);
1965 silc_free(nickname);
1966 silc_client_command_free(cmd);
1969 /* KICK command. Kicks a client out of channel. */
1971 SILC_CLIENT_CMD_FUNC(kick)
1973 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1974 SilcClient client = cmd->client;
1975 SilcClientConnection conn = cmd->conn;
1976 SilcIDCacheEntry id_cache = NULL;
1977 SilcChannelEntry channel;
1978 SilcBuffer buffer, idp, idp2;
1979 SilcClientEntry target;
1981 char *nickname = NULL;
1984 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1985 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1989 if (cmd->argc < 3) {
1990 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1991 "Usage: /KICK <channel> <nickname> [<comment>]");
1992 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1996 if (cmd->argv[1][0] == '*') {
1997 if (!conn->current_channel) {
1998 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2001 name = conn->current_channel->channel_name;
2003 name = cmd->argv[1];
2006 if (!conn->current_channel) {
2007 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2011 /* Get the Channel ID of the channel */
2012 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
2014 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2018 channel = (SilcChannelEntry)id_cache->context;
2020 /* Parse the typed nickname. */
2021 if (client->internal->params->nickname_parse)
2022 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
2024 nickname = strdup(cmd->argv[2]);
2026 /* Get the target client */
2027 target = silc_idlist_get_client(cmd->client, conn, nickname,
2028 cmd->argv[2], FALSE);
2030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "No such client: %s", cmd->argv[2]);
2032 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2036 /* Send KICK command to the server */
2037 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2038 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
2040 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
2041 ++conn->cmd_ident, 2,
2042 1, idp->data, idp->len,
2043 2, idp2->data, idp2->len);
2045 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
2046 ++conn->cmd_ident, 3,
2047 1, idp->data, idp->len,
2048 2, idp2->data, idp2->len,
2050 strlen(cmd->argv[3]));
2051 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2052 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2053 silc_buffer_free(buffer);
2054 silc_buffer_free(idp);
2055 silc_buffer_free(idp2);
2057 /* Notify application */
2058 COMMAND(SILC_STATUS_OK);
2061 silc_free(nickname);
2062 silc_client_command_free(cmd);
2065 static void silc_client_command_oper_send(unsigned char *data,
2066 SilcUInt32 data_len, void *context)
2068 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2069 SilcClientConnection conn = cmd->conn;
2070 SilcBuffer buffer, auth;
2072 if (cmd->argc >= 3) {
2073 /* Encode the public key authentication payload */
2074 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2075 cmd->client->private_key,
2077 conn->internal->hash,
2081 /* Encode the password authentication payload */
2082 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2086 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER,
2087 ++conn->cmd_ident, 2,
2089 strlen(cmd->argv[1]),
2090 2, auth ? auth->data : NULL,
2091 auth ? auth->len : 0);
2092 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2093 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2095 silc_buffer_free(buffer);
2096 silc_buffer_clear(auth);
2097 silc_buffer_free(auth);
2099 /* Notify application */
2100 COMMAND(SILC_STATUS_OK);
2103 /* OPER command. Used to obtain server operator privileges. */
2105 SILC_CLIENT_CMD_FUNC(oper)
2107 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2108 SilcClientConnection conn = cmd->conn;
2111 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2112 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2116 if (cmd->argc < 2) {
2117 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2118 "Usage: /OPER <username> [-pubkey]");
2119 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2123 if (cmd->argc < 3) {
2124 /* Get passphrase */
2125 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2126 silc_client_command_oper_send,
2131 silc_client_command_oper_send(NULL, 0, context);
2134 silc_client_command_free(cmd);
2137 static void silc_client_command_silcoper_send(unsigned char *data,
2138 SilcUInt32 data_len,
2141 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2142 SilcClientConnection conn = cmd->conn;
2143 SilcBuffer buffer, auth;
2145 if (cmd->argc >= 3) {
2146 /* Encode the public key authentication payload */
2147 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
2148 cmd->client->private_key,
2150 conn->internal->hash,
2154 /* Encode the password authentication payload */
2155 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
2159 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER,
2160 ++conn->cmd_ident, 2,
2162 strlen(cmd->argv[1]),
2163 2, auth ? auth->data : NULL,
2164 auth ? auth->len : 0);
2165 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2166 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2168 silc_buffer_free(buffer);
2169 silc_buffer_clear(auth);
2170 silc_buffer_free(auth);
2172 /* Notify application */
2173 COMMAND(SILC_STATUS_OK);
2176 /* SILCOPER command. Used to obtain router operator privileges. */
2178 SILC_CLIENT_CMD_FUNC(silcoper)
2180 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2181 SilcClientConnection conn = cmd->conn;
2184 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2185 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2189 if (cmd->argc < 2) {
2190 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2191 "Usage: /SILCOPER <username> [-pubkey]");
2192 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2196 if (cmd->argc < 3) {
2197 /* Get passphrase */
2198 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
2199 silc_client_command_silcoper_send,
2204 silc_client_command_silcoper_send(NULL, 0, context);
2207 silc_client_command_free(cmd);
2210 /* Command BAN. This is used to manage the ban list of the channel. */
2212 SILC_CLIENT_CMD_FUNC(ban)
2214 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2215 SilcClientConnection conn = cmd->conn;
2216 SilcChannelEntry channel;
2217 SilcBuffer buffer, chidp, args = NULL;
2218 char *name, *ban = NULL;
2219 unsigned char action[1];
2220 SilcPublicKey pubkey = NULL;
2223 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2224 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2228 if (cmd->argc < 2) {
2229 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2230 "Usage: /BAN <channel> "
2231 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2232 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2236 if (cmd->argv[1][0] == '*') {
2237 if (!conn->current_channel) {
2238 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2242 channel = conn->current_channel;
2244 name = cmd->argv[1];
2246 channel = silc_client_get_channel(cmd->client, conn, name);
2248 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2253 if (cmd->argc == 3) {
2254 if (cmd->argv[2][0] == '+')
2259 /* Check if it is public key file to be added to invite list */
2260 if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2261 SILC_PKCS_FILE_PEM))
2262 silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
2263 SILC_PKCS_FILE_BIN);
2270 args = silc_buffer_alloc_size(2);
2271 silc_buffer_format(args,
2272 SILC_STR_UI_SHORT(1),
2275 chidp = silc_pkcs_public_key_payload_encode(pubkey);
2276 args = silc_argument_payload_encode_one(args, chidp->data,
2278 silc_buffer_free(chidp);
2279 silc_pkcs_public_key_free(pubkey);
2281 args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1);
2285 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2287 /* Send the command */
2288 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2289 ++conn->cmd_ident, 3,
2290 1, chidp->data, chidp->len,
2291 2, args ? action : NULL,
2293 3, args ? args->data : NULL,
2294 args ? args->len : 0);
2295 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2296 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2297 silc_buffer_free(buffer);
2298 silc_buffer_free(chidp);
2299 silc_buffer_free(args);
2301 /* Notify application */
2302 COMMAND(SILC_STATUS_OK);
2305 silc_client_command_free(cmd);
2308 /* Command DETACH. This is used to detach from the server */
2310 SILC_CLIENT_CMD_FUNC(detach)
2312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2313 SilcClientConnection conn = cmd->conn;
2317 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2318 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2322 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2323 ++conn->cmd_ident, 0);
2324 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2325 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2326 silc_buffer_free(buffer);
2328 /* Notify application */
2329 COMMAND(SILC_STATUS_OK);
2332 silc_client_command_free(cmd);
2335 /* Command WATCH. */
2337 SILC_CLIENT_CMD_FUNC(watch)
2339 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2340 SilcClientConnection conn = cmd->conn;
2341 SilcBuffer buffer, idp = NULL;
2345 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2346 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2350 if (cmd->argc < 3) {
2351 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2355 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2357 if (!strcasecmp(cmd->argv[1], "-add")) {
2359 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2362 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2366 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2367 ++conn->cmd_ident, 2,
2368 1, idp->data, idp->len,
2371 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2372 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2373 silc_buffer_free(buffer);
2375 /* Notify application */
2376 COMMAND(SILC_STATUS_OK);
2380 silc_buffer_free(idp);
2381 silc_client_command_free(cmd);
2384 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2386 SILC_CLIENT_CMD_FUNC(leave)
2388 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2389 SilcClientConnection conn = cmd->conn;
2390 SilcChannelEntry channel;
2391 SilcBuffer buffer, idp;
2395 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2396 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2400 if (cmd->argc != 2) {
2401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2402 "Usage: /LEAVE <channel>");
2403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2407 if (cmd->argv[1][0] == '*') {
2408 if (!conn->current_channel) {
2409 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2412 name = conn->current_channel->channel_name;
2414 name = cmd->argv[1];
2417 /* Get the channel entry */
2418 channel = silc_client_get_channel(cmd->client, conn, name);
2420 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2424 /* Send LEAVE command to the server */
2425 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2426 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE,
2427 ++conn->cmd_ident, 1,
2428 1, idp->data, idp->len);
2429 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2430 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2431 silc_buffer_free(buffer);
2432 silc_buffer_free(idp);
2434 /* Notify application */
2435 COMMAND(SILC_STATUS_OK);
2437 if (conn->current_channel == channel)
2438 conn->current_channel = NULL;
2441 silc_client_command_free(cmd);
2444 /* Command USERS. Requests the USERS of the clients joined on requested
2447 SILC_CLIENT_CMD_FUNC(users)
2449 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2450 SilcClientConnection conn = cmd->conn;
2455 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2456 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2460 if (cmd->argc != 2) {
2461 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2462 "Usage: /USERS <channel>");
2463 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2467 if (cmd->argv[1][0] == '*') {
2468 if (!conn->current_channel) {
2469 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2472 name = conn->current_channel->channel_name;
2474 name = cmd->argv[1];
2477 /* Send USERS command to the server */
2478 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2479 ++conn->cmd_ident, 1,
2480 2, name, strlen(name));
2481 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2482 NULL, 0, NULL, NULL, buffer->data,
2484 silc_buffer_free(buffer);
2486 /* Notify application */
2487 COMMAND(SILC_STATUS_OK);
2490 silc_client_command_free(cmd);
2493 /* Command GETKEY. Used to fetch remote client's public key. */
2495 SILC_CLIENT_CMD_FUNC(getkey)
2497 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2498 SilcClientConnection conn = cmd->conn;
2499 SilcClient client = cmd->client;
2500 SilcClientEntry client_entry = NULL;
2501 SilcServerEntry server_entry = NULL;
2502 char *nickname = NULL;
2503 SilcBuffer idp, buffer;
2505 SILC_LOG_DEBUG(("Start"));
2508 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2509 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2513 if (cmd->argc < 2) {
2514 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2515 "Usage: /GETKEY <nickname or server name>");
2516 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2520 /* Parse the typed nickname. */
2521 if (client->internal->params->nickname_parse)
2522 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2524 nickname = strdup(cmd->argv[1]);
2526 /* Find client entry */
2527 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2529 if (!client_entry) {
2530 /* Check whether user requested server actually */
2531 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2533 if (!server_entry) {
2534 /* No. what ever user wants we don't have it, so resolve it. We
2535 will first try to resolve the client, and if that fails then
2536 we'll try to resolve the server. */
2538 if (!cmd->pending) {
2539 /* This will send the IDENTIFY command for nickname */
2540 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2541 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2543 silc_client_command_getkey,
2544 silc_client_command_dup(cmd));
2548 SilcClientCommandReplyContext reply =
2549 (SilcClientCommandReplyContext)context2;
2552 /* If nickname was not found, then resolve the server. */
2553 silc_command_get_status(reply->payload, NULL, &error);
2554 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2555 /* This sends the IDENTIFY command to resolve the server. */
2556 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2558 silc_client_command_reply_identify_i, 0,
2560 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2562 2, cmd->argv[1], cmd->argv_lens[1]);
2563 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2565 silc_client_command_getkey,
2566 silc_client_command_dup(cmd));
2570 /* If server was not found, then we've resolved both nickname and
2571 server and did not find anybody. */
2572 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2573 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2574 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2575 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2576 silc_get_status_message(error));
2577 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2581 COMMAND_ERROR(error);
2586 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2588 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2591 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY,
2592 ++conn->cmd_ident, 1,
2593 1, idp->data, idp->len);
2594 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2595 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2596 silc_buffer_free(buffer);
2597 silc_buffer_free(idp);
2599 /* Notify application */
2600 COMMAND(SILC_STATUS_OK);
2603 silc_free(nickname);
2604 silc_client_command_free(cmd);
2607 /* Register a new command indicated by the `command' to the SILC client.
2608 The `name' is optional command name. If provided the command may be
2609 searched using the silc_client_command_find by that name. The
2610 `command_function' is the function to be called when the command is
2611 executed, and the `command_reply_function' is the function to be
2612 called after the server has sent reply back to the command.
2614 The `ident' is optional identifier for the command. If non-zero
2615 the `command_reply_function' for the command type `command' will be
2616 called only if the command reply sent by server includes the
2617 command identifier `ident'. Application usually does not need it
2618 and set it to zero value. */
2620 bool silc_client_command_register(SilcClient client,
2621 SilcCommand command,
2623 SilcCommandCb command_function,
2624 SilcCommandCb command_reply_function,
2628 SilcClientCommand cmd;
2630 cmd = silc_calloc(1, sizeof(*cmd));
2632 cmd->command = command_function;
2633 cmd->reply = command_reply_function;
2634 cmd->name = name ? strdup(name) : NULL;
2635 cmd->max_args = max_args;
2638 silc_list_add(client->internal->commands, cmd);
2643 /* Unregister a command indicated by the `command' with command function
2644 `command_function' and command reply function `command_reply_function'.
2645 Returns TRUE if the command was found and unregistered. */
2647 bool silc_client_command_unregister(SilcClient client,
2648 SilcCommand command,
2649 SilcCommandCb command_function,
2650 SilcCommandCb command_reply_function,
2653 SilcClientCommand cmd;
2655 silc_list_start(client->internal->commands);
2656 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2657 if (cmd->cmd == command && cmd->command == command_function &&
2658 cmd->reply == command_reply_function && cmd->ident == ident) {
2659 silc_list_del(client->internal->commands, cmd);
2660 silc_free(cmd->name);
2669 /* Private range commands, specific to this implementation (and compatible
2670 with SILC Server). */
2672 /* CONNECT command. Connects the server to another server. */
2674 SILC_CLIENT_CMD_FUNC(connect)
2676 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2677 SilcClientConnection conn = cmd->conn;
2679 unsigned char port[4];
2683 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2684 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2688 if (cmd->argc < 2) {
2689 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2690 "Usage: /CONNECT <server> [<port>]");
2691 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2695 if (cmd->argc == 3) {
2696 tmp = atoi(cmd->argv[2]);
2697 SILC_PUT32_MSB(tmp, port);
2701 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
2702 ++conn->cmd_ident, 2,
2704 strlen(cmd->argv[1]),
2707 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
2708 ++conn->cmd_ident, 1,
2710 strlen(cmd->argv[1]));
2711 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2712 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2713 silc_buffer_free(buffer);
2715 /* Notify application */
2716 COMMAND(SILC_STATUS_OK);
2719 silc_client_command_free(cmd);
2723 /* CLOSE command. Close server connection to the remote server */
2725 SILC_CLIENT_CMD_FUNC(close)
2727 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2728 SilcClientConnection conn = cmd->conn;
2730 unsigned char port[4];
2734 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2735 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2739 if (cmd->argc < 2) {
2740 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2741 "Usage: /CLOSE <server> [<port>]");
2742 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2746 if (cmd->argc == 3) {
2747 tmp = atoi(cmd->argv[2]);
2748 SILC_PUT32_MSB(tmp, port);
2752 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
2753 ++conn->cmd_ident, 2,
2755 strlen(cmd->argv[1]),
2758 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
2759 ++conn->cmd_ident, 1,
2761 strlen(cmd->argv[1]));
2762 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2763 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2764 silc_buffer_free(buffer);
2766 /* Notify application */
2767 COMMAND(SILC_STATUS_OK);
2770 silc_client_command_free(cmd);
2773 /* SHUTDOWN command. Shutdowns the server. */
2775 SILC_CLIENT_CMD_FUNC(shutdown)
2777 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2780 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2781 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2785 /* Send the command */
2786 silc_client_command_send(cmd->client, cmd->conn,
2787 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2789 /* Notify application */
2790 COMMAND(SILC_STATUS_OK);
2793 silc_client_command_free(cmd);
2796 /* Register all default commands provided by the client library for the
2799 void silc_client_commands_register(SilcClient client)
2801 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2804 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
2805 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2806 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2807 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2808 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2809 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2810 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2811 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2812 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2813 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2814 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2815 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2816 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2817 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2818 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2819 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2820 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
2821 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
2822 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2823 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2824 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2825 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2826 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2827 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2828 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2829 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2831 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2832 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2833 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2836 /* Unregister all commands. */
2838 void silc_client_commands_unregister(SilcClient client)
2840 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2841 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2842 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2843 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2844 SILC_CLIENT_CMDU(list, LIST, "LIST");
2845 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2846 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2847 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2848 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2849 SILC_CLIENT_CMDU(info, INFO, "INFO");
2850 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2851 SILC_CLIENT_CMDU(ping, PING, "PING");
2852 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2853 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2854 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2855 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2856 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2857 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2858 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2859 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2860 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2861 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2862 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2863 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2864 SILC_CLIENT_CMDU(users, USERS, "USERS");
2865 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2867 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2868 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2869 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2872 /**** Client side incoming command handling **********************************/
2874 void silc_client_command_process_whois(SilcClient client,
2875 SilcSocketConnection sock,
2876 SilcCommandPayload payload,
2877 SilcArgumentPayload args);
2879 /* Client is able to receive some command packets even though they are
2880 special case. Server may send WHOIS command to the client to retrieve
2881 Requested Attributes information for WHOIS query the server is
2882 processing. This function currently handles only the WHOIS command,
2883 but if in the future for commands may arrive then this can be made
2884 to support other commands too. */
2886 void silc_client_command_process(SilcClient client,
2887 SilcSocketConnection sock,
2888 SilcPacketContext *packet)
2890 SilcCommandPayload payload;
2891 SilcCommand command;
2892 SilcArgumentPayload args;
2894 /* Get command payload from packet */
2895 payload = silc_command_payload_parse(packet->buffer->data,
2896 packet->buffer->len);
2898 /* Silently ignore bad reply packet */
2899 SILC_LOG_DEBUG(("Bad command packet"));
2904 args = silc_command_get_args(payload);
2906 /* Get the command */
2907 command = silc_command_get(payload);
2910 case SILC_COMMAND_WHOIS:
2911 /* Ignore everything if requested by application */
2912 if (client->internal->params->ignore_requested_attributes)
2915 silc_client_command_process_whois(client, sock, payload, args);
2922 silc_command_payload_free(payload);
2925 void silc_client_command_process_whois(SilcClient client,
2926 SilcSocketConnection sock,
2927 SilcCommandPayload payload,
2928 SilcArgumentPayload args)
2933 SilcBuffer buffer, packet;
2935 SILC_LOG_DEBUG(("Received WHOIS command"));
2937 /* Try to take the Requested Attributes */
2938 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2942 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2946 /* Process requested attributes */
2947 buffer = silc_client_attributes_process(client, sock, attrs);
2949 silc_attribute_payload_list_free(attrs);
2953 /* Send the attributes back */
2955 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2957 silc_command_get_ident(payload),
2958 1, 11, buffer->data, buffer->len);
2959 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2960 NULL, 0, NULL, NULL, packet->data,
2962 silc_buffer_free(packet);
2963 silc_buffer_free(buffer);