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 && !strcmp(cmd->name, name))
81 /* Calls the command (executes it). Application can call this after
82 it has allocated the SilcClientCommandContext with the function
83 silc_client_command_alloc and found the command from the client
84 library by calling silc_client_command_find. This will execute
87 void silc_client_command_call(SilcClientCommand command,
88 SilcClientCommandContext cmd)
91 (*command->command)((void *)cmd, NULL);
94 /* Add new pending command to be executed when reply to a command has been
95 received. The `reply_cmd' is the command that will call the `callback'
96 with `context' when reply has been received. It can be SILC_COMMAND_NONE
97 to match any command with the `ident'. If `ident' is non-zero
98 the `callback' will be executed when received reply with command
99 identifier `ident'. If there already exists pending command for the
100 specified command, ident, callback and context this function has no
103 void silc_client_command_pending(SilcClientConnection conn,
104 SilcCommand reply_cmd,
106 SilcCommandCb callback,
109 SilcClientCommandPending *reply;
112 reply = silc_calloc(1, sizeof(*reply));
113 reply->reply_cmd = reply_cmd;
114 reply->ident = ident;
115 reply->context = context;
116 reply->callback = callback;
117 silc_dlist_add(conn->internal->pending_commands, reply);
120 /* Deletes pending command by reply command type. */
122 void silc_client_command_pending_del(SilcClientConnection conn,
123 SilcCommand reply_cmd,
126 SilcClientCommandPending *r;
128 if (!conn->internal->pending_commands)
131 silc_dlist_start(conn->internal->pending_commands);
132 while ((r = silc_dlist_get(conn->internal->pending_commands))
134 if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
136 && r->ident == ident) {
137 silc_dlist_del(conn->internal->pending_commands, r);
143 /* Checks for pending commands and marks callbacks to be called from
144 the command reply function. */
146 SilcClientCommandPendingCallbacks
147 silc_client_command_pending_check(SilcClientConnection conn,
148 SilcClientCommandReplyContext ctx,
151 SilcUInt32 *callbacks_count)
153 SilcClientCommandPending *r;
154 SilcClientCommandPendingCallbacks callbacks = NULL;
157 silc_dlist_start(conn->internal->pending_commands);
158 while ((r = silc_dlist_get(conn->internal->pending_commands))
160 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
161 && r->ident == ident) {
162 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
163 callbacks[i].context = r->context;
164 callbacks[i].callback = r->callback;
165 r->reply_check = TRUE;
171 *callbacks_count = i;
175 /* Allocate Command Context */
177 SilcClientCommandContext silc_client_command_alloc(void)
179 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
184 /* Free command context and its internals */
186 void silc_client_command_free(SilcClientCommandContext ctx)
189 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
191 if (ctx->users < 1) {
194 for (i = 0; i < ctx->argc; i++)
195 silc_free(ctx->argv[i]);
196 silc_free(ctx->argv_lens);
197 silc_free(ctx->argv_types);
202 /* Duplicate Command Context by adding reference counter. The context won't
203 be free'd untill it hits zero. */
205 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
208 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
213 /* Command WHOIS. This command is used to query information about
216 SILC_CLIENT_CMD_FUNC(whois)
218 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
219 SilcClientConnection conn = cmd->conn;
220 SilcBuffer buffer, attrs = NULL;
221 unsigned char count[4], *tmp = NULL;
224 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
225 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
229 /* Given without arguments fetches client's own information */
231 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
232 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
234 1, 4, buffer->data, buffer->len);
235 silc_buffer_free(buffer);
239 if (cmd->argc == 2) {
240 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
241 ++conn->cmd_ident, 1,
245 if (!strcasecmp(cmd->argv[2], "-details"))
246 attrs = silc_client_attributes_request(0);
248 if (!attrs || cmd->argc > 3) {
249 int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
250 SILC_PUT32_MSB(c, count);
254 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
255 ++conn->cmd_ident, 3,
256 1, cmd->argv[1], cmd->argv_lens[1],
257 2, tmp ? tmp : NULL, tmp ? 4 : 0,
258 3, attrs ? attrs->data : NULL,
259 attrs ? attrs->len : 0);
261 silc_client_packet_send(cmd->client, cmd->conn->sock,
262 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
263 buffer->data, buffer->len, TRUE);
264 silc_buffer_free(buffer);
266 /* Notify application */
267 COMMAND(SILC_STATUS_OK);
270 silc_client_command_free(cmd);
273 /* Command WHOWAS. This command is used to query history information about
274 specific user that used to exist in the network. */
276 SILC_CLIENT_CMD_FUNC(whowas)
278 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
279 SilcClientConnection conn = cmd->conn;
281 unsigned char count[4];
284 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
285 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
289 if (cmd->argc < 2 || cmd->argc > 3) {
290 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
291 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
292 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
293 SILC_STATUS_ERR_TOO_MANY_PARAMS));
297 if (cmd->argc == 2) {
298 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
299 ++conn->cmd_ident, 1,
303 int c = atoi(cmd->argv[2]);
304 memset(count, 0, sizeof(count));
305 SILC_PUT32_MSB(c, count);
306 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
307 ++conn->cmd_ident, 2,
308 1, cmd->argv[1], cmd->argv_lens[1],
309 2, count, sizeof(count));
311 silc_client_packet_send(cmd->client, cmd->conn->sock,
312 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
313 buffer->data, buffer->len, TRUE);
314 silc_buffer_free(buffer);
316 /* Notify application */
317 COMMAND(SILC_STATUS_OK);
320 silc_client_command_free(cmd);
323 /* Command IDENTIFY. This command is used to query information about
324 specific user, especially ID's.
326 NOTE: This command is used only internally by the client library
327 and application MUST NOT call this command directly. */
329 SILC_CLIENT_CMD_FUNC(identify)
331 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
332 SilcClientConnection conn = cmd->conn;
334 unsigned char count[4];
337 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
338 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
342 if (cmd->argc < 2 || cmd->argc > 3)
345 if (cmd->argc == 2) {
346 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
347 ++conn->cmd_ident, 1,
351 int c = atoi(cmd->argv[2]);
352 memset(count, 0, sizeof(count));
353 SILC_PUT32_MSB(c, count);
354 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
355 ++conn->cmd_ident, 2,
358 4, count, sizeof(count));
361 silc_client_packet_send(cmd->client, cmd->conn->sock,
362 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
363 buffer->data, buffer->len, TRUE);
364 silc_buffer_free(buffer);
367 silc_client_command_free(cmd);
370 /* Command NICK. Shows current nickname/sets new nickname on current
373 SILC_CLIENT_CMD_FUNC(nick)
375 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
376 SilcClientConnection conn = cmd->conn;
380 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
381 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
386 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
387 "Usage: /NICK <nickname>");
388 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
392 if (!strcmp(conn->nickname, cmd->argv[1]))
395 /* Show current nickname */
398 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
399 "Your nickname is %s on server %s",
400 conn->nickname, conn->remote_host);
402 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
403 "Your nickname is %s", conn->nickname);
406 COMMAND(SILC_STATUS_OK);
410 if (cmd->argv_lens[1] > 128)
411 cmd->argv_lens[1] = 128;
413 /* Send the NICK command */
414 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
418 ++cmd->conn->cmd_ident);
419 silc_client_packet_send(cmd->client, cmd->conn->sock,
420 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
421 buffer->data, buffer->len, TRUE);
422 silc_buffer_free(buffer);
425 silc_client_command_free(cmd);
428 /* Command LIST. Lists channels on the current server. */
430 SILC_CLIENT_CMD_FUNC(list)
432 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
433 SilcClientConnection conn = cmd->conn;
434 SilcIDCacheEntry id_cache = NULL;
435 SilcChannelEntry channel;
436 SilcBuffer buffer, idp = NULL;
440 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
441 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
445 if (cmd->argc == 2) {
448 /* Get the Channel ID of the channel */
449 if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
451 channel = (SilcChannelEntry)id_cache->context;
452 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
457 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
458 ++conn->cmd_ident, 0);
460 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
461 ++conn->cmd_ident, 1,
462 1, idp->data, idp->len);
464 silc_client_packet_send(cmd->client, cmd->conn->sock,
465 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
466 buffer->data, buffer->len, TRUE);
467 silc_buffer_free(buffer);
469 silc_buffer_free(idp);
471 /* Notify application */
472 COMMAND(SILC_STATUS_OK);
475 silc_client_command_free(cmd);
478 /* Command TOPIC. Sets/shows topic on a channel. */
480 SILC_CLIENT_CMD_FUNC(topic)
482 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
483 SilcClientConnection conn = cmd->conn;
484 SilcIDCacheEntry id_cache = NULL;
485 SilcChannelEntry channel;
486 SilcBuffer buffer, idp;
490 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
491 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
495 if (cmd->argc < 2 || cmd->argc > 3) {
496 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
497 "Usage: /TOPIC <channel> [<topic>]");
498 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
499 SILC_STATUS_ERR_TOO_MANY_PARAMS));
503 if (cmd->argv[1][0] == '*') {
504 if (!conn->current_channel) {
505 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
508 name = conn->current_channel->channel_name;
513 if (!conn->current_channel) {
514 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
518 /* Get the Channel ID of the channel */
519 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
521 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
525 channel = (SilcChannelEntry)id_cache->context;
527 /* Send TOPIC command to the server */
528 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
530 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
531 ++conn->cmd_ident, 2,
532 1, idp->data, idp->len,
534 strlen(cmd->argv[2]));
536 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
537 ++conn->cmd_ident, 1,
538 1, idp->data, idp->len);
539 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
540 0, NULL, NULL, buffer->data, buffer->len, TRUE);
541 silc_buffer_free(buffer);
542 silc_buffer_free(idp);
544 /* Notify application */
545 COMMAND(SILC_STATUS_OK);
548 silc_client_command_free(cmd);
551 /* Command INVITE. Invites specific client to join a channel. This is
552 also used to mange the invite list of the channel. */
554 SILC_CLIENT_CMD_FUNC(invite)
556 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
557 SilcClient client = cmd->client;
558 SilcClientConnection conn = cmd->conn;
559 SilcClientEntry client_entry = NULL;
560 SilcChannelEntry channel;
561 SilcBuffer buffer, clidp, chidp;
563 char *nickname = NULL, *name;
567 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
568 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
573 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
574 "Usage: /INVITE <channel> [<nickname>[@server>]"
575 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
576 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
580 if (cmd->argv[1][0] == '*') {
581 if (!conn->current_channel) {
582 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
586 channel = conn->current_channel;
590 channel = silc_client_get_channel(cmd->client, conn, name);
592 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
597 /* Parse the typed nickname. */
598 if (cmd->argc == 3) {
599 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
600 if (client->internal->params->nickname_parse)
601 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
603 nickname = strdup(cmd->argv[2]);
605 /* Find client entry */
606 client_entry = silc_idlist_get_client(client, conn, nickname,
610 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
614 /* Client entry not found, it was requested thus mark this to be
616 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
618 silc_client_command_invite,
619 silc_client_command_dup(cmd));
624 invite = cmd->argv[2];
626 if (cmd->argv[2][0] == '+')
633 /* Send the command */
634 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
636 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
637 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
638 ++conn->cmd_ident, 3,
639 1, chidp->data, chidp->len,
640 2, clidp->data, clidp->len,
641 type, invite, invite ?
643 silc_buffer_free(clidp);
645 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
646 ++conn->cmd_ident, 2,
647 1, chidp->data, chidp->len,
648 type, invite, invite ?
652 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
653 0, NULL, NULL, buffer->data, buffer->len, TRUE);
654 silc_buffer_free(buffer);
655 silc_buffer_free(chidp);
657 /* Notify application */
658 COMMAND(SILC_STATUS_OK);
662 silc_client_command_free(cmd);
667 SilcClientConnection conn;
670 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
672 QuitInternal q = (QuitInternal)context;
674 /* Close connection */
675 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
676 silc_client_close_connection(q->client, q->conn->sock->user_data);
681 /* Command QUIT. Closes connection with current server. */
683 SILC_CLIENT_CMD_FUNC(quit)
685 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
690 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
691 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
696 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
697 &cmd->argv[1], &cmd->argv_lens[1],
698 &cmd->argv_types[1], 0);
700 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
701 NULL, NULL, NULL, 0);
702 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
704 buffer->data, buffer->len, TRUE);
705 silc_buffer_free(buffer);
707 q = silc_calloc(1, sizeof(*q));
708 q->client = cmd->client;
711 /* Sleep for a while */
714 /* We quit the connection with little timeout */
715 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
716 silc_client_command_quit_cb, (void *)q,
717 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
719 /* Notify application */
720 COMMAND(SILC_STATUS_OK);
723 silc_client_command_free(cmd);
726 /* Timeout callback to remove the killed client from cache */
728 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
730 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
731 SilcClient client = cmd->client;
732 SilcClientConnection conn = cmd->conn;
733 SilcClientEntry target;
734 char *nickname = NULL;
736 /* Parse the typed nickname. */
737 if (client->internal->params->nickname_parse)
738 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
740 nickname = strdup(cmd->argv[1]);
742 /* Get the target client */
743 target = silc_idlist_get_client(cmd->client, conn, nickname,
744 cmd->argv[1], FALSE);
746 /* Remove the client from all channels and free it */
747 silc_client_del_client(client, conn, target);
750 silc_client_command_free(cmd);
753 /* Kill command's pending command callback to actually remove the killed
754 client from our local cache. */
756 SILC_CLIENT_CMD_FUNC(kill_remove)
758 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
759 SilcClientCommandReplyContext reply =
760 (SilcClientCommandReplyContext)context2;
763 silc_command_get_status(reply->payload, &status, NULL);
764 if (status == SILC_STATUS_OK) {
765 /* Remove with timeout */
766 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
767 silc_client_command_kill_remove_later, context,
768 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
772 silc_client_command_free(cmd);
775 /* Command KILL. Router operator can use this command to remove an client
776 fromthe SILC Network. */
778 SILC_CLIENT_CMD_FUNC(kill)
780 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
781 SilcClient client = cmd->client;
782 SilcClientConnection conn = cmd->conn;
783 SilcBuffer buffer, idp;
784 SilcClientEntry target;
785 char *nickname = NULL;
788 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
789 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
794 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
795 "Usage: /KILL <nickname> [<comment>]");
796 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
800 /* Parse the typed nickname. */
801 if (client->internal->params->nickname_parse)
802 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
804 nickname = strdup(cmd->argv[1]);
806 /* Get the target client */
807 target = silc_idlist_get_client(cmd->client, conn, nickname,
811 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
815 /* Client entry not found, it was requested thus mark this to be
817 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
819 silc_client_command_kill,
820 silc_client_command_dup(cmd));
825 /* Send the KILL command to the server */
826 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
828 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
829 ++conn->cmd_ident, 1,
830 1, idp->data, idp->len);
832 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
833 ++conn->cmd_ident, 2,
834 1, idp->data, idp->len,
836 strlen(cmd->argv[2]));
837 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
838 0, NULL, NULL, buffer->data, buffer->len, TRUE);
839 silc_buffer_free(buffer);
840 silc_buffer_free(idp);
842 /* Notify application */
843 COMMAND(SILC_STATUS_OK);
845 /* Register a pending callback that will actually remove the killed
846 client from our cache. */
847 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
848 silc_client_command_kill_remove,
849 silc_client_command_dup(cmd));
853 silc_client_command_free(cmd);
856 /* Command INFO. Request information about specific server. If specific
857 server is not provided the current server is used. */
859 SILC_CLIENT_CMD_FUNC(info)
861 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
862 SilcClientConnection conn = cmd->conn;
867 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
868 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
873 name = strdup(cmd->argv[1]);
875 /* Send the command */
877 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
878 1, name, strlen(name));
880 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
881 NULL, NULL, NULL, 0);
882 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
883 0, NULL, NULL, buffer->data, buffer->len, TRUE);
884 silc_buffer_free(buffer);
888 /* Notify application */
889 COMMAND(SILC_STATUS_OK);
892 silc_client_command_free(cmd);
895 /* Command STATS. Shows server and network statistics. */
897 SILC_CLIENT_CMD_FUNC(stats)
899 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
900 SilcClientConnection conn = cmd->conn;
901 SilcBuffer buffer, idp = NULL;
904 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
905 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
909 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
911 /* Send the command */
912 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
913 ++conn->cmd_ident, 1,
914 SILC_ID_SERVER, idp->data, idp->len);
915 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
916 0, NULL, NULL, buffer->data, buffer->len, TRUE);
917 silc_buffer_free(buffer);
918 silc_buffer_free(idp);
920 /* Notify application */
921 COMMAND(SILC_STATUS_OK);
924 silc_client_command_free(cmd);
927 /* Command PING. Sends ping to server. This is used to test the
928 communication channel. */
930 SILC_CLIENT_CMD_FUNC(ping)
932 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
933 SilcClientConnection conn = cmd->conn;
939 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
940 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
944 /* Send the command */
945 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
946 1, conn->remote_id_data,
947 silc_id_get_len(conn->remote_id,
949 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
950 0, NULL, NULL, buffer->data, buffer->len, TRUE);
951 silc_buffer_free(buffer);
953 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
956 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
957 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
961 /* Start counting time */
962 for (i = 0; i < conn->internal->ping_count; i++) {
963 if (conn->internal->ping[i].dest_id == NULL) {
964 conn->internal->ping[i].start_time = time(NULL);
965 conn->internal->ping[i].dest_id = id;
966 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
970 if (i >= conn->internal->ping_count) {
971 i = conn->internal->ping_count;
972 conn->internal->ping =
973 silc_realloc(conn->internal->ping,
974 sizeof(*conn->internal->ping) * (i + 1));
975 conn->internal->ping[i].start_time = time(NULL);
976 conn->internal->ping[i].dest_id = id;
977 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
978 conn->internal->ping_count++;
981 /* Notify application */
982 COMMAND(SILC_STATUS_OK);
985 silc_client_command_free(cmd);
988 /* Command JOIN. Joins to a channel. */
990 SILC_CLIENT_CMD_FUNC(join)
992 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
993 SilcClientConnection conn = cmd->conn;
994 SilcChannelEntry channel;
995 SilcBuffer buffer, idp, auth = NULL;
996 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
997 int i, passphrase_len = 0;
1000 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1001 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1005 if (cmd->argc < 2) {
1006 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1010 /* See if we have joined to the requested channel already */
1011 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1012 if (channel && silc_client_on_channel(channel, conn->local_entry))
1015 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1017 if (cmd->argv_lens[1] > 256)
1018 cmd->argv_lens[1] = 256;
1020 name = cmd->argv[1];
1022 for (i = 2; i < cmd->argc; i++) {
1023 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1024 cipher = cmd->argv[i + 1];
1026 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1027 hmac = cmd->argv[i + 1];
1029 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1030 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1031 cmd->client->private_key,
1033 cmd->client->sha1hash,
1038 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1039 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1040 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1041 cmd->argv_lens[i], 0);
1042 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1043 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1044 0, pu8, passphrase_len);
1047 passphrase = strdup(cmd->argv[i]);
1048 passphrase_len = cmd->argv_lens[i];
1053 /* Send JOIN command to the server */
1055 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1056 1, name, strlen(name),
1057 2, idp->data, idp->len,
1058 3, passphrase, passphrase_len,
1059 4, cipher, cipher ? strlen(cipher) : 0,
1060 5, hmac, hmac ? strlen(hmac) : 0,
1061 6, auth ? auth->data : NULL,
1062 auth ? auth->len : 0);
1063 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1064 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1065 silc_buffer_free(buffer);
1066 silc_buffer_free(idp);
1068 silc_buffer_free(auth);
1069 silc_free(passphrase);
1071 /* Notify application */
1072 COMMAND(SILC_STATUS_OK);
1075 silc_client_command_free(cmd);
1078 /* MOTD command. Requests motd from server. */
1080 SILC_CLIENT_CMD_FUNC(motd)
1082 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1083 SilcClientConnection conn = cmd->conn;
1087 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1088 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1092 if (cmd->argc < 1 || cmd->argc > 2) {
1093 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1094 "Usage: /MOTD [<server>]");
1095 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1096 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1100 /* Send TOPIC command to the server */
1102 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1103 1, conn->remote_host,
1104 strlen(conn->remote_host));
1106 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1109 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1110 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1111 silc_buffer_free(buffer);
1113 /* Notify application */
1114 COMMAND(SILC_STATUS_OK);
1117 silc_client_command_free(cmd);
1120 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1121 modes as client cannot set itself server/router operator privileges. */
1123 SILC_CLIENT_CMD_FUNC(umode)
1125 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1126 SilcClientConnection conn = cmd->conn;
1127 SilcBuffer buffer, idp;
1128 unsigned char *cp, modebuf[4];
1129 SilcUInt32 mode, add, len;
1133 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1134 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1138 if (cmd->argc < 2) {
1139 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1140 "Usage: /UMODE +|-<modes>");
1141 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1145 mode = conn->local_entry->mode;
1147 /* Are we adding or removing mode */
1148 if (cmd->argv[1][0] == '-')
1154 cp = cmd->argv[1] + 1;
1156 for (i = 0; i < len; i++) {
1161 mode |= SILC_UMODE_SERVER_OPERATOR;
1162 mode |= SILC_UMODE_ROUTER_OPERATOR;
1163 mode |= SILC_UMODE_GONE;
1164 mode |= SILC_UMODE_INDISPOSED;
1165 mode |= SILC_UMODE_BUSY;
1166 mode |= SILC_UMODE_PAGE;
1167 mode |= SILC_UMODE_HYPER;
1168 mode |= SILC_UMODE_ROBOT;
1169 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1170 mode |= SILC_UMODE_REJECT_WATCHING;
1172 mode = SILC_UMODE_NONE;
1177 mode |= SILC_UMODE_SERVER_OPERATOR;
1179 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1183 mode |= SILC_UMODE_ROUTER_OPERATOR;
1185 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1189 mode |= SILC_UMODE_GONE;
1191 mode &= ~SILC_UMODE_GONE;
1195 mode |= SILC_UMODE_INDISPOSED;
1197 mode &= ~SILC_UMODE_INDISPOSED;
1201 mode |= SILC_UMODE_BUSY;
1203 mode &= ~SILC_UMODE_BUSY;
1207 mode |= SILC_UMODE_PAGE;
1209 mode &= ~SILC_UMODE_PAGE;
1213 mode |= SILC_UMODE_HYPER;
1215 mode &= ~SILC_UMODE_HYPER;
1219 mode |= SILC_UMODE_ROBOT;
1221 mode &= ~SILC_UMODE_ROBOT;
1225 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1227 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1231 mode |= SILC_UMODE_REJECT_WATCHING;
1233 mode &= ~SILC_UMODE_REJECT_WATCHING;
1237 mode |= SILC_UMODE_BLOCK_INVITE;
1239 mode &= ~SILC_UMODE_BLOCK_INVITE;
1242 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1248 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1249 SILC_PUT32_MSB(mode, modebuf);
1251 /* Send the command packet. We support sending only one mode at once
1252 that requires an argument. */
1254 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1255 1, idp->data, idp->len,
1256 2, modebuf, sizeof(modebuf));
1257 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1258 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1259 silc_buffer_free(buffer);
1260 silc_buffer_free(idp);
1262 /* Notify application */
1263 COMMAND(SILC_STATUS_OK);
1266 silc_client_command_free(cmd);
1269 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1270 can be set several at once. Those modes that require argument must be set
1271 separately (unless set with modes that does not require arguments). */
1273 SILC_CLIENT_CMD_FUNC(cmode)
1275 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1276 SilcClientConnection conn = cmd->conn;
1277 SilcChannelEntry channel;
1278 SilcBuffer buffer, chidp, auth = NULL;
1279 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1280 SilcUInt32 mode, add, type, len, arg_len = 0;
1284 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1285 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1289 if (cmd->argc < 3) {
1290 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1291 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1292 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1296 if (cmd->argv[1][0] == '*') {
1297 if (!conn->current_channel) {
1298 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1302 channel = conn->current_channel;
1304 name = cmd->argv[1];
1306 channel = silc_client_get_channel(cmd->client, conn, name);
1308 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1313 mode = channel->mode;
1315 /* Are we adding or removing mode */
1316 if (cmd->argv[2][0] == '-')
1321 /* Argument type to be sent to server */
1325 cp = cmd->argv[2] + 1;
1327 for (i = 0; i < len; i++) {
1331 mode |= SILC_CHANNEL_MODE_PRIVATE;
1333 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1337 mode |= SILC_CHANNEL_MODE_SECRET;
1339 mode &= ~SILC_CHANNEL_MODE_SECRET;
1343 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1345 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1349 mode |= SILC_CHANNEL_MODE_INVITE;
1351 mode &= ~SILC_CHANNEL_MODE_INVITE;
1355 mode |= SILC_CHANNEL_MODE_TOPIC;
1357 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1361 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1363 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1367 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1369 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1374 mode |= SILC_CHANNEL_MODE_ULIMIT;
1376 if (cmd->argc < 4) {
1377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1378 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1379 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1382 ll = atoi(cmd->argv[3]);
1383 SILC_PUT32_MSB(ll, tmp);
1387 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1392 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1394 if (cmd->argc < 4) {
1395 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1396 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1397 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1401 arg_len = cmd->argv_lens[3];
1403 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1408 mode |= SILC_CHANNEL_MODE_CIPHER;
1410 if (cmd->argc < 4) {
1411 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1412 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1413 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1417 arg_len = cmd->argv_lens[3];
1419 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1424 mode |= SILC_CHANNEL_MODE_HMAC;
1426 if (cmd->argc < 4) {
1427 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1428 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1429 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1433 arg_len = cmd->argv_lens[3];
1435 mode &= ~SILC_CHANNEL_MODE_HMAC;
1440 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1442 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1443 cmd->client->private_key,
1445 cmd->client->sha1hash,
1449 arg_len = auth->len;
1451 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1455 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1461 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1462 SILC_PUT32_MSB(mode, modebuf);
1464 /* Send the command packet. We support sending only one mode at once
1465 that requires an argument. */
1468 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1469 1, chidp->data, chidp->len,
1470 2, modebuf, sizeof(modebuf),
1471 type, arg, arg_len);
1474 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1475 1, chidp->data, chidp->len,
1476 2, modebuf, sizeof(modebuf));
1479 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1480 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1481 silc_buffer_free(buffer);
1482 silc_buffer_free(chidp);
1484 silc_buffer_free(auth);
1486 /* Notify application */
1487 COMMAND(SILC_STATUS_OK);
1490 silc_client_command_free(cmd);
1493 /* CUMODE command. Changes client's mode on a channel. */
1495 SILC_CLIENT_CMD_FUNC(cumode)
1497 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1498 SilcClient client = cmd->client;
1499 SilcClientConnection conn = cmd->conn;
1500 SilcChannelEntry channel;
1501 SilcChannelUser chu;
1502 SilcClientEntry client_entry;
1503 SilcBuffer buffer, clidp, chidp, auth = NULL;
1504 unsigned char *name, *cp, modebuf[4];
1505 SilcUInt32 mode = 0, add, len;
1506 char *nickname = NULL;
1510 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1511 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1515 if (cmd->argc < 4) {
1516 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1517 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1518 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1522 if (cmd->argv[1][0] == '*') {
1523 if (!conn->current_channel) {
1524 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1528 channel = conn->current_channel;
1530 name = cmd->argv[1];
1532 channel = silc_client_get_channel(cmd->client, conn, name);
1534 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1539 /* Parse the typed nickname. */
1540 if (client->internal->params->nickname_parse)
1541 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1543 nickname = strdup(cmd->argv[3]);
1545 /* Find client entry */
1546 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1547 cmd->argv[3], TRUE);
1548 if (!client_entry) {
1550 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1554 /* Client entry not found, it was requested thus mark this to be
1556 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1558 silc_client_command_cumode,
1559 silc_client_command_dup(cmd));
1564 /* Get the current mode */
1565 chu = silc_client_on_channel(channel, client_entry);
1569 /* Are we adding or removing mode */
1570 if (cmd->argv[2][0] == '-')
1576 cp = cmd->argv[2] + 1;
1578 for (i = 0; i < len; i++) {
1582 mode |= SILC_CHANNEL_UMODE_CHANFO;
1583 mode |= SILC_CHANNEL_UMODE_CHANOP;
1584 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1585 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1586 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1588 mode = SILC_CHANNEL_UMODE_NONE;
1593 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1594 cmd->client->private_key,
1596 cmd->client->sha1hash,
1599 mode |= SILC_CHANNEL_UMODE_CHANFO;
1601 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1606 mode |= SILC_CHANNEL_UMODE_CHANOP;
1608 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1612 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1614 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1618 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1620 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1624 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1626 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1630 mode |= SILC_CHANNEL_UMODE_QUIET;
1632 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1635 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1641 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1642 SILC_PUT32_MSB(mode, modebuf);
1643 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1645 /* Send the command packet. We support sending only one mode at once
1646 that requires an argument. */
1647 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1649 1, chidp->data, chidp->len,
1651 3, clidp->data, clidp->len,
1652 4, auth ? auth->data : NULL,
1653 auth ? auth->len : 0);
1655 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1656 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1657 silc_buffer_free(buffer);
1658 silc_buffer_free(chidp);
1659 silc_buffer_free(clidp);
1661 silc_buffer_free(auth);
1663 /* Notify application */
1664 COMMAND(SILC_STATUS_OK);
1667 silc_free(nickname);
1668 silc_client_command_free(cmd);
1671 /* KICK command. Kicks a client out of channel. */
1673 SILC_CLIENT_CMD_FUNC(kick)
1675 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1676 SilcClient client = cmd->client;
1677 SilcClientConnection conn = cmd->conn;
1678 SilcIDCacheEntry id_cache = NULL;
1679 SilcChannelEntry channel;
1680 SilcBuffer buffer, idp, idp2;
1681 SilcClientEntry target;
1683 char *nickname = NULL;
1686 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1687 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1691 if (cmd->argc < 3) {
1692 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1693 "Usage: /KICK <channel> <nickname> [<comment>]");
1694 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1698 if (cmd->argv[1][0] == '*') {
1699 if (!conn->current_channel) {
1700 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1703 name = conn->current_channel->channel_name;
1705 name = cmd->argv[1];
1708 if (!conn->current_channel) {
1709 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1713 /* Get the Channel ID of the channel */
1714 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1716 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1720 channel = (SilcChannelEntry)id_cache->context;
1722 /* Parse the typed nickname. */
1723 if (client->internal->params->nickname_parse)
1724 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1726 nickname = strdup(cmd->argv[2]);
1728 /* Get the target client */
1729 target = silc_idlist_get_client(cmd->client, conn, nickname,
1730 cmd->argv[2], FALSE);
1732 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1733 "No such client: %s", cmd->argv[2]);
1734 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1738 /* Send KICK command to the server */
1739 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1740 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1742 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1743 1, idp->data, idp->len,
1744 2, idp2->data, idp2->len);
1746 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1747 1, idp->data, idp->len,
1748 2, idp2->data, idp2->len,
1750 strlen(cmd->argv[3]));
1751 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1752 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1753 silc_buffer_free(buffer);
1754 silc_buffer_free(idp);
1755 silc_buffer_free(idp2);
1757 /* Notify application */
1758 COMMAND(SILC_STATUS_OK);
1761 silc_free(nickname);
1762 silc_client_command_free(cmd);
1765 static void silc_client_command_oper_send(unsigned char *data,
1766 SilcUInt32 data_len, void *context)
1768 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1769 SilcClientConnection conn = cmd->conn;
1770 SilcBuffer buffer, auth;
1772 if (cmd->argc >= 3) {
1773 /* Encode the public key authentication payload */
1774 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1775 cmd->client->private_key,
1777 conn->internal->hash,
1781 /* Encode the password authentication payload */
1782 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1786 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1788 strlen(cmd->argv[1]),
1789 2, auth ? auth->data : NULL,
1790 auth ? auth->len : 0);
1791 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1792 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1794 silc_buffer_free(buffer);
1795 silc_buffer_free(auth);
1797 /* Notify application */
1798 COMMAND(SILC_STATUS_OK);
1801 /* OPER command. Used to obtain server operator privileges. */
1803 SILC_CLIENT_CMD_FUNC(oper)
1805 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1806 SilcClientConnection conn = cmd->conn;
1809 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1810 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1814 if (cmd->argc < 2) {
1815 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1816 "Usage: /OPER <username> [-pubkey]");
1817 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1821 if (cmd->argc < 3) {
1822 /* Get passphrase */
1823 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1824 silc_client_command_oper_send,
1829 silc_client_command_oper_send(NULL, 0, context);
1832 silc_client_command_free(cmd);
1835 static void silc_client_command_silcoper_send(unsigned char *data,
1836 SilcUInt32 data_len,
1839 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1840 SilcClientConnection conn = cmd->conn;
1841 SilcBuffer buffer, auth;
1843 if (cmd->argc >= 3) {
1844 /* Encode the public key authentication payload */
1845 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1846 cmd->client->private_key,
1848 conn->internal->hash,
1852 /* Encode the password authentication payload */
1853 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1857 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1859 strlen(cmd->argv[1]),
1860 2, auth ? auth->data : NULL,
1861 auth ? auth->len : 0);
1862 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1863 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1865 silc_buffer_free(buffer);
1866 silc_buffer_free(auth);
1868 /* Notify application */
1869 COMMAND(SILC_STATUS_OK);
1872 /* SILCOPER command. Used to obtain router operator privileges. */
1874 SILC_CLIENT_CMD_FUNC(silcoper)
1876 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1877 SilcClientConnection conn = cmd->conn;
1880 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1881 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1885 if (cmd->argc < 2) {
1886 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1887 "Usage: /SILCOPER <username> [-pubkey]");
1888 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1892 if (cmd->argc < 3) {
1893 /* Get passphrase */
1894 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1895 silc_client_command_silcoper_send,
1900 silc_client_command_silcoper_send(NULL, 0, context);
1903 silc_client_command_free(cmd);
1906 /* Command BAN. This is used to manage the ban list of the channel. */
1908 SILC_CLIENT_CMD_FUNC(ban)
1910 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1911 SilcClientConnection conn = cmd->conn;
1912 SilcChannelEntry channel;
1913 SilcBuffer buffer, chidp;
1915 char *name, *ban = NULL;
1918 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1919 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1923 if (cmd->argc < 2) {
1924 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1925 "Usage: /BAN <channel> "
1926 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1927 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1931 if (cmd->argv[1][0] == '*') {
1932 if (!conn->current_channel) {
1933 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1937 channel = conn->current_channel;
1939 name = cmd->argv[1];
1941 channel = silc_client_get_channel(cmd->client, conn, name);
1943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1948 if (cmd->argc == 3) {
1949 if (cmd->argv[2][0] == '+')
1958 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1960 /* Send the command */
1961 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1962 ++conn->cmd_ident, 2,
1963 1, chidp->data, chidp->len,
1964 type, ban, ban ? strlen(ban) : 0);
1965 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1966 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1967 silc_buffer_free(buffer);
1968 silc_buffer_free(chidp);
1970 /* Notify application */
1971 COMMAND(SILC_STATUS_OK);
1974 silc_client_command_free(cmd);
1977 /* Command DETACH. This is used to detach from the server */
1979 SILC_CLIENT_CMD_FUNC(detach)
1981 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1982 SilcClientConnection conn = cmd->conn;
1986 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1987 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1991 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1992 ++conn->cmd_ident, 0);
1993 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1994 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1995 silc_buffer_free(buffer);
1997 /* Notify application */
1998 COMMAND(SILC_STATUS_OK);
2001 silc_client_command_free(cmd);
2004 /* Command WATCH. */
2006 SILC_CLIENT_CMD_FUNC(watch)
2008 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2009 SilcClientConnection conn = cmd->conn;
2010 SilcBuffer buffer, idp = NULL;
2014 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2015 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2019 if (cmd->argc < 3) {
2020 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2024 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2026 if (!strcasecmp(cmd->argv[1], "-add")) {
2028 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2031 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2035 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2036 ++conn->cmd_ident, 2,
2037 1, idp->data, idp->len,
2040 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2041 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2042 silc_buffer_free(buffer);
2044 /* Notify application */
2045 COMMAND(SILC_STATUS_OK);
2049 silc_buffer_free(idp);
2050 silc_client_command_free(cmd);
2053 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2055 SILC_CLIENT_CMD_FUNC(leave)
2057 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2058 SilcClientConnection conn = cmd->conn;
2059 SilcChannelEntry channel;
2060 SilcChannelUser chu;
2061 SilcBuffer buffer, idp;
2065 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2066 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2070 if (cmd->argc != 2) {
2071 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2072 "Usage: /LEAVE <channel>");
2073 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2077 if (cmd->argv[1][0] == '*') {
2078 if (!conn->current_channel) {
2079 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2082 name = conn->current_channel->channel_name;
2084 name = cmd->argv[1];
2087 /* Get the channel entry */
2088 channel = silc_client_get_channel(cmd->client, conn, name);
2090 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2094 /* Remove us from channel */
2095 chu = silc_client_on_channel(channel, conn->local_entry);
2097 silc_hash_table_del(chu->client->channels, chu->channel);
2098 silc_hash_table_del(chu->channel->user_list, chu->client);
2102 /* Send LEAVE command to the server */
2103 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2104 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2105 1, idp->data, idp->len);
2106 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2107 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2108 silc_buffer_free(buffer);
2109 silc_buffer_free(idp);
2111 /* Notify application */
2112 COMMAND(SILC_STATUS_OK);
2114 if (conn->current_channel == channel)
2115 conn->current_channel = NULL;
2117 silc_client_del_channel(cmd->client, cmd->conn, channel);
2120 silc_client_command_free(cmd);
2123 /* Command USERS. Requests the USERS of the clients joined on requested
2126 SILC_CLIENT_CMD_FUNC(users)
2128 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2129 SilcClientConnection conn = cmd->conn;
2134 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2135 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2139 if (cmd->argc != 2) {
2140 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2141 "Usage: /USERS <channel>");
2142 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2146 if (cmd->argv[1][0] == '*') {
2147 if (!conn->current_channel) {
2148 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2151 name = conn->current_channel->channel_name;
2153 name = cmd->argv[1];
2156 /* Send USERS command to the server */
2157 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2158 ++conn->cmd_ident, 1,
2159 2, name, strlen(name));
2160 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2161 NULL, 0, NULL, NULL, buffer->data,
2163 silc_buffer_free(buffer);
2165 /* Notify application */
2166 COMMAND(SILC_STATUS_OK);
2169 silc_client_command_free(cmd);
2172 /* Command GETKEY. Used to fetch remote client's public key. */
2174 SILC_CLIENT_CMD_FUNC(getkey)
2176 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2177 SilcClientConnection conn = cmd->conn;
2178 SilcClient client = cmd->client;
2179 SilcClientEntry client_entry = NULL;
2180 SilcServerEntry server_entry = NULL;
2181 char *nickname = NULL;
2182 SilcBuffer idp, buffer;
2184 SILC_LOG_DEBUG(("Start"));
2187 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2188 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2192 if (cmd->argc < 2) {
2193 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2194 "Usage: /GETKEY <nickname or server name>");
2195 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2199 /* Parse the typed nickname. */
2200 if (client->internal->params->nickname_parse)
2201 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2203 nickname = strdup(cmd->argv[1]);
2205 /* Find client entry */
2206 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2208 if (!client_entry) {
2209 /* Check whether user requested server actually */
2210 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2212 if (!server_entry) {
2213 /* No. what ever user wants we don't have it, so resolve it. We
2214 will first try to resolve the client, and if that fails then
2215 we'll try to resolve the server. */
2217 if (!cmd->pending) {
2218 /* This will send the IDENTIFY command for nickname */
2219 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2220 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2222 silc_client_command_getkey,
2223 silc_client_command_dup(cmd));
2227 SilcClientCommandReplyContext reply =
2228 (SilcClientCommandReplyContext)context2;
2231 /* If nickname was not found, then resolve the server. */
2232 silc_command_get_status(reply->payload, NULL, &error);
2233 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2234 /* This sends the IDENTIFY command to resolve the server. */
2235 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2237 silc_client_command_reply_identify_i, 0,
2239 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2241 2, cmd->argv[1], cmd->argv_lens[1]);
2242 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2244 silc_client_command_getkey,
2245 silc_client_command_dup(cmd));
2249 /* If server was not found, then we've resolved both nickname and
2250 server and did not find anybody. */
2251 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2252 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2253 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2254 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2255 silc_get_status_message(error));
2256 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2260 COMMAND_ERROR(error);
2265 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2267 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2270 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2271 1, idp->data, idp->len);
2272 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2273 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2274 silc_buffer_free(buffer);
2275 silc_buffer_free(idp);
2277 /* Notify application */
2278 COMMAND(SILC_STATUS_OK);
2281 silc_free(nickname);
2282 silc_client_command_free(cmd);
2285 /* Register a new command indicated by the `command' to the SILC client.
2286 The `name' is optional command name. If provided the command may be
2287 searched using the silc_client_command_find by that name. The
2288 `command_function' is the function to be called when the command is
2289 executed, and the `command_reply_function' is the function to be
2290 called after the server has sent reply back to the command.
2292 The `ident' is optional identifier for the command. If non-zero
2293 the `command_reply_function' for the command type `command' will be
2294 called only if the command reply sent by server includes the
2295 command identifier `ident'. Application usually does not need it
2296 and set it to zero value. */
2298 bool silc_client_command_register(SilcClient client,
2299 SilcCommand command,
2301 SilcCommandCb command_function,
2302 SilcCommandCb command_reply_function,
2306 SilcClientCommand cmd;
2308 cmd = silc_calloc(1, sizeof(*cmd));
2310 cmd->command = command_function;
2311 cmd->reply = command_reply_function;
2312 cmd->name = name ? strdup(name) : NULL;
2313 cmd->max_args = max_args;
2316 silc_list_add(client->internal->commands, cmd);
2321 /* Unregister a command indicated by the `command' with command function
2322 `command_function' and command reply function `command_reply_function'.
2323 Returns TRUE if the command was found and unregistered. */
2325 bool silc_client_command_unregister(SilcClient client,
2326 SilcCommand command,
2327 SilcCommandCb command_function,
2328 SilcCommandCb command_reply_function,
2331 SilcClientCommand cmd;
2333 silc_list_start(client->internal->commands);
2334 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2335 if (cmd->cmd == command && cmd->command == command_function &&
2336 cmd->reply == command_reply_function && cmd->ident == ident) {
2337 silc_list_del(client->internal->commands, cmd);
2338 silc_free(cmd->name);
2347 /* Private range commands, specific to this implementation (and compatible
2348 with SILC Server). */
2350 /* CONNECT command. Connects the server to another server. */
2352 SILC_CLIENT_CMD_FUNC(connect)
2354 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2355 SilcClientConnection conn = cmd->conn;
2357 unsigned char port[4];
2361 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2362 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2366 if (cmd->argc < 2) {
2367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2368 "Usage: /CONNECT <server> [<port>]");
2369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2373 if (cmd->argc == 3) {
2374 tmp = atoi(cmd->argv[2]);
2375 SILC_PUT32_MSB(tmp, port);
2379 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2381 strlen(cmd->argv[1]),
2384 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2386 strlen(cmd->argv[1]));
2387 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2388 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2389 silc_buffer_free(buffer);
2391 /* Notify application */
2392 COMMAND(SILC_STATUS_OK);
2395 silc_client_command_free(cmd);
2399 /* CLOSE command. Close server connection to the remote server */
2401 SILC_CLIENT_CMD_FUNC(close)
2403 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2404 SilcClientConnection conn = cmd->conn;
2406 unsigned char port[4];
2410 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2411 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2415 if (cmd->argc < 2) {
2416 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2417 "Usage: /CLOSE <server> [<port>]");
2418 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2422 if (cmd->argc == 3) {
2423 tmp = atoi(cmd->argv[2]);
2424 SILC_PUT32_MSB(tmp, port);
2428 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2430 strlen(cmd->argv[1]),
2433 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2435 strlen(cmd->argv[1]));
2436 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2437 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2438 silc_buffer_free(buffer);
2440 /* Notify application */
2441 COMMAND(SILC_STATUS_OK);
2444 silc_client_command_free(cmd);
2447 /* SHUTDOWN command. Shutdowns the server. */
2449 SILC_CLIENT_CMD_FUNC(shutdown)
2451 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2454 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2455 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2459 /* Send the command */
2460 silc_client_command_send(cmd->client, cmd->conn,
2461 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2463 /* Notify application */
2464 COMMAND(SILC_STATUS_OK);
2467 silc_client_command_free(cmd);
2470 /* Register all default commands provided by the client library for the
2473 void silc_client_commands_register(SilcClient client)
2475 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2478 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2479 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2480 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2481 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2482 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2483 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2484 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2485 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2486 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2487 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2488 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2489 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2490 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2491 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2492 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2493 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2494 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2495 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2496 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2497 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2498 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2499 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2500 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2501 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2502 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2503 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2505 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2506 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2507 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2510 /* Unregister all commands. */
2512 void silc_client_commands_unregister(SilcClient client)
2514 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2515 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2516 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2517 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2518 SILC_CLIENT_CMDU(list, LIST, "LIST");
2519 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2520 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2521 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2522 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2523 SILC_CLIENT_CMDU(info, INFO, "INFO");
2524 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2525 SILC_CLIENT_CMDU(ping, PING, "PING");
2526 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2527 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2528 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2529 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2530 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2531 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2532 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2533 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2534 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2535 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2536 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2537 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2538 SILC_CLIENT_CMDU(users, USERS, "USERS");
2539 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2541 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2542 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2543 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2546 /**** Client side incoming command handling **********************************/
2548 void silc_client_command_process_whois(SilcClient client,
2549 SilcSocketConnection sock,
2550 SilcCommandPayload payload,
2551 SilcArgumentPayload args);
2553 /* Client is able to receive some command packets even though they are
2554 special case. Server may send WHOIS command to the client to retrieve
2555 Requested Attributes information for WHOIS query the server is
2556 processing. This function currently handles only the WHOIS command,
2557 but if in the future for commands may arrive then this can be made
2558 to support other commands too. */
2560 void silc_client_command_process(SilcClient client,
2561 SilcSocketConnection sock,
2562 SilcPacketContext *packet)
2564 SilcCommandPayload payload;
2565 SilcCommand command;
2566 SilcArgumentPayload args;
2568 /* Get command payload from packet */
2569 payload = silc_command_payload_parse(packet->buffer->data,
2570 packet->buffer->len);
2572 /* Silently ignore bad reply packet */
2573 SILC_LOG_DEBUG(("Bad command packet"));
2578 args = silc_command_get_args(payload);
2580 /* Get the command */
2581 command = silc_command_get(payload);
2584 case SILC_COMMAND_WHOIS:
2585 /* Ignore everything if requested by application */
2586 if (client->internal->params->ignore_requested_attributes)
2589 silc_client_command_process_whois(client, sock, payload, args);
2596 silc_command_payload_free(payload);
2599 void silc_client_command_process_whois(SilcClient client,
2600 SilcSocketConnection sock,
2601 SilcCommandPayload payload,
2602 SilcArgumentPayload args)
2607 SilcBuffer buffer, packet;
2609 SILC_LOG_DEBUG(("Received WHOIS command"));
2611 /* Try to take the Requested Attributes */
2612 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2616 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2620 /* Process requested attributes */
2621 buffer = silc_client_attributes_process(client, sock, attrs);
2623 silc_attribute_payload_list_free(attrs);
2627 /* Send the attributes back */
2629 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2631 silc_command_get_ident(payload),
2632 1, 11, buffer->data, buffer->len);
2633 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2634 NULL, 0, NULL, NULL, packet->data,
2636 silc_buffer_free(packet);
2637 silc_buffer_free(buffer);