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->disconnect(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->internal->
1027 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1028 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1029 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1030 cmd->argv_lens[i], 0);
1031 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1032 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1033 0, pu8, passphrase_len);
1036 passphrase = strdup(cmd->argv[i]);
1037 passphrase_len = cmd->argv_lens[i];
1042 /* Send JOIN command to the server */
1044 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1045 1, name, strlen(name),
1046 2, idp->data, idp->len,
1047 3, passphrase, passphrase_len,
1048 4, cipher, cipher ? strlen(cipher) : 0,
1049 5, hmac, hmac ? strlen(hmac) : 0,
1050 6, auth ? auth->data : NULL,
1051 auth ? auth->len : 0);
1052 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1053 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1054 silc_buffer_free(buffer);
1055 silc_buffer_free(idp);
1057 silc_buffer_free(auth);
1058 silc_free(passphrase);
1060 /* Notify application */
1061 COMMAND(SILC_STATUS_OK);
1064 silc_client_command_free(cmd);
1067 /* MOTD command. Requests motd from server. */
1069 SILC_CLIENT_CMD_FUNC(motd)
1071 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1072 SilcClientConnection conn = cmd->conn;
1076 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1077 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1081 if (cmd->argc < 1 || cmd->argc > 2) {
1082 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1083 "Usage: /MOTD [<server>]");
1084 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1085 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1089 /* Send TOPIC command to the server */
1091 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1092 1, conn->remote_host,
1093 strlen(conn->remote_host));
1095 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1098 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1099 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1100 silc_buffer_free(buffer);
1102 /* Notify application */
1103 COMMAND(SILC_STATUS_OK);
1106 silc_client_command_free(cmd);
1109 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1110 modes as client cannot set itself server/router operator privileges. */
1112 SILC_CLIENT_CMD_FUNC(umode)
1114 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1115 SilcClientConnection conn = cmd->conn;
1116 SilcBuffer buffer, idp;
1117 unsigned char *cp, modebuf[4];
1118 SilcUInt32 mode, add, len;
1122 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1123 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1127 if (cmd->argc < 2) {
1128 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1129 "Usage: /UMODE +|-<modes>");
1130 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1134 mode = conn->local_entry->mode;
1136 /* Are we adding or removing mode */
1137 if (cmd->argv[1][0] == '-')
1143 cp = cmd->argv[1] + 1;
1145 for (i = 0; i < len; i++) {
1150 mode |= SILC_UMODE_SERVER_OPERATOR;
1151 mode |= SILC_UMODE_ROUTER_OPERATOR;
1152 mode |= SILC_UMODE_GONE;
1153 mode |= SILC_UMODE_INDISPOSED;
1154 mode |= SILC_UMODE_BUSY;
1155 mode |= SILC_UMODE_PAGE;
1156 mode |= SILC_UMODE_HYPER;
1157 mode |= SILC_UMODE_ROBOT;
1158 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1159 mode |= SILC_UMODE_REJECT_WATCHING;
1161 mode = SILC_UMODE_NONE;
1166 mode |= SILC_UMODE_SERVER_OPERATOR;
1168 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1172 mode |= SILC_UMODE_ROUTER_OPERATOR;
1174 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1178 mode |= SILC_UMODE_GONE;
1180 mode &= ~SILC_UMODE_GONE;
1184 mode |= SILC_UMODE_INDISPOSED;
1186 mode &= ~SILC_UMODE_INDISPOSED;
1190 mode |= SILC_UMODE_BUSY;
1192 mode &= ~SILC_UMODE_BUSY;
1196 mode |= SILC_UMODE_PAGE;
1198 mode &= ~SILC_UMODE_PAGE;
1202 mode |= SILC_UMODE_HYPER;
1204 mode &= ~SILC_UMODE_HYPER;
1208 mode |= SILC_UMODE_ROBOT;
1210 mode &= ~SILC_UMODE_ROBOT;
1214 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1216 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1220 mode |= SILC_UMODE_REJECT_WATCHING;
1222 mode &= ~SILC_UMODE_REJECT_WATCHING;
1226 mode |= SILC_UMODE_BLOCK_INVITE;
1228 mode &= ~SILC_UMODE_BLOCK_INVITE;
1231 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1237 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1238 SILC_PUT32_MSB(mode, modebuf);
1240 /* Send the command packet. We support sending only one mode at once
1241 that requires an argument. */
1243 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1244 1, idp->data, idp->len,
1245 2, modebuf, sizeof(modebuf));
1246 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1247 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1248 silc_buffer_free(buffer);
1249 silc_buffer_free(idp);
1251 /* Notify application */
1252 COMMAND(SILC_STATUS_OK);
1255 silc_client_command_free(cmd);
1258 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1259 can be set several at once. Those modes that require argument must be set
1260 separately (unless set with modes that does not require arguments). */
1262 SILC_CLIENT_CMD_FUNC(cmode)
1264 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1265 SilcClientConnection conn = cmd->conn;
1266 SilcChannelEntry channel;
1267 SilcBuffer buffer, chidp, auth = NULL;
1268 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1269 SilcUInt32 mode, add, type, len, arg_len = 0;
1273 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1274 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1278 if (cmd->argc < 3) {
1279 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1280 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1281 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1285 if (cmd->argv[1][0] == '*') {
1286 if (!conn->current_channel) {
1287 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1291 channel = conn->current_channel;
1293 name = cmd->argv[1];
1295 channel = silc_client_get_channel(cmd->client, conn, name);
1297 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1302 mode = channel->mode;
1304 /* Are we adding or removing mode */
1305 if (cmd->argv[2][0] == '-')
1310 /* Argument type to be sent to server */
1314 cp = cmd->argv[2] + 1;
1316 for (i = 0; i < len; i++) {
1320 mode |= SILC_CHANNEL_MODE_PRIVATE;
1322 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1326 mode |= SILC_CHANNEL_MODE_SECRET;
1328 mode &= ~SILC_CHANNEL_MODE_SECRET;
1332 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1334 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1338 mode |= SILC_CHANNEL_MODE_INVITE;
1340 mode &= ~SILC_CHANNEL_MODE_INVITE;
1344 mode |= SILC_CHANNEL_MODE_TOPIC;
1346 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1350 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1352 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1356 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1358 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1363 mode |= SILC_CHANNEL_MODE_ULIMIT;
1365 if (cmd->argc < 4) {
1366 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1367 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1368 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1371 ll = atoi(cmd->argv[3]);
1372 SILC_PUT32_MSB(ll, tmp);
1376 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1381 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1383 if (cmd->argc < 4) {
1384 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1385 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1386 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1390 arg_len = cmd->argv_lens[3];
1392 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1397 mode |= SILC_CHANNEL_MODE_CIPHER;
1399 if (cmd->argc < 4) {
1400 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1401 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1402 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1406 arg_len = cmd->argv_lens[3];
1408 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1413 mode |= SILC_CHANNEL_MODE_HMAC;
1415 if (cmd->argc < 4) {
1416 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1417 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1418 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1422 arg_len = cmd->argv_lens[3];
1424 mode &= ~SILC_CHANNEL_MODE_HMAC;
1429 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1431 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1432 cmd->client->private_key,
1434 cmd->client->internal->
1439 arg_len = auth->len;
1441 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1445 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1451 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1452 SILC_PUT32_MSB(mode, modebuf);
1454 /* Send the command packet. We support sending only one mode at once
1455 that requires an argument. */
1458 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1459 1, chidp->data, chidp->len,
1460 2, modebuf, sizeof(modebuf),
1461 type, arg, arg_len);
1464 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1465 1, chidp->data, chidp->len,
1466 2, modebuf, sizeof(modebuf));
1469 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1470 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1471 silc_buffer_free(buffer);
1472 silc_buffer_free(chidp);
1474 silc_buffer_free(auth);
1476 /* Notify application */
1477 COMMAND(SILC_STATUS_OK);
1480 silc_client_command_free(cmd);
1483 /* CUMODE command. Changes client's mode on a channel. */
1485 SILC_CLIENT_CMD_FUNC(cumode)
1487 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1488 SilcClient client = cmd->client;
1489 SilcClientConnection conn = cmd->conn;
1490 SilcChannelEntry channel;
1491 SilcChannelUser chu;
1492 SilcClientEntry client_entry;
1493 SilcBuffer buffer, clidp, chidp, auth = NULL;
1494 unsigned char *name, *cp, modebuf[4];
1495 SilcUInt32 mode = 0, add, len;
1496 char *nickname = NULL;
1500 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1501 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1505 if (cmd->argc < 4) {
1506 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1507 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1508 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1512 if (cmd->argv[1][0] == '*') {
1513 if (!conn->current_channel) {
1514 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1518 channel = conn->current_channel;
1520 name = cmd->argv[1];
1522 channel = silc_client_get_channel(cmd->client, conn, name);
1524 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1529 /* Parse the typed nickname. */
1530 if (client->internal->params->nickname_parse)
1531 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1533 nickname = strdup(cmd->argv[3]);
1535 /* Find client entry */
1536 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1537 cmd->argv[3], TRUE);
1538 if (!client_entry) {
1540 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1544 /* Client entry not found, it was requested thus mark this to be
1546 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1548 silc_client_command_cumode,
1549 silc_client_command_dup(cmd));
1554 /* Get the current mode */
1555 chu = silc_client_on_channel(channel, client_entry);
1559 /* Are we adding or removing mode */
1560 if (cmd->argv[2][0] == '-')
1566 cp = cmd->argv[2] + 1;
1568 for (i = 0; i < len; i++) {
1572 mode |= SILC_CHANNEL_UMODE_CHANFO;
1573 mode |= SILC_CHANNEL_UMODE_CHANOP;
1574 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1575 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1576 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1578 mode = SILC_CHANNEL_UMODE_NONE;
1583 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1584 cmd->client->private_key,
1586 cmd->client->internal->
1590 mode |= SILC_CHANNEL_UMODE_CHANFO;
1592 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1597 mode |= SILC_CHANNEL_UMODE_CHANOP;
1599 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1603 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1605 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1609 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1611 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1615 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1617 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1621 mode |= SILC_CHANNEL_UMODE_QUIET;
1623 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1626 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1632 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1633 SILC_PUT32_MSB(mode, modebuf);
1634 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1636 /* Send the command packet. We support sending only one mode at once
1637 that requires an argument. */
1638 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1640 1, chidp->data, chidp->len,
1642 3, clidp->data, clidp->len,
1643 4, auth ? auth->data : NULL,
1644 auth ? auth->len : 0);
1646 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1647 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1648 silc_buffer_free(buffer);
1649 silc_buffer_free(chidp);
1650 silc_buffer_free(clidp);
1652 silc_buffer_free(auth);
1654 /* Notify application */
1655 COMMAND(SILC_STATUS_OK);
1658 silc_free(nickname);
1659 silc_client_command_free(cmd);
1662 /* KICK command. Kicks a client out of channel. */
1664 SILC_CLIENT_CMD_FUNC(kick)
1666 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1667 SilcClient client = cmd->client;
1668 SilcClientConnection conn = cmd->conn;
1669 SilcIDCacheEntry id_cache = NULL;
1670 SilcChannelEntry channel;
1671 SilcBuffer buffer, idp, idp2;
1672 SilcClientEntry target;
1674 char *nickname = NULL;
1677 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1678 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1682 if (cmd->argc < 3) {
1683 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1684 "Usage: /KICK <channel> <nickname> [<comment>]");
1685 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1689 if (cmd->argv[1][0] == '*') {
1690 if (!conn->current_channel) {
1691 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1694 name = conn->current_channel->channel_name;
1696 name = cmd->argv[1];
1699 if (!conn->current_channel) {
1700 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1704 /* Get the Channel ID of the channel */
1705 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1706 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1710 channel = (SilcChannelEntry)id_cache->context;
1712 /* Parse the typed nickname. */
1713 if (client->internal->params->nickname_parse)
1714 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1716 nickname = strdup(cmd->argv[2]);
1718 /* Get the target client */
1719 target = silc_idlist_get_client(cmd->client, conn, nickname,
1720 cmd->argv[2], FALSE);
1722 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1723 "No such client: %s", cmd->argv[2]);
1724 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1728 /* Send KICK command to the server */
1729 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1730 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1732 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1733 1, idp->data, idp->len,
1734 2, idp2->data, idp2->len);
1736 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1737 1, idp->data, idp->len,
1738 2, idp2->data, idp2->len,
1740 strlen(cmd->argv[3]));
1741 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1742 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1743 silc_buffer_free(buffer);
1744 silc_buffer_free(idp);
1745 silc_buffer_free(idp2);
1747 /* Notify application */
1748 COMMAND(SILC_STATUS_OK);
1751 silc_free(nickname);
1752 silc_client_command_free(cmd);
1755 static void silc_client_command_oper_send(unsigned char *data,
1756 SilcUInt32 data_len, void *context)
1758 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1759 SilcClientConnection conn = cmd->conn;
1760 SilcBuffer buffer, auth;
1762 if (cmd->argc >= 3) {
1763 /* Encode the public key authentication payload */
1764 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1765 cmd->client->private_key,
1766 cmd->client->rng, conn->hash,
1770 /* Encode the password authentication payload */
1771 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1775 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1777 strlen(cmd->argv[1]),
1778 2, auth ? auth->data : NULL,
1779 auth ? auth->len : 0);
1780 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1781 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1783 silc_buffer_free(buffer);
1784 silc_buffer_free(auth);
1786 /* Notify application */
1787 COMMAND(SILC_STATUS_OK);
1790 /* OPER command. Used to obtain server operator privileges. */
1792 SILC_CLIENT_CMD_FUNC(oper)
1794 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1795 SilcClientConnection conn = cmd->conn;
1798 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1799 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1803 if (cmd->argc < 2) {
1804 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1805 "Usage: /OPER <username> [-pubkey]");
1806 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1810 if (cmd->argc < 3) {
1811 /* Get passphrase */
1812 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1813 silc_client_command_oper_send,
1818 silc_client_command_oper_send(NULL, 0, context);
1821 silc_client_command_free(cmd);
1824 static void silc_client_command_silcoper_send(unsigned char *data,
1825 SilcUInt32 data_len,
1828 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1829 SilcClientConnection conn = cmd->conn;
1830 SilcBuffer buffer, auth;
1832 if (cmd->argc >= 3) {
1833 /* Encode the public key authentication payload */
1834 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1835 cmd->client->private_key,
1836 cmd->client->rng, conn->hash,
1840 /* Encode the password authentication payload */
1841 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1845 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1847 strlen(cmd->argv[1]),
1848 2, auth ? auth->data : NULL,
1849 auth ? auth->len : 0);
1850 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1851 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1853 silc_buffer_free(buffer);
1854 silc_buffer_free(auth);
1856 /* Notify application */
1857 COMMAND(SILC_STATUS_OK);
1860 /* SILCOPER command. Used to obtain router operator privileges. */
1862 SILC_CLIENT_CMD_FUNC(silcoper)
1864 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1865 SilcClientConnection conn = cmd->conn;
1868 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1869 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1873 if (cmd->argc < 2) {
1874 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1875 "Usage: /SILCOPER <username> [-pubkey]");
1876 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1880 if (cmd->argc < 3) {
1881 /* Get passphrase */
1882 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1883 silc_client_command_silcoper_send,
1888 silc_client_command_silcoper_send(NULL, 0, context);
1891 silc_client_command_free(cmd);
1894 /* Command BAN. This is used to manage the ban list of the channel. */
1896 SILC_CLIENT_CMD_FUNC(ban)
1898 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1899 SilcClientConnection conn = cmd->conn;
1900 SilcChannelEntry channel;
1901 SilcBuffer buffer, chidp;
1903 char *name, *ban = NULL;
1906 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1907 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1911 if (cmd->argc < 2) {
1912 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1913 "Usage: /BAN <channel> "
1914 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1915 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1919 if (cmd->argv[1][0] == '*') {
1920 if (!conn->current_channel) {
1921 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1925 channel = conn->current_channel;
1927 name = cmd->argv[1];
1929 channel = silc_client_get_channel(cmd->client, conn, name);
1931 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1936 if (cmd->argc == 3) {
1937 if (cmd->argv[2][0] == '+')
1946 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1948 /* Send the command */
1949 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1950 ++conn->cmd_ident, 2,
1951 1, chidp->data, chidp->len,
1952 type, ban, ban ? strlen(ban) : 0);
1953 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1954 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1955 silc_buffer_free(buffer);
1956 silc_buffer_free(chidp);
1958 /* Notify application */
1959 COMMAND(SILC_STATUS_OK);
1962 silc_client_command_free(cmd);
1965 /* Command DETACH. This is used to detach from the server */
1967 SILC_CLIENT_CMD_FUNC(detach)
1969 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1970 SilcClientConnection conn = cmd->conn;
1974 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1975 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1979 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1980 ++conn->cmd_ident, 0);
1981 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1982 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1983 silc_buffer_free(buffer);
1985 /* Notify application */
1986 COMMAND(SILC_STATUS_OK);
1989 silc_client_command_free(cmd);
1992 /* Command WATCH. */
1994 SILC_CLIENT_CMD_FUNC(watch)
1996 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1997 SilcClientConnection conn = cmd->conn;
1998 SilcBuffer buffer, idp = NULL;
2002 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2003 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2007 if (cmd->argc < 3) {
2008 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2014 if (!strcasecmp(cmd->argv[1], "-add")) {
2016 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2019 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2023 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2024 ++conn->cmd_ident, 2,
2025 1, idp->data, idp->len,
2028 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2029 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2030 silc_buffer_free(buffer);
2032 /* Notify application */
2033 COMMAND(SILC_STATUS_OK);
2037 silc_buffer_free(idp);
2038 silc_client_command_free(cmd);
2041 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2043 SILC_CLIENT_CMD_FUNC(leave)
2045 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2046 SilcClientConnection conn = cmd->conn;
2047 SilcChannelEntry channel;
2048 SilcChannelUser chu;
2049 SilcBuffer buffer, idp;
2053 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2054 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2058 if (cmd->argc != 2) {
2059 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2060 "Usage: /LEAVE <channel>");
2061 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2065 if (cmd->argv[1][0] == '*') {
2066 if (!conn->current_channel) {
2067 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2070 name = conn->current_channel->channel_name;
2072 name = cmd->argv[1];
2075 /* Get the channel entry */
2076 channel = silc_client_get_channel(cmd->client, conn, name);
2078 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2082 /* Remove us from channel */
2083 chu = silc_client_on_channel(channel, conn->local_entry);
2085 silc_hash_table_del(chu->client->channels, chu->channel);
2086 silc_hash_table_del(chu->channel->user_list, chu->client);
2090 /* Send LEAVE command to the server */
2091 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2092 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2093 1, idp->data, idp->len);
2094 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2095 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2096 silc_buffer_free(buffer);
2097 silc_buffer_free(idp);
2099 /* Notify application */
2100 COMMAND(SILC_STATUS_OK);
2102 if (conn->current_channel == channel)
2103 conn->current_channel = NULL;
2105 silc_client_del_channel(cmd->client, cmd->conn, channel);
2108 silc_client_command_free(cmd);
2111 /* Command USERS. Requests the USERS of the clients joined on requested
2114 SILC_CLIENT_CMD_FUNC(users)
2116 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2117 SilcClientConnection conn = cmd->conn;
2122 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2123 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2127 if (cmd->argc != 2) {
2128 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2129 "Usage: /USERS <channel>");
2130 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2134 if (cmd->argv[1][0] == '*') {
2135 if (!conn->current_channel) {
2136 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2139 name = conn->current_channel->channel_name;
2141 name = cmd->argv[1];
2144 /* Send USERS command to the server */
2145 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2146 ++conn->cmd_ident, 1,
2147 2, name, strlen(name));
2148 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2149 NULL, 0, NULL, NULL, buffer->data,
2151 silc_buffer_free(buffer);
2153 /* Notify application */
2154 COMMAND(SILC_STATUS_OK);
2157 silc_client_command_free(cmd);
2160 /* Command GETKEY. Used to fetch remote client's public key. */
2162 SILC_CLIENT_CMD_FUNC(getkey)
2164 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2165 SilcClientConnection conn = cmd->conn;
2166 SilcClient client = cmd->client;
2167 SilcClientEntry client_entry = NULL;
2168 SilcServerEntry server_entry = NULL;
2169 char *nickname = NULL;
2170 SilcBuffer idp, buffer;
2172 SILC_LOG_DEBUG(("Start"));
2175 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2176 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2180 if (cmd->argc < 2) {
2181 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2182 "Usage: /GETKEY <nickname or server name>");
2183 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2187 /* Parse the typed nickname. */
2188 if (client->internal->params->nickname_parse)
2189 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2191 nickname = strdup(cmd->argv[1]);
2193 /* Find client entry */
2194 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2196 if (!client_entry) {
2197 /* Check whether user requested server actually */
2198 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2200 if (!server_entry) {
2201 /* No. what ever user wants we don't have it, so resolve it. We
2202 will first try to resolve the client, and if that fails then
2203 we'll try to resolve the server. */
2205 if (!cmd->pending) {
2206 /* This will send the IDENTIFY command for nickname */
2207 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2208 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2210 silc_client_command_getkey,
2211 silc_client_command_dup(cmd));
2215 SilcClientCommandReplyContext reply =
2216 (SilcClientCommandReplyContext)context2;
2219 /* If nickname was not found, then resolve the server. */
2220 silc_command_get_status(reply->payload, NULL, &error);
2221 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2222 /* This sends the IDENTIFY command to resolve the server. */
2223 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2225 silc_client_command_reply_identify_i, 0,
2227 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2229 2, cmd->argv[1], cmd->argv_lens[1]);
2230 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2232 silc_client_command_getkey,
2233 silc_client_command_dup(cmd));
2237 /* If server was not found, then we've resolved both nickname and
2238 server and did not find anybody. */
2239 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2240 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2241 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2242 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2243 silc_get_status_message(error));
2244 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2248 COMMAND_ERROR(error);
2253 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2255 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2258 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2259 1, idp->data, idp->len);
2260 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2261 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2262 silc_buffer_free(buffer);
2263 silc_buffer_free(idp);
2265 /* Notify application */
2266 COMMAND(SILC_STATUS_OK);
2269 silc_free(nickname);
2270 silc_client_command_free(cmd);
2273 /* Register a new command indicated by the `command' to the SILC client.
2274 The `name' is optional command name. If provided the command may be
2275 searched using the silc_client_command_find by that name. The
2276 `command_function' is the function to be called when the command is
2277 executed, and the `command_reply_function' is the function to be
2278 called after the server has sent reply back to the command.
2280 The `ident' is optional identifier for the command. If non-zero
2281 the `command_reply_function' for the command type `command' will be
2282 called only if the command reply sent by server includes the
2283 command identifier `ident'. Application usually does not need it
2284 and set it to zero value. */
2286 bool silc_client_command_register(SilcClient client,
2287 SilcCommand command,
2289 SilcCommandCb command_function,
2290 SilcCommandCb command_reply_function,
2294 SilcClientCommand cmd;
2296 cmd = silc_calloc(1, sizeof(*cmd));
2298 cmd->command = command_function;
2299 cmd->reply = command_reply_function;
2300 cmd->name = name ? strdup(name) : NULL;
2301 cmd->max_args = max_args;
2304 silc_list_add(client->internal->commands, cmd);
2309 /* Unregister a command indicated by the `command' with command function
2310 `command_function' and command reply function `command_reply_function'.
2311 Returns TRUE if the command was found and unregistered. */
2313 bool silc_client_command_unregister(SilcClient client,
2314 SilcCommand command,
2315 SilcCommandCb command_function,
2316 SilcCommandCb command_reply_function,
2319 SilcClientCommand cmd;
2321 silc_list_start(client->internal->commands);
2322 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2323 if (cmd->cmd == command && cmd->command == command_function &&
2324 cmd->reply == command_reply_function && cmd->ident == ident) {
2325 silc_list_del(client->internal->commands, cmd);
2326 silc_free(cmd->name);
2335 /* Private range commands, specific to this implementation (and compatible
2336 with SILC Server). */
2338 /* CONNECT command. Connects the server to another server. */
2340 SILC_CLIENT_CMD_FUNC(connect)
2342 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2343 SilcClientConnection conn = cmd->conn;
2345 unsigned char port[4];
2349 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2350 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2354 if (cmd->argc < 2) {
2355 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2356 "Usage: /CONNECT <server> [<port>]");
2357 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2361 if (cmd->argc == 3) {
2362 tmp = atoi(cmd->argv[2]);
2363 SILC_PUT32_MSB(tmp, port);
2367 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2369 strlen(cmd->argv[1]),
2372 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2374 strlen(cmd->argv[1]));
2375 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2376 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2377 silc_buffer_free(buffer);
2379 /* Notify application */
2380 COMMAND(SILC_STATUS_OK);
2383 silc_client_command_free(cmd);
2387 /* CLOSE command. Close server connection to the remote server */
2389 SILC_CLIENT_CMD_FUNC(close)
2391 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2392 SilcClientConnection conn = cmd->conn;
2394 unsigned char port[4];
2398 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2399 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2403 if (cmd->argc < 2) {
2404 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2405 "Usage: /CLOSE <server> [<port>]");
2406 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2410 if (cmd->argc == 3) {
2411 tmp = atoi(cmd->argv[2]);
2412 SILC_PUT32_MSB(tmp, port);
2416 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2418 strlen(cmd->argv[1]),
2421 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2423 strlen(cmd->argv[1]));
2424 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2425 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2426 silc_buffer_free(buffer);
2428 /* Notify application */
2429 COMMAND(SILC_STATUS_OK);
2432 silc_client_command_free(cmd);
2435 /* SHUTDOWN command. Shutdowns the server. */
2437 SILC_CLIENT_CMD_FUNC(shutdown)
2439 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2442 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2443 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2447 /* Send the command */
2448 silc_client_command_send(cmd->client, cmd->conn,
2449 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2451 /* Notify application */
2452 COMMAND(SILC_STATUS_OK);
2455 silc_client_command_free(cmd);
2458 /* Register all default commands provided by the client library for the
2461 void silc_client_commands_register(SilcClient client)
2463 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2466 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2467 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2468 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2469 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2470 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2471 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2472 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2473 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2474 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2475 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2476 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2477 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2478 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2479 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2480 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2481 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2482 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2483 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2484 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2485 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2486 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2487 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2488 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2489 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2490 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2491 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2493 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2494 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2495 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2498 /* Unregister all commands. */
2500 void silc_client_commands_unregister(SilcClient client)
2502 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2503 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2504 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2505 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2506 SILC_CLIENT_CMDU(list, LIST, "LIST");
2507 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2508 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2509 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2510 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2511 SILC_CLIENT_CMDU(info, INFO, "INFO");
2512 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2513 SILC_CLIENT_CMDU(ping, PING, "PING");
2514 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2515 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2516 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2517 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2518 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2519 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2520 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2521 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2522 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2523 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2524 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2525 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2526 SILC_CLIENT_CMDU(users, USERS, "USERS");
2527 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2529 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2530 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2531 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2534 /**** Client side incoming command handling **********************************/
2536 void silc_client_command_process_whois(SilcClient client,
2537 SilcSocketConnection sock,
2538 SilcCommandPayload payload,
2539 SilcArgumentPayload args);
2541 /* Client is able to receive some command packets even though they are
2542 special case. Server may send WHOIS command to the client to retrieve
2543 Requested Attributes information for WHOIS query the server is
2544 processing. This function currently handles only the WHOIS command,
2545 but if in the future for commands may arrive then this can be made
2546 to support other commands too. */
2548 void silc_client_command_process(SilcClient client,
2549 SilcSocketConnection sock,
2550 SilcPacketContext *packet)
2552 SilcCommandPayload payload;
2553 SilcCommand command;
2554 SilcArgumentPayload args;
2556 /* Get command payload from packet */
2557 payload = silc_command_payload_parse(packet->buffer->data,
2558 packet->buffer->len);
2560 /* Silently ignore bad reply packet */
2561 SILC_LOG_DEBUG(("Bad command packet"));
2566 args = silc_command_get_args(payload);
2568 /* Get the command */
2569 command = silc_command_get(payload);
2572 case SILC_COMMAND_WHOIS:
2573 /* Ignore everything if requested by application */
2574 if (client->internal->params->ignore_requested_attributes)
2577 silc_client_command_process_whois(client, sock, payload, args);
2584 silc_command_payload_free(payload);
2587 void silc_client_command_process_whois(SilcClient client,
2588 SilcSocketConnection sock,
2589 SilcCommandPayload payload,
2590 SilcArgumentPayload args)
2595 SilcBuffer buffer, packet;
2597 SILC_LOG_DEBUG(("Received WHOIS command"));
2599 /* Try to take the Requested Attributes */
2600 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2604 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2608 /* Process requested attributes */
2609 buffer = silc_client_attributes_process(client, sock, attrs);
2611 silc_attribute_payload_list_free(attrs);
2615 /* Send the attributes back */
2617 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2619 silc_command_get_ident(payload),
2620 1, 11, buffer->data, buffer->len);
2621 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2622 NULL, 0, NULL, NULL, packet->data,
2624 silc_buffer_free(packet);
2625 silc_buffer_free(buffer);