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_lens);
262 silc_free(ctx->argv_types);
267 /* Duplicate Command Context by adding reference counter. The context won't
268 be free'd untill it hits zero. */
270 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
273 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
278 /* Command WHOIS. This command is used to query information about
281 SILC_CLIENT_CMD_FUNC(whois)
283 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
284 SilcClientConnection conn = cmd->conn;
285 SilcBuffer buffer, attrs = NULL;
286 unsigned char count[4], *tmp = NULL;
289 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
290 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
294 /* Given without arguments fetches client's own information */
296 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
297 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
299 1, 4, buffer->data, buffer->len);
300 silc_buffer_free(buffer);
304 if (cmd->argc == 2) {
305 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
306 ++conn->cmd_ident, 1,
310 if (!strcasecmp(cmd->argv[2], "-details"))
311 attrs = silc_client_attributes_request(0);
313 if (!attrs || cmd->argc > 3) {
314 int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
315 SILC_PUT32_MSB(c, count);
319 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
320 ++conn->cmd_ident, 3,
321 1, cmd->argv[1], cmd->argv_lens[1],
322 2, tmp ? tmp : NULL, tmp ? 4 : 0,
323 3, attrs ? attrs->data : NULL,
324 attrs ? attrs->len : 0);
326 silc_client_packet_send(cmd->client, cmd->conn->sock,
327 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
328 buffer->data, buffer->len, TRUE);
329 silc_buffer_free(buffer);
331 /* Notify application */
332 COMMAND(SILC_STATUS_OK);
335 silc_client_command_free(cmd);
338 /* Command WHOWAS. This command is used to query history information about
339 specific user that used to exist in the network. */
341 SILC_CLIENT_CMD_FUNC(whowas)
343 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
344 SilcClientConnection conn = cmd->conn;
346 unsigned char count[4];
349 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
350 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
354 if (cmd->argc < 2 || cmd->argc > 3) {
355 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
356 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
357 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
358 SILC_STATUS_ERR_TOO_MANY_PARAMS));
362 if (cmd->argc == 2) {
363 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
364 ++conn->cmd_ident, 1,
368 int c = atoi(cmd->argv[2]);
369 memset(count, 0, sizeof(count));
370 SILC_PUT32_MSB(c, count);
371 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
372 ++conn->cmd_ident, 2,
373 1, cmd->argv[1], cmd->argv_lens[1],
374 2, count, sizeof(count));
376 silc_client_packet_send(cmd->client, cmd->conn->sock,
377 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
378 buffer->data, buffer->len, TRUE);
379 silc_buffer_free(buffer);
381 /* Notify application */
382 COMMAND(SILC_STATUS_OK);
385 silc_client_command_free(cmd);
388 /* Command IDENTIFY. This command is used to query information about
389 specific user, especially ID's.
391 NOTE: This command is used only internally by the client library
392 and application MUST NOT call this command directly. */
394 SILC_CLIENT_CMD_FUNC(identify)
396 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
397 SilcClientConnection conn = cmd->conn;
399 unsigned char count[4];
402 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
407 if (cmd->argc < 2 || cmd->argc > 3)
410 if (cmd->argc == 2) {
411 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
412 ++conn->cmd_ident, 1,
416 int c = atoi(cmd->argv[2]);
417 memset(count, 0, sizeof(count));
418 SILC_PUT32_MSB(c, count);
419 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
420 ++conn->cmd_ident, 2,
423 4, count, sizeof(count));
426 silc_client_packet_send(cmd->client, cmd->conn->sock,
427 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
428 buffer->data, buffer->len, TRUE);
429 silc_buffer_free(buffer);
432 silc_client_command_free(cmd);
435 /* Command NICK. Shows current nickname/sets new nickname on current
438 SILC_CLIENT_CMD_FUNC(nick)
440 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
441 SilcClientConnection conn = cmd->conn;
445 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
446 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
451 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
452 "Usage: /NICK <nickname>");
453 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
457 if (!strcmp(conn->nickname, cmd->argv[1]))
460 /* Show current nickname */
463 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
464 "Your nickname is %s on server %s",
465 conn->nickname, conn->remote_host);
467 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
468 "Your nickname is %s", conn->nickname);
471 COMMAND(SILC_STATUS_OK);
475 if (cmd->argv_lens[1] > 128)
476 cmd->argv_lens[1] = 128;
478 /* Send the NICK command */
479 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
483 ++cmd->conn->cmd_ident);
484 silc_client_packet_send(cmd->client, cmd->conn->sock,
485 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
486 buffer->data, buffer->len, TRUE);
487 silc_buffer_free(buffer);
490 silc_client_command_free(cmd);
493 /* Command LIST. Lists channels on the current server. */
495 SILC_CLIENT_CMD_FUNC(list)
497 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
498 SilcClientConnection conn = cmd->conn;
499 SilcIDCacheEntry id_cache = NULL;
500 SilcChannelEntry channel;
501 SilcBuffer buffer, idp = NULL;
505 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
510 if (cmd->argc == 2) {
513 /* Get the Channel ID of the channel */
514 if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
516 channel = (SilcChannelEntry)id_cache->context;
517 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
522 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
523 ++conn->cmd_ident, 0);
525 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
526 ++conn->cmd_ident, 1,
527 1, idp->data, idp->len);
529 silc_client_packet_send(cmd->client, cmd->conn->sock,
530 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
531 buffer->data, buffer->len, TRUE);
532 silc_buffer_free(buffer);
534 silc_buffer_free(idp);
536 /* Notify application */
537 COMMAND(SILC_STATUS_OK);
540 silc_client_command_free(cmd);
543 /* Command TOPIC. Sets/shows topic on a channel. */
545 SILC_CLIENT_CMD_FUNC(topic)
547 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
548 SilcClientConnection conn = cmd->conn;
549 SilcIDCacheEntry id_cache = NULL;
550 SilcChannelEntry channel;
551 SilcBuffer buffer, idp;
555 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
556 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
560 if (cmd->argc < 2 || cmd->argc > 3) {
561 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
562 "Usage: /TOPIC <channel> [<topic>]");
563 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
564 SILC_STATUS_ERR_TOO_MANY_PARAMS));
568 if (cmd->argv[1][0] == '*') {
569 if (!conn->current_channel) {
570 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
573 name = conn->current_channel->channel_name;
578 if (!conn->current_channel) {
579 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
583 /* Get the Channel ID of the channel */
584 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
586 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
590 channel = (SilcChannelEntry)id_cache->context;
592 /* Send TOPIC command to the server */
593 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
595 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
596 ++conn->cmd_ident, 2,
597 1, idp->data, idp->len,
599 strlen(cmd->argv[2]));
601 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
602 ++conn->cmd_ident, 1,
603 1, idp->data, idp->len);
604 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
605 0, NULL, NULL, buffer->data, buffer->len, TRUE);
606 silc_buffer_free(buffer);
607 silc_buffer_free(idp);
609 /* Notify application */
610 COMMAND(SILC_STATUS_OK);
613 silc_client_command_free(cmd);
616 /* Command INVITE. Invites specific client to join a channel. This is
617 also used to mange the invite list of the channel. */
619 SILC_CLIENT_CMD_FUNC(invite)
621 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
622 SilcClient client = cmd->client;
623 SilcClientConnection conn = cmd->conn;
624 SilcClientEntry client_entry = NULL;
625 SilcChannelEntry channel;
626 SilcBuffer buffer, clidp, chidp;
628 char *nickname = NULL, *name;
632 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
633 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
638 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
639 "Usage: /INVITE <channel> [<nickname>[@server>]"
640 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
641 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
645 if (cmd->argv[1][0] == '*') {
646 if (!conn->current_channel) {
647 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
651 channel = conn->current_channel;
655 channel = silc_client_get_channel(cmd->client, conn, name);
657 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
662 /* Parse the typed nickname. */
663 if (cmd->argc == 3) {
664 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
665 if (client->internal->params->nickname_parse)
666 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
668 nickname = strdup(cmd->argv[2]);
670 /* Find client entry */
671 client_entry = silc_idlist_get_client(client, conn, nickname,
675 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
679 /* Client entry not found, it was requested thus mark this to be
681 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
683 silc_client_command_invite,
684 silc_client_command_dup(cmd));
689 invite = cmd->argv[2];
691 if (cmd->argv[2][0] == '+')
698 /* Send the command */
699 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
701 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
702 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
703 ++conn->cmd_ident, 3,
704 1, chidp->data, chidp->len,
705 2, clidp->data, clidp->len,
706 type, invite, invite ?
708 silc_buffer_free(clidp);
710 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
711 ++conn->cmd_ident, 2,
712 1, chidp->data, chidp->len,
713 type, invite, invite ?
717 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
718 0, NULL, NULL, buffer->data, buffer->len, TRUE);
719 silc_buffer_free(buffer);
720 silc_buffer_free(chidp);
722 /* Notify application */
723 COMMAND(SILC_STATUS_OK);
727 silc_client_command_free(cmd);
732 SilcClientConnection conn;
735 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
737 QuitInternal q = (QuitInternal)context;
739 /* Close connection */
740 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
741 silc_client_close_connection(q->client, q->conn->sock->user_data);
746 /* Command QUIT. Closes connection with current server. */
748 SILC_CLIENT_CMD_FUNC(quit)
750 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
755 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
756 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
761 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
762 &cmd->argv[1], &cmd->argv_lens[1],
763 &cmd->argv_types[1], 0);
765 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
766 NULL, NULL, NULL, 0);
767 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
769 buffer->data, buffer->len, TRUE);
770 silc_buffer_free(buffer);
772 q = silc_calloc(1, sizeof(*q));
773 q->client = cmd->client;
776 /* Sleep for a while */
779 /* We quit the connection with little timeout */
780 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
781 silc_client_command_quit_cb, (void *)q,
782 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
784 /* Notify application */
785 COMMAND(SILC_STATUS_OK);
788 silc_client_command_free(cmd);
791 /* Timeout callback to remove the killed client from cache */
793 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
795 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
796 SilcClient client = cmd->client;
797 SilcClientConnection conn = cmd->conn;
798 SilcClientEntry target;
799 char *nickname = NULL;
801 /* Parse the typed nickname. */
802 if (client->internal->params->nickname_parse)
803 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
805 nickname = strdup(cmd->argv[1]);
807 /* Get the target client */
808 target = silc_idlist_get_client(cmd->client, conn, nickname,
809 cmd->argv[1], FALSE);
811 /* Remove the client from all channels and free it */
812 silc_client_del_client(client, conn, target);
815 silc_client_command_free(cmd);
818 /* Kill command's pending command callback to actually remove the killed
819 client from our local cache. */
821 SILC_CLIENT_CMD_FUNC(kill_remove)
823 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
824 SilcClientCommandReplyContext reply =
825 (SilcClientCommandReplyContext)context2;
828 silc_command_get_status(reply->payload, &status, NULL);
829 if (status == SILC_STATUS_OK) {
830 /* Remove with timeout */
831 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
832 silc_client_command_kill_remove_later, context,
833 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
837 silc_client_command_free(cmd);
840 /* Command KILL. Router operator can use this command to remove an client
841 fromthe SILC Network. */
843 SILC_CLIENT_CMD_FUNC(kill)
845 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
846 SilcClient client = cmd->client;
847 SilcClientConnection conn = cmd->conn;
848 SilcBuffer buffer, idp, auth = NULL;
849 SilcClientEntry target;
850 char *nickname = NULL, *comment = NULL;
853 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
854 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
859 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
860 "Usage: /KILL <nickname> [<comment>] [-pubkey]");
861 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
865 /* Parse the typed nickname. */
866 if (client->internal->params->nickname_parse)
867 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
869 nickname = strdup(cmd->argv[1]);
871 /* Get the target client */
872 target = silc_idlist_get_client(cmd->client, conn, nickname,
876 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
880 /* Client entry not found, it was requested thus mark this to be
882 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
884 silc_client_command_kill,
885 silc_client_command_dup(cmd));
890 if (cmd->argc >= 3) {
891 if (strcasecmp(cmd->argv[2], "-pubkey"))
892 comment = cmd->argv[2];
894 if (!strcasecmp(cmd->argv[2], "-pubkey") ||
895 (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
896 /* Encode the public key authentication payload */
897 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
898 cmd->client->private_key,
901 target->id, SILC_ID_CLIENT);
905 /* Send the KILL command to the server */
906 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
908 silc_command_payload_encode_va(SILC_COMMAND_KILL,
909 ++conn->cmd_ident, 3,
910 1, idp->data, idp->len,
911 2, comment, comment ? strlen(comment) : 0,
912 3, auth ? auth->data : NULL,
913 auth ? auth->len : 0);
914 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
915 0, NULL, NULL, buffer->data, buffer->len, TRUE);
916 silc_buffer_free(buffer);
917 silc_buffer_free(idp);
918 silc_buffer_free(auth);
920 /* Notify application */
921 COMMAND(SILC_STATUS_OK);
923 /* Register a pending callback that will actually remove the killed
924 client from our cache. */
925 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
926 silc_client_command_kill_remove,
927 silc_client_command_dup(cmd));
931 silc_client_command_free(cmd);
934 /* Command INFO. Request information about specific server. If specific
935 server is not provided the current server is used. */
937 SILC_CLIENT_CMD_FUNC(info)
939 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
940 SilcClientConnection conn = cmd->conn;
945 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
946 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
951 name = strdup(cmd->argv[1]);
953 /* Send the command */
955 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
956 1, name, strlen(name));
958 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
959 NULL, NULL, NULL, 0);
960 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
961 0, NULL, NULL, buffer->data, buffer->len, TRUE);
962 silc_buffer_free(buffer);
966 /* Notify application */
967 COMMAND(SILC_STATUS_OK);
970 silc_client_command_free(cmd);
973 /* Command STATS. Shows server and network statistics. */
975 SILC_CLIENT_CMD_FUNC(stats)
977 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
978 SilcClientConnection conn = cmd->conn;
979 SilcBuffer buffer, idp = NULL;
982 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
983 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
987 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
989 /* Send the command */
990 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
991 ++conn->cmd_ident, 1,
992 SILC_ID_SERVER, idp->data, idp->len);
993 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
994 0, NULL, NULL, buffer->data, buffer->len, TRUE);
995 silc_buffer_free(buffer);
996 silc_buffer_free(idp);
998 /* Notify application */
999 COMMAND(SILC_STATUS_OK);
1002 silc_client_command_free(cmd);
1005 /* Command PING. Sends ping to server. This is used to test the
1006 communication channel. */
1008 SILC_CLIENT_CMD_FUNC(ping)
1010 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1011 SilcClientConnection conn = cmd->conn;
1012 SilcBuffer buffer, idp;
1017 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1018 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1022 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1024 /* Send the command */
1025 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1026 1, idp->data, idp->len);
1027 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1028 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1029 silc_buffer_free(buffer);
1030 silc_buffer_free(idp);
1032 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1035 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1036 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1040 /* Start counting time */
1041 for (i = 0; i < conn->internal->ping_count; i++) {
1042 if (conn->internal->ping[i].dest_id == NULL) {
1043 conn->internal->ping[i].start_time = time(NULL);
1044 conn->internal->ping[i].dest_id = id;
1045 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1049 if (i >= conn->internal->ping_count) {
1050 i = conn->internal->ping_count;
1051 conn->internal->ping =
1052 silc_realloc(conn->internal->ping,
1053 sizeof(*conn->internal->ping) * (i + 1));
1054 conn->internal->ping[i].start_time = time(NULL);
1055 conn->internal->ping[i].dest_id = id;
1056 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1057 conn->internal->ping_count++;
1060 /* Notify application */
1061 COMMAND(SILC_STATUS_OK);
1064 silc_client_command_free(cmd);
1067 /* Command JOIN. Joins to a channel. */
1069 SILC_CLIENT_CMD_FUNC(join)
1071 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1072 SilcClientConnection conn = cmd->conn;
1073 SilcChannelEntry channel;
1074 SilcBuffer buffer, idp, auth = NULL;
1075 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1076 int i, passphrase_len = 0;
1079 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1080 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1084 if (cmd->argc < 2) {
1085 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1089 /* See if we have joined to the requested channel already */
1090 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1091 if (channel && silc_client_on_channel(channel, conn->local_entry))
1094 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1096 if (cmd->argv_lens[1] > 256)
1097 cmd->argv_lens[1] = 256;
1099 name = cmd->argv[1];
1101 for (i = 2; i < cmd->argc; i++) {
1102 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1103 cipher = cmd->argv[i + 1];
1105 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1106 hmac = cmd->argv[i + 1];
1108 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1109 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1110 cmd->client->private_key,
1112 cmd->client->sha1hash,
1117 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1118 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1119 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1120 cmd->argv_lens[i], 0);
1121 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1122 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1123 0, pu8, passphrase_len);
1126 passphrase = strdup(cmd->argv[i]);
1127 passphrase_len = cmd->argv_lens[i];
1132 /* Send JOIN command to the server */
1134 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1135 1, name, strlen(name),
1136 2, idp->data, idp->len,
1137 3, passphrase, passphrase_len,
1138 4, cipher, cipher ? strlen(cipher) : 0,
1139 5, hmac, hmac ? strlen(hmac) : 0,
1140 6, auth ? auth->data : NULL,
1141 auth ? auth->len : 0);
1142 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1143 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1144 silc_buffer_free(buffer);
1145 silc_buffer_free(idp);
1147 silc_buffer_free(auth);
1148 silc_free(passphrase);
1150 /* Notify application */
1151 COMMAND(SILC_STATUS_OK);
1154 silc_client_command_free(cmd);
1157 /* MOTD command. Requests motd from server. */
1159 SILC_CLIENT_CMD_FUNC(motd)
1161 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1162 SilcClientConnection conn = cmd->conn;
1166 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1167 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1171 if (cmd->argc < 1 || cmd->argc > 2) {
1172 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1173 "Usage: /MOTD [<server>]");
1174 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1175 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1179 /* Send TOPIC command to the server */
1181 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1182 1, conn->remote_host,
1183 strlen(conn->remote_host));
1185 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1188 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1189 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1190 silc_buffer_free(buffer);
1192 /* Notify application */
1193 COMMAND(SILC_STATUS_OK);
1196 silc_client_command_free(cmd);
1199 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1200 modes as client cannot set itself server/router operator privileges. */
1202 SILC_CLIENT_CMD_FUNC(umode)
1204 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1205 SilcClientConnection conn = cmd->conn;
1206 SilcBuffer buffer, idp;
1207 unsigned char *cp, modebuf[4];
1208 SilcUInt32 mode, add, len;
1212 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1213 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1217 if (cmd->argc < 2) {
1218 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1219 "Usage: /UMODE +|-<modes>");
1220 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1224 mode = conn->local_entry->mode;
1226 /* Are we adding or removing mode */
1227 if (cmd->argv[1][0] == '-')
1233 cp = cmd->argv[1] + 1;
1235 for (i = 0; i < len; i++) {
1240 mode |= SILC_UMODE_SERVER_OPERATOR;
1241 mode |= SILC_UMODE_ROUTER_OPERATOR;
1242 mode |= SILC_UMODE_GONE;
1243 mode |= SILC_UMODE_INDISPOSED;
1244 mode |= SILC_UMODE_BUSY;
1245 mode |= SILC_UMODE_PAGE;
1246 mode |= SILC_UMODE_HYPER;
1247 mode |= SILC_UMODE_ROBOT;
1248 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1249 mode |= SILC_UMODE_REJECT_WATCHING;
1251 mode = SILC_UMODE_NONE;
1256 mode |= SILC_UMODE_SERVER_OPERATOR;
1258 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1262 mode |= SILC_UMODE_ROUTER_OPERATOR;
1264 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1268 mode |= SILC_UMODE_GONE;
1270 mode &= ~SILC_UMODE_GONE;
1274 mode |= SILC_UMODE_INDISPOSED;
1276 mode &= ~SILC_UMODE_INDISPOSED;
1280 mode |= SILC_UMODE_BUSY;
1282 mode &= ~SILC_UMODE_BUSY;
1286 mode |= SILC_UMODE_PAGE;
1288 mode &= ~SILC_UMODE_PAGE;
1292 mode |= SILC_UMODE_HYPER;
1294 mode &= ~SILC_UMODE_HYPER;
1298 mode |= SILC_UMODE_ROBOT;
1300 mode &= ~SILC_UMODE_ROBOT;
1304 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1306 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1310 mode |= SILC_UMODE_REJECT_WATCHING;
1312 mode &= ~SILC_UMODE_REJECT_WATCHING;
1316 mode |= SILC_UMODE_BLOCK_INVITE;
1318 mode &= ~SILC_UMODE_BLOCK_INVITE;
1321 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1327 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1328 SILC_PUT32_MSB(mode, modebuf);
1330 /* Send the command packet. We support sending only one mode at once
1331 that requires an argument. */
1333 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1334 1, idp->data, idp->len,
1335 2, modebuf, sizeof(modebuf));
1336 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1337 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1338 silc_buffer_free(buffer);
1339 silc_buffer_free(idp);
1341 /* Notify application */
1342 COMMAND(SILC_STATUS_OK);
1345 silc_client_command_free(cmd);
1348 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1349 can be set several at once. Those modes that require argument must be set
1350 separately (unless set with modes that does not require arguments). */
1352 SILC_CLIENT_CMD_FUNC(cmode)
1354 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1355 SilcClientConnection conn = cmd->conn;
1356 SilcChannelEntry channel;
1357 SilcBuffer buffer, chidp, auth = NULL;
1358 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1359 SilcUInt32 mode, add, type, len, arg_len = 0;
1363 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1364 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1368 if (cmd->argc < 3) {
1369 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1370 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1371 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1375 if (cmd->argv[1][0] == '*') {
1376 if (!conn->current_channel) {
1377 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1381 channel = conn->current_channel;
1383 name = cmd->argv[1];
1385 channel = silc_client_get_channel(cmd->client, conn, name);
1387 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1392 mode = channel->mode;
1394 /* Are we adding or removing mode */
1395 if (cmd->argv[2][0] == '-')
1400 /* Argument type to be sent to server */
1404 cp = cmd->argv[2] + 1;
1406 for (i = 0; i < len; i++) {
1410 mode |= SILC_CHANNEL_MODE_PRIVATE;
1412 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1416 mode |= SILC_CHANNEL_MODE_SECRET;
1418 mode &= ~SILC_CHANNEL_MODE_SECRET;
1422 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1424 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1428 mode |= SILC_CHANNEL_MODE_INVITE;
1430 mode &= ~SILC_CHANNEL_MODE_INVITE;
1434 mode |= SILC_CHANNEL_MODE_TOPIC;
1436 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1440 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1442 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1446 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1448 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1453 mode |= SILC_CHANNEL_MODE_ULIMIT;
1455 if (cmd->argc < 4) {
1456 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1457 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1458 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1461 ll = atoi(cmd->argv[3]);
1462 SILC_PUT32_MSB(ll, tmp);
1466 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1471 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1473 if (cmd->argc < 4) {
1474 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1475 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1476 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1480 arg_len = cmd->argv_lens[3];
1482 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1487 mode |= SILC_CHANNEL_MODE_CIPHER;
1489 if (cmd->argc < 4) {
1490 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1491 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1492 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1496 arg_len = cmd->argv_lens[3];
1498 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1503 mode |= SILC_CHANNEL_MODE_HMAC;
1505 if (cmd->argc < 4) {
1506 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1507 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1508 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1512 arg_len = cmd->argv_lens[3];
1514 mode &= ~SILC_CHANNEL_MODE_HMAC;
1519 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1521 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1522 cmd->client->private_key,
1524 cmd->client->sha1hash,
1528 arg_len = auth->len;
1530 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1534 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1540 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1541 SILC_PUT32_MSB(mode, modebuf);
1543 /* Send the command packet. We support sending only one mode at once
1544 that requires an argument. */
1547 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1548 1, chidp->data, chidp->len,
1549 2, modebuf, sizeof(modebuf),
1550 type, arg, arg_len);
1553 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1554 1, chidp->data, chidp->len,
1555 2, modebuf, sizeof(modebuf));
1558 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1559 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1560 silc_buffer_free(buffer);
1561 silc_buffer_free(chidp);
1563 silc_buffer_free(auth);
1565 /* Notify application */
1566 COMMAND(SILC_STATUS_OK);
1569 silc_client_command_free(cmd);
1572 /* CUMODE command. Changes client's mode on a channel. */
1574 SILC_CLIENT_CMD_FUNC(cumode)
1576 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1577 SilcClient client = cmd->client;
1578 SilcClientConnection conn = cmd->conn;
1579 SilcChannelEntry channel;
1580 SilcChannelUser chu;
1581 SilcClientEntry client_entry;
1582 SilcBuffer buffer, clidp, chidp, auth = NULL;
1583 unsigned char *name, *cp, modebuf[4];
1584 SilcUInt32 mode = 0, add, len;
1585 char *nickname = NULL;
1589 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1590 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1594 if (cmd->argc < 4) {
1595 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1596 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1597 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1601 if (cmd->argv[1][0] == '*') {
1602 if (!conn->current_channel) {
1603 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1607 channel = conn->current_channel;
1609 name = cmd->argv[1];
1611 channel = silc_client_get_channel(cmd->client, conn, name);
1613 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1618 /* Parse the typed nickname. */
1619 if (client->internal->params->nickname_parse)
1620 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1622 nickname = strdup(cmd->argv[3]);
1624 /* Find client entry */
1625 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1626 cmd->argv[3], TRUE);
1627 if (!client_entry) {
1629 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1633 /* Client entry not found, it was requested thus mark this to be
1635 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1637 silc_client_command_cumode,
1638 silc_client_command_dup(cmd));
1643 /* Get the current mode */
1644 chu = silc_client_on_channel(channel, client_entry);
1648 /* Are we adding or removing mode */
1649 if (cmd->argv[2][0] == '-')
1655 cp = cmd->argv[2] + 1;
1657 for (i = 0; i < len; i++) {
1661 mode |= SILC_CHANNEL_UMODE_CHANFO;
1662 mode |= SILC_CHANNEL_UMODE_CHANOP;
1663 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1664 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1665 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1667 mode = SILC_CHANNEL_UMODE_NONE;
1672 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1673 cmd->client->private_key,
1675 cmd->client->sha1hash,
1678 mode |= SILC_CHANNEL_UMODE_CHANFO;
1680 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1685 mode |= SILC_CHANNEL_UMODE_CHANOP;
1687 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1691 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1693 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1697 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1699 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1703 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1705 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1709 mode |= SILC_CHANNEL_UMODE_QUIET;
1711 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1714 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1720 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1721 SILC_PUT32_MSB(mode, modebuf);
1722 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1724 /* Send the command packet. We support sending only one mode at once
1725 that requires an argument. */
1726 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1728 1, chidp->data, chidp->len,
1730 3, clidp->data, clidp->len,
1731 4, auth ? auth->data : NULL,
1732 auth ? auth->len : 0);
1734 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1735 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1736 silc_buffer_free(buffer);
1737 silc_buffer_free(chidp);
1738 silc_buffer_free(clidp);
1740 silc_buffer_free(auth);
1742 /* Notify application */
1743 COMMAND(SILC_STATUS_OK);
1746 silc_free(nickname);
1747 silc_client_command_free(cmd);
1750 /* KICK command. Kicks a client out of channel. */
1752 SILC_CLIENT_CMD_FUNC(kick)
1754 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1755 SilcClient client = cmd->client;
1756 SilcClientConnection conn = cmd->conn;
1757 SilcIDCacheEntry id_cache = NULL;
1758 SilcChannelEntry channel;
1759 SilcBuffer buffer, idp, idp2;
1760 SilcClientEntry target;
1762 char *nickname = NULL;
1765 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1766 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1770 if (cmd->argc < 3) {
1771 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1772 "Usage: /KICK <channel> <nickname> [<comment>]");
1773 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1777 if (cmd->argv[1][0] == '*') {
1778 if (!conn->current_channel) {
1779 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1782 name = conn->current_channel->channel_name;
1784 name = cmd->argv[1];
1787 if (!conn->current_channel) {
1788 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1792 /* Get the Channel ID of the channel */
1793 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1795 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1799 channel = (SilcChannelEntry)id_cache->context;
1801 /* Parse the typed nickname. */
1802 if (client->internal->params->nickname_parse)
1803 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1805 nickname = strdup(cmd->argv[2]);
1807 /* Get the target client */
1808 target = silc_idlist_get_client(cmd->client, conn, nickname,
1809 cmd->argv[2], FALSE);
1811 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1812 "No such client: %s", cmd->argv[2]);
1813 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1817 /* Send KICK command to the server */
1818 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1819 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1821 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1822 1, idp->data, idp->len,
1823 2, idp2->data, idp2->len);
1825 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1826 1, idp->data, idp->len,
1827 2, idp2->data, idp2->len,
1829 strlen(cmd->argv[3]));
1830 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1831 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1832 silc_buffer_free(buffer);
1833 silc_buffer_free(idp);
1834 silc_buffer_free(idp2);
1836 /* Notify application */
1837 COMMAND(SILC_STATUS_OK);
1840 silc_free(nickname);
1841 silc_client_command_free(cmd);
1844 static void silc_client_command_oper_send(unsigned char *data,
1845 SilcUInt32 data_len, void *context)
1847 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1848 SilcClientConnection conn = cmd->conn;
1849 SilcBuffer buffer, auth;
1851 if (cmd->argc >= 3) {
1852 /* Encode the public key authentication payload */
1853 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1854 cmd->client->private_key,
1856 conn->internal->hash,
1860 /* Encode the password authentication payload */
1861 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1865 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1867 strlen(cmd->argv[1]),
1868 2, auth ? auth->data : NULL,
1869 auth ? auth->len : 0);
1870 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1871 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1873 silc_buffer_free(buffer);
1874 silc_buffer_free(auth);
1876 /* Notify application */
1877 COMMAND(SILC_STATUS_OK);
1880 /* OPER command. Used to obtain server operator privileges. */
1882 SILC_CLIENT_CMD_FUNC(oper)
1884 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1885 SilcClientConnection conn = cmd->conn;
1888 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1889 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1893 if (cmd->argc < 2) {
1894 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1895 "Usage: /OPER <username> [-pubkey]");
1896 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1900 if (cmd->argc < 3) {
1901 /* Get passphrase */
1902 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1903 silc_client_command_oper_send,
1908 silc_client_command_oper_send(NULL, 0, context);
1911 silc_client_command_free(cmd);
1914 static void silc_client_command_silcoper_send(unsigned char *data,
1915 SilcUInt32 data_len,
1918 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1919 SilcClientConnection conn = cmd->conn;
1920 SilcBuffer buffer, auth;
1922 if (cmd->argc >= 3) {
1923 /* Encode the public key authentication payload */
1924 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1925 cmd->client->private_key,
1927 conn->internal->hash,
1931 /* Encode the password authentication payload */
1932 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1936 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1938 strlen(cmd->argv[1]),
1939 2, auth ? auth->data : NULL,
1940 auth ? auth->len : 0);
1941 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1942 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1944 silc_buffer_free(buffer);
1945 silc_buffer_free(auth);
1947 /* Notify application */
1948 COMMAND(SILC_STATUS_OK);
1951 /* SILCOPER command. Used to obtain router operator privileges. */
1953 SILC_CLIENT_CMD_FUNC(silcoper)
1955 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1956 SilcClientConnection conn = cmd->conn;
1959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1960 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1964 if (cmd->argc < 2) {
1965 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1966 "Usage: /SILCOPER <username> [-pubkey]");
1967 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1971 if (cmd->argc < 3) {
1972 /* Get passphrase */
1973 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1974 silc_client_command_silcoper_send,
1979 silc_client_command_silcoper_send(NULL, 0, context);
1982 silc_client_command_free(cmd);
1985 /* Command BAN. This is used to manage the ban list of the channel. */
1987 SILC_CLIENT_CMD_FUNC(ban)
1989 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1990 SilcClientConnection conn = cmd->conn;
1991 SilcChannelEntry channel;
1992 SilcBuffer buffer, chidp;
1994 char *name, *ban = NULL;
1997 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1998 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2002 if (cmd->argc < 2) {
2003 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2004 "Usage: /BAN <channel> "
2005 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2006 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2010 if (cmd->argv[1][0] == '*') {
2011 if (!conn->current_channel) {
2012 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2016 channel = conn->current_channel;
2018 name = cmd->argv[1];
2020 channel = silc_client_get_channel(cmd->client, conn, name);
2022 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2027 if (cmd->argc == 3) {
2028 if (cmd->argv[2][0] == '+')
2037 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2039 /* Send the command */
2040 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2041 ++conn->cmd_ident, 2,
2042 1, chidp->data, chidp->len,
2043 type, ban, ban ? strlen(ban) : 0);
2044 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2045 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2046 silc_buffer_free(buffer);
2047 silc_buffer_free(chidp);
2049 /* Notify application */
2050 COMMAND(SILC_STATUS_OK);
2053 silc_client_command_free(cmd);
2056 /* Command DETACH. This is used to detach from the server */
2058 SILC_CLIENT_CMD_FUNC(detach)
2060 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2061 SilcClientConnection conn = cmd->conn;
2065 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2066 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2070 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2071 ++conn->cmd_ident, 0);
2072 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2073 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2074 silc_buffer_free(buffer);
2076 /* Notify application */
2077 COMMAND(SILC_STATUS_OK);
2080 silc_client_command_free(cmd);
2083 /* Command WATCH. */
2085 SILC_CLIENT_CMD_FUNC(watch)
2087 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2088 SilcClientConnection conn = cmd->conn;
2089 SilcBuffer buffer, idp = NULL;
2093 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2094 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2098 if (cmd->argc < 3) {
2099 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2103 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2105 if (!strcasecmp(cmd->argv[1], "-add")) {
2107 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2110 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2114 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2115 ++conn->cmd_ident, 2,
2116 1, idp->data, idp->len,
2119 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2120 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2121 silc_buffer_free(buffer);
2123 /* Notify application */
2124 COMMAND(SILC_STATUS_OK);
2128 silc_buffer_free(idp);
2129 silc_client_command_free(cmd);
2132 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2134 SILC_CLIENT_CMD_FUNC(leave)
2136 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2137 SilcClientConnection conn = cmd->conn;
2138 SilcChannelEntry channel;
2139 SilcChannelUser chu;
2140 SilcBuffer buffer, idp;
2144 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2145 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2149 if (cmd->argc != 2) {
2150 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2151 "Usage: /LEAVE <channel>");
2152 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2156 if (cmd->argv[1][0] == '*') {
2157 if (!conn->current_channel) {
2158 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2161 name = conn->current_channel->channel_name;
2163 name = cmd->argv[1];
2166 /* Get the channel entry */
2167 channel = silc_client_get_channel(cmd->client, conn, name);
2169 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2173 /* Remove us from channel */
2174 chu = silc_client_on_channel(channel, conn->local_entry);
2176 silc_hash_table_del(chu->client->channels, chu->channel);
2177 silc_hash_table_del(chu->channel->user_list, chu->client);
2181 /* Send LEAVE command to the server */
2182 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2183 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2184 1, idp->data, idp->len);
2185 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2186 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2187 silc_buffer_free(buffer);
2188 silc_buffer_free(idp);
2190 /* Notify application */
2191 COMMAND(SILC_STATUS_OK);
2193 if (conn->current_channel == channel)
2194 conn->current_channel = NULL;
2196 silc_client_del_channel(cmd->client, cmd->conn, channel);
2199 silc_client_command_free(cmd);
2202 /* Command USERS. Requests the USERS of the clients joined on requested
2205 SILC_CLIENT_CMD_FUNC(users)
2207 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2208 SilcClientConnection conn = cmd->conn;
2213 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2214 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2218 if (cmd->argc != 2) {
2219 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2220 "Usage: /USERS <channel>");
2221 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2225 if (cmd->argv[1][0] == '*') {
2226 if (!conn->current_channel) {
2227 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2230 name = conn->current_channel->channel_name;
2232 name = cmd->argv[1];
2235 /* Send USERS command to the server */
2236 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2237 ++conn->cmd_ident, 1,
2238 2, name, strlen(name));
2239 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2240 NULL, 0, NULL, NULL, buffer->data,
2242 silc_buffer_free(buffer);
2244 /* Notify application */
2245 COMMAND(SILC_STATUS_OK);
2248 silc_client_command_free(cmd);
2251 /* Command GETKEY. Used to fetch remote client's public key. */
2253 SILC_CLIENT_CMD_FUNC(getkey)
2255 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2256 SilcClientConnection conn = cmd->conn;
2257 SilcClient client = cmd->client;
2258 SilcClientEntry client_entry = NULL;
2259 SilcServerEntry server_entry = NULL;
2260 char *nickname = NULL;
2261 SilcBuffer idp, buffer;
2263 SILC_LOG_DEBUG(("Start"));
2266 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2267 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2271 if (cmd->argc < 2) {
2272 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2273 "Usage: /GETKEY <nickname or server name>");
2274 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2278 /* Parse the typed nickname. */
2279 if (client->internal->params->nickname_parse)
2280 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2282 nickname = strdup(cmd->argv[1]);
2284 /* Find client entry */
2285 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2287 if (!client_entry) {
2288 /* Check whether user requested server actually */
2289 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2291 if (!server_entry) {
2292 /* No. what ever user wants we don't have it, so resolve it. We
2293 will first try to resolve the client, and if that fails then
2294 we'll try to resolve the server. */
2296 if (!cmd->pending) {
2297 /* This will send the IDENTIFY command for nickname */
2298 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2299 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2301 silc_client_command_getkey,
2302 silc_client_command_dup(cmd));
2306 SilcClientCommandReplyContext reply =
2307 (SilcClientCommandReplyContext)context2;
2310 /* If nickname was not found, then resolve the server. */
2311 silc_command_get_status(reply->payload, NULL, &error);
2312 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2313 /* This sends the IDENTIFY command to resolve the server. */
2314 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2316 silc_client_command_reply_identify_i, 0,
2318 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2320 2, cmd->argv[1], cmd->argv_lens[1]);
2321 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2323 silc_client_command_getkey,
2324 silc_client_command_dup(cmd));
2328 /* If server was not found, then we've resolved both nickname and
2329 server and did not find anybody. */
2330 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2331 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2332 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2333 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2334 silc_get_status_message(error));
2335 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2339 COMMAND_ERROR(error);
2344 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2346 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2349 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2350 1, idp->data, idp->len);
2351 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2352 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2353 silc_buffer_free(buffer);
2354 silc_buffer_free(idp);
2356 /* Notify application */
2357 COMMAND(SILC_STATUS_OK);
2360 silc_free(nickname);
2361 silc_client_command_free(cmd);
2364 /* Register a new command indicated by the `command' to the SILC client.
2365 The `name' is optional command name. If provided the command may be
2366 searched using the silc_client_command_find by that name. The
2367 `command_function' is the function to be called when the command is
2368 executed, and the `command_reply_function' is the function to be
2369 called after the server has sent reply back to the command.
2371 The `ident' is optional identifier for the command. If non-zero
2372 the `command_reply_function' for the command type `command' will be
2373 called only if the command reply sent by server includes the
2374 command identifier `ident'. Application usually does not need it
2375 and set it to zero value. */
2377 bool silc_client_command_register(SilcClient client,
2378 SilcCommand command,
2380 SilcCommandCb command_function,
2381 SilcCommandCb command_reply_function,
2385 SilcClientCommand cmd;
2387 cmd = silc_calloc(1, sizeof(*cmd));
2389 cmd->command = command_function;
2390 cmd->reply = command_reply_function;
2391 cmd->name = name ? strdup(name) : NULL;
2392 cmd->max_args = max_args;
2395 silc_list_add(client->internal->commands, cmd);
2400 /* Unregister a command indicated by the `command' with command function
2401 `command_function' and command reply function `command_reply_function'.
2402 Returns TRUE if the command was found and unregistered. */
2404 bool silc_client_command_unregister(SilcClient client,
2405 SilcCommand command,
2406 SilcCommandCb command_function,
2407 SilcCommandCb command_reply_function,
2410 SilcClientCommand cmd;
2412 silc_list_start(client->internal->commands);
2413 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2414 if (cmd->cmd == command && cmd->command == command_function &&
2415 cmd->reply == command_reply_function && cmd->ident == ident) {
2416 silc_list_del(client->internal->commands, cmd);
2417 silc_free(cmd->name);
2426 /* Private range commands, specific to this implementation (and compatible
2427 with SILC Server). */
2429 /* CONNECT command. Connects the server to another server. */
2431 SILC_CLIENT_CMD_FUNC(connect)
2433 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2434 SilcClientConnection conn = cmd->conn;
2436 unsigned char port[4];
2440 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2441 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2445 if (cmd->argc < 2) {
2446 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2447 "Usage: /CONNECT <server> [<port>]");
2448 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2452 if (cmd->argc == 3) {
2453 tmp = atoi(cmd->argv[2]);
2454 SILC_PUT32_MSB(tmp, port);
2458 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2460 strlen(cmd->argv[1]),
2463 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2465 strlen(cmd->argv[1]));
2466 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2467 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2468 silc_buffer_free(buffer);
2470 /* Notify application */
2471 COMMAND(SILC_STATUS_OK);
2474 silc_client_command_free(cmd);
2478 /* CLOSE command. Close server connection to the remote server */
2480 SILC_CLIENT_CMD_FUNC(close)
2482 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2483 SilcClientConnection conn = cmd->conn;
2485 unsigned char port[4];
2489 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2490 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2494 if (cmd->argc < 2) {
2495 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2496 "Usage: /CLOSE <server> [<port>]");
2497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2501 if (cmd->argc == 3) {
2502 tmp = atoi(cmd->argv[2]);
2503 SILC_PUT32_MSB(tmp, port);
2507 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2509 strlen(cmd->argv[1]),
2512 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2514 strlen(cmd->argv[1]));
2515 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2516 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2517 silc_buffer_free(buffer);
2519 /* Notify application */
2520 COMMAND(SILC_STATUS_OK);
2523 silc_client_command_free(cmd);
2526 /* SHUTDOWN command. Shutdowns the server. */
2528 SILC_CLIENT_CMD_FUNC(shutdown)
2530 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2533 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2534 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2538 /* Send the command */
2539 silc_client_command_send(cmd->client, cmd->conn,
2540 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2542 /* Notify application */
2543 COMMAND(SILC_STATUS_OK);
2546 silc_client_command_free(cmd);
2549 /* Register all default commands provided by the client library for the
2552 void silc_client_commands_register(SilcClient client)
2554 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2557 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2558 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2559 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2560 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2561 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2562 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2563 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2564 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2565 SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
2566 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2567 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2568 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2569 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2570 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2571 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2572 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2573 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2574 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2575 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2576 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2577 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2578 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2579 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2580 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2581 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2582 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2584 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2585 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2586 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2589 /* Unregister all commands. */
2591 void silc_client_commands_unregister(SilcClient client)
2593 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2594 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2595 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2596 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2597 SILC_CLIENT_CMDU(list, LIST, "LIST");
2598 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2599 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2600 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2601 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2602 SILC_CLIENT_CMDU(info, INFO, "INFO");
2603 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2604 SILC_CLIENT_CMDU(ping, PING, "PING");
2605 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2606 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2607 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2608 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2609 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2610 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2611 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2612 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2613 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2614 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2615 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2616 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2617 SILC_CLIENT_CMDU(users, USERS, "USERS");
2618 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2620 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2621 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2622 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2625 /**** Client side incoming command handling **********************************/
2627 void silc_client_command_process_whois(SilcClient client,
2628 SilcSocketConnection sock,
2629 SilcCommandPayload payload,
2630 SilcArgumentPayload args);
2632 /* Client is able to receive some command packets even though they are
2633 special case. Server may send WHOIS command to the client to retrieve
2634 Requested Attributes information for WHOIS query the server is
2635 processing. This function currently handles only the WHOIS command,
2636 but if in the future for commands may arrive then this can be made
2637 to support other commands too. */
2639 void silc_client_command_process(SilcClient client,
2640 SilcSocketConnection sock,
2641 SilcPacketContext *packet)
2643 SilcCommandPayload payload;
2644 SilcCommand command;
2645 SilcArgumentPayload args;
2647 /* Get command payload from packet */
2648 payload = silc_command_payload_parse(packet->buffer->data,
2649 packet->buffer->len);
2651 /* Silently ignore bad reply packet */
2652 SILC_LOG_DEBUG(("Bad command packet"));
2657 args = silc_command_get_args(payload);
2659 /* Get the command */
2660 command = silc_command_get(payload);
2663 case SILC_COMMAND_WHOIS:
2664 /* Ignore everything if requested by application */
2665 if (client->internal->params->ignore_requested_attributes)
2668 silc_client_command_process_whois(client, sock, payload, args);
2675 silc_command_payload_free(payload);
2678 void silc_client_command_process_whois(SilcClient client,
2679 SilcSocketConnection sock,
2680 SilcCommandPayload payload,
2681 SilcArgumentPayload args)
2686 SilcBuffer buffer, packet;
2688 SILC_LOG_DEBUG(("Received WHOIS command"));
2690 /* Try to take the Requested Attributes */
2691 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2695 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2699 /* Process requested attributes */
2700 buffer = silc_client_attributes_process(client, sock, attrs);
2702 silc_attribute_payload_list_free(attrs);
2706 /* Send the attributes back */
2708 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2710 silc_command_get_ident(payload),
2711 1, 11, buffer->data, buffer->len);
2712 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2713 NULL, 0, NULL, NULL, packet->data,
2715 silc_buffer_free(packet);
2716 silc_buffer_free(buffer);