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,
53 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
54 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
55 NULL, 0, NULL, NULL, packet->data,
57 silc_buffer_free(packet);
60 /* Finds and returns a pointer to the command list. Return NULL if the
61 command is not found. */
63 SilcClientCommand silc_client_command_find(SilcClient client,
66 SilcClientCommand cmd;
68 silc_list_start(client->internal->commands);
69 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
70 if (cmd->name && !strcmp(cmd->name, name))
77 /* Calls the command (executes it). Application can call this after
78 it has allocated the SilcClientCommandContext with the function
79 silc_client_command_alloc and found the command from the client
80 library by calling silc_client_command_find. This will execute
83 void silc_client_command_call(SilcClientCommand command,
84 SilcClientCommandContext cmd)
86 (*command->command)((void *)cmd, NULL);
89 /* Add new pending command to be executed when reply to a command has been
90 received. The `reply_cmd' is the command that will call the `callback'
91 with `context' when reply has been received. It can be SILC_COMMAND_NONE
92 to match any command with the `ident'. If `ident' is non-zero
93 the `callback' will be executed when received reply with command
94 identifier `ident'. If there already exists pending command for the
95 specified command, ident, callback and context this function has no
98 void silc_client_command_pending(SilcClientConnection conn,
99 SilcCommand reply_cmd,
101 SilcCommandCb callback,
104 SilcClientCommandPending *reply;
106 reply = silc_calloc(1, sizeof(*reply));
107 reply->reply_cmd = reply_cmd;
108 reply->ident = ident;
109 reply->context = context;
110 reply->callback = callback;
111 silc_dlist_add(conn->pending_commands, reply);
114 /* Deletes pending command by reply command type. */
116 void silc_client_command_pending_del(SilcClientConnection conn,
117 SilcCommand reply_cmd,
120 SilcClientCommandPending *r;
122 if (!conn->pending_commands)
125 silc_dlist_start(conn->pending_commands);
126 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
127 if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
129 && r->ident == ident) {
130 silc_dlist_del(conn->pending_commands, r);
136 /* Checks for pending commands and marks callbacks to be called from
137 the command reply function. */
139 SilcClientCommandPendingCallbacks
140 silc_client_command_pending_check(SilcClientConnection conn,
141 SilcClientCommandReplyContext ctx,
144 SilcUInt32 *callbacks_count)
146 SilcClientCommandPending *r;
147 SilcClientCommandPendingCallbacks callbacks = NULL;
150 silc_dlist_start(conn->pending_commands);
151 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
152 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
153 && r->ident == ident) {
154 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
155 callbacks[i].context = r->context;
156 callbacks[i].callback = r->callback;
157 r->reply_check = TRUE;
163 *callbacks_count = i;
167 /* Allocate Command Context */
169 SilcClientCommandContext silc_client_command_alloc(void)
171 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
176 /* Free command context and its internals */
178 void silc_client_command_free(SilcClientCommandContext ctx)
181 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
183 if (ctx->users < 1) {
186 for (i = 0; i < ctx->argc; i++)
187 silc_free(ctx->argv[i]);
188 silc_free(ctx->argv_lens);
189 silc_free(ctx->argv_types);
194 /* Duplicate Command Context by adding reference counter. The context won't
195 be free'd untill it hits zero. */
197 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
200 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
205 /* Command WHOIS. This command is used to query information about
208 SILC_CLIENT_CMD_FUNC(whois)
210 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
211 SilcClientConnection conn = cmd->conn;
212 SilcBuffer buffer, attrs = NULL;
213 unsigned char count[4], *tmp = NULL;
216 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
217 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
221 /* Given without arguments fetches client's own information */
223 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
224 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
226 1, 4, buffer->data, buffer->len);
227 silc_buffer_free(buffer);
231 if (cmd->argc == 2) {
232 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
233 ++conn->cmd_ident, 1,
237 if (!strcasecmp(cmd->argv[2], "-details"))
238 attrs = silc_client_attributes_request(0);
240 if (!attrs || cmd->argc > 3) {
241 int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
242 SILC_PUT32_MSB(c, count);
246 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
247 ++conn->cmd_ident, 3,
248 1, cmd->argv[1], cmd->argv_lens[1],
249 2, tmp ? tmp : NULL, tmp ? 4 : 0,
250 3, attrs ? attrs->data : NULL,
251 attrs ? attrs->len : 0);
253 silc_client_packet_send(cmd->client, cmd->conn->sock,
254 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
255 buffer->data, buffer->len, TRUE);
256 silc_buffer_free(buffer);
258 /* Notify application */
259 COMMAND(SILC_STATUS_OK);
262 silc_client_command_free(cmd);
265 /* Command WHOWAS. This command is used to query history information about
266 specific user that used to exist in the network. */
268 SILC_CLIENT_CMD_FUNC(whowas)
270 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
271 SilcClientConnection conn = cmd->conn;
273 unsigned char count[4];
276 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
277 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
281 if (cmd->argc < 2 || cmd->argc > 3) {
282 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
283 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
284 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
285 SILC_STATUS_ERR_TOO_MANY_PARAMS));
289 if (cmd->argc == 2) {
290 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
291 ++conn->cmd_ident, 1,
295 int c = atoi(cmd->argv[2]);
296 memset(count, 0, sizeof(count));
297 SILC_PUT32_MSB(c, count);
298 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
299 ++conn->cmd_ident, 2,
300 1, cmd->argv[1], cmd->argv_lens[1],
301 2, count, sizeof(count));
303 silc_client_packet_send(cmd->client, cmd->conn->sock,
304 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
305 buffer->data, buffer->len, TRUE);
306 silc_buffer_free(buffer);
308 /* Notify application */
309 COMMAND(SILC_STATUS_OK);
312 silc_client_command_free(cmd);
315 /* Command IDENTIFY. This command is used to query information about
316 specific user, especially ID's.
318 NOTE: This command is used only internally by the client library
319 and application MUST NOT call this command directly. */
321 SILC_CLIENT_CMD_FUNC(identify)
323 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
324 SilcClientConnection conn = cmd->conn;
326 unsigned char count[4];
329 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
330 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
334 if (cmd->argc < 2 || cmd->argc > 3)
337 if (cmd->argc == 2) {
338 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
339 ++conn->cmd_ident, 1,
343 int c = atoi(cmd->argv[2]);
344 memset(count, 0, sizeof(count));
345 SILC_PUT32_MSB(c, count);
346 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
347 ++conn->cmd_ident, 2,
350 4, count, sizeof(count));
353 silc_client_packet_send(cmd->client, cmd->conn->sock,
354 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
355 buffer->data, buffer->len, TRUE);
356 silc_buffer_free(buffer);
359 silc_client_command_free(cmd);
362 /* Command NICK. Shows current nickname/sets new nickname on current
365 SILC_CLIENT_CMD_FUNC(nick)
367 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
368 SilcClientConnection conn = cmd->conn;
372 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
373 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
378 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
379 "Usage: /NICK <nickname>");
380 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
384 if (!strcmp(conn->nickname, cmd->argv[1]))
387 /* Show current nickname */
390 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
391 "Your nickname is %s on server %s",
392 conn->nickname, conn->remote_host);
394 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
395 "Your nickname is %s", conn->nickname);
398 COMMAND(SILC_STATUS_OK);
402 if (cmd->argv_lens[1] > 128)
403 cmd->argv_lens[1] = 128;
405 /* Send the NICK command */
406 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
410 ++cmd->conn->cmd_ident);
411 silc_client_packet_send(cmd->client, cmd->conn->sock,
412 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
413 buffer->data, buffer->len, TRUE);
414 silc_buffer_free(buffer);
417 silc_client_command_free(cmd);
420 /* Command LIST. Lists channels on the current server. */
422 SILC_CLIENT_CMD_FUNC(list)
424 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
425 SilcClientConnection conn = cmd->conn;
426 SilcIDCacheEntry id_cache = NULL;
427 SilcChannelEntry channel;
428 SilcBuffer buffer, idp = NULL;
432 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
433 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
437 if (cmd->argc == 2) {
440 /* Get the Channel ID of the channel */
441 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
442 channel = (SilcChannelEntry)id_cache->context;
443 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
448 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
449 ++conn->cmd_ident, 0);
451 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
452 ++conn->cmd_ident, 1,
453 1, idp->data, idp->len);
455 silc_client_packet_send(cmd->client, cmd->conn->sock,
456 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
457 buffer->data, buffer->len, TRUE);
458 silc_buffer_free(buffer);
460 silc_buffer_free(idp);
462 /* Notify application */
463 COMMAND(SILC_STATUS_OK);
466 silc_client_command_free(cmd);
469 /* Command TOPIC. Sets/shows topic on a channel. */
471 SILC_CLIENT_CMD_FUNC(topic)
473 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
474 SilcClientConnection conn = cmd->conn;
475 SilcIDCacheEntry id_cache = NULL;
476 SilcChannelEntry channel;
477 SilcBuffer buffer, idp;
481 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
482 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
486 if (cmd->argc < 2 || cmd->argc > 3) {
487 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
488 "Usage: /TOPIC <channel> [<topic>]");
489 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
490 SILC_STATUS_ERR_TOO_MANY_PARAMS));
494 if (cmd->argv[1][0] == '*') {
495 if (!conn->current_channel) {
496 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
499 name = conn->current_channel->channel_name;
504 if (!conn->current_channel) {
505 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
509 /* Get the Channel ID of the channel */
510 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
511 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
515 channel = (SilcChannelEntry)id_cache->context;
517 /* Send TOPIC command to the server */
518 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
520 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
521 ++conn->cmd_ident, 2,
522 1, idp->data, idp->len,
524 strlen(cmd->argv[2]));
526 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
527 ++conn->cmd_ident, 1,
528 1, idp->data, idp->len);
529 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
530 0, NULL, NULL, buffer->data, buffer->len, TRUE);
531 silc_buffer_free(buffer);
532 silc_buffer_free(idp);
534 /* Notify application */
535 COMMAND(SILC_STATUS_OK);
538 silc_client_command_free(cmd);
541 /* Command INVITE. Invites specific client to join a channel. This is
542 also used to mange the invite list of the channel. */
544 SILC_CLIENT_CMD_FUNC(invite)
546 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
547 SilcClient client = cmd->client;
548 SilcClientConnection conn = cmd->conn;
549 SilcClientEntry client_entry = NULL;
550 SilcChannelEntry channel;
551 SilcBuffer buffer, clidp, chidp;
553 char *nickname = NULL, *name;
557 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
558 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
563 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
564 "Usage: /INVITE <channel> [<nickname>[@server>]"
565 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
566 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
570 if (cmd->argv[1][0] == '*') {
571 if (!conn->current_channel) {
572 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
576 channel = conn->current_channel;
580 channel = silc_client_get_channel(cmd->client, conn, name);
582 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
587 /* Parse the typed nickname. */
588 if (cmd->argc == 3) {
589 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
590 if (client->internal->params->nickname_parse)
591 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
593 nickname = strdup(cmd->argv[2]);
595 /* Find client entry */
596 client_entry = silc_idlist_get_client(client, conn, nickname,
600 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
604 /* Client entry not found, it was requested thus mark this to be
606 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
608 silc_client_command_invite,
609 silc_client_command_dup(cmd));
614 invite = cmd->argv[2];
616 if (cmd->argv[2][0] == '+')
623 /* Send the command */
624 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
626 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
627 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
628 ++conn->cmd_ident, 3,
629 1, chidp->data, chidp->len,
630 2, clidp->data, clidp->len,
631 type, invite, invite ?
633 silc_buffer_free(clidp);
635 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
636 ++conn->cmd_ident, 2,
637 1, chidp->data, chidp->len,
638 type, invite, invite ?
642 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
643 0, NULL, NULL, buffer->data, buffer->len, TRUE);
644 silc_buffer_free(buffer);
645 silc_buffer_free(chidp);
647 /* Notify application */
648 COMMAND(SILC_STATUS_OK);
652 silc_client_command_free(cmd);
657 SilcClientConnection conn;
660 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
662 QuitInternal q = (QuitInternal)context;
664 /* Close connection */
665 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
666 silc_client_close_connection(q->client, q->conn->sock->user_data);
671 /* Command QUIT. Closes connection with current server. */
673 SILC_CLIENT_CMD_FUNC(quit)
675 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
680 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
681 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
686 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
687 &cmd->argv[1], &cmd->argv_lens[1],
688 &cmd->argv_types[1], 0);
690 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
691 NULL, NULL, NULL, 0);
692 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
694 buffer->data, buffer->len, TRUE);
695 silc_buffer_free(buffer);
697 q = silc_calloc(1, sizeof(*q));
698 q->client = cmd->client;
701 /* Sleep for a while */
704 /* We quit the connection with little timeout */
705 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
706 silc_client_command_quit_cb, (void *)q,
707 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
709 /* Notify application */
710 COMMAND(SILC_STATUS_OK);
713 silc_client_command_free(cmd);
716 /* Timeout callback to remove the killed client from cache */
718 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
720 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
721 SilcClient client = cmd->client;
722 SilcClientConnection conn = cmd->conn;
723 SilcClientEntry target;
724 char *nickname = NULL;
726 /* Parse the typed nickname. */
727 if (client->internal->params->nickname_parse)
728 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
730 nickname = strdup(cmd->argv[1]);
732 /* Get the target client */
733 target = silc_idlist_get_client(cmd->client, conn, nickname,
734 cmd->argv[1], FALSE);
736 /* Remove the client from all channels and free it */
737 silc_client_del_client(client, conn, target);
740 silc_client_command_free(cmd);
743 /* Kill command's pending command callback to actually remove the killed
744 client from our local cache. */
746 SILC_CLIENT_CMD_FUNC(kill_remove)
748 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
749 SilcClientCommandReplyContext reply =
750 (SilcClientCommandReplyContext)context2;
753 silc_command_get_status(reply->payload, &status, NULL);
754 if (status == SILC_STATUS_OK) {
755 /* Remove with timeout */
756 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
757 silc_client_command_kill_remove_later, context,
758 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
762 silc_client_command_free(cmd);
765 /* Command KILL. Router operator can use this command to remove an client
766 fromthe SILC Network. */
768 SILC_CLIENT_CMD_FUNC(kill)
770 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
771 SilcClient client = cmd->client;
772 SilcClientConnection conn = cmd->conn;
773 SilcBuffer buffer, idp;
774 SilcClientEntry target;
775 char *nickname = NULL;
778 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
779 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
784 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
785 "Usage: /KILL <nickname> [<comment>]");
786 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
790 /* Parse the typed nickname. */
791 if (client->internal->params->nickname_parse)
792 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
794 nickname = strdup(cmd->argv[1]);
796 /* Get the target client */
797 target = silc_idlist_get_client(cmd->client, conn, nickname,
801 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
805 /* Client entry not found, it was requested thus mark this to be
807 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
809 silc_client_command_kill,
810 silc_client_command_dup(cmd));
815 /* Send the KILL command to the server */
816 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
818 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
819 ++conn->cmd_ident, 1,
820 1, idp->data, idp->len);
822 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
823 ++conn->cmd_ident, 2,
824 1, idp->data, idp->len,
826 strlen(cmd->argv[2]));
827 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
828 0, NULL, NULL, buffer->data, buffer->len, TRUE);
829 silc_buffer_free(buffer);
830 silc_buffer_free(idp);
832 /* Notify application */
833 COMMAND(SILC_STATUS_OK);
835 /* Register a pending callback that will actually remove the killed
836 client from our cache. */
837 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
838 silc_client_command_kill_remove,
839 silc_client_command_dup(cmd));
843 silc_client_command_free(cmd);
846 /* Command INFO. Request information about specific server. If specific
847 server is not provided the current server is used. */
849 SILC_CLIENT_CMD_FUNC(info)
851 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
852 SilcClientConnection conn = cmd->conn;
857 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
858 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
863 name = strdup(cmd->argv[1]);
865 /* Send the command */
867 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
868 1, name, strlen(name));
870 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
871 NULL, NULL, NULL, 0);
872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
874 silc_buffer_free(buffer);
878 /* Notify application */
879 COMMAND(SILC_STATUS_OK);
882 silc_client_command_free(cmd);
885 /* Command STATS. Shows server and network statistics. */
887 SILC_CLIENT_CMD_FUNC(stats)
889 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
890 SilcClientConnection conn = cmd->conn;
891 SilcBuffer buffer, idp = NULL;
894 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
895 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
899 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
901 /* Send the command */
902 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
903 ++conn->cmd_ident, 1,
904 SILC_ID_SERVER, idp->data, idp->len);
905 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
906 0, NULL, NULL, buffer->data, buffer->len, TRUE);
907 silc_buffer_free(buffer);
908 silc_buffer_free(idp);
910 /* Notify application */
911 COMMAND(SILC_STATUS_OK);
914 silc_client_command_free(cmd);
917 /* Command PING. Sends ping to server. This is used to test the
918 communication channel. */
920 SILC_CLIENT_CMD_FUNC(ping)
922 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
923 SilcClientConnection conn = cmd->conn;
929 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
930 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
934 /* Send the command */
935 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
936 1, conn->remote_id_data,
937 silc_id_get_len(conn->remote_id,
939 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
940 0, NULL, NULL, buffer->data, buffer->len, TRUE);
941 silc_buffer_free(buffer);
943 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
946 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
947 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
951 /* Start counting time */
952 for (i = 0; i < conn->ping_count; i++) {
953 if (conn->ping[i].dest_id == NULL) {
954 conn->ping[i].start_time = time(NULL);
955 conn->ping[i].dest_id = id;
956 conn->ping[i].dest_name = strdup(conn->remote_host);
960 if (i >= conn->ping_count) {
961 i = conn->ping_count;
962 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
963 conn->ping[i].start_time = time(NULL);
964 conn->ping[i].dest_id = id;
965 conn->ping[i].dest_name = strdup(conn->remote_host);
969 /* Notify application */
970 COMMAND(SILC_STATUS_OK);
973 silc_client_command_free(cmd);
976 /* Command JOIN. Joins to a channel. */
978 SILC_CLIENT_CMD_FUNC(join)
980 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
981 SilcClientConnection conn = cmd->conn;
982 SilcChannelEntry channel;
983 SilcBuffer buffer, idp, auth = NULL;
984 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
985 int i, passphrase_len = 0;
988 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
989 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
994 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
998 /* See if we have joined to the requested channel already */
999 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1000 if (channel && silc_client_on_channel(channel, conn->local_entry))
1003 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1005 if (cmd->argv_lens[1] > 256)
1006 cmd->argv_lens[1] = 256;
1008 name = cmd->argv[1];
1010 for (i = 2; i < cmd->argc; i++) {
1011 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1012 cipher = cmd->argv[i + 1];
1014 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1015 hmac = cmd->argv[i + 1];
1017 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1018 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1019 cmd->client->private_key,
1021 cmd->client->sha1hash,
1026 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1027 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1028 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1029 cmd->argv_lens[i], 0);
1030 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1031 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1032 0, pu8, passphrase_len);
1035 passphrase = strdup(cmd->argv[i]);
1036 passphrase_len = cmd->argv_lens[i];
1041 /* Send JOIN command to the server */
1043 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1044 1, name, strlen(name),
1045 2, idp->data, idp->len,
1046 3, passphrase, passphrase_len,
1047 4, cipher, cipher ? strlen(cipher) : 0,
1048 5, hmac, hmac ? strlen(hmac) : 0,
1049 6, auth ? auth->data : NULL,
1050 auth ? auth->len : 0);
1051 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1052 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1053 silc_buffer_free(buffer);
1054 silc_buffer_free(idp);
1056 silc_buffer_free(auth);
1057 silc_free(passphrase);
1059 /* Notify application */
1060 COMMAND(SILC_STATUS_OK);
1063 silc_client_command_free(cmd);
1066 /* MOTD command. Requests motd from server. */
1068 SILC_CLIENT_CMD_FUNC(motd)
1070 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1071 SilcClientConnection conn = cmd->conn;
1075 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1076 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1080 if (cmd->argc < 1 || cmd->argc > 2) {
1081 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1082 "Usage: /MOTD [<server>]");
1083 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1084 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1088 /* Send TOPIC command to the server */
1090 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1091 1, conn->remote_host,
1092 strlen(conn->remote_host));
1094 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1097 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1098 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1099 silc_buffer_free(buffer);
1101 /* Notify application */
1102 COMMAND(SILC_STATUS_OK);
1105 silc_client_command_free(cmd);
1108 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1109 modes as client cannot set itself server/router operator privileges. */
1111 SILC_CLIENT_CMD_FUNC(umode)
1113 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1114 SilcClientConnection conn = cmd->conn;
1115 SilcBuffer buffer, idp;
1116 unsigned char *cp, modebuf[4];
1117 SilcUInt32 mode, add, len;
1121 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1122 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1126 if (cmd->argc < 2) {
1127 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1128 "Usage: /UMODE +|-<modes>");
1129 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1133 mode = conn->local_entry->mode;
1135 /* Are we adding or removing mode */
1136 if (cmd->argv[1][0] == '-')
1142 cp = cmd->argv[1] + 1;
1144 for (i = 0; i < len; i++) {
1149 mode |= SILC_UMODE_SERVER_OPERATOR;
1150 mode |= SILC_UMODE_ROUTER_OPERATOR;
1151 mode |= SILC_UMODE_GONE;
1152 mode |= SILC_UMODE_INDISPOSED;
1153 mode |= SILC_UMODE_BUSY;
1154 mode |= SILC_UMODE_PAGE;
1155 mode |= SILC_UMODE_HYPER;
1156 mode |= SILC_UMODE_ROBOT;
1157 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1158 mode |= SILC_UMODE_REJECT_WATCHING;
1160 mode = SILC_UMODE_NONE;
1165 mode |= SILC_UMODE_SERVER_OPERATOR;
1167 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1171 mode |= SILC_UMODE_ROUTER_OPERATOR;
1173 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1177 mode |= SILC_UMODE_GONE;
1179 mode &= ~SILC_UMODE_GONE;
1183 mode |= SILC_UMODE_INDISPOSED;
1185 mode &= ~SILC_UMODE_INDISPOSED;
1189 mode |= SILC_UMODE_BUSY;
1191 mode &= ~SILC_UMODE_BUSY;
1195 mode |= SILC_UMODE_PAGE;
1197 mode &= ~SILC_UMODE_PAGE;
1201 mode |= SILC_UMODE_HYPER;
1203 mode &= ~SILC_UMODE_HYPER;
1207 mode |= SILC_UMODE_ROBOT;
1209 mode &= ~SILC_UMODE_ROBOT;
1213 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1215 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1219 mode |= SILC_UMODE_REJECT_WATCHING;
1221 mode &= ~SILC_UMODE_REJECT_WATCHING;
1225 mode |= SILC_UMODE_BLOCK_INVITE;
1227 mode &= ~SILC_UMODE_BLOCK_INVITE;
1230 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1236 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1237 SILC_PUT32_MSB(mode, modebuf);
1239 /* Send the command packet. We support sending only one mode at once
1240 that requires an argument. */
1242 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1243 1, idp->data, idp->len,
1244 2, modebuf, sizeof(modebuf));
1245 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1246 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1247 silc_buffer_free(buffer);
1248 silc_buffer_free(idp);
1250 /* Notify application */
1251 COMMAND(SILC_STATUS_OK);
1254 silc_client_command_free(cmd);
1257 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1258 can be set several at once. Those modes that require argument must be set
1259 separately (unless set with modes that does not require arguments). */
1261 SILC_CLIENT_CMD_FUNC(cmode)
1263 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1264 SilcClientConnection conn = cmd->conn;
1265 SilcChannelEntry channel;
1266 SilcBuffer buffer, chidp, auth = NULL;
1267 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1268 SilcUInt32 mode, add, type, len, arg_len = 0;
1272 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1273 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1277 if (cmd->argc < 3) {
1278 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1279 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1280 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1284 if (cmd->argv[1][0] == '*') {
1285 if (!conn->current_channel) {
1286 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1290 channel = conn->current_channel;
1292 name = cmd->argv[1];
1294 channel = silc_client_get_channel(cmd->client, conn, name);
1296 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1301 mode = channel->mode;
1303 /* Are we adding or removing mode */
1304 if (cmd->argv[2][0] == '-')
1309 /* Argument type to be sent to server */
1313 cp = cmd->argv[2] + 1;
1315 for (i = 0; i < len; i++) {
1319 mode |= SILC_CHANNEL_MODE_PRIVATE;
1321 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1325 mode |= SILC_CHANNEL_MODE_SECRET;
1327 mode &= ~SILC_CHANNEL_MODE_SECRET;
1331 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1333 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1337 mode |= SILC_CHANNEL_MODE_INVITE;
1339 mode &= ~SILC_CHANNEL_MODE_INVITE;
1343 mode |= SILC_CHANNEL_MODE_TOPIC;
1345 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1349 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1351 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1355 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1357 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1362 mode |= SILC_CHANNEL_MODE_ULIMIT;
1364 if (cmd->argc < 4) {
1365 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1366 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1367 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1370 ll = atoi(cmd->argv[3]);
1371 SILC_PUT32_MSB(ll, tmp);
1375 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1380 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1382 if (cmd->argc < 4) {
1383 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1384 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1385 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1389 arg_len = cmd->argv_lens[3];
1391 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1396 mode |= SILC_CHANNEL_MODE_CIPHER;
1398 if (cmd->argc < 4) {
1399 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1400 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1405 arg_len = cmd->argv_lens[3];
1407 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1412 mode |= SILC_CHANNEL_MODE_HMAC;
1414 if (cmd->argc < 4) {
1415 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1416 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1417 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1421 arg_len = cmd->argv_lens[3];
1423 mode &= ~SILC_CHANNEL_MODE_HMAC;
1428 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1430 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1431 cmd->client->private_key,
1433 cmd->client->sha1hash,
1437 arg_len = auth->len;
1439 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1443 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1449 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1450 SILC_PUT32_MSB(mode, modebuf);
1452 /* Send the command packet. We support sending only one mode at once
1453 that requires an argument. */
1456 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1457 1, chidp->data, chidp->len,
1458 2, modebuf, sizeof(modebuf),
1459 type, arg, arg_len);
1462 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1463 1, chidp->data, chidp->len,
1464 2, modebuf, sizeof(modebuf));
1467 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1468 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1469 silc_buffer_free(buffer);
1470 silc_buffer_free(chidp);
1472 silc_buffer_free(auth);
1474 /* Notify application */
1475 COMMAND(SILC_STATUS_OK);
1478 silc_client_command_free(cmd);
1481 /* CUMODE command. Changes client's mode on a channel. */
1483 SILC_CLIENT_CMD_FUNC(cumode)
1485 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1486 SilcClient client = cmd->client;
1487 SilcClientConnection conn = cmd->conn;
1488 SilcChannelEntry channel;
1489 SilcChannelUser chu;
1490 SilcClientEntry client_entry;
1491 SilcBuffer buffer, clidp, chidp, auth = NULL;
1492 unsigned char *name, *cp, modebuf[4];
1493 SilcUInt32 mode = 0, add, len;
1494 char *nickname = NULL;
1498 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1499 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1503 if (cmd->argc < 4) {
1504 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1505 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1510 if (cmd->argv[1][0] == '*') {
1511 if (!conn->current_channel) {
1512 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1516 channel = conn->current_channel;
1518 name = cmd->argv[1];
1520 channel = silc_client_get_channel(cmd->client, conn, name);
1522 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1527 /* Parse the typed nickname. */
1528 if (client->internal->params->nickname_parse)
1529 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1531 nickname = strdup(cmd->argv[3]);
1533 /* Find client entry */
1534 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1535 cmd->argv[3], TRUE);
1536 if (!client_entry) {
1538 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1542 /* Client entry not found, it was requested thus mark this to be
1544 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1546 silc_client_command_cumode,
1547 silc_client_command_dup(cmd));
1552 /* Get the current mode */
1553 chu = silc_client_on_channel(channel, client_entry);
1557 /* Are we adding or removing mode */
1558 if (cmd->argv[2][0] == '-')
1564 cp = cmd->argv[2] + 1;
1566 for (i = 0; i < len; i++) {
1570 mode |= SILC_CHANNEL_UMODE_CHANFO;
1571 mode |= SILC_CHANNEL_UMODE_CHANOP;
1572 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1573 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1574 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1576 mode = SILC_CHANNEL_UMODE_NONE;
1581 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1582 cmd->client->private_key,
1584 cmd->client->sha1hash,
1587 mode |= SILC_CHANNEL_UMODE_CHANFO;
1589 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1594 mode |= SILC_CHANNEL_UMODE_CHANOP;
1596 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1600 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1602 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1606 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1608 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1612 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1614 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1618 mode |= SILC_CHANNEL_UMODE_QUIET;
1620 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1623 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1629 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1630 SILC_PUT32_MSB(mode, modebuf);
1631 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1633 /* Send the command packet. We support sending only one mode at once
1634 that requires an argument. */
1635 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1637 1, chidp->data, chidp->len,
1639 3, clidp->data, clidp->len,
1640 4, auth ? auth->data : NULL,
1641 auth ? auth->len : 0);
1643 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1644 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1645 silc_buffer_free(buffer);
1646 silc_buffer_free(chidp);
1647 silc_buffer_free(clidp);
1649 silc_buffer_free(auth);
1651 /* Notify application */
1652 COMMAND(SILC_STATUS_OK);
1655 silc_free(nickname);
1656 silc_client_command_free(cmd);
1659 /* KICK command. Kicks a client out of channel. */
1661 SILC_CLIENT_CMD_FUNC(kick)
1663 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1664 SilcClient client = cmd->client;
1665 SilcClientConnection conn = cmd->conn;
1666 SilcIDCacheEntry id_cache = NULL;
1667 SilcChannelEntry channel;
1668 SilcBuffer buffer, idp, idp2;
1669 SilcClientEntry target;
1671 char *nickname = NULL;
1674 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1675 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1679 if (cmd->argc < 3) {
1680 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1681 "Usage: /KICK <channel> <nickname> [<comment>]");
1682 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1686 if (cmd->argv[1][0] == '*') {
1687 if (!conn->current_channel) {
1688 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1691 name = conn->current_channel->channel_name;
1693 name = cmd->argv[1];
1696 if (!conn->current_channel) {
1697 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1701 /* Get the Channel ID of the channel */
1702 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1703 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1707 channel = (SilcChannelEntry)id_cache->context;
1709 /* Parse the typed nickname. */
1710 if (client->internal->params->nickname_parse)
1711 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1713 nickname = strdup(cmd->argv[2]);
1715 /* Get the target client */
1716 target = silc_idlist_get_client(cmd->client, conn, nickname,
1717 cmd->argv[2], FALSE);
1719 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1720 "No such client: %s", cmd->argv[2]);
1721 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1725 /* Send KICK command to the server */
1726 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1727 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1729 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1730 1, idp->data, idp->len,
1731 2, idp2->data, idp2->len);
1733 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1734 1, idp->data, idp->len,
1735 2, idp2->data, idp2->len,
1737 strlen(cmd->argv[3]));
1738 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1739 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1740 silc_buffer_free(buffer);
1741 silc_buffer_free(idp);
1742 silc_buffer_free(idp2);
1744 /* Notify application */
1745 COMMAND(SILC_STATUS_OK);
1748 silc_free(nickname);
1749 silc_client_command_free(cmd);
1752 static void silc_client_command_oper_send(unsigned char *data,
1753 SilcUInt32 data_len, void *context)
1755 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1756 SilcClientConnection conn = cmd->conn;
1757 SilcBuffer buffer, auth;
1759 if (cmd->argc >= 3) {
1760 /* Encode the public key authentication payload */
1761 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1762 cmd->client->private_key,
1763 cmd->client->rng, conn->hash,
1767 /* Encode the password authentication payload */
1768 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1772 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1774 strlen(cmd->argv[1]),
1775 2, auth ? auth->data : NULL,
1776 auth ? auth->len : 0);
1777 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1778 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1780 silc_buffer_free(buffer);
1781 silc_buffer_free(auth);
1783 /* Notify application */
1784 COMMAND(SILC_STATUS_OK);
1787 /* OPER command. Used to obtain server operator privileges. */
1789 SILC_CLIENT_CMD_FUNC(oper)
1791 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1792 SilcClientConnection conn = cmd->conn;
1795 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1796 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1800 if (cmd->argc < 2) {
1801 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1802 "Usage: /OPER <username> [-pubkey]");
1803 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1807 if (cmd->argc < 3) {
1808 /* Get passphrase */
1809 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1810 silc_client_command_oper_send,
1815 silc_client_command_oper_send(NULL, 0, context);
1818 silc_client_command_free(cmd);
1821 static void silc_client_command_silcoper_send(unsigned char *data,
1822 SilcUInt32 data_len,
1825 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1826 SilcClientConnection conn = cmd->conn;
1827 SilcBuffer buffer, auth;
1829 if (cmd->argc >= 3) {
1830 /* Encode the public key authentication payload */
1831 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1832 cmd->client->private_key,
1833 cmd->client->rng, conn->hash,
1837 /* Encode the password authentication payload */
1838 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1842 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1844 strlen(cmd->argv[1]),
1845 2, auth ? auth->data : NULL,
1846 auth ? auth->len : 0);
1847 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1848 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1850 silc_buffer_free(buffer);
1851 silc_buffer_free(auth);
1853 /* Notify application */
1854 COMMAND(SILC_STATUS_OK);
1857 /* SILCOPER command. Used to obtain router operator privileges. */
1859 SILC_CLIENT_CMD_FUNC(silcoper)
1861 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1862 SilcClientConnection conn = cmd->conn;
1865 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1866 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1870 if (cmd->argc < 2) {
1871 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1872 "Usage: /SILCOPER <username> [-pubkey]");
1873 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1877 if (cmd->argc < 3) {
1878 /* Get passphrase */
1879 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1880 silc_client_command_silcoper_send,
1885 silc_client_command_silcoper_send(NULL, 0, context);
1888 silc_client_command_free(cmd);
1891 /* Command BAN. This is used to manage the ban list of the channel. */
1893 SILC_CLIENT_CMD_FUNC(ban)
1895 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1896 SilcClientConnection conn = cmd->conn;
1897 SilcChannelEntry channel;
1898 SilcBuffer buffer, chidp;
1900 char *name, *ban = NULL;
1903 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1904 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1908 if (cmd->argc < 2) {
1909 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1910 "Usage: /BAN <channel> "
1911 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1912 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1916 if (cmd->argv[1][0] == '*') {
1917 if (!conn->current_channel) {
1918 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1922 channel = conn->current_channel;
1924 name = cmd->argv[1];
1926 channel = silc_client_get_channel(cmd->client, conn, name);
1928 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1933 if (cmd->argc == 3) {
1934 if (cmd->argv[2][0] == '+')
1943 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1945 /* Send the command */
1946 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1947 ++conn->cmd_ident, 2,
1948 1, chidp->data, chidp->len,
1949 type, ban, ban ? strlen(ban) : 0);
1950 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1951 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1952 silc_buffer_free(buffer);
1953 silc_buffer_free(chidp);
1955 /* Notify application */
1956 COMMAND(SILC_STATUS_OK);
1959 silc_client_command_free(cmd);
1962 /* Command DETACH. This is used to detach from the server */
1964 SILC_CLIENT_CMD_FUNC(detach)
1966 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1967 SilcClientConnection conn = cmd->conn;
1971 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1972 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1976 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1977 ++conn->cmd_ident, 0);
1978 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1979 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1980 silc_buffer_free(buffer);
1982 /* Notify application */
1983 COMMAND(SILC_STATUS_OK);
1986 silc_client_command_free(cmd);
1989 /* Command WATCH. */
1991 SILC_CLIENT_CMD_FUNC(watch)
1993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1994 SilcClientConnection conn = cmd->conn;
1995 SilcBuffer buffer, idp = NULL;
1999 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2000 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2004 if (cmd->argc < 3) {
2005 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2009 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2011 if (!strcasecmp(cmd->argv[1], "-add")) {
2013 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2016 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2020 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2021 ++conn->cmd_ident, 2,
2022 1, idp->data, idp->len,
2025 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2026 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2027 silc_buffer_free(buffer);
2029 /* Notify application */
2030 COMMAND(SILC_STATUS_OK);
2034 silc_buffer_free(idp);
2035 silc_client_command_free(cmd);
2038 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2040 SILC_CLIENT_CMD_FUNC(leave)
2042 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2043 SilcClientConnection conn = cmd->conn;
2044 SilcChannelEntry channel;
2045 SilcChannelUser chu;
2046 SilcBuffer buffer, idp;
2050 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2051 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2055 if (cmd->argc != 2) {
2056 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2057 "Usage: /LEAVE <channel>");
2058 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2062 if (cmd->argv[1][0] == '*') {
2063 if (!conn->current_channel) {
2064 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2067 name = conn->current_channel->channel_name;
2069 name = cmd->argv[1];
2072 /* Get the channel entry */
2073 channel = silc_client_get_channel(cmd->client, conn, name);
2075 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2079 /* Remove us from channel */
2080 chu = silc_client_on_channel(channel, conn->local_entry);
2082 silc_hash_table_del(chu->client->channels, chu->channel);
2083 silc_hash_table_del(chu->channel->user_list, chu->client);
2087 /* Send LEAVE command to the server */
2088 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2089 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2090 1, idp->data, idp->len);
2091 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2092 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2093 silc_buffer_free(buffer);
2094 silc_buffer_free(idp);
2096 /* Notify application */
2097 COMMAND(SILC_STATUS_OK);
2099 if (conn->current_channel == channel)
2100 conn->current_channel = NULL;
2102 silc_client_del_channel(cmd->client, cmd->conn, channel);
2105 silc_client_command_free(cmd);
2108 /* Command USERS. Requests the USERS of the clients joined on requested
2111 SILC_CLIENT_CMD_FUNC(users)
2113 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2114 SilcClientConnection conn = cmd->conn;
2119 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2120 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2124 if (cmd->argc != 2) {
2125 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2126 "Usage: /USERS <channel>");
2127 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2131 if (cmd->argv[1][0] == '*') {
2132 if (!conn->current_channel) {
2133 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2136 name = conn->current_channel->channel_name;
2138 name = cmd->argv[1];
2141 /* Send USERS command to the server */
2142 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2143 ++conn->cmd_ident, 1,
2144 2, name, strlen(name));
2145 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2146 NULL, 0, NULL, NULL, buffer->data,
2148 silc_buffer_free(buffer);
2150 /* Notify application */
2151 COMMAND(SILC_STATUS_OK);
2154 silc_client_command_free(cmd);
2157 /* Command GETKEY. Used to fetch remote client's public key. */
2159 SILC_CLIENT_CMD_FUNC(getkey)
2161 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2162 SilcClientConnection conn = cmd->conn;
2163 SilcClient client = cmd->client;
2164 SilcClientEntry client_entry = NULL;
2165 SilcServerEntry server_entry = NULL;
2166 char *nickname = NULL;
2167 SilcBuffer idp, buffer;
2169 SILC_LOG_DEBUG(("Start"));
2172 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2173 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2177 if (cmd->argc < 2) {
2178 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2179 "Usage: /GETKEY <nickname or server name>");
2180 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2184 /* Parse the typed nickname. */
2185 if (client->internal->params->nickname_parse)
2186 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2188 nickname = strdup(cmd->argv[1]);
2190 /* Find client entry */
2191 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2193 if (!client_entry) {
2194 /* Check whether user requested server actually */
2195 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2197 if (!server_entry) {
2198 /* No. what ever user wants we don't have it, so resolve it. We
2199 will first try to resolve the client, and if that fails then
2200 we'll try to resolve the server. */
2202 if (!cmd->pending) {
2203 /* This will send the IDENTIFY command for nickname */
2204 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2205 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2207 silc_client_command_getkey,
2208 silc_client_command_dup(cmd));
2212 SilcClientCommandReplyContext reply =
2213 (SilcClientCommandReplyContext)context2;
2216 /* If nickname was not found, then resolve the server. */
2217 silc_command_get_status(reply->payload, NULL, &error);
2218 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2219 /* This sends the IDENTIFY command to resolve the server. */
2220 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2222 silc_client_command_reply_identify_i, 0,
2224 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2226 2, cmd->argv[1], cmd->argv_lens[1]);
2227 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2229 silc_client_command_getkey,
2230 silc_client_command_dup(cmd));
2234 /* If server was not found, then we've resolved both nickname and
2235 server and did not find anybody. */
2236 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2237 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2238 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2239 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2240 silc_get_status_message(error));
2241 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2245 COMMAND_ERROR(error);
2250 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2252 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2255 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2256 1, idp->data, idp->len);
2257 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2258 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2259 silc_buffer_free(buffer);
2260 silc_buffer_free(idp);
2262 /* Notify application */
2263 COMMAND(SILC_STATUS_OK);
2266 silc_free(nickname);
2267 silc_client_command_free(cmd);
2270 /* Register a new command indicated by the `command' to the SILC client.
2271 The `name' is optional command name. If provided the command may be
2272 searched using the silc_client_command_find by that name. The
2273 `command_function' is the function to be called when the command is
2274 executed, and the `command_reply_function' is the function to be
2275 called after the server has sent reply back to the command.
2277 The `ident' is optional identifier for the command. If non-zero
2278 the `command_reply_function' for the command type `command' will be
2279 called only if the command reply sent by server includes the
2280 command identifier `ident'. Application usually does not need it
2281 and set it to zero value. */
2283 bool silc_client_command_register(SilcClient client,
2284 SilcCommand command,
2286 SilcCommandCb command_function,
2287 SilcCommandCb command_reply_function,
2291 SilcClientCommand cmd;
2293 cmd = silc_calloc(1, sizeof(*cmd));
2295 cmd->command = command_function;
2296 cmd->reply = command_reply_function;
2297 cmd->name = name ? strdup(name) : NULL;
2298 cmd->max_args = max_args;
2301 silc_list_add(client->internal->commands, cmd);
2306 /* Unregister a command indicated by the `command' with command function
2307 `command_function' and command reply function `command_reply_function'.
2308 Returns TRUE if the command was found and unregistered. */
2310 bool silc_client_command_unregister(SilcClient client,
2311 SilcCommand command,
2312 SilcCommandCb command_function,
2313 SilcCommandCb command_reply_function,
2316 SilcClientCommand cmd;
2318 silc_list_start(client->internal->commands);
2319 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2320 if (cmd->cmd == command && cmd->command == command_function &&
2321 cmd->reply == command_reply_function && cmd->ident == ident) {
2322 silc_list_del(client->internal->commands, cmd);
2323 silc_free(cmd->name);
2332 /* Private range commands, specific to this implementation (and compatible
2333 with SILC Server). */
2335 /* CONNECT command. Connects the server to another server. */
2337 SILC_CLIENT_CMD_FUNC(connect)
2339 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2340 SilcClientConnection conn = cmd->conn;
2342 unsigned char port[4];
2346 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2347 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2351 if (cmd->argc < 2) {
2352 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2353 "Usage: /CONNECT <server> [<port>]");
2354 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2358 if (cmd->argc == 3) {
2359 tmp = atoi(cmd->argv[2]);
2360 SILC_PUT32_MSB(tmp, port);
2364 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2366 strlen(cmd->argv[1]),
2369 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2371 strlen(cmd->argv[1]));
2372 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2373 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2374 silc_buffer_free(buffer);
2376 /* Notify application */
2377 COMMAND(SILC_STATUS_OK);
2380 silc_client_command_free(cmd);
2384 /* CLOSE command. Close server connection to the remote server */
2386 SILC_CLIENT_CMD_FUNC(close)
2388 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2389 SilcClientConnection conn = cmd->conn;
2391 unsigned char port[4];
2395 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2396 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2400 if (cmd->argc < 2) {
2401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2402 "Usage: /CLOSE <server> [<port>]");
2403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2407 if (cmd->argc == 3) {
2408 tmp = atoi(cmd->argv[2]);
2409 SILC_PUT32_MSB(tmp, port);
2413 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2415 strlen(cmd->argv[1]),
2418 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2420 strlen(cmd->argv[1]));
2421 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2422 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2423 silc_buffer_free(buffer);
2425 /* Notify application */
2426 COMMAND(SILC_STATUS_OK);
2429 silc_client_command_free(cmd);
2432 /* SHUTDOWN command. Shutdowns the server. */
2434 SILC_CLIENT_CMD_FUNC(shutdown)
2436 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2439 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2440 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2444 /* Send the command */
2445 silc_client_command_send(cmd->client, cmd->conn,
2446 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2448 /* Notify application */
2449 COMMAND(SILC_STATUS_OK);
2452 silc_client_command_free(cmd);
2455 /* Register all default commands provided by the client library for the
2458 void silc_client_commands_register(SilcClient client)
2460 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2463 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2464 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2465 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2466 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2467 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2468 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2469 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2470 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2471 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2472 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2473 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2474 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2475 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2476 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2477 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2478 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2479 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2480 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2481 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2482 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2483 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2484 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2485 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2486 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2487 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2488 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2490 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2491 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2492 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2495 /* Unregister all commands. */
2497 void silc_client_commands_unregister(SilcClient client)
2499 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2500 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2501 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2502 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2503 SILC_CLIENT_CMDU(list, LIST, "LIST");
2504 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2505 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2506 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2507 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2508 SILC_CLIENT_CMDU(info, INFO, "INFO");
2509 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2510 SILC_CLIENT_CMDU(ping, PING, "PING");
2511 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2512 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2513 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2514 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2515 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2516 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2517 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2518 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2519 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2520 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2521 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2522 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2523 SILC_CLIENT_CMDU(users, USERS, "USERS");
2524 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2526 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2527 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2528 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2531 /**** Client side incoming command handling **********************************/
2533 void silc_client_command_process_whois(SilcClient client,
2534 SilcSocketConnection sock,
2535 SilcCommandPayload payload,
2536 SilcArgumentPayload args);
2538 /* Client is able to receive some command packets even though they are
2539 special case. Server may send WHOIS command to the client to retrieve
2540 Requested Attributes information for WHOIS query the server is
2541 processing. This function currently handles only the WHOIS command,
2542 but if in the future for commands may arrive then this can be made
2543 to support other commands too. */
2545 void silc_client_command_process(SilcClient client,
2546 SilcSocketConnection sock,
2547 SilcPacketContext *packet)
2549 SilcCommandPayload payload;
2550 SilcCommand command;
2551 SilcArgumentPayload args;
2553 /* Get command payload from packet */
2554 payload = silc_command_payload_parse(packet->buffer->data,
2555 packet->buffer->len);
2557 /* Silently ignore bad reply packet */
2558 SILC_LOG_DEBUG(("Bad command packet"));
2563 args = silc_command_get_args(payload);
2565 /* Get the command */
2566 command = silc_command_get(payload);
2569 case SILC_COMMAND_WHOIS:
2570 /* Ignore everything if requested by application */
2571 if (client->internal->params->ignore_requested_attributes)
2574 silc_client_command_process_whois(client, sock, payload, args);
2581 silc_command_payload_free(payload);
2584 void silc_client_command_process_whois(SilcClient client,
2585 SilcSocketConnection sock,
2586 SilcCommandPayload payload,
2587 SilcArgumentPayload args)
2592 SilcBuffer buffer, packet;
2594 SILC_LOG_DEBUG(("Received WHOIS command"));
2596 /* Try to take the Requested Attributes */
2597 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2601 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2605 /* Process requested attributes */
2606 buffer = silc_client_attributes_process(client, sock, attrs);
2608 silc_attribute_payload_list_free(attrs);
2612 /* Send the attributes back */
2614 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2616 silc_command_get_ident(payload),
2617 1, 11, buffer->data, buffer->len);
2618 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2619 NULL, 0, NULL, NULL, packet->data,
2621 silc_buffer_free(packet);
2622 silc_buffer_free(buffer);