5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, use /SERVER to connect");
29 /* Command operation that is called at the end of all commands.
30 Usage: COMMAND(status); */
31 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
32 cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
34 /* Error to application. Usage: COMMAND_ERROR(status); */
35 #define COMMAND_ERROR(status) \
36 cmd->client->internal->ops->command(cmd->client, \
37 cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
39 #define SAY cmd->client->internal->ops->say
41 /* Generic function to send any command. The arguments must be sent already
42 encoded into correct form and in correct order. */
44 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
45 SilcCommand command, SilcUInt16 ident,
51 assert(client && conn);
55 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
56 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
57 NULL, 0, NULL, NULL, packet->data,
59 silc_buffer_free(packet);
62 /* Finds and returns a pointer to the command list. Return NULL if the
63 command is not found. */
65 SilcClientCommand silc_client_command_find(SilcClient client,
68 SilcClientCommand cmd;
72 silc_list_start(client->internal->commands);
73 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
74 if (cmd->name && !strcasecmp(cmd->name, name))
81 /* Executes a command */
83 bool silc_client_command_call(SilcClient client,
84 SilcClientConnection conn,
85 const char *command_line, ...)
89 unsigned char **argv = NULL;
90 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
91 SilcClientCommand cmd;
92 SilcClientCommandContext ctx;
98 va_start(va, command_line);
102 /* Get command name */
103 command_name = silc_memdup(command_line, strcspn(command_line, " "));
107 /* Find command by name */
108 cmd = silc_client_command_find(client, command_name);
110 silc_free(command_name);
114 /* Parse command line */
115 silc_parse_command_line((char *)command_line, &argv, &argv_lens,
116 &argv_types, &argc, cmd->max_args);
118 silc_free(command_name);
120 arg = va_arg(va, char *);
124 /* Find command by name */
125 cmd = silc_client_command_find(client, arg);
130 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
131 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
132 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
133 argv[argc] = silc_memdup(arg, strlen(arg));
134 argv_lens[argc] = strlen(arg);
135 argv_types[argc] = argc;
137 arg = va_arg(va, char *);
141 /* Allocate command context. */
142 ctx = silc_client_command_alloc();
143 ctx->client = client;
148 ctx->argv_lens = argv_lens;
149 ctx->argv_types = argv_types;
151 /* Call the command */
152 cmd->command(ctx, NULL);
159 /* Add new pending command to be executed when reply to a command has been
160 received. The `reply_cmd' is the command that will call the `callback'
161 with `context' when reply has been received. It can be SILC_COMMAND_NONE
162 to match any command with the `ident'. If `ident' is non-zero
163 the `callback' will be executed when received reply with command
164 identifier `ident'. If there already exists pending command for the
165 specified command, ident, callback and context this function has no
168 void silc_client_command_pending(SilcClientConnection conn,
169 SilcCommand reply_cmd,
171 SilcCommandCb callback,
174 SilcClientCommandPending *reply;
177 reply = silc_calloc(1, sizeof(*reply));
178 reply->reply_cmd = reply_cmd;
179 reply->ident = ident;
180 reply->context = context;
181 reply->callback = callback;
182 silc_dlist_add(conn->internal->pending_commands, reply);
185 /* Deletes pending command by reply command type. */
187 void silc_client_command_pending_del(SilcClientConnection conn,
188 SilcCommand reply_cmd,
191 SilcClientCommandPending *r;
193 if (!conn->internal->pending_commands)
196 silc_dlist_start(conn->internal->pending_commands);
197 while ((r = silc_dlist_get(conn->internal->pending_commands))
199 if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
201 && r->ident == ident) {
202 silc_dlist_del(conn->internal->pending_commands, r);
208 /* Checks for pending commands and marks callbacks to be called from
209 the command reply function. */
211 SilcClientCommandPendingCallbacks
212 silc_client_command_pending_check(SilcClientConnection conn,
213 SilcClientCommandReplyContext ctx,
216 SilcUInt32 *callbacks_count)
218 SilcClientCommandPending *r;
219 SilcClientCommandPendingCallbacks callbacks = NULL;
222 silc_dlist_start(conn->internal->pending_commands);
223 while ((r = silc_dlist_get(conn->internal->pending_commands))
225 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
226 && r->ident == ident) {
227 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
228 callbacks[i].context = r->context;
229 callbacks[i].callback = r->callback;
230 r->reply_check = TRUE;
236 *callbacks_count = i;
240 /* Allocate Command Context */
242 SilcClientCommandContext silc_client_command_alloc(void)
244 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
249 /* Free command context and its internals */
251 void silc_client_command_free(SilcClientCommandContext ctx)
254 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
256 if (ctx->users < 1) {
259 for (i = 0; i < ctx->argc; i++)
260 silc_free(ctx->argv[i]);
261 silc_free(ctx->argv);
262 silc_free(ctx->argv_lens);
263 silc_free(ctx->argv_types);
268 /* Duplicate Command Context by adding reference counter. The context won't
269 be free'd untill it hits zero. */
271 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
274 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
279 /* Command WHOIS. This command is used to query information about
282 SILC_CLIENT_CMD_FUNC(whois)
284 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
285 SilcClientConnection conn = cmd->conn;
286 SilcBuffer buffer, attrs = NULL;
287 unsigned char count[4], *tmp = NULL;
290 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
291 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
295 /* Given without arguments fetches client's own information */
297 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
298 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
300 1, 4, buffer->data, buffer->len);
301 silc_buffer_free(buffer);
305 if (cmd->argc == 2) {
306 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
307 ++conn->cmd_ident, 1,
311 if (!strcasecmp(cmd->argv[2], "-details"))
312 attrs = silc_client_attributes_request(0);
314 if (!attrs || cmd->argc > 3) {
315 int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
316 SILC_PUT32_MSB(c, count);
320 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
321 ++conn->cmd_ident, 3,
322 1, cmd->argv[1], cmd->argv_lens[1],
323 2, tmp ? tmp : NULL, tmp ? 4 : 0,
324 3, attrs ? attrs->data : NULL,
325 attrs ? attrs->len : 0);
327 silc_client_packet_send(cmd->client, cmd->conn->sock,
328 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
329 buffer->data, buffer->len, TRUE);
330 silc_buffer_free(buffer);
332 /* Notify application */
333 COMMAND(SILC_STATUS_OK);
336 silc_client_command_free(cmd);
339 /* Command WHOWAS. This command is used to query history information about
340 specific user that used to exist in the network. */
342 SILC_CLIENT_CMD_FUNC(whowas)
344 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
345 SilcClientConnection conn = cmd->conn;
347 unsigned char count[4];
350 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
351 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
355 if (cmd->argc < 2 || cmd->argc > 3) {
356 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
357 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
358 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
359 SILC_STATUS_ERR_TOO_MANY_PARAMS));
363 if (cmd->argc == 2) {
364 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
365 ++conn->cmd_ident, 1,
369 int c = atoi(cmd->argv[2]);
370 memset(count, 0, sizeof(count));
371 SILC_PUT32_MSB(c, count);
372 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
373 ++conn->cmd_ident, 2,
374 1, cmd->argv[1], cmd->argv_lens[1],
375 2, count, sizeof(count));
377 silc_client_packet_send(cmd->client, cmd->conn->sock,
378 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
379 buffer->data, buffer->len, TRUE);
380 silc_buffer_free(buffer);
382 /* Notify application */
383 COMMAND(SILC_STATUS_OK);
386 silc_client_command_free(cmd);
389 /* Command IDENTIFY. This command is used to query information about
390 specific user, especially ID's.
392 NOTE: This command is used only internally by the client library
393 and application MUST NOT call this command directly. */
395 SILC_CLIENT_CMD_FUNC(identify)
397 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
398 SilcClientConnection conn = cmd->conn;
400 unsigned char count[4];
403 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
404 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
408 if (cmd->argc < 2 || cmd->argc > 3)
411 if (cmd->argc == 2) {
412 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
413 ++conn->cmd_ident, 1,
417 int c = atoi(cmd->argv[2]);
418 memset(count, 0, sizeof(count));
419 SILC_PUT32_MSB(c, count);
420 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
421 ++conn->cmd_ident, 2,
424 4, count, sizeof(count));
427 silc_client_packet_send(cmd->client, cmd->conn->sock,
428 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
429 buffer->data, buffer->len, TRUE);
430 silc_buffer_free(buffer);
433 silc_client_command_free(cmd);
436 /* Command NICK. Shows current nickname/sets new nickname on current
439 SILC_CLIENT_CMD_FUNC(nick)
441 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
442 SilcClientConnection conn = cmd->conn;
446 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
447 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
452 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
453 "Usage: /NICK <nickname>");
454 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
458 if (!strcmp(conn->nickname, cmd->argv[1]))
461 /* Show current nickname */
464 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
465 "Your nickname is %s on server %s",
466 conn->nickname, conn->remote_host);
468 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
469 "Your nickname is %s", conn->nickname);
472 COMMAND(SILC_STATUS_OK);
476 if (cmd->argv_lens[1] > 128)
477 cmd->argv_lens[1] = 128;
479 /* Send the NICK command */
480 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
484 ++cmd->conn->cmd_ident);
485 silc_client_packet_send(cmd->client, cmd->conn->sock,
486 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
487 buffer->data, buffer->len, TRUE);
488 silc_buffer_free(buffer);
491 silc_client_command_free(cmd);
494 /* Command LIST. Lists channels on the current server. */
496 SILC_CLIENT_CMD_FUNC(list)
498 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
499 SilcClientConnection conn = cmd->conn;
500 SilcIDCacheEntry id_cache = NULL;
501 SilcChannelEntry channel;
502 SilcBuffer buffer, idp = NULL;
506 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
507 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
511 if (cmd->argc == 2) {
514 /* Get the Channel ID of the channel */
515 if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
517 channel = (SilcChannelEntry)id_cache->context;
518 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
523 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
524 ++conn->cmd_ident, 0);
526 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
527 ++conn->cmd_ident, 1,
528 1, idp->data, idp->len);
530 silc_client_packet_send(cmd->client, cmd->conn->sock,
531 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
532 buffer->data, buffer->len, TRUE);
533 silc_buffer_free(buffer);
535 silc_buffer_free(idp);
537 /* Notify application */
538 COMMAND(SILC_STATUS_OK);
541 silc_client_command_free(cmd);
544 /* Command TOPIC. Sets/shows topic on a channel. */
546 SILC_CLIENT_CMD_FUNC(topic)
548 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
549 SilcClientConnection conn = cmd->conn;
550 SilcIDCacheEntry id_cache = NULL;
551 SilcChannelEntry channel;
552 SilcBuffer buffer, idp;
556 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
557 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
561 if (cmd->argc < 2 || cmd->argc > 3) {
562 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
563 "Usage: /TOPIC <channel> [<topic>]");
564 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
565 SILC_STATUS_ERR_TOO_MANY_PARAMS));
569 if (cmd->argv[1][0] == '*') {
570 if (!conn->current_channel) {
571 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
574 name = conn->current_channel->channel_name;
579 if (!conn->current_channel) {
580 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
584 /* Get the Channel ID of the channel */
585 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
587 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
591 channel = (SilcChannelEntry)id_cache->context;
593 /* Send TOPIC command to the server */
594 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
596 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
597 ++conn->cmd_ident, 2,
598 1, idp->data, idp->len,
600 strlen(cmd->argv[2]));
602 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
603 ++conn->cmd_ident, 1,
604 1, idp->data, idp->len);
605 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
606 0, NULL, NULL, buffer->data, buffer->len, TRUE);
607 silc_buffer_free(buffer);
608 silc_buffer_free(idp);
610 /* Notify application */
611 COMMAND(SILC_STATUS_OK);
614 silc_client_command_free(cmd);
617 /* Command INVITE. Invites specific client to join a channel. This is
618 also used to mange the invite list of the channel. */
620 SILC_CLIENT_CMD_FUNC(invite)
622 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
623 SilcClient client = cmd->client;
624 SilcClientConnection conn = cmd->conn;
625 SilcClientEntry client_entry = NULL;
626 SilcChannelEntry channel;
627 SilcBuffer buffer, clidp, chidp;
629 char *nickname = NULL, *name;
633 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
634 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
639 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
640 "Usage: /INVITE <channel> [<nickname>[@server>]"
641 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
642 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
646 if (cmd->argv[1][0] == '*') {
647 if (!conn->current_channel) {
648 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
652 channel = conn->current_channel;
656 channel = silc_client_get_channel(cmd->client, conn, name);
658 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
663 /* Parse the typed nickname. */
664 if (cmd->argc == 3) {
665 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
666 if (client->internal->params->nickname_parse)
667 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
669 nickname = strdup(cmd->argv[2]);
671 /* Find client entry */
672 client_entry = silc_idlist_get_client(client, conn, nickname,
676 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
680 /* Client entry not found, it was requested thus mark this to be
682 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
684 silc_client_command_invite,
685 silc_client_command_dup(cmd));
690 invite = cmd->argv[2];
692 if (cmd->argv[2][0] == '+')
699 /* Send the command */
700 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
702 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
703 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
704 ++conn->cmd_ident, 3,
705 1, chidp->data, chidp->len,
706 2, clidp->data, clidp->len,
707 type, invite, invite ?
709 silc_buffer_free(clidp);
711 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
712 ++conn->cmd_ident, 2,
713 1, chidp->data, chidp->len,
714 type, invite, invite ?
718 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
719 0, NULL, NULL, buffer->data, buffer->len, TRUE);
720 silc_buffer_free(buffer);
721 silc_buffer_free(chidp);
723 /* Notify application */
724 COMMAND(SILC_STATUS_OK);
728 silc_client_command_free(cmd);
733 SilcClientConnection conn;
736 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
738 QuitInternal q = (QuitInternal)context;
740 /* Close connection */
741 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
742 silc_client_close_connection(q->client, q->conn->sock->user_data);
747 /* Command QUIT. Closes connection with current server. */
749 SILC_CLIENT_CMD_FUNC(quit)
751 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
756 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
757 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
762 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
763 &cmd->argv[1], &cmd->argv_lens[1],
764 &cmd->argv_types[1], 0);
766 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
767 NULL, NULL, NULL, 0);
768 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
770 buffer->data, buffer->len, TRUE);
771 silc_buffer_free(buffer);
773 q = silc_calloc(1, sizeof(*q));
774 q->client = cmd->client;
777 /* Sleep for a while */
780 /* We quit the connection with little timeout */
781 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
782 silc_client_command_quit_cb, (void *)q,
783 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
785 /* Notify application */
786 COMMAND(SILC_STATUS_OK);
789 silc_client_command_free(cmd);
792 /* Timeout callback to remove the killed client from cache */
794 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
796 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
797 SilcClient client = cmd->client;
798 SilcClientConnection conn = cmd->conn;
799 SilcClientEntry target;
800 char *nickname = NULL;
802 /* Parse the typed nickname. */
803 if (client->internal->params->nickname_parse)
804 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
806 nickname = strdup(cmd->argv[1]);
808 /* Get the target client */
809 target = silc_idlist_get_client(cmd->client, conn, nickname,
810 cmd->argv[1], FALSE);
812 /* Remove the client from all channels and free it */
813 silc_client_del_client(client, conn, target);
816 silc_client_command_free(cmd);
819 /* Kill command's pending command callback to actually remove the killed
820 client from our local cache. */
822 SILC_CLIENT_CMD_FUNC(kill_remove)
824 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
825 SilcClientCommandReplyContext reply =
826 (SilcClientCommandReplyContext)context2;
829 silc_command_get_status(reply->payload, &status, NULL);
830 if (status == SILC_STATUS_OK) {
831 /* Remove with timeout */
832 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
833 silc_client_command_kill_remove_later, context,
834 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
838 silc_client_command_free(cmd);
841 /* Command KILL. Router operator can use this command to remove an client
842 fromthe SILC Network. */
844 SILC_CLIENT_CMD_FUNC(kill)
846 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
847 SilcClient client = cmd->client;
848 SilcClientConnection conn = cmd->conn;
849 SilcBuffer buffer, idp, auth = NULL;
850 SilcClientEntry target;
851 char *nickname = NULL, *comment = NULL;
854 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
855 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
860 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
861 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
862 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
866 /* Parse the typed nickname. */
867 if (client->internal->params->nickname_parse)
868 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
870 nickname = strdup(cmd->argv[1]);
872 /* Get the target client */
873 target = silc_idlist_get_client(cmd->client, conn, nickname,
877 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
881 /* Client entry not found, it was requested thus mark this to be
883 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
885 silc_client_command_kill,
886 silc_client_command_dup(cmd));
891 if (cmd->argc >= 3) {
892 if (strcasecmp(cmd->argv[2], "-pubkey"))
893 comment = cmd->argv[2];
895 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
896 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
897 /* Encode the public key authentication payload */
898 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
899 cmd->client->private_key,
902 target->id, SILC_ID_CLIENT);
906 /* Send the KILL command to the server */
907 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
909 silc_command_payload_encode_va(SILC_COMMAND_KILL,
910 ++conn->cmd_ident, 3,
911 1, idp->data, idp->len,
912 2, comment, comment ? strlen(comment) : 0,
913 3, auth ? auth->data : NULL,
914 auth ? auth->len : 0);
915 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
916 0, NULL, NULL, buffer->data, buffer->len, TRUE);
917 silc_buffer_free(buffer);
918 silc_buffer_free(idp);
919 silc_buffer_free(auth);
921 /* Notify application */
922 COMMAND(SILC_STATUS_OK);
924 /* Register a pending callback that will actually remove the killed
925 client from our cache. */
926 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
927 silc_client_command_kill_remove,
928 silc_client_command_dup(cmd));
932 silc_client_command_free(cmd);
935 /* Command INFO. Request information about specific server. If specific
936 server is not provided the current server is used. */
938 SILC_CLIENT_CMD_FUNC(info)
940 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
941 SilcClientConnection conn = cmd->conn;
946 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
947 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
952 name = strdup(cmd->argv[1]);
954 /* Send the command */
956 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
957 1, name, strlen(name));
959 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
960 NULL, NULL, NULL, 0);
961 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
962 0, NULL, NULL, buffer->data, buffer->len, TRUE);
963 silc_buffer_free(buffer);
967 /* Notify application */
968 COMMAND(SILC_STATUS_OK);
971 silc_client_command_free(cmd);
974 /* Command STATS. Shows server and network statistics. */
976 SILC_CLIENT_CMD_FUNC(stats)
978 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
979 SilcClientConnection conn = cmd->conn;
980 SilcBuffer buffer, idp = NULL;
983 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
984 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
988 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
990 /* Send the command */
991 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
992 ++conn->cmd_ident, 1,
993 SILC_ID_SERVER, idp->data, idp->len);
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);
999 /* Notify application */
1000 COMMAND(SILC_STATUS_OK);
1003 silc_client_command_free(cmd);
1006 /* Command PING. Sends ping to server. This is used to test the
1007 communication channel. */
1009 SILC_CLIENT_CMD_FUNC(ping)
1011 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1012 SilcClientConnection conn = cmd->conn;
1013 SilcBuffer buffer, idp;
1018 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1019 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1023 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1025 /* Send the command */
1026 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1027 1, idp->data, idp->len);
1028 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1029 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1030 silc_buffer_free(buffer);
1031 silc_buffer_free(idp);
1033 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1036 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1037 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1041 /* Start counting time */
1042 for (i = 0; i < conn->internal->ping_count; i++) {
1043 if (conn->internal->ping[i].dest_id == NULL) {
1044 conn->internal->ping[i].start_time = time(NULL);
1045 conn->internal->ping[i].dest_id = id;
1046 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1050 if (i >= conn->internal->ping_count) {
1051 i = conn->internal->ping_count;
1052 conn->internal->ping =
1053 silc_realloc(conn->internal->ping,
1054 sizeof(*conn->internal->ping) * (i + 1));
1055 conn->internal->ping[i].start_time = time(NULL);
1056 conn->internal->ping[i].dest_id = id;
1057 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1058 conn->internal->ping_count++;
1061 /* Notify application */
1062 COMMAND(SILC_STATUS_OK);
1065 silc_client_command_free(cmd);
1068 /* Command JOIN. Joins to a channel. */
1070 SILC_CLIENT_CMD_FUNC(join)
1072 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1073 SilcClientConnection conn = cmd->conn;
1074 SilcChannelEntry channel;
1075 SilcBuffer buffer, idp, auth = NULL;
1076 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1077 int i, passphrase_len = 0;
1080 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1081 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1085 if (cmd->argc < 2) {
1086 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1090 /* See if we have joined to the requested channel already */
1091 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1092 if (channel && silc_client_on_channel(channel, conn->local_entry))
1095 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1097 if (cmd->argv_lens[1] > 256)
1098 cmd->argv_lens[1] = 256;
1100 name = cmd->argv[1];
1102 for (i = 2; i < cmd->argc; i++) {
1103 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1104 cipher = cmd->argv[i + 1];
1106 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1107 hmac = cmd->argv[i + 1];
1109 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1110 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1111 cmd->client->private_key,
1113 cmd->client->sha1hash,
1118 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1119 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1120 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1121 cmd->argv_lens[i], 0);
1122 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1123 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1124 0, pu8, passphrase_len);
1127 passphrase = strdup(cmd->argv[i]);
1128 passphrase_len = cmd->argv_lens[i];
1133 /* Send JOIN command to the server */
1135 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1136 1, name, strlen(name),
1137 2, idp->data, idp->len,
1138 3, passphrase, passphrase_len,
1139 4, cipher, cipher ? strlen(cipher) : 0,
1140 5, hmac, hmac ? strlen(hmac) : 0,
1141 6, auth ? auth->data : NULL,
1142 auth ? auth->len : 0);
1143 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1144 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1145 silc_buffer_free(buffer);
1146 silc_buffer_free(idp);
1148 silc_buffer_free(auth);
1149 silc_free(passphrase);
1151 /* Notify application */
1152 COMMAND(SILC_STATUS_OK);
1155 silc_client_command_free(cmd);
1158 /* MOTD command. Requests motd from server. */
1160 SILC_CLIENT_CMD_FUNC(motd)
1162 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1163 SilcClientConnection conn = cmd->conn;
1167 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1168 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1172 if (cmd->argc < 1 || cmd->argc > 2) {
1173 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1174 "Usage: /MOTD [<server>]");
1175 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1176 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1180 /* Send TOPIC command to the server */
1182 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1183 1, conn->remote_host,
1184 strlen(conn->remote_host));
1186 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1189 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1190 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1191 silc_buffer_free(buffer);
1193 /* Notify application */
1194 COMMAND(SILC_STATUS_OK);
1197 silc_client_command_free(cmd);
1200 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1201 modes as client cannot set itself server/router operator privileges. */
1203 SILC_CLIENT_CMD_FUNC(umode)
1205 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1206 SilcClientConnection conn = cmd->conn;
1207 SilcBuffer buffer, idp;
1208 unsigned char *cp, modebuf[4];
1209 SilcUInt32 mode, add, len;
1213 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1214 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1218 if (cmd->argc < 2) {
1219 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1220 "Usage: /UMODE +|-<modes>");
1221 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1225 mode = conn->local_entry->mode;
1227 /* Are we adding or removing mode */
1228 if (cmd->argv[1][0] == '-')
1234 cp = cmd->argv[1] + 1;
1236 for (i = 0; i < len; i++) {
1241 mode |= SILC_UMODE_SERVER_OPERATOR;
1242 mode |= SILC_UMODE_ROUTER_OPERATOR;
1243 mode |= SILC_UMODE_GONE;
1244 mode |= SILC_UMODE_INDISPOSED;
1245 mode |= SILC_UMODE_BUSY;
1246 mode |= SILC_UMODE_PAGE;
1247 mode |= SILC_UMODE_HYPER;
1248 mode |= SILC_UMODE_ROBOT;
1249 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1250 mode |= SILC_UMODE_REJECT_WATCHING;
1252 mode = SILC_UMODE_NONE;
1257 mode |= SILC_UMODE_SERVER_OPERATOR;
1259 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1263 mode |= SILC_UMODE_ROUTER_OPERATOR;
1265 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1269 mode |= SILC_UMODE_GONE;
1271 mode &= ~SILC_UMODE_GONE;
1275 mode |= SILC_UMODE_INDISPOSED;
1277 mode &= ~SILC_UMODE_INDISPOSED;
1281 mode |= SILC_UMODE_BUSY;
1283 mode &= ~SILC_UMODE_BUSY;
1287 mode |= SILC_UMODE_PAGE;
1289 mode &= ~SILC_UMODE_PAGE;
1293 mode |= SILC_UMODE_HYPER;
1295 mode &= ~SILC_UMODE_HYPER;
1299 mode |= SILC_UMODE_ROBOT;
1301 mode &= ~SILC_UMODE_ROBOT;
1305 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1307 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1311 mode |= SILC_UMODE_REJECT_WATCHING;
1313 mode &= ~SILC_UMODE_REJECT_WATCHING;
1317 mode |= SILC_UMODE_BLOCK_INVITE;
1319 mode &= ~SILC_UMODE_BLOCK_INVITE;
1322 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1328 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1329 SILC_PUT32_MSB(mode, modebuf);
1331 /* Send the command packet. We support sending only one mode at once
1332 that requires an argument. */
1334 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1335 1, idp->data, idp->len,
1336 2, modebuf, sizeof(modebuf));
1337 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1338 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1339 silc_buffer_free(buffer);
1340 silc_buffer_free(idp);
1342 /* Notify application */
1343 COMMAND(SILC_STATUS_OK);
1346 silc_client_command_free(cmd);
1349 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1350 can be set several at once. Those modes that require argument must be set
1351 separately (unless set with modes that does not require arguments). */
1353 SILC_CLIENT_CMD_FUNC(cmode)
1355 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1356 SilcClientConnection conn = cmd->conn;
1357 SilcChannelEntry channel;
1358 SilcBuffer buffer, chidp, auth = NULL;
1359 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1360 SilcUInt32 mode, add, type, len, arg_len = 0;
1364 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1365 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1369 if (cmd->argc < 3) {
1370 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1371 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1372 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1376 if (cmd->argv[1][0] == '*') {
1377 if (!conn->current_channel) {
1378 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1382 channel = conn->current_channel;
1384 name = cmd->argv[1];
1386 channel = silc_client_get_channel(cmd->client, conn, name);
1388 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1393 mode = channel->mode;
1395 /* Are we adding or removing mode */
1396 if (cmd->argv[2][0] == '-')
1401 /* Argument type to be sent to server */
1405 cp = cmd->argv[2] + 1;
1407 for (i = 0; i < len; i++) {
1411 mode |= SILC_CHANNEL_MODE_PRIVATE;
1413 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1417 mode |= SILC_CHANNEL_MODE_SECRET;
1419 mode &= ~SILC_CHANNEL_MODE_SECRET;
1423 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1425 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1429 mode |= SILC_CHANNEL_MODE_INVITE;
1431 mode &= ~SILC_CHANNEL_MODE_INVITE;
1435 mode |= SILC_CHANNEL_MODE_TOPIC;
1437 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1441 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1443 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1447 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1449 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1454 mode |= SILC_CHANNEL_MODE_ULIMIT;
1456 if (cmd->argc < 4) {
1457 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1458 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1459 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1462 ll = atoi(cmd->argv[3]);
1463 SILC_PUT32_MSB(ll, tmp);
1467 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1472 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1474 if (cmd->argc < 4) {
1475 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1476 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1477 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1481 arg_len = cmd->argv_lens[3];
1483 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1488 mode |= SILC_CHANNEL_MODE_CIPHER;
1490 if (cmd->argc < 4) {
1491 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1492 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1493 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1497 arg_len = cmd->argv_lens[3];
1499 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1504 mode |= SILC_CHANNEL_MODE_HMAC;
1506 if (cmd->argc < 4) {
1507 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1508 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1509 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1513 arg_len = cmd->argv_lens[3];
1515 mode &= ~SILC_CHANNEL_MODE_HMAC;
1520 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1522 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1523 cmd->client->private_key,
1525 cmd->client->sha1hash,
1529 arg_len = auth->len;
1531 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1535 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1541 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1542 SILC_PUT32_MSB(mode, modebuf);
1544 /* Send the command packet. We support sending only one mode at once
1545 that requires an argument. */
1548 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1549 1, chidp->data, chidp->len,
1550 2, modebuf, sizeof(modebuf),
1551 type, arg, arg_len);
1554 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1555 1, chidp->data, chidp->len,
1556 2, modebuf, sizeof(modebuf));
1559 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1560 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1561 silc_buffer_free(buffer);
1562 silc_buffer_free(chidp);
1564 silc_buffer_free(auth);
1566 /* Notify application */
1567 COMMAND(SILC_STATUS_OK);
1570 silc_client_command_free(cmd);
1573 /* CUMODE command. Changes client's mode on a channel. */
1575 SILC_CLIENT_CMD_FUNC(cumode)
1577 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1578 SilcClient client = cmd->client;
1579 SilcClientConnection conn = cmd->conn;
1580 SilcChannelEntry channel;
1581 SilcChannelUser chu;
1582 SilcClientEntry client_entry;
1583 SilcBuffer buffer, clidp, chidp, auth = NULL;
1584 unsigned char *name, *cp, modebuf[4];
1585 SilcUInt32 mode = 0, add, len;
1586 char *nickname = NULL;
1590 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1591 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1595 if (cmd->argc < 4) {
1596 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1597 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1598 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1602 if (cmd->argv[1][0] == '*') {
1603 if (!conn->current_channel) {
1604 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1608 channel = conn->current_channel;
1610 name = cmd->argv[1];
1612 channel = silc_client_get_channel(cmd->client, conn, name);
1614 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1619 /* Parse the typed nickname. */
1620 if (client->internal->params->nickname_parse)
1621 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1623 nickname = strdup(cmd->argv[3]);
1625 /* Find client entry */
1626 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1627 cmd->argv[3], TRUE);
1628 if (!client_entry) {
1630 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1634 /* Client entry not found, it was requested thus mark this to be
1636 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1638 silc_client_command_cumode,
1639 silc_client_command_dup(cmd));
1644 /* Get the current mode */
1645 chu = silc_client_on_channel(channel, client_entry);
1649 /* Are we adding or removing mode */
1650 if (cmd->argv[2][0] == '-')
1656 cp = cmd->argv[2] + 1;
1658 for (i = 0; i < len; i++) {
1662 mode |= SILC_CHANNEL_UMODE_CHANFO;
1663 mode |= SILC_CHANNEL_UMODE_CHANOP;
1664 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1665 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1666 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1668 mode = SILC_CHANNEL_UMODE_NONE;
1673 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1674 cmd->client->private_key,
1676 cmd->client->sha1hash,
1679 mode |= SILC_CHANNEL_UMODE_CHANFO;
1681 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1686 mode |= SILC_CHANNEL_UMODE_CHANOP;
1688 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1692 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1694 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1698 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1700 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1704 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1706 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1710 mode |= SILC_CHANNEL_UMODE_QUIET;
1712 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1715 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1721 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1722 SILC_PUT32_MSB(mode, modebuf);
1723 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1725 /* Send the command packet. We support sending only one mode at once
1726 that requires an argument. */
1727 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1729 1, chidp->data, chidp->len,
1731 3, clidp->data, clidp->len,
1732 4, auth ? auth->data : NULL,
1733 auth ? auth->len : 0);
1735 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1736 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1737 silc_buffer_free(buffer);
1738 silc_buffer_free(chidp);
1739 silc_buffer_free(clidp);
1741 silc_buffer_free(auth);
1743 /* Notify application */
1744 COMMAND(SILC_STATUS_OK);
1747 silc_free(nickname);
1748 silc_client_command_free(cmd);
1751 /* KICK command. Kicks a client out of channel. */
1753 SILC_CLIENT_CMD_FUNC(kick)
1755 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1756 SilcClient client = cmd->client;
1757 SilcClientConnection conn = cmd->conn;
1758 SilcIDCacheEntry id_cache = NULL;
1759 SilcChannelEntry channel;
1760 SilcBuffer buffer, idp, idp2;
1761 SilcClientEntry target;
1763 char *nickname = NULL;
1766 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1767 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1771 if (cmd->argc < 3) {
1772 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1773 "Usage: /KICK <channel> <nickname> [<comment>]");
1774 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1778 if (cmd->argv[1][0] == '*') {
1779 if (!conn->current_channel) {
1780 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1783 name = conn->current_channel->channel_name;
1785 name = cmd->argv[1];
1788 if (!conn->current_channel) {
1789 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1793 /* Get the Channel ID of the channel */
1794 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1796 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1800 channel = (SilcChannelEntry)id_cache->context;
1802 /* Parse the typed nickname. */
1803 if (client->internal->params->nickname_parse)
1804 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1806 nickname = strdup(cmd->argv[2]);
1808 /* Get the target client */
1809 target = silc_idlist_get_client(cmd->client, conn, nickname,
1810 cmd->argv[2], FALSE);
1812 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1813 "No such client: %s", cmd->argv[2]);
1814 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1818 /* Send KICK command to the server */
1819 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1820 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1822 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1823 1, idp->data, idp->len,
1824 2, idp2->data, idp2->len);
1826 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1827 1, idp->data, idp->len,
1828 2, idp2->data, idp2->len,
1830 strlen(cmd->argv[3]));
1831 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1832 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1833 silc_buffer_free(buffer);
1834 silc_buffer_free(idp);
1835 silc_buffer_free(idp2);
1837 /* Notify application */
1838 COMMAND(SILC_STATUS_OK);
1841 silc_free(nickname);
1842 silc_client_command_free(cmd);
1845 static void silc_client_command_oper_send(unsigned char *data,
1846 SilcUInt32 data_len, void *context)
1848 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1849 SilcClientConnection conn = cmd->conn;
1850 SilcBuffer buffer, auth;
1852 if (cmd->argc >= 3) {
1853 /* Encode the public key authentication payload */
1854 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1855 cmd->client->private_key,
1857 conn->internal->hash,
1861 /* Encode the password authentication payload */
1862 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1866 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1868 strlen(cmd->argv[1]),
1869 2, auth ? auth->data : NULL,
1870 auth ? auth->len : 0);
1871 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1872 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1874 silc_buffer_free(buffer);
1875 silc_buffer_free(auth);
1877 /* Notify application */
1878 COMMAND(SILC_STATUS_OK);
1881 /* OPER command. Used to obtain server operator privileges. */
1883 SILC_CLIENT_CMD_FUNC(oper)
1885 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1886 SilcClientConnection conn = cmd->conn;
1889 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1890 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1894 if (cmd->argc < 2) {
1895 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1896 "Usage: /OPER <username> [-pubkey]");
1897 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1901 if (cmd->argc < 3) {
1902 /* Get passphrase */
1903 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1904 silc_client_command_oper_send,
1909 silc_client_command_oper_send(NULL, 0, context);
1912 silc_client_command_free(cmd);
1915 static void silc_client_command_silcoper_send(unsigned char *data,
1916 SilcUInt32 data_len,
1919 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1920 SilcClientConnection conn = cmd->conn;
1921 SilcBuffer buffer, auth;
1923 if (cmd->argc >= 3) {
1924 /* Encode the public key authentication payload */
1925 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1926 cmd->client->private_key,
1928 conn->internal->hash,
1932 /* Encode the password authentication payload */
1933 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1937 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1939 strlen(cmd->argv[1]),
1940 2, auth ? auth->data : NULL,
1941 auth ? auth->len : 0);
1942 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1943 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1945 silc_buffer_free(buffer);
1946 silc_buffer_free(auth);
1948 /* Notify application */
1949 COMMAND(SILC_STATUS_OK);
1952 /* SILCOPER command. Used to obtain router operator privileges. */
1954 SILC_CLIENT_CMD_FUNC(silcoper)
1956 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1957 SilcClientConnection conn = cmd->conn;
1960 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1961 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1965 if (cmd->argc < 2) {
1966 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1967 "Usage: /SILCOPER <username> [-pubkey]");
1968 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1972 if (cmd->argc < 3) {
1973 /* Get passphrase */
1974 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1975 silc_client_command_silcoper_send,
1980 silc_client_command_silcoper_send(NULL, 0, context);
1983 silc_client_command_free(cmd);
1986 /* Command BAN. This is used to manage the ban list of the channel. */
1988 SILC_CLIENT_CMD_FUNC(ban)
1990 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1991 SilcClientConnection conn = cmd->conn;
1992 SilcChannelEntry channel;
1993 SilcBuffer buffer, chidp;
1995 char *name, *ban = NULL;
1998 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1999 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2003 if (cmd->argc < 2) {
2004 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2005 "Usage: /BAN <channel> "
2006 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2007 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2011 if (cmd->argv[1][0] == '*') {
2012 if (!conn->current_channel) {
2013 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2017 channel = conn->current_channel;
2019 name = cmd->argv[1];
2021 channel = silc_client_get_channel(cmd->client, conn, name);
2023 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2028 if (cmd->argc == 3) {
2029 if (cmd->argv[2][0] == '+')
2038 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2040 /* Send the command */
2041 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2042 ++conn->cmd_ident, 2,
2043 1, chidp->data, chidp->len,
2044 type, ban, ban ? strlen(ban) : 0);
2045 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2046 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2047 silc_buffer_free(buffer);
2048 silc_buffer_free(chidp);
2050 /* Notify application */
2051 COMMAND(SILC_STATUS_OK);
2054 silc_client_command_free(cmd);
2057 /* Command DETACH. This is used to detach from the server */
2059 SILC_CLIENT_CMD_FUNC(detach)
2061 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2062 SilcClientConnection conn = cmd->conn;
2066 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2067 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2071 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2072 ++conn->cmd_ident, 0);
2073 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2074 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2075 silc_buffer_free(buffer);
2077 /* Notify application */
2078 COMMAND(SILC_STATUS_OK);
2081 silc_client_command_free(cmd);
2084 /* Command WATCH. */
2086 SILC_CLIENT_CMD_FUNC(watch)
2088 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2089 SilcClientConnection conn = cmd->conn;
2090 SilcBuffer buffer, idp = NULL;
2094 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2095 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2099 if (cmd->argc < 3) {
2100 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2104 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2106 if (!strcasecmp(cmd->argv[1], "-add")) {
2108 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2111 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2115 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2116 ++conn->cmd_ident, 2,
2117 1, idp->data, idp->len,
2120 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2121 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2122 silc_buffer_free(buffer);
2124 /* Notify application */
2125 COMMAND(SILC_STATUS_OK);
2129 silc_buffer_free(idp);
2130 silc_client_command_free(cmd);
2133 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2135 SILC_CLIENT_CMD_FUNC(leave)
2137 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2138 SilcClientConnection conn = cmd->conn;
2139 SilcChannelEntry channel;
2140 SilcChannelUser chu;
2141 SilcBuffer buffer, idp;
2145 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2146 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2150 if (cmd->argc != 2) {
2151 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2152 "Usage: /LEAVE <channel>");
2153 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2157 if (cmd->argv[1][0] == '*') {
2158 if (!conn->current_channel) {
2159 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2162 name = conn->current_channel->channel_name;
2164 name = cmd->argv[1];
2167 /* Get the channel entry */
2168 channel = silc_client_get_channel(cmd->client, conn, name);
2170 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2174 /* Remove us from channel */
2175 chu = silc_client_on_channel(channel, conn->local_entry);
2177 silc_hash_table_del(chu->client->channels, chu->channel);
2178 silc_hash_table_del(chu->channel->user_list, chu->client);
2182 /* Send LEAVE command to the server */
2183 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2184 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2185 1, idp->data, idp->len);
2186 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2187 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2188 silc_buffer_free(buffer);
2189 silc_buffer_free(idp);
2191 /* Notify application */
2192 COMMAND(SILC_STATUS_OK);
2194 if (conn->current_channel == channel)
2195 conn->current_channel = NULL;
2197 silc_client_del_channel(cmd->client, cmd->conn, channel);
2200 silc_client_command_free(cmd);
2203 /* Command USERS. Requests the USERS of the clients joined on requested
2206 SILC_CLIENT_CMD_FUNC(users)
2208 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2209 SilcClientConnection conn = cmd->conn;
2214 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2215 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2219 if (cmd->argc != 2) {
2220 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2221 "Usage: /USERS <channel>");
2222 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2226 if (cmd->argv[1][0] == '*') {
2227 if (!conn->current_channel) {
2228 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2231 name = conn->current_channel->channel_name;
2233 name = cmd->argv[1];
2236 /* Send USERS command to the server */
2237 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2238 ++conn->cmd_ident, 1,
2239 2, name, strlen(name));
2240 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2241 NULL, 0, NULL, NULL, buffer->data,
2243 silc_buffer_free(buffer);
2245 /* Notify application */
2246 COMMAND(SILC_STATUS_OK);
2249 silc_client_command_free(cmd);
2252 /* Command GETKEY. Used to fetch remote client's public key. */
2254 SILC_CLIENT_CMD_FUNC(getkey)
2256 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2257 SilcClientConnection conn = cmd->conn;
2258 SilcClient client = cmd->client;
2259 SilcClientEntry client_entry = NULL;
2260 SilcServerEntry server_entry = NULL;
2261 char *nickname = NULL;
2262 SilcBuffer idp, buffer;
2264 SILC_LOG_DEBUG(("Start"));
2267 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2268 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2272 if (cmd->argc < 2) {
2273 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2274 "Usage: /GETKEY <nickname or server name>");
2275 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2279 /* Parse the typed nickname. */
2280 if (client->internal->params->nickname_parse)
2281 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2283 nickname = strdup(cmd->argv[1]);
2285 /* Find client entry */
2286 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2288 if (!client_entry) {
2289 /* Check whether user requested server actually */
2290 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2292 if (!server_entry) {
2293 /* No. what ever user wants we don't have it, so resolve it. We
2294 will first try to resolve the client, and if that fails then
2295 we'll try to resolve the server. */
2297 if (!cmd->pending) {
2298 /* This will send the IDENTIFY command for nickname */
2299 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2300 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2302 silc_client_command_getkey,
2303 silc_client_command_dup(cmd));
2307 SilcClientCommandReplyContext reply =
2308 (SilcClientCommandReplyContext)context2;
2311 /* If nickname was not found, then resolve the server. */
2312 silc_command_get_status(reply->payload, NULL, &error);
2313 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2314 /* This sends the IDENTIFY command to resolve the server. */
2315 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2317 silc_client_command_reply_identify_i, 0,
2319 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2321 2, cmd->argv[1], cmd->argv_lens[1]);
2322 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2324 silc_client_command_getkey,
2325 silc_client_command_dup(cmd));
2329 /* If server was not found, then we've resolved both nickname and
2330 server and did not find anybody. */
2331 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2332 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2333 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2334 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2335 silc_get_status_message(error));
2336 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2340 COMMAND_ERROR(error);
2345 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2347 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2350 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2351 1, idp->data, idp->len);
2352 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2353 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2354 silc_buffer_free(buffer);
2355 silc_buffer_free(idp);
2357 /* Notify application */
2358 COMMAND(SILC_STATUS_OK);
2361 silc_free(nickname);
2362 silc_client_command_free(cmd);
2365 /* Register a new command indicated by the `command' to the SILC client.
2366 The `name' is optional command name. If provided the command may be
2367 searched using the silc_client_command_find by that name. The
2368 `command_function' is the function to be called when the command is
2369 executed, and the `command_reply_function' is the function to be
2370 called after the server has sent reply back to the command.
2372 The `ident' is optional identifier for the command. If non-zero
2373 the `command_reply_function' for the command type `command' will be
2374 called only if the command reply sent by server includes the
2375 command identifier `ident'. Application usually does not need it
2376 and set it to zero value. */
2378 bool silc_client_command_register(SilcClient client,
2379 SilcCommand command,
2381 SilcCommandCb command_function,
2382 SilcCommandCb command_reply_function,
2386 SilcClientCommand cmd;
2388 cmd = silc_calloc(1, sizeof(*cmd));
2390 cmd->command = command_function;
2391 cmd->reply = command_reply_function;
2392 cmd->name = name ? strdup(name) : NULL;
2393 cmd->max_args = max_args;
2396 silc_list_add(client->internal->commands, cmd);
2401 /* Unregister a command indicated by the `command' with command function
2402 `command_function' and command reply function `command_reply_function'.
2403 Returns TRUE if the command was found and unregistered. */
2405 bool silc_client_command_unregister(SilcClient client,
2406 SilcCommand command,
2407 SilcCommandCb command_function,
2408 SilcCommandCb command_reply_function,
2411 SilcClientCommand cmd;
2413 silc_list_start(client->internal->commands);
2414 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2415 if (cmd->cmd == command && cmd->command == command_function &&
2416 cmd->reply == command_reply_function && cmd->ident == ident) {
2417 silc_list_del(client->internal->commands, cmd);
2418 silc_free(cmd->name);
2427 /* Private range commands, specific to this implementation (and compatible
2428 with SILC Server). */
2430 /* CONNECT command. Connects the server to another server. */
2432 SILC_CLIENT_CMD_FUNC(connect)
2434 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2435 SilcClientConnection conn = cmd->conn;
2437 unsigned char port[4];
2441 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2442 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2446 if (cmd->argc < 2) {
2447 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2448 "Usage: /CONNECT <server> [<port>]");
2449 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2453 if (cmd->argc == 3) {
2454 tmp = atoi(cmd->argv[2]);
2455 SILC_PUT32_MSB(tmp, port);
2459 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2461 strlen(cmd->argv[1]),
2464 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2466 strlen(cmd->argv[1]));
2467 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2468 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2469 silc_buffer_free(buffer);
2471 /* Notify application */
2472 COMMAND(SILC_STATUS_OK);
2475 silc_client_command_free(cmd);
2479 /* CLOSE command. Close server connection to the remote server */
2481 SILC_CLIENT_CMD_FUNC(close)
2483 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2484 SilcClientConnection conn = cmd->conn;
2486 unsigned char port[4];
2490 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2491 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2495 if (cmd->argc < 2) {
2496 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2497 "Usage: /CLOSE <server> [<port>]");
2498 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2502 if (cmd->argc == 3) {
2503 tmp = atoi(cmd->argv[2]);
2504 SILC_PUT32_MSB(tmp, port);
2508 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2510 strlen(cmd->argv[1]),
2513 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2515 strlen(cmd->argv[1]));
2516 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2517 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2518 silc_buffer_free(buffer);
2520 /* Notify application */
2521 COMMAND(SILC_STATUS_OK);
2524 silc_client_command_free(cmd);
2527 /* SHUTDOWN command. Shutdowns the server. */
2529 SILC_CLIENT_CMD_FUNC(shutdown)
2531 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2534 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2535 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2539 /* Send the command */
2540 silc_client_command_send(cmd->client, cmd->conn,
2541 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2543 /* Notify application */
2544 COMMAND(SILC_STATUS_OK);
2547 silc_client_command_free(cmd);
2550 /* Register all default commands provided by the client library for the
2553 void silc_client_commands_register(SilcClient client)
2555 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2558 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2559 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2560 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2561 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2562 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2563 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2564 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2565 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2566 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2567 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2568 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2569 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2570 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2571 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2572 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2573 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2574 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2575 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2576 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2577 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2578 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2579 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2580 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2581 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2582 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2583 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2585 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2586 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2587 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2590 /* Unregister all commands. */
2592 void silc_client_commands_unregister(SilcClient client)
2594 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2595 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2596 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2597 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2598 SILC_CLIENT_CMDU(list, LIST, "LIST");
2599 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2600 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2601 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2602 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2603 SILC_CLIENT_CMDU(info, INFO, "INFO");
2604 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2605 SILC_CLIENT_CMDU(ping, PING, "PING");
2606 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2607 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2608 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2609 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2610 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2611 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2612 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2613 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2614 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2615 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2616 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2617 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2618 SILC_CLIENT_CMDU(users, USERS, "USERS");
2619 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2621 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2622 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2623 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2626 /**** Client side incoming command handling **********************************/
2628 void silc_client_command_process_whois(SilcClient client,
2629 SilcSocketConnection sock,
2630 SilcCommandPayload payload,
2631 SilcArgumentPayload args);
2633 /* Client is able to receive some command packets even though they are
2634 special case. Server may send WHOIS command to the client to retrieve
2635 Requested Attributes information for WHOIS query the server is
2636 processing. This function currently handles only the WHOIS command,
2637 but if in the future for commands may arrive then this can be made
2638 to support other commands too. */
2640 void silc_client_command_process(SilcClient client,
2641 SilcSocketConnection sock,
2642 SilcPacketContext *packet)
2644 SilcCommandPayload payload;
2645 SilcCommand command;
2646 SilcArgumentPayload args;
2648 /* Get command payload from packet */
2649 payload = silc_command_payload_parse(packet->buffer->data,
2650 packet->buffer->len);
2652 /* Silently ignore bad reply packet */
2653 SILC_LOG_DEBUG(("Bad command packet"));
2658 args = silc_command_get_args(payload);
2660 /* Get the command */
2661 command = silc_command_get(payload);
2664 case SILC_COMMAND_WHOIS:
2665 /* Ignore everything if requested by application */
2666 if (client->internal->params->ignore_requested_attributes)
2669 silc_client_command_process_whois(client, sock, payload, args);
2676 silc_command_payload_free(payload);
2679 void silc_client_command_process_whois(SilcClient client,
2680 SilcSocketConnection sock,
2681 SilcCommandPayload payload,
2682 SilcArgumentPayload args)
2687 SilcBuffer buffer, packet;
2689 SILC_LOG_DEBUG(("Received WHOIS command"));
2691 /* Try to take the Requested Attributes */
2692 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2696 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2700 /* Process requested attributes */
2701 buffer = silc_client_attributes_process(client, sock, attrs);
2703 silc_attribute_payload_list_free(attrs);
2707 /* Send the attributes back */
2709 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2711 silc_command_get_ident(payload),
2712 1, 11, buffer->data, buffer->len);
2713 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2714 NULL, 0, NULL, NULL, packet->data,
2716 silc_buffer_free(packet);
2717 silc_buffer_free(buffer);