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 + 1;
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;
849 SilcClientEntry target;
850 char *nickname = 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>]");
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 /* Send the KILL command to the server */
891 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
893 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
894 ++conn->cmd_ident, 1,
895 1, idp->data, idp->len);
897 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
898 ++conn->cmd_ident, 2,
899 1, idp->data, idp->len,
901 strlen(cmd->argv[2]));
902 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
903 0, NULL, NULL, buffer->data, buffer->len, TRUE);
904 silc_buffer_free(buffer);
905 silc_buffer_free(idp);
907 /* Notify application */
908 COMMAND(SILC_STATUS_OK);
910 /* Register a pending callback that will actually remove the killed
911 client from our cache. */
912 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
913 silc_client_command_kill_remove,
914 silc_client_command_dup(cmd));
918 silc_client_command_free(cmd);
921 /* Command INFO. Request information about specific server. If specific
922 server is not provided the current server is used. */
924 SILC_CLIENT_CMD_FUNC(info)
926 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
927 SilcClientConnection conn = cmd->conn;
932 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
933 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
938 name = strdup(cmd->argv[1]);
940 /* Send the command */
942 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
943 1, name, strlen(name));
945 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
946 NULL, NULL, NULL, 0);
947 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
948 0, NULL, NULL, buffer->data, buffer->len, TRUE);
949 silc_buffer_free(buffer);
953 /* Notify application */
954 COMMAND(SILC_STATUS_OK);
957 silc_client_command_free(cmd);
960 /* Command STATS. Shows server and network statistics. */
962 SILC_CLIENT_CMD_FUNC(stats)
964 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
965 SilcClientConnection conn = cmd->conn;
966 SilcBuffer buffer, idp = NULL;
969 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
970 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
974 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
976 /* Send the command */
977 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
978 ++conn->cmd_ident, 1,
979 SILC_ID_SERVER, idp->data, idp->len);
980 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
981 0, NULL, NULL, buffer->data, buffer->len, TRUE);
982 silc_buffer_free(buffer);
983 silc_buffer_free(idp);
985 /* Notify application */
986 COMMAND(SILC_STATUS_OK);
989 silc_client_command_free(cmd);
992 /* Command PING. Sends ping to server. This is used to test the
993 communication channel. */
995 SILC_CLIENT_CMD_FUNC(ping)
997 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
998 SilcClientConnection conn = cmd->conn;
1004 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1005 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1009 /* Send the command */
1010 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1011 1, conn->remote_id_data,
1012 silc_id_get_len(conn->remote_id,
1014 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1015 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1016 silc_buffer_free(buffer);
1018 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
1021 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1022 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1026 /* Start counting time */
1027 for (i = 0; i < conn->internal->ping_count; i++) {
1028 if (conn->internal->ping[i].dest_id == NULL) {
1029 conn->internal->ping[i].start_time = time(NULL);
1030 conn->internal->ping[i].dest_id = id;
1031 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1035 if (i >= conn->internal->ping_count) {
1036 i = conn->internal->ping_count;
1037 conn->internal->ping =
1038 silc_realloc(conn->internal->ping,
1039 sizeof(*conn->internal->ping) * (i + 1));
1040 conn->internal->ping[i].start_time = time(NULL);
1041 conn->internal->ping[i].dest_id = id;
1042 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
1043 conn->internal->ping_count++;
1046 /* Notify application */
1047 COMMAND(SILC_STATUS_OK);
1050 silc_client_command_free(cmd);
1053 /* Command JOIN. Joins to a channel. */
1055 SILC_CLIENT_CMD_FUNC(join)
1057 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1058 SilcClientConnection conn = cmd->conn;
1059 SilcChannelEntry channel;
1060 SilcBuffer buffer, idp, auth = NULL;
1061 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
1062 int i, passphrase_len = 0;
1065 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1066 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1070 if (cmd->argc < 2) {
1071 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1075 /* See if we have joined to the requested channel already */
1076 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1077 if (channel && silc_client_on_channel(channel, conn->local_entry))
1080 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1082 if (cmd->argv_lens[1] > 256)
1083 cmd->argv_lens[1] = 256;
1085 name = cmd->argv[1];
1087 for (i = 2; i < cmd->argc; i++) {
1088 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1089 cipher = cmd->argv[i + 1];
1091 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1092 hmac = cmd->argv[i + 1];
1094 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1095 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1096 cmd->client->private_key,
1098 cmd->client->sha1hash,
1103 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1104 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1105 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1106 cmd->argv_lens[i], 0);
1107 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1108 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1109 0, pu8, passphrase_len);
1112 passphrase = strdup(cmd->argv[i]);
1113 passphrase_len = cmd->argv_lens[i];
1118 /* Send JOIN command to the server */
1120 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1121 1, name, strlen(name),
1122 2, idp->data, idp->len,
1123 3, passphrase, passphrase_len,
1124 4, cipher, cipher ? strlen(cipher) : 0,
1125 5, hmac, hmac ? strlen(hmac) : 0,
1126 6, auth ? auth->data : NULL,
1127 auth ? auth->len : 0);
1128 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1129 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1130 silc_buffer_free(buffer);
1131 silc_buffer_free(idp);
1133 silc_buffer_free(auth);
1134 silc_free(passphrase);
1136 /* Notify application */
1137 COMMAND(SILC_STATUS_OK);
1140 silc_client_command_free(cmd);
1143 /* MOTD command. Requests motd from server. */
1145 SILC_CLIENT_CMD_FUNC(motd)
1147 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1148 SilcClientConnection conn = cmd->conn;
1152 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1153 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1157 if (cmd->argc < 1 || cmd->argc > 2) {
1158 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1159 "Usage: /MOTD [<server>]");
1160 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1161 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1165 /* Send TOPIC command to the server */
1167 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1168 1, conn->remote_host,
1169 strlen(conn->remote_host));
1171 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1174 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1175 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1176 silc_buffer_free(buffer);
1178 /* Notify application */
1179 COMMAND(SILC_STATUS_OK);
1182 silc_client_command_free(cmd);
1185 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1186 modes as client cannot set itself server/router operator privileges. */
1188 SILC_CLIENT_CMD_FUNC(umode)
1190 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1191 SilcClientConnection conn = cmd->conn;
1192 SilcBuffer buffer, idp;
1193 unsigned char *cp, modebuf[4];
1194 SilcUInt32 mode, add, len;
1198 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1199 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1203 if (cmd->argc < 2) {
1204 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1205 "Usage: /UMODE +|-<modes>");
1206 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1210 mode = conn->local_entry->mode;
1212 /* Are we adding or removing mode */
1213 if (cmd->argv[1][0] == '-')
1219 cp = cmd->argv[1] + 1;
1221 for (i = 0; i < len; i++) {
1226 mode |= SILC_UMODE_SERVER_OPERATOR;
1227 mode |= SILC_UMODE_ROUTER_OPERATOR;
1228 mode |= SILC_UMODE_GONE;
1229 mode |= SILC_UMODE_INDISPOSED;
1230 mode |= SILC_UMODE_BUSY;
1231 mode |= SILC_UMODE_PAGE;
1232 mode |= SILC_UMODE_HYPER;
1233 mode |= SILC_UMODE_ROBOT;
1234 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1235 mode |= SILC_UMODE_REJECT_WATCHING;
1237 mode = SILC_UMODE_NONE;
1242 mode |= SILC_UMODE_SERVER_OPERATOR;
1244 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1248 mode |= SILC_UMODE_ROUTER_OPERATOR;
1250 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1254 mode |= SILC_UMODE_GONE;
1256 mode &= ~SILC_UMODE_GONE;
1260 mode |= SILC_UMODE_INDISPOSED;
1262 mode &= ~SILC_UMODE_INDISPOSED;
1266 mode |= SILC_UMODE_BUSY;
1268 mode &= ~SILC_UMODE_BUSY;
1272 mode |= SILC_UMODE_PAGE;
1274 mode &= ~SILC_UMODE_PAGE;
1278 mode |= SILC_UMODE_HYPER;
1280 mode &= ~SILC_UMODE_HYPER;
1284 mode |= SILC_UMODE_ROBOT;
1286 mode &= ~SILC_UMODE_ROBOT;
1290 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1292 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1296 mode |= SILC_UMODE_REJECT_WATCHING;
1298 mode &= ~SILC_UMODE_REJECT_WATCHING;
1302 mode |= SILC_UMODE_BLOCK_INVITE;
1304 mode &= ~SILC_UMODE_BLOCK_INVITE;
1307 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1313 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1314 SILC_PUT32_MSB(mode, modebuf);
1316 /* Send the command packet. We support sending only one mode at once
1317 that requires an argument. */
1319 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1320 1, idp->data, idp->len,
1321 2, modebuf, sizeof(modebuf));
1322 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1323 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1324 silc_buffer_free(buffer);
1325 silc_buffer_free(idp);
1327 /* Notify application */
1328 COMMAND(SILC_STATUS_OK);
1331 silc_client_command_free(cmd);
1334 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1335 can be set several at once. Those modes that require argument must be set
1336 separately (unless set with modes that does not require arguments). */
1338 SILC_CLIENT_CMD_FUNC(cmode)
1340 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1341 SilcClientConnection conn = cmd->conn;
1342 SilcChannelEntry channel;
1343 SilcBuffer buffer, chidp, auth = NULL;
1344 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1345 SilcUInt32 mode, add, type, len, arg_len = 0;
1349 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1350 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1354 if (cmd->argc < 3) {
1355 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1356 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1357 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1361 if (cmd->argv[1][0] == '*') {
1362 if (!conn->current_channel) {
1363 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1367 channel = conn->current_channel;
1369 name = cmd->argv[1];
1371 channel = silc_client_get_channel(cmd->client, conn, name);
1373 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1378 mode = channel->mode;
1380 /* Are we adding or removing mode */
1381 if (cmd->argv[2][0] == '-')
1386 /* Argument type to be sent to server */
1390 cp = cmd->argv[2] + 1;
1392 for (i = 0; i < len; i++) {
1396 mode |= SILC_CHANNEL_MODE_PRIVATE;
1398 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1402 mode |= SILC_CHANNEL_MODE_SECRET;
1404 mode &= ~SILC_CHANNEL_MODE_SECRET;
1408 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1410 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1414 mode |= SILC_CHANNEL_MODE_INVITE;
1416 mode &= ~SILC_CHANNEL_MODE_INVITE;
1420 mode |= SILC_CHANNEL_MODE_TOPIC;
1422 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1426 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1428 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1432 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1434 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1439 mode |= SILC_CHANNEL_MODE_ULIMIT;
1441 if (cmd->argc < 4) {
1442 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1443 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1444 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1447 ll = atoi(cmd->argv[3]);
1448 SILC_PUT32_MSB(ll, tmp);
1452 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1457 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1459 if (cmd->argc < 4) {
1460 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1461 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1462 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1466 arg_len = cmd->argv_lens[3];
1468 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1473 mode |= SILC_CHANNEL_MODE_CIPHER;
1475 if (cmd->argc < 4) {
1476 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1477 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1478 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1482 arg_len = cmd->argv_lens[3];
1484 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1489 mode |= SILC_CHANNEL_MODE_HMAC;
1491 if (cmd->argc < 4) {
1492 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1493 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1494 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1498 arg_len = cmd->argv_lens[3];
1500 mode &= ~SILC_CHANNEL_MODE_HMAC;
1505 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1507 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1508 cmd->client->private_key,
1510 cmd->client->sha1hash,
1514 arg_len = auth->len;
1516 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1520 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1526 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1527 SILC_PUT32_MSB(mode, modebuf);
1529 /* Send the command packet. We support sending only one mode at once
1530 that requires an argument. */
1533 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1534 1, chidp->data, chidp->len,
1535 2, modebuf, sizeof(modebuf),
1536 type, arg, arg_len);
1539 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1540 1, chidp->data, chidp->len,
1541 2, modebuf, sizeof(modebuf));
1544 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1545 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1546 silc_buffer_free(buffer);
1547 silc_buffer_free(chidp);
1549 silc_buffer_free(auth);
1551 /* Notify application */
1552 COMMAND(SILC_STATUS_OK);
1555 silc_client_command_free(cmd);
1558 /* CUMODE command. Changes client's mode on a channel. */
1560 SILC_CLIENT_CMD_FUNC(cumode)
1562 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1563 SilcClient client = cmd->client;
1564 SilcClientConnection conn = cmd->conn;
1565 SilcChannelEntry channel;
1566 SilcChannelUser chu;
1567 SilcClientEntry client_entry;
1568 SilcBuffer buffer, clidp, chidp, auth = NULL;
1569 unsigned char *name, *cp, modebuf[4];
1570 SilcUInt32 mode = 0, add, len;
1571 char *nickname = NULL;
1575 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1576 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1580 if (cmd->argc < 4) {
1581 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1582 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1583 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1587 if (cmd->argv[1][0] == '*') {
1588 if (!conn->current_channel) {
1589 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1593 channel = conn->current_channel;
1595 name = cmd->argv[1];
1597 channel = silc_client_get_channel(cmd->client, conn, name);
1599 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1604 /* Parse the typed nickname. */
1605 if (client->internal->params->nickname_parse)
1606 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1608 nickname = strdup(cmd->argv[3]);
1610 /* Find client entry */
1611 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1612 cmd->argv[3], TRUE);
1613 if (!client_entry) {
1615 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1619 /* Client entry not found, it was requested thus mark this to be
1621 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1623 silc_client_command_cumode,
1624 silc_client_command_dup(cmd));
1629 /* Get the current mode */
1630 chu = silc_client_on_channel(channel, client_entry);
1634 /* Are we adding or removing mode */
1635 if (cmd->argv[2][0] == '-')
1641 cp = cmd->argv[2] + 1;
1643 for (i = 0; i < len; i++) {
1647 mode |= SILC_CHANNEL_UMODE_CHANFO;
1648 mode |= SILC_CHANNEL_UMODE_CHANOP;
1649 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1650 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1651 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1653 mode = SILC_CHANNEL_UMODE_NONE;
1658 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1659 cmd->client->private_key,
1661 cmd->client->sha1hash,
1664 mode |= SILC_CHANNEL_UMODE_CHANFO;
1666 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1671 mode |= SILC_CHANNEL_UMODE_CHANOP;
1673 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1677 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1679 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1683 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1685 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1689 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1691 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1695 mode |= SILC_CHANNEL_UMODE_QUIET;
1697 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1700 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1706 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1707 SILC_PUT32_MSB(mode, modebuf);
1708 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1710 /* Send the command packet. We support sending only one mode at once
1711 that requires an argument. */
1712 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1714 1, chidp->data, chidp->len,
1716 3, clidp->data, clidp->len,
1717 4, auth ? auth->data : NULL,
1718 auth ? auth->len : 0);
1720 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1721 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1722 silc_buffer_free(buffer);
1723 silc_buffer_free(chidp);
1724 silc_buffer_free(clidp);
1726 silc_buffer_free(auth);
1728 /* Notify application */
1729 COMMAND(SILC_STATUS_OK);
1732 silc_free(nickname);
1733 silc_client_command_free(cmd);
1736 /* KICK command. Kicks a client out of channel. */
1738 SILC_CLIENT_CMD_FUNC(kick)
1740 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1741 SilcClient client = cmd->client;
1742 SilcClientConnection conn = cmd->conn;
1743 SilcIDCacheEntry id_cache = NULL;
1744 SilcChannelEntry channel;
1745 SilcBuffer buffer, idp, idp2;
1746 SilcClientEntry target;
1748 char *nickname = NULL;
1751 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1752 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1756 if (cmd->argc < 3) {
1757 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1758 "Usage: /KICK <channel> <nickname> [<comment>]");
1759 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1763 if (cmd->argv[1][0] == '*') {
1764 if (!conn->current_channel) {
1765 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1768 name = conn->current_channel->channel_name;
1770 name = cmd->argv[1];
1773 if (!conn->current_channel) {
1774 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1778 /* Get the Channel ID of the channel */
1779 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1781 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1785 channel = (SilcChannelEntry)id_cache->context;
1787 /* Parse the typed nickname. */
1788 if (client->internal->params->nickname_parse)
1789 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1791 nickname = strdup(cmd->argv[2]);
1793 /* Get the target client */
1794 target = silc_idlist_get_client(cmd->client, conn, nickname,
1795 cmd->argv[2], FALSE);
1797 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1798 "No such client: %s", cmd->argv[2]);
1799 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1803 /* Send KICK command to the server */
1804 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1805 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1807 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1808 1, idp->data, idp->len,
1809 2, idp2->data, idp2->len);
1811 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1812 1, idp->data, idp->len,
1813 2, idp2->data, idp2->len,
1815 strlen(cmd->argv[3]));
1816 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1817 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1818 silc_buffer_free(buffer);
1819 silc_buffer_free(idp);
1820 silc_buffer_free(idp2);
1822 /* Notify application */
1823 COMMAND(SILC_STATUS_OK);
1826 silc_free(nickname);
1827 silc_client_command_free(cmd);
1830 static void silc_client_command_oper_send(unsigned char *data,
1831 SilcUInt32 data_len, void *context)
1833 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1834 SilcClientConnection conn = cmd->conn;
1835 SilcBuffer buffer, auth;
1837 if (cmd->argc >= 3) {
1838 /* Encode the public key authentication payload */
1839 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1840 cmd->client->private_key,
1842 conn->internal->hash,
1846 /* Encode the password authentication payload */
1847 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1851 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1853 strlen(cmd->argv[1]),
1854 2, auth ? auth->data : NULL,
1855 auth ? auth->len : 0);
1856 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1857 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1859 silc_buffer_free(buffer);
1860 silc_buffer_free(auth);
1862 /* Notify application */
1863 COMMAND(SILC_STATUS_OK);
1866 /* OPER command. Used to obtain server operator privileges. */
1868 SILC_CLIENT_CMD_FUNC(oper)
1870 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1871 SilcClientConnection conn = cmd->conn;
1874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1875 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1879 if (cmd->argc < 2) {
1880 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1881 "Usage: /OPER <username> [-pubkey]");
1882 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1886 if (cmd->argc < 3) {
1887 /* Get passphrase */
1888 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1889 silc_client_command_oper_send,
1894 silc_client_command_oper_send(NULL, 0, context);
1897 silc_client_command_free(cmd);
1900 static void silc_client_command_silcoper_send(unsigned char *data,
1901 SilcUInt32 data_len,
1904 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1905 SilcClientConnection conn = cmd->conn;
1906 SilcBuffer buffer, auth;
1908 if (cmd->argc >= 3) {
1909 /* Encode the public key authentication payload */
1910 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1911 cmd->client->private_key,
1913 conn->internal->hash,
1917 /* Encode the password authentication payload */
1918 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1922 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1924 strlen(cmd->argv[1]),
1925 2, auth ? auth->data : NULL,
1926 auth ? auth->len : 0);
1927 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1928 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1930 silc_buffer_free(buffer);
1931 silc_buffer_free(auth);
1933 /* Notify application */
1934 COMMAND(SILC_STATUS_OK);
1937 /* SILCOPER command. Used to obtain router operator privileges. */
1939 SILC_CLIENT_CMD_FUNC(silcoper)
1941 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1942 SilcClientConnection conn = cmd->conn;
1945 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1946 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1950 if (cmd->argc < 2) {
1951 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1952 "Usage: /SILCOPER <username> [-pubkey]");
1953 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1957 if (cmd->argc < 3) {
1958 /* Get passphrase */
1959 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1960 silc_client_command_silcoper_send,
1965 silc_client_command_silcoper_send(NULL, 0, context);
1968 silc_client_command_free(cmd);
1971 /* Command BAN. This is used to manage the ban list of the channel. */
1973 SILC_CLIENT_CMD_FUNC(ban)
1975 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1976 SilcClientConnection conn = cmd->conn;
1977 SilcChannelEntry channel;
1978 SilcBuffer buffer, chidp;
1980 char *name, *ban = NULL;
1983 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1984 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1988 if (cmd->argc < 2) {
1989 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1990 "Usage: /BAN <channel> "
1991 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1992 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1996 if (cmd->argv[1][0] == '*') {
1997 if (!conn->current_channel) {
1998 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2002 channel = conn->current_channel;
2004 name = cmd->argv[1];
2006 channel = silc_client_get_channel(cmd->client, conn, name);
2008 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2013 if (cmd->argc == 3) {
2014 if (cmd->argv[2][0] == '+')
2023 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2025 /* Send the command */
2026 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
2027 ++conn->cmd_ident, 2,
2028 1, chidp->data, chidp->len,
2029 type, ban, ban ? strlen(ban) : 0);
2030 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2031 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2032 silc_buffer_free(buffer);
2033 silc_buffer_free(chidp);
2035 /* Notify application */
2036 COMMAND(SILC_STATUS_OK);
2039 silc_client_command_free(cmd);
2042 /* Command DETACH. This is used to detach from the server */
2044 SILC_CLIENT_CMD_FUNC(detach)
2046 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2047 SilcClientConnection conn = cmd->conn;
2051 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2052 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2056 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2057 ++conn->cmd_ident, 0);
2058 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2059 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2060 silc_buffer_free(buffer);
2062 /* Notify application */
2063 COMMAND(SILC_STATUS_OK);
2066 silc_client_command_free(cmd);
2069 /* Command WATCH. */
2071 SILC_CLIENT_CMD_FUNC(watch)
2073 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2074 SilcClientConnection conn = cmd->conn;
2075 SilcBuffer buffer, idp = NULL;
2079 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2080 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2084 if (cmd->argc < 3) {
2085 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2089 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2091 if (!strcasecmp(cmd->argv[1], "-add")) {
2093 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2096 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2100 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2101 ++conn->cmd_ident, 2,
2102 1, idp->data, idp->len,
2105 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2106 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2107 silc_buffer_free(buffer);
2109 /* Notify application */
2110 COMMAND(SILC_STATUS_OK);
2114 silc_buffer_free(idp);
2115 silc_client_command_free(cmd);
2118 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2120 SILC_CLIENT_CMD_FUNC(leave)
2122 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2123 SilcClientConnection conn = cmd->conn;
2124 SilcChannelEntry channel;
2125 SilcChannelUser chu;
2126 SilcBuffer buffer, idp;
2130 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2131 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2135 if (cmd->argc != 2) {
2136 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2137 "Usage: /LEAVE <channel>");
2138 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2142 if (cmd->argv[1][0] == '*') {
2143 if (!conn->current_channel) {
2144 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2147 name = conn->current_channel->channel_name;
2149 name = cmd->argv[1];
2152 /* Get the channel entry */
2153 channel = silc_client_get_channel(cmd->client, conn, name);
2155 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2159 /* Remove us from channel */
2160 chu = silc_client_on_channel(channel, conn->local_entry);
2162 silc_hash_table_del(chu->client->channels, chu->channel);
2163 silc_hash_table_del(chu->channel->user_list, chu->client);
2167 /* Send LEAVE command to the server */
2168 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2169 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2170 1, idp->data, idp->len);
2171 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2172 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2173 silc_buffer_free(buffer);
2174 silc_buffer_free(idp);
2176 /* Notify application */
2177 COMMAND(SILC_STATUS_OK);
2179 if (conn->current_channel == channel)
2180 conn->current_channel = NULL;
2182 silc_client_del_channel(cmd->client, cmd->conn, channel);
2185 silc_client_command_free(cmd);
2188 /* Command USERS. Requests the USERS of the clients joined on requested
2191 SILC_CLIENT_CMD_FUNC(users)
2193 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2194 SilcClientConnection conn = cmd->conn;
2199 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2200 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2204 if (cmd->argc != 2) {
2205 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2206 "Usage: /USERS <channel>");
2207 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2211 if (cmd->argv[1][0] == '*') {
2212 if (!conn->current_channel) {
2213 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2216 name = conn->current_channel->channel_name;
2218 name = cmd->argv[1];
2221 /* Send USERS command to the server */
2222 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2223 ++conn->cmd_ident, 1,
2224 2, name, strlen(name));
2225 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2226 NULL, 0, NULL, NULL, buffer->data,
2228 silc_buffer_free(buffer);
2230 /* Notify application */
2231 COMMAND(SILC_STATUS_OK);
2234 silc_client_command_free(cmd);
2237 /* Command GETKEY. Used to fetch remote client's public key. */
2239 SILC_CLIENT_CMD_FUNC(getkey)
2241 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2242 SilcClientConnection conn = cmd->conn;
2243 SilcClient client = cmd->client;
2244 SilcClientEntry client_entry = NULL;
2245 SilcServerEntry server_entry = NULL;
2246 char *nickname = NULL;
2247 SilcBuffer idp, buffer;
2249 SILC_LOG_DEBUG(("Start"));
2252 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2253 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2257 if (cmd->argc < 2) {
2258 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2259 "Usage: /GETKEY <nickname or server name>");
2260 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2264 /* Parse the typed nickname. */
2265 if (client->internal->params->nickname_parse)
2266 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2268 nickname = strdup(cmd->argv[1]);
2270 /* Find client entry */
2271 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2273 if (!client_entry) {
2274 /* Check whether user requested server actually */
2275 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2277 if (!server_entry) {
2278 /* No. what ever user wants we don't have it, so resolve it. We
2279 will first try to resolve the client, and if that fails then
2280 we'll try to resolve the server. */
2282 if (!cmd->pending) {
2283 /* This will send the IDENTIFY command for nickname */
2284 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2285 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2287 silc_client_command_getkey,
2288 silc_client_command_dup(cmd));
2292 SilcClientCommandReplyContext reply =
2293 (SilcClientCommandReplyContext)context2;
2296 /* If nickname was not found, then resolve the server. */
2297 silc_command_get_status(reply->payload, NULL, &error);
2298 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2299 /* This sends the IDENTIFY command to resolve the server. */
2300 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2302 silc_client_command_reply_identify_i, 0,
2304 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2306 2, cmd->argv[1], cmd->argv_lens[1]);
2307 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2309 silc_client_command_getkey,
2310 silc_client_command_dup(cmd));
2314 /* If server was not found, then we've resolved both nickname and
2315 server and did not find anybody. */
2316 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2317 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2318 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2319 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2320 silc_get_status_message(error));
2321 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2325 COMMAND_ERROR(error);
2330 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2332 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2335 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2336 1, idp->data, idp->len);
2337 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2338 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2339 silc_buffer_free(buffer);
2340 silc_buffer_free(idp);
2342 /* Notify application */
2343 COMMAND(SILC_STATUS_OK);
2346 silc_free(nickname);
2347 silc_client_command_free(cmd);
2350 /* Register a new command indicated by the `command' to the SILC client.
2351 The `name' is optional command name. If provided the command may be
2352 searched using the silc_client_command_find by that name. The
2353 `command_function' is the function to be called when the command is
2354 executed, and the `command_reply_function' is the function to be
2355 called after the server has sent reply back to the command.
2357 The `ident' is optional identifier for the command. If non-zero
2358 the `command_reply_function' for the command type `command' will be
2359 called only if the command reply sent by server includes the
2360 command identifier `ident'. Application usually does not need it
2361 and set it to zero value. */
2363 bool silc_client_command_register(SilcClient client,
2364 SilcCommand command,
2366 SilcCommandCb command_function,
2367 SilcCommandCb command_reply_function,
2371 SilcClientCommand cmd;
2373 cmd = silc_calloc(1, sizeof(*cmd));
2375 cmd->command = command_function;
2376 cmd->reply = command_reply_function;
2377 cmd->name = name ? strdup(name) : NULL;
2378 cmd->max_args = max_args;
2381 silc_list_add(client->internal->commands, cmd);
2386 /* Unregister a command indicated by the `command' with command function
2387 `command_function' and command reply function `command_reply_function'.
2388 Returns TRUE if the command was found and unregistered. */
2390 bool silc_client_command_unregister(SilcClient client,
2391 SilcCommand command,
2392 SilcCommandCb command_function,
2393 SilcCommandCb command_reply_function,
2396 SilcClientCommand cmd;
2398 silc_list_start(client->internal->commands);
2399 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2400 if (cmd->cmd == command && cmd->command == command_function &&
2401 cmd->reply == command_reply_function && cmd->ident == ident) {
2402 silc_list_del(client->internal->commands, cmd);
2403 silc_free(cmd->name);
2412 /* Private range commands, specific to this implementation (and compatible
2413 with SILC Server). */
2415 /* CONNECT command. Connects the server to another server. */
2417 SILC_CLIENT_CMD_FUNC(connect)
2419 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2420 SilcClientConnection conn = cmd->conn;
2422 unsigned char port[4];
2426 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2427 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2431 if (cmd->argc < 2) {
2432 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2433 "Usage: /CONNECT <server> [<port>]");
2434 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2438 if (cmd->argc == 3) {
2439 tmp = atoi(cmd->argv[2]);
2440 SILC_PUT32_MSB(tmp, port);
2444 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2446 strlen(cmd->argv[1]),
2449 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2451 strlen(cmd->argv[1]));
2452 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2453 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2454 silc_buffer_free(buffer);
2456 /* Notify application */
2457 COMMAND(SILC_STATUS_OK);
2460 silc_client_command_free(cmd);
2464 /* CLOSE command. Close server connection to the remote server */
2466 SILC_CLIENT_CMD_FUNC(close)
2468 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2469 SilcClientConnection conn = cmd->conn;
2471 unsigned char port[4];
2475 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2476 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2480 if (cmd->argc < 2) {
2481 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2482 "Usage: /CLOSE <server> [<port>]");
2483 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2487 if (cmd->argc == 3) {
2488 tmp = atoi(cmd->argv[2]);
2489 SILC_PUT32_MSB(tmp, port);
2493 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2495 strlen(cmd->argv[1]),
2498 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2500 strlen(cmd->argv[1]));
2501 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2502 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2503 silc_buffer_free(buffer);
2505 /* Notify application */
2506 COMMAND(SILC_STATUS_OK);
2509 silc_client_command_free(cmd);
2512 /* SHUTDOWN command. Shutdowns the server. */
2514 SILC_CLIENT_CMD_FUNC(shutdown)
2516 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2519 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2520 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2524 /* Send the command */
2525 silc_client_command_send(cmd->client, cmd->conn,
2526 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2528 /* Notify application */
2529 COMMAND(SILC_STATUS_OK);
2532 silc_client_command_free(cmd);
2535 /* Register all default commands provided by the client library for the
2538 void silc_client_commands_register(SilcClient client)
2540 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2543 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2544 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2545 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2546 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2547 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2548 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2549 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2550 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2551 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2552 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2553 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2554 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2555 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2556 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2557 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2558 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2559 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2560 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2561 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2562 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2563 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2564 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2565 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2566 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2567 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2568 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2570 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2571 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2572 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2575 /* Unregister all commands. */
2577 void silc_client_commands_unregister(SilcClient client)
2579 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2580 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2581 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2582 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2583 SILC_CLIENT_CMDU(list, LIST, "LIST");
2584 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2585 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2586 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2587 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2588 SILC_CLIENT_CMDU(info, INFO, "INFO");
2589 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2590 SILC_CLIENT_CMDU(ping, PING, "PING");
2591 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2592 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2593 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2594 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2595 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2596 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2597 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2598 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2599 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2600 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2601 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2602 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2603 SILC_CLIENT_CMDU(users, USERS, "USERS");
2604 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2606 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2607 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2608 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2611 /**** Client side incoming command handling **********************************/
2613 void silc_client_command_process_whois(SilcClient client,
2614 SilcSocketConnection sock,
2615 SilcCommandPayload payload,
2616 SilcArgumentPayload args);
2618 /* Client is able to receive some command packets even though they are
2619 special case. Server may send WHOIS command to the client to retrieve
2620 Requested Attributes information for WHOIS query the server is
2621 processing. This function currently handles only the WHOIS command,
2622 but if in the future for commands may arrive then this can be made
2623 to support other commands too. */
2625 void silc_client_command_process(SilcClient client,
2626 SilcSocketConnection sock,
2627 SilcPacketContext *packet)
2629 SilcCommandPayload payload;
2630 SilcCommand command;
2631 SilcArgumentPayload args;
2633 /* Get command payload from packet */
2634 payload = silc_command_payload_parse(packet->buffer->data,
2635 packet->buffer->len);
2637 /* Silently ignore bad reply packet */
2638 SILC_LOG_DEBUG(("Bad command packet"));
2643 args = silc_command_get_args(payload);
2645 /* Get the command */
2646 command = silc_command_get(payload);
2649 case SILC_COMMAND_WHOIS:
2650 /* Ignore everything if requested by application */
2651 if (client->internal->params->ignore_requested_attributes)
2654 silc_client_command_process_whois(client, sock, payload, args);
2661 silc_command_payload_free(payload);
2664 void silc_client_command_process_whois(SilcClient client,
2665 SilcSocketConnection sock,
2666 SilcCommandPayload payload,
2667 SilcArgumentPayload args)
2672 SilcBuffer buffer, packet;
2674 SILC_LOG_DEBUG(("Received WHOIS command"));
2676 /* Try to take the Requested Attributes */
2677 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2681 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2685 /* Process requested attributes */
2686 buffer = silc_client_attributes_process(client, sock, attrs);
2688 silc_attribute_payload_list_free(attrs);
2692 /* Send the attributes back */
2694 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2696 silc_command_get_ident(payload),
2697 1, 11, buffer->data, buffer->len);
2698 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2699 NULL, 0, NULL, NULL, packet->data,
2701 silc_buffer_free(packet);
2702 silc_buffer_free(buffer);