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->internal->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->internal->pending_commands)
125 silc_dlist_start(conn->internal->pending_commands);
126 while ((r = silc_dlist_get(conn->internal->pending_commands))
128 if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
130 && r->ident == ident) {
131 silc_dlist_del(conn->internal->pending_commands, r);
137 /* Checks for pending commands and marks callbacks to be called from
138 the command reply function. */
140 SilcClientCommandPendingCallbacks
141 silc_client_command_pending_check(SilcClientConnection conn,
142 SilcClientCommandReplyContext ctx,
145 SilcUInt32 *callbacks_count)
147 SilcClientCommandPending *r;
148 SilcClientCommandPendingCallbacks callbacks = NULL;
151 silc_dlist_start(conn->internal->pending_commands);
152 while ((r = silc_dlist_get(conn->internal->pending_commands))
154 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
155 && r->ident == ident) {
156 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
157 callbacks[i].context = r->context;
158 callbacks[i].callback = r->callback;
159 r->reply_check = TRUE;
165 *callbacks_count = i;
169 /* Allocate Command Context */
171 SilcClientCommandContext silc_client_command_alloc(void)
173 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
178 /* Free command context and its internals */
180 void silc_client_command_free(SilcClientCommandContext ctx)
183 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
185 if (ctx->users < 1) {
188 for (i = 0; i < ctx->argc; i++)
189 silc_free(ctx->argv[i]);
190 silc_free(ctx->argv_lens);
191 silc_free(ctx->argv_types);
196 /* Duplicate Command Context by adding reference counter. The context won't
197 be free'd untill it hits zero. */
199 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
202 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
207 /* Command WHOIS. This command is used to query information about
210 SILC_CLIENT_CMD_FUNC(whois)
212 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
213 SilcClientConnection conn = cmd->conn;
214 SilcBuffer buffer, attrs = NULL;
215 unsigned char count[4], *tmp = NULL;
218 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
219 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
223 /* Given without arguments fetches client's own information */
225 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
226 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
228 1, 4, buffer->data, buffer->len);
229 silc_buffer_free(buffer);
233 if (cmd->argc == 2) {
234 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
235 ++conn->cmd_ident, 1,
239 if (!strcasecmp(cmd->argv[2], "-details"))
240 attrs = silc_client_attributes_request(0);
242 if (!attrs || cmd->argc > 3) {
243 int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
244 SILC_PUT32_MSB(c, count);
248 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
249 ++conn->cmd_ident, 3,
250 1, cmd->argv[1], cmd->argv_lens[1],
251 2, tmp ? tmp : NULL, tmp ? 4 : 0,
252 3, attrs ? attrs->data : NULL,
253 attrs ? attrs->len : 0);
255 silc_client_packet_send(cmd->client, cmd->conn->sock,
256 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
257 buffer->data, buffer->len, TRUE);
258 silc_buffer_free(buffer);
260 /* Notify application */
261 COMMAND(SILC_STATUS_OK);
264 silc_client_command_free(cmd);
267 /* Command WHOWAS. This command is used to query history information about
268 specific user that used to exist in the network. */
270 SILC_CLIENT_CMD_FUNC(whowas)
272 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
273 SilcClientConnection conn = cmd->conn;
275 unsigned char count[4];
278 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
279 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
283 if (cmd->argc < 2 || cmd->argc > 3) {
284 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
285 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
286 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
287 SILC_STATUS_ERR_TOO_MANY_PARAMS));
291 if (cmd->argc == 2) {
292 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
293 ++conn->cmd_ident, 1,
297 int c = atoi(cmd->argv[2]);
298 memset(count, 0, sizeof(count));
299 SILC_PUT32_MSB(c, count);
300 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
301 ++conn->cmd_ident, 2,
302 1, cmd->argv[1], cmd->argv_lens[1],
303 2, count, sizeof(count));
305 silc_client_packet_send(cmd->client, cmd->conn->sock,
306 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
307 buffer->data, buffer->len, TRUE);
308 silc_buffer_free(buffer);
310 /* Notify application */
311 COMMAND(SILC_STATUS_OK);
314 silc_client_command_free(cmd);
317 /* Command IDENTIFY. This command is used to query information about
318 specific user, especially ID's.
320 NOTE: This command is used only internally by the client library
321 and application MUST NOT call this command directly. */
323 SILC_CLIENT_CMD_FUNC(identify)
325 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
326 SilcClientConnection conn = cmd->conn;
328 unsigned char count[4];
331 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
332 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
336 if (cmd->argc < 2 || cmd->argc > 3)
339 if (cmd->argc == 2) {
340 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
341 ++conn->cmd_ident, 1,
345 int c = atoi(cmd->argv[2]);
346 memset(count, 0, sizeof(count));
347 SILC_PUT32_MSB(c, count);
348 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
349 ++conn->cmd_ident, 2,
352 4, count, sizeof(count));
355 silc_client_packet_send(cmd->client, cmd->conn->sock,
356 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
357 buffer->data, buffer->len, TRUE);
358 silc_buffer_free(buffer);
361 silc_client_command_free(cmd);
364 /* Command NICK. Shows current nickname/sets new nickname on current
367 SILC_CLIENT_CMD_FUNC(nick)
369 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
370 SilcClientConnection conn = cmd->conn;
374 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
375 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
380 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
381 "Usage: /NICK <nickname>");
382 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
386 if (!strcmp(conn->nickname, cmd->argv[1]))
389 /* Show current nickname */
392 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
393 "Your nickname is %s on server %s",
394 conn->nickname, conn->remote_host);
396 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
397 "Your nickname is %s", conn->nickname);
400 COMMAND(SILC_STATUS_OK);
404 if (cmd->argv_lens[1] > 128)
405 cmd->argv_lens[1] = 128;
407 /* Send the NICK command */
408 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
412 ++cmd->conn->cmd_ident);
413 silc_client_packet_send(cmd->client, cmd->conn->sock,
414 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
415 buffer->data, buffer->len, TRUE);
416 silc_buffer_free(buffer);
419 silc_client_command_free(cmd);
422 /* Command LIST. Lists channels on the current server. */
424 SILC_CLIENT_CMD_FUNC(list)
426 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
427 SilcClientConnection conn = cmd->conn;
428 SilcIDCacheEntry id_cache = NULL;
429 SilcChannelEntry channel;
430 SilcBuffer buffer, idp = NULL;
434 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
435 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
439 if (cmd->argc == 2) {
442 /* Get the Channel ID of the channel */
443 if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
445 channel = (SilcChannelEntry)id_cache->context;
446 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
451 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
452 ++conn->cmd_ident, 0);
454 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
455 ++conn->cmd_ident, 1,
456 1, idp->data, idp->len);
458 silc_client_packet_send(cmd->client, cmd->conn->sock,
459 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
460 buffer->data, buffer->len, TRUE);
461 silc_buffer_free(buffer);
463 silc_buffer_free(idp);
465 /* Notify application */
466 COMMAND(SILC_STATUS_OK);
469 silc_client_command_free(cmd);
472 /* Command TOPIC. Sets/shows topic on a channel. */
474 SILC_CLIENT_CMD_FUNC(topic)
476 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
477 SilcClientConnection conn = cmd->conn;
478 SilcIDCacheEntry id_cache = NULL;
479 SilcChannelEntry channel;
480 SilcBuffer buffer, idp;
484 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
485 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
489 if (cmd->argc < 2 || cmd->argc > 3) {
490 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
491 "Usage: /TOPIC <channel> [<topic>]");
492 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
493 SILC_STATUS_ERR_TOO_MANY_PARAMS));
497 if (cmd->argv[1][0] == '*') {
498 if (!conn->current_channel) {
499 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
502 name = conn->current_channel->channel_name;
507 if (!conn->current_channel) {
508 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
512 /* Get the Channel ID of the channel */
513 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
515 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
519 channel = (SilcChannelEntry)id_cache->context;
521 /* Send TOPIC command to the server */
522 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
524 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
525 ++conn->cmd_ident, 2,
526 1, idp->data, idp->len,
528 strlen(cmd->argv[2]));
530 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
531 ++conn->cmd_ident, 1,
532 1, idp->data, idp->len);
533 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
534 0, NULL, NULL, buffer->data, buffer->len, TRUE);
535 silc_buffer_free(buffer);
536 silc_buffer_free(idp);
538 /* Notify application */
539 COMMAND(SILC_STATUS_OK);
542 silc_client_command_free(cmd);
545 /* Command INVITE. Invites specific client to join a channel. This is
546 also used to mange the invite list of the channel. */
548 SILC_CLIENT_CMD_FUNC(invite)
550 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
551 SilcClient client = cmd->client;
552 SilcClientConnection conn = cmd->conn;
553 SilcClientEntry client_entry = NULL;
554 SilcChannelEntry channel;
555 SilcBuffer buffer, clidp, chidp;
557 char *nickname = NULL, *name;
561 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
562 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
567 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
568 "Usage: /INVITE <channel> [<nickname>[@server>]"
569 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
570 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
574 if (cmd->argv[1][0] == '*') {
575 if (!conn->current_channel) {
576 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
580 channel = conn->current_channel;
584 channel = silc_client_get_channel(cmd->client, conn, name);
586 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
591 /* Parse the typed nickname. */
592 if (cmd->argc == 3) {
593 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
594 if (client->internal->params->nickname_parse)
595 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
597 nickname = strdup(cmd->argv[2]);
599 /* Find client entry */
600 client_entry = silc_idlist_get_client(client, conn, nickname,
604 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
608 /* Client entry not found, it was requested thus mark this to be
610 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
612 silc_client_command_invite,
613 silc_client_command_dup(cmd));
618 invite = cmd->argv[2];
620 if (cmd->argv[2][0] == '+')
627 /* Send the command */
628 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
630 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
631 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
632 ++conn->cmd_ident, 3,
633 1, chidp->data, chidp->len,
634 2, clidp->data, clidp->len,
635 type, invite, invite ?
637 silc_buffer_free(clidp);
639 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
640 ++conn->cmd_ident, 2,
641 1, chidp->data, chidp->len,
642 type, invite, invite ?
646 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
647 0, NULL, NULL, buffer->data, buffer->len, TRUE);
648 silc_buffer_free(buffer);
649 silc_buffer_free(chidp);
651 /* Notify application */
652 COMMAND(SILC_STATUS_OK);
656 silc_client_command_free(cmd);
661 SilcClientConnection conn;
664 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
666 QuitInternal q = (QuitInternal)context;
668 /* Close connection */
669 q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
670 silc_client_close_connection(q->client, q->conn->sock->user_data);
675 /* Command QUIT. Closes connection with current server. */
677 SILC_CLIENT_CMD_FUNC(quit)
679 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
684 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
685 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
690 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
691 &cmd->argv[1], &cmd->argv_lens[1],
692 &cmd->argv_types[1], 0);
694 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
695 NULL, NULL, NULL, 0);
696 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
698 buffer->data, buffer->len, TRUE);
699 silc_buffer_free(buffer);
701 q = silc_calloc(1, sizeof(*q));
702 q->client = cmd->client;
705 /* Sleep for a while */
708 /* We quit the connection with little timeout */
709 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
710 silc_client_command_quit_cb, (void *)q,
711 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
713 /* Notify application */
714 COMMAND(SILC_STATUS_OK);
717 silc_client_command_free(cmd);
720 /* Timeout callback to remove the killed client from cache */
722 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
724 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
725 SilcClient client = cmd->client;
726 SilcClientConnection conn = cmd->conn;
727 SilcClientEntry target;
728 char *nickname = NULL;
730 /* Parse the typed nickname. */
731 if (client->internal->params->nickname_parse)
732 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
734 nickname = strdup(cmd->argv[1]);
736 /* Get the target client */
737 target = silc_idlist_get_client(cmd->client, conn, nickname,
738 cmd->argv[1], FALSE);
740 /* Remove the client from all channels and free it */
741 silc_client_del_client(client, conn, target);
744 silc_client_command_free(cmd);
747 /* Kill command's pending command callback to actually remove the killed
748 client from our local cache. */
750 SILC_CLIENT_CMD_FUNC(kill_remove)
752 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
753 SilcClientCommandReplyContext reply =
754 (SilcClientCommandReplyContext)context2;
757 silc_command_get_status(reply->payload, &status, NULL);
758 if (status == SILC_STATUS_OK) {
759 /* Remove with timeout */
760 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
761 silc_client_command_kill_remove_later, context,
762 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
766 silc_client_command_free(cmd);
769 /* Command KILL. Router operator can use this command to remove an client
770 fromthe SILC Network. */
772 SILC_CLIENT_CMD_FUNC(kill)
774 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
775 SilcClient client = cmd->client;
776 SilcClientConnection conn = cmd->conn;
777 SilcBuffer buffer, idp;
778 SilcClientEntry target;
779 char *nickname = NULL;
782 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
783 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
788 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
789 "Usage: /KILL <nickname> [<comment>]");
790 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
794 /* Parse the typed nickname. */
795 if (client->internal->params->nickname_parse)
796 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
798 nickname = strdup(cmd->argv[1]);
800 /* Get the target client */
801 target = silc_idlist_get_client(cmd->client, conn, nickname,
805 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
809 /* Client entry not found, it was requested thus mark this to be
811 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
813 silc_client_command_kill,
814 silc_client_command_dup(cmd));
819 /* Send the KILL command to the server */
820 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
822 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
823 ++conn->cmd_ident, 1,
824 1, idp->data, idp->len);
826 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
827 ++conn->cmd_ident, 2,
828 1, idp->data, idp->len,
830 strlen(cmd->argv[2]));
831 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
832 0, NULL, NULL, buffer->data, buffer->len, TRUE);
833 silc_buffer_free(buffer);
834 silc_buffer_free(idp);
836 /* Notify application */
837 COMMAND(SILC_STATUS_OK);
839 /* Register a pending callback that will actually remove the killed
840 client from our cache. */
841 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
842 silc_client_command_kill_remove,
843 silc_client_command_dup(cmd));
847 silc_client_command_free(cmd);
850 /* Command INFO. Request information about specific server. If specific
851 server is not provided the current server is used. */
853 SILC_CLIENT_CMD_FUNC(info)
855 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
856 SilcClientConnection conn = cmd->conn;
861 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
862 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
867 name = strdup(cmd->argv[1]);
869 /* Send the command */
871 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
872 1, name, strlen(name));
874 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
875 NULL, NULL, NULL, 0);
876 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
877 0, NULL, NULL, buffer->data, buffer->len, TRUE);
878 silc_buffer_free(buffer);
882 /* Notify application */
883 COMMAND(SILC_STATUS_OK);
886 silc_client_command_free(cmd);
889 /* Command STATS. Shows server and network statistics. */
891 SILC_CLIENT_CMD_FUNC(stats)
893 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
894 SilcClientConnection conn = cmd->conn;
895 SilcBuffer buffer, idp = NULL;
898 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
899 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
903 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
905 /* Send the command */
906 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
907 ++conn->cmd_ident, 1,
908 SILC_ID_SERVER, idp->data, idp->len);
909 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
910 0, NULL, NULL, buffer->data, buffer->len, TRUE);
911 silc_buffer_free(buffer);
912 silc_buffer_free(idp);
914 /* Notify application */
915 COMMAND(SILC_STATUS_OK);
918 silc_client_command_free(cmd);
921 /* Command PING. Sends ping to server. This is used to test the
922 communication channel. */
924 SILC_CLIENT_CMD_FUNC(ping)
926 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
927 SilcClientConnection conn = cmd->conn;
933 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
934 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
938 /* Send the command */
939 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
940 1, conn->remote_id_data,
941 silc_id_get_len(conn->remote_id,
943 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
944 0, NULL, NULL, buffer->data, buffer->len, TRUE);
945 silc_buffer_free(buffer);
947 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
950 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
951 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
955 /* Start counting time */
956 for (i = 0; i < conn->internal->ping_count; i++) {
957 if (conn->internal->ping[i].dest_id == NULL) {
958 conn->internal->ping[i].start_time = time(NULL);
959 conn->internal->ping[i].dest_id = id;
960 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
964 if (i >= conn->internal->ping_count) {
965 i = conn->internal->ping_count;
966 conn->internal->ping =
967 silc_realloc(conn->internal->ping,
968 sizeof(*conn->internal->ping) * (i + 1));
969 conn->internal->ping[i].start_time = time(NULL);
970 conn->internal->ping[i].dest_id = id;
971 conn->internal->ping[i].dest_name = strdup(conn->remote_host);
972 conn->internal->ping_count++;
975 /* Notify application */
976 COMMAND(SILC_STATUS_OK);
979 silc_client_command_free(cmd);
982 /* Command JOIN. Joins to a channel. */
984 SILC_CLIENT_CMD_FUNC(join)
986 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
987 SilcClientConnection conn = cmd->conn;
988 SilcChannelEntry channel;
989 SilcBuffer buffer, idp, auth = NULL;
990 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
991 int i, passphrase_len = 0;
994 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
995 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1000 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1004 /* See if we have joined to the requested channel already */
1005 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1006 if (channel && silc_client_on_channel(channel, conn->local_entry))
1009 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1011 if (cmd->argv_lens[1] > 256)
1012 cmd->argv_lens[1] = 256;
1014 name = cmd->argv[1];
1016 for (i = 2; i < cmd->argc; i++) {
1017 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1018 cipher = cmd->argv[i + 1];
1020 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1021 hmac = cmd->argv[i + 1];
1023 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1024 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1025 cmd->client->private_key,
1027 cmd->client->sha1hash,
1032 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1033 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1034 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1035 cmd->argv_lens[i], 0);
1036 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1037 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1038 0, pu8, passphrase_len);
1041 passphrase = strdup(cmd->argv[i]);
1042 passphrase_len = cmd->argv_lens[i];
1047 /* Send JOIN command to the server */
1049 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1050 1, name, strlen(name),
1051 2, idp->data, idp->len,
1052 3, passphrase, passphrase_len,
1053 4, cipher, cipher ? strlen(cipher) : 0,
1054 5, hmac, hmac ? strlen(hmac) : 0,
1055 6, auth ? auth->data : NULL,
1056 auth ? auth->len : 0);
1057 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1058 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1059 silc_buffer_free(buffer);
1060 silc_buffer_free(idp);
1062 silc_buffer_free(auth);
1063 silc_free(passphrase);
1065 /* Notify application */
1066 COMMAND(SILC_STATUS_OK);
1069 silc_client_command_free(cmd);
1072 /* MOTD command. Requests motd from server. */
1074 SILC_CLIENT_CMD_FUNC(motd)
1076 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1077 SilcClientConnection conn = cmd->conn;
1081 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1082 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1086 if (cmd->argc < 1 || cmd->argc > 2) {
1087 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1088 "Usage: /MOTD [<server>]");
1089 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1090 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1094 /* Send TOPIC command to the server */
1096 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1097 1, conn->remote_host,
1098 strlen(conn->remote_host));
1100 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1103 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1104 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1105 silc_buffer_free(buffer);
1107 /* Notify application */
1108 COMMAND(SILC_STATUS_OK);
1111 silc_client_command_free(cmd);
1114 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1115 modes as client cannot set itself server/router operator privileges. */
1117 SILC_CLIENT_CMD_FUNC(umode)
1119 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1120 SilcClientConnection conn = cmd->conn;
1121 SilcBuffer buffer, idp;
1122 unsigned char *cp, modebuf[4];
1123 SilcUInt32 mode, add, len;
1127 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1128 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1132 if (cmd->argc < 2) {
1133 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1134 "Usage: /UMODE +|-<modes>");
1135 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1139 mode = conn->local_entry->mode;
1141 /* Are we adding or removing mode */
1142 if (cmd->argv[1][0] == '-')
1148 cp = cmd->argv[1] + 1;
1150 for (i = 0; i < len; i++) {
1155 mode |= SILC_UMODE_SERVER_OPERATOR;
1156 mode |= SILC_UMODE_ROUTER_OPERATOR;
1157 mode |= SILC_UMODE_GONE;
1158 mode |= SILC_UMODE_INDISPOSED;
1159 mode |= SILC_UMODE_BUSY;
1160 mode |= SILC_UMODE_PAGE;
1161 mode |= SILC_UMODE_HYPER;
1162 mode |= SILC_UMODE_ROBOT;
1163 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1164 mode |= SILC_UMODE_REJECT_WATCHING;
1166 mode = SILC_UMODE_NONE;
1171 mode |= SILC_UMODE_SERVER_OPERATOR;
1173 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1177 mode |= SILC_UMODE_ROUTER_OPERATOR;
1179 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1183 mode |= SILC_UMODE_GONE;
1185 mode &= ~SILC_UMODE_GONE;
1189 mode |= SILC_UMODE_INDISPOSED;
1191 mode &= ~SILC_UMODE_INDISPOSED;
1195 mode |= SILC_UMODE_BUSY;
1197 mode &= ~SILC_UMODE_BUSY;
1201 mode |= SILC_UMODE_PAGE;
1203 mode &= ~SILC_UMODE_PAGE;
1207 mode |= SILC_UMODE_HYPER;
1209 mode &= ~SILC_UMODE_HYPER;
1213 mode |= SILC_UMODE_ROBOT;
1215 mode &= ~SILC_UMODE_ROBOT;
1219 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1221 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1225 mode |= SILC_UMODE_REJECT_WATCHING;
1227 mode &= ~SILC_UMODE_REJECT_WATCHING;
1231 mode |= SILC_UMODE_BLOCK_INVITE;
1233 mode &= ~SILC_UMODE_BLOCK_INVITE;
1236 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1242 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1243 SILC_PUT32_MSB(mode, modebuf);
1245 /* Send the command packet. We support sending only one mode at once
1246 that requires an argument. */
1248 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1249 1, idp->data, idp->len,
1250 2, modebuf, sizeof(modebuf));
1251 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1252 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1253 silc_buffer_free(buffer);
1254 silc_buffer_free(idp);
1256 /* Notify application */
1257 COMMAND(SILC_STATUS_OK);
1260 silc_client_command_free(cmd);
1263 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1264 can be set several at once. Those modes that require argument must be set
1265 separately (unless set with modes that does not require arguments). */
1267 SILC_CLIENT_CMD_FUNC(cmode)
1269 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1270 SilcClientConnection conn = cmd->conn;
1271 SilcChannelEntry channel;
1272 SilcBuffer buffer, chidp, auth = NULL;
1273 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1274 SilcUInt32 mode, add, type, len, arg_len = 0;
1278 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1279 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1283 if (cmd->argc < 3) {
1284 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1285 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1286 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1290 if (cmd->argv[1][0] == '*') {
1291 if (!conn->current_channel) {
1292 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1296 channel = conn->current_channel;
1298 name = cmd->argv[1];
1300 channel = silc_client_get_channel(cmd->client, conn, name);
1302 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1307 mode = channel->mode;
1309 /* Are we adding or removing mode */
1310 if (cmd->argv[2][0] == '-')
1315 /* Argument type to be sent to server */
1319 cp = cmd->argv[2] + 1;
1321 for (i = 0; i < len; i++) {
1325 mode |= SILC_CHANNEL_MODE_PRIVATE;
1327 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1331 mode |= SILC_CHANNEL_MODE_SECRET;
1333 mode &= ~SILC_CHANNEL_MODE_SECRET;
1337 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1339 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1343 mode |= SILC_CHANNEL_MODE_INVITE;
1345 mode &= ~SILC_CHANNEL_MODE_INVITE;
1349 mode |= SILC_CHANNEL_MODE_TOPIC;
1351 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1355 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1357 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1361 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1363 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1368 mode |= SILC_CHANNEL_MODE_ULIMIT;
1370 if (cmd->argc < 4) {
1371 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1372 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1373 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1376 ll = atoi(cmd->argv[3]);
1377 SILC_PUT32_MSB(ll, tmp);
1381 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1386 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1388 if (cmd->argc < 4) {
1389 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1390 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1391 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1395 arg_len = cmd->argv_lens[3];
1397 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1402 mode |= SILC_CHANNEL_MODE_CIPHER;
1404 if (cmd->argc < 4) {
1405 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1406 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1407 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1411 arg_len = cmd->argv_lens[3];
1413 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1418 mode |= SILC_CHANNEL_MODE_HMAC;
1420 if (cmd->argc < 4) {
1421 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1422 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1423 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1427 arg_len = cmd->argv_lens[3];
1429 mode &= ~SILC_CHANNEL_MODE_HMAC;
1434 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1436 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1437 cmd->client->private_key,
1439 cmd->client->sha1hash,
1443 arg_len = auth->len;
1445 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1449 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1455 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1456 SILC_PUT32_MSB(mode, modebuf);
1458 /* Send the command packet. We support sending only one mode at once
1459 that requires an argument. */
1462 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1463 1, chidp->data, chidp->len,
1464 2, modebuf, sizeof(modebuf),
1465 type, arg, arg_len);
1468 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1469 1, chidp->data, chidp->len,
1470 2, modebuf, sizeof(modebuf));
1473 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1474 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1475 silc_buffer_free(buffer);
1476 silc_buffer_free(chidp);
1478 silc_buffer_free(auth);
1480 /* Notify application */
1481 COMMAND(SILC_STATUS_OK);
1484 silc_client_command_free(cmd);
1487 /* CUMODE command. Changes client's mode on a channel. */
1489 SILC_CLIENT_CMD_FUNC(cumode)
1491 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1492 SilcClient client = cmd->client;
1493 SilcClientConnection conn = cmd->conn;
1494 SilcChannelEntry channel;
1495 SilcChannelUser chu;
1496 SilcClientEntry client_entry;
1497 SilcBuffer buffer, clidp, chidp, auth = NULL;
1498 unsigned char *name, *cp, modebuf[4];
1499 SilcUInt32 mode = 0, add, len;
1500 char *nickname = NULL;
1504 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1505 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1509 if (cmd->argc < 4) {
1510 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1511 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1512 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1516 if (cmd->argv[1][0] == '*') {
1517 if (!conn->current_channel) {
1518 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1522 channel = conn->current_channel;
1524 name = cmd->argv[1];
1526 channel = silc_client_get_channel(cmd->client, conn, name);
1528 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1533 /* Parse the typed nickname. */
1534 if (client->internal->params->nickname_parse)
1535 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1537 nickname = strdup(cmd->argv[3]);
1539 /* Find client entry */
1540 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1541 cmd->argv[3], TRUE);
1542 if (!client_entry) {
1544 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1548 /* Client entry not found, it was requested thus mark this to be
1550 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1552 silc_client_command_cumode,
1553 silc_client_command_dup(cmd));
1558 /* Get the current mode */
1559 chu = silc_client_on_channel(channel, client_entry);
1563 /* Are we adding or removing mode */
1564 if (cmd->argv[2][0] == '-')
1570 cp = cmd->argv[2] + 1;
1572 for (i = 0; i < len; i++) {
1576 mode |= SILC_CHANNEL_UMODE_CHANFO;
1577 mode |= SILC_CHANNEL_UMODE_CHANOP;
1578 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1579 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1580 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1582 mode = SILC_CHANNEL_UMODE_NONE;
1587 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1588 cmd->client->private_key,
1590 cmd->client->sha1hash,
1593 mode |= SILC_CHANNEL_UMODE_CHANFO;
1595 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1600 mode |= SILC_CHANNEL_UMODE_CHANOP;
1602 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1606 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1608 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1612 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1614 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1618 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1620 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1624 mode |= SILC_CHANNEL_UMODE_QUIET;
1626 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1629 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1635 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1636 SILC_PUT32_MSB(mode, modebuf);
1637 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1639 /* Send the command packet. We support sending only one mode at once
1640 that requires an argument. */
1641 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1643 1, chidp->data, chidp->len,
1645 3, clidp->data, clidp->len,
1646 4, auth ? auth->data : NULL,
1647 auth ? auth->len : 0);
1649 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1650 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1651 silc_buffer_free(buffer);
1652 silc_buffer_free(chidp);
1653 silc_buffer_free(clidp);
1655 silc_buffer_free(auth);
1657 /* Notify application */
1658 COMMAND(SILC_STATUS_OK);
1661 silc_free(nickname);
1662 silc_client_command_free(cmd);
1665 /* KICK command. Kicks a client out of channel. */
1667 SILC_CLIENT_CMD_FUNC(kick)
1669 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1670 SilcClient client = cmd->client;
1671 SilcClientConnection conn = cmd->conn;
1672 SilcIDCacheEntry id_cache = NULL;
1673 SilcChannelEntry channel;
1674 SilcBuffer buffer, idp, idp2;
1675 SilcClientEntry target;
1677 char *nickname = NULL;
1680 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1681 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1685 if (cmd->argc < 3) {
1686 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1687 "Usage: /KICK <channel> <nickname> [<comment>]");
1688 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1692 if (cmd->argv[1][0] == '*') {
1693 if (!conn->current_channel) {
1694 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1697 name = conn->current_channel->channel_name;
1699 name = cmd->argv[1];
1702 if (!conn->current_channel) {
1703 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1707 /* Get the Channel ID of the channel */
1708 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
1710 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1714 channel = (SilcChannelEntry)id_cache->context;
1716 /* Parse the typed nickname. */
1717 if (client->internal->params->nickname_parse)
1718 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1720 nickname = strdup(cmd->argv[2]);
1722 /* Get the target client */
1723 target = silc_idlist_get_client(cmd->client, conn, nickname,
1724 cmd->argv[2], FALSE);
1726 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1727 "No such client: %s", cmd->argv[2]);
1728 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1732 /* Send KICK command to the server */
1733 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1734 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1736 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1737 1, idp->data, idp->len,
1738 2, idp2->data, idp2->len);
1740 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1741 1, idp->data, idp->len,
1742 2, idp2->data, idp2->len,
1744 strlen(cmd->argv[3]));
1745 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1746 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1747 silc_buffer_free(buffer);
1748 silc_buffer_free(idp);
1749 silc_buffer_free(idp2);
1751 /* Notify application */
1752 COMMAND(SILC_STATUS_OK);
1755 silc_free(nickname);
1756 silc_client_command_free(cmd);
1759 static void silc_client_command_oper_send(unsigned char *data,
1760 SilcUInt32 data_len, void *context)
1762 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1763 SilcClientConnection conn = cmd->conn;
1764 SilcBuffer buffer, auth;
1766 if (cmd->argc >= 3) {
1767 /* Encode the public key authentication payload */
1768 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1769 cmd->client->private_key,
1771 conn->internal->hash,
1775 /* Encode the password authentication payload */
1776 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1780 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1782 strlen(cmd->argv[1]),
1783 2, auth ? auth->data : NULL,
1784 auth ? auth->len : 0);
1785 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1786 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1788 silc_buffer_free(buffer);
1789 silc_buffer_free(auth);
1791 /* Notify application */
1792 COMMAND(SILC_STATUS_OK);
1795 /* OPER command. Used to obtain server operator privileges. */
1797 SILC_CLIENT_CMD_FUNC(oper)
1799 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1800 SilcClientConnection conn = cmd->conn;
1803 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1804 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1808 if (cmd->argc < 2) {
1809 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1810 "Usage: /OPER <username> [-pubkey]");
1811 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1815 if (cmd->argc < 3) {
1816 /* Get passphrase */
1817 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1818 silc_client_command_oper_send,
1823 silc_client_command_oper_send(NULL, 0, context);
1826 silc_client_command_free(cmd);
1829 static void silc_client_command_silcoper_send(unsigned char *data,
1830 SilcUInt32 data_len,
1833 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1834 SilcClientConnection conn = cmd->conn;
1835 SilcBuffer buffer, auth;
1837 if (cmd->argc >= 3) {
1838 /* Encode the public key authentication payload */
1839 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1840 cmd->client->private_key,
1842 conn->internal->hash,
1846 /* Encode the password authentication payload */
1847 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1851 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1853 strlen(cmd->argv[1]),
1854 2, auth ? auth->data : NULL,
1855 auth ? auth->len : 0);
1856 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1857 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1859 silc_buffer_free(buffer);
1860 silc_buffer_free(auth);
1862 /* Notify application */
1863 COMMAND(SILC_STATUS_OK);
1866 /* SILCOPER command. Used to obtain router operator privileges. */
1868 SILC_CLIENT_CMD_FUNC(silcoper)
1870 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1871 SilcClientConnection conn = cmd->conn;
1874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1875 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1879 if (cmd->argc < 2) {
1880 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1881 "Usage: /SILCOPER <username> [-pubkey]");
1882 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1886 if (cmd->argc < 3) {
1887 /* Get passphrase */
1888 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1889 silc_client_command_silcoper_send,
1894 silc_client_command_silcoper_send(NULL, 0, context);
1897 silc_client_command_free(cmd);
1900 /* Command BAN. This is used to manage the ban list of the channel. */
1902 SILC_CLIENT_CMD_FUNC(ban)
1904 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1905 SilcClientConnection conn = cmd->conn;
1906 SilcChannelEntry channel;
1907 SilcBuffer buffer, chidp;
1909 char *name, *ban = NULL;
1912 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1913 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1917 if (cmd->argc < 2) {
1918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1919 "Usage: /BAN <channel> "
1920 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1921 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1925 if (cmd->argv[1][0] == '*') {
1926 if (!conn->current_channel) {
1927 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1931 channel = conn->current_channel;
1933 name = cmd->argv[1];
1935 channel = silc_client_get_channel(cmd->client, conn, name);
1937 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1942 if (cmd->argc == 3) {
1943 if (cmd->argv[2][0] == '+')
1952 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1954 /* Send the command */
1955 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1956 ++conn->cmd_ident, 2,
1957 1, chidp->data, chidp->len,
1958 type, ban, ban ? strlen(ban) : 0);
1959 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1960 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1961 silc_buffer_free(buffer);
1962 silc_buffer_free(chidp);
1964 /* Notify application */
1965 COMMAND(SILC_STATUS_OK);
1968 silc_client_command_free(cmd);
1971 /* Command DETACH. This is used to detach from the server */
1973 SILC_CLIENT_CMD_FUNC(detach)
1975 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1976 SilcClientConnection conn = cmd->conn;
1980 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1981 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1985 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1986 ++conn->cmd_ident, 0);
1987 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1988 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1989 silc_buffer_free(buffer);
1991 /* Notify application */
1992 COMMAND(SILC_STATUS_OK);
1995 silc_client_command_free(cmd);
1998 /* Command WATCH. */
2000 SILC_CLIENT_CMD_FUNC(watch)
2002 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2003 SilcClientConnection conn = cmd->conn;
2004 SilcBuffer buffer, idp = NULL;
2008 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2009 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2013 if (cmd->argc < 3) {
2014 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2018 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2020 if (!strcasecmp(cmd->argv[1], "-add")) {
2022 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2025 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2029 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2030 ++conn->cmd_ident, 2,
2031 1, idp->data, idp->len,
2034 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2035 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2036 silc_buffer_free(buffer);
2038 /* Notify application */
2039 COMMAND(SILC_STATUS_OK);
2043 silc_buffer_free(idp);
2044 silc_client_command_free(cmd);
2047 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2049 SILC_CLIENT_CMD_FUNC(leave)
2051 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2052 SilcClientConnection conn = cmd->conn;
2053 SilcChannelEntry channel;
2054 SilcChannelUser chu;
2055 SilcBuffer buffer, idp;
2059 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2060 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2064 if (cmd->argc != 2) {
2065 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2066 "Usage: /LEAVE <channel>");
2067 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2071 if (cmd->argv[1][0] == '*') {
2072 if (!conn->current_channel) {
2073 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2076 name = conn->current_channel->channel_name;
2078 name = cmd->argv[1];
2081 /* Get the channel entry */
2082 channel = silc_client_get_channel(cmd->client, conn, name);
2084 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2088 /* Remove us from channel */
2089 chu = silc_client_on_channel(channel, conn->local_entry);
2091 silc_hash_table_del(chu->client->channels, chu->channel);
2092 silc_hash_table_del(chu->channel->user_list, chu->client);
2096 /* Send LEAVE command to the server */
2097 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2098 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2099 1, idp->data, idp->len);
2100 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2101 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2102 silc_buffer_free(buffer);
2103 silc_buffer_free(idp);
2105 /* Notify application */
2106 COMMAND(SILC_STATUS_OK);
2108 if (conn->current_channel == channel)
2109 conn->current_channel = NULL;
2111 silc_client_del_channel(cmd->client, cmd->conn, channel);
2114 silc_client_command_free(cmd);
2117 /* Command USERS. Requests the USERS of the clients joined on requested
2120 SILC_CLIENT_CMD_FUNC(users)
2122 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2123 SilcClientConnection conn = cmd->conn;
2128 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2129 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2133 if (cmd->argc != 2) {
2134 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2135 "Usage: /USERS <channel>");
2136 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2140 if (cmd->argv[1][0] == '*') {
2141 if (!conn->current_channel) {
2142 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2145 name = conn->current_channel->channel_name;
2147 name = cmd->argv[1];
2150 /* Send USERS command to the server */
2151 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2152 ++conn->cmd_ident, 1,
2153 2, name, strlen(name));
2154 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2155 NULL, 0, NULL, NULL, buffer->data,
2157 silc_buffer_free(buffer);
2159 /* Notify application */
2160 COMMAND(SILC_STATUS_OK);
2163 silc_client_command_free(cmd);
2166 /* Command GETKEY. Used to fetch remote client's public key. */
2168 SILC_CLIENT_CMD_FUNC(getkey)
2170 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2171 SilcClientConnection conn = cmd->conn;
2172 SilcClient client = cmd->client;
2173 SilcClientEntry client_entry = NULL;
2174 SilcServerEntry server_entry = NULL;
2175 char *nickname = NULL;
2176 SilcBuffer idp, buffer;
2178 SILC_LOG_DEBUG(("Start"));
2181 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2182 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2186 if (cmd->argc < 2) {
2187 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2188 "Usage: /GETKEY <nickname or server name>");
2189 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2193 /* Parse the typed nickname. */
2194 if (client->internal->params->nickname_parse)
2195 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2197 nickname = strdup(cmd->argv[1]);
2199 /* Find client entry */
2200 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2202 if (!client_entry) {
2203 /* Check whether user requested server actually */
2204 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2206 if (!server_entry) {
2207 /* No. what ever user wants we don't have it, so resolve it. We
2208 will first try to resolve the client, and if that fails then
2209 we'll try to resolve the server. */
2211 if (!cmd->pending) {
2212 /* This will send the IDENTIFY command for nickname */
2213 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2214 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2216 silc_client_command_getkey,
2217 silc_client_command_dup(cmd));
2221 SilcClientCommandReplyContext reply =
2222 (SilcClientCommandReplyContext)context2;
2225 /* If nickname was not found, then resolve the server. */
2226 silc_command_get_status(reply->payload, NULL, &error);
2227 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2228 /* This sends the IDENTIFY command to resolve the server. */
2229 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2231 silc_client_command_reply_identify_i, 0,
2233 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2235 2, cmd->argv[1], cmd->argv_lens[1]);
2236 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2238 silc_client_command_getkey,
2239 silc_client_command_dup(cmd));
2243 /* If server was not found, then we've resolved both nickname and
2244 server and did not find anybody. */
2245 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2246 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2247 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2248 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2249 silc_get_status_message(error));
2250 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2254 COMMAND_ERROR(error);
2259 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2261 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2264 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2265 1, idp->data, idp->len);
2266 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2267 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2268 silc_buffer_free(buffer);
2269 silc_buffer_free(idp);
2271 /* Notify application */
2272 COMMAND(SILC_STATUS_OK);
2275 silc_free(nickname);
2276 silc_client_command_free(cmd);
2279 /* Register a new command indicated by the `command' to the SILC client.
2280 The `name' is optional command name. If provided the command may be
2281 searched using the silc_client_command_find by that name. The
2282 `command_function' is the function to be called when the command is
2283 executed, and the `command_reply_function' is the function to be
2284 called after the server has sent reply back to the command.
2286 The `ident' is optional identifier for the command. If non-zero
2287 the `command_reply_function' for the command type `command' will be
2288 called only if the command reply sent by server includes the
2289 command identifier `ident'. Application usually does not need it
2290 and set it to zero value. */
2292 bool silc_client_command_register(SilcClient client,
2293 SilcCommand command,
2295 SilcCommandCb command_function,
2296 SilcCommandCb command_reply_function,
2300 SilcClientCommand cmd;
2302 cmd = silc_calloc(1, sizeof(*cmd));
2304 cmd->command = command_function;
2305 cmd->reply = command_reply_function;
2306 cmd->name = name ? strdup(name) : NULL;
2307 cmd->max_args = max_args;
2310 silc_list_add(client->internal->commands, cmd);
2315 /* Unregister a command indicated by the `command' with command function
2316 `command_function' and command reply function `command_reply_function'.
2317 Returns TRUE if the command was found and unregistered. */
2319 bool silc_client_command_unregister(SilcClient client,
2320 SilcCommand command,
2321 SilcCommandCb command_function,
2322 SilcCommandCb command_reply_function,
2325 SilcClientCommand cmd;
2327 silc_list_start(client->internal->commands);
2328 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2329 if (cmd->cmd == command && cmd->command == command_function &&
2330 cmd->reply == command_reply_function && cmd->ident == ident) {
2331 silc_list_del(client->internal->commands, cmd);
2332 silc_free(cmd->name);
2341 /* Private range commands, specific to this implementation (and compatible
2342 with SILC Server). */
2344 /* CONNECT command. Connects the server to another server. */
2346 SILC_CLIENT_CMD_FUNC(connect)
2348 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2349 SilcClientConnection conn = cmd->conn;
2351 unsigned char port[4];
2355 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2356 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2360 if (cmd->argc < 2) {
2361 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2362 "Usage: /CONNECT <server> [<port>]");
2363 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2367 if (cmd->argc == 3) {
2368 tmp = atoi(cmd->argv[2]);
2369 SILC_PUT32_MSB(tmp, port);
2373 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2375 strlen(cmd->argv[1]),
2378 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2380 strlen(cmd->argv[1]));
2381 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2382 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2383 silc_buffer_free(buffer);
2385 /* Notify application */
2386 COMMAND(SILC_STATUS_OK);
2389 silc_client_command_free(cmd);
2393 /* CLOSE command. Close server connection to the remote server */
2395 SILC_CLIENT_CMD_FUNC(close)
2397 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2398 SilcClientConnection conn = cmd->conn;
2400 unsigned char port[4];
2404 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2405 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2409 if (cmd->argc < 2) {
2410 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2411 "Usage: /CLOSE <server> [<port>]");
2412 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2416 if (cmd->argc == 3) {
2417 tmp = atoi(cmd->argv[2]);
2418 SILC_PUT32_MSB(tmp, port);
2422 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2424 strlen(cmd->argv[1]),
2427 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2429 strlen(cmd->argv[1]));
2430 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2431 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2432 silc_buffer_free(buffer);
2434 /* Notify application */
2435 COMMAND(SILC_STATUS_OK);
2438 silc_client_command_free(cmd);
2441 /* SHUTDOWN command. Shutdowns the server. */
2443 SILC_CLIENT_CMD_FUNC(shutdown)
2445 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2448 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2449 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2453 /* Send the command */
2454 silc_client_command_send(cmd->client, cmd->conn,
2455 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2457 /* Notify application */
2458 COMMAND(SILC_STATUS_OK);
2461 silc_client_command_free(cmd);
2464 /* Register all default commands provided by the client library for the
2467 void silc_client_commands_register(SilcClient client)
2469 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2472 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2473 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2474 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2475 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2476 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2477 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2478 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2479 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2480 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2481 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2482 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2483 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2484 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2485 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2486 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2487 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2488 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2489 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2490 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2491 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2492 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2493 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2494 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2495 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2496 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2497 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2499 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2500 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2501 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2504 /* Unregister all commands. */
2506 void silc_client_commands_unregister(SilcClient client)
2508 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2509 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2510 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2511 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2512 SILC_CLIENT_CMDU(list, LIST, "LIST");
2513 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2514 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2515 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2516 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2517 SILC_CLIENT_CMDU(info, INFO, "INFO");
2518 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2519 SILC_CLIENT_CMDU(ping, PING, "PING");
2520 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2521 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2522 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2523 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2524 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2525 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2526 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2527 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2528 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2529 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2530 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2531 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2532 SILC_CLIENT_CMDU(users, USERS, "USERS");
2533 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2535 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2536 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2537 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2540 /**** Client side incoming command handling **********************************/
2542 void silc_client_command_process_whois(SilcClient client,
2543 SilcSocketConnection sock,
2544 SilcCommandPayload payload,
2545 SilcArgumentPayload args);
2547 /* Client is able to receive some command packets even though they are
2548 special case. Server may send WHOIS command to the client to retrieve
2549 Requested Attributes information for WHOIS query the server is
2550 processing. This function currently handles only the WHOIS command,
2551 but if in the future for commands may arrive then this can be made
2552 to support other commands too. */
2554 void silc_client_command_process(SilcClient client,
2555 SilcSocketConnection sock,
2556 SilcPacketContext *packet)
2558 SilcCommandPayload payload;
2559 SilcCommand command;
2560 SilcArgumentPayload args;
2562 /* Get command payload from packet */
2563 payload = silc_command_payload_parse(packet->buffer->data,
2564 packet->buffer->len);
2566 /* Silently ignore bad reply packet */
2567 SILC_LOG_DEBUG(("Bad command packet"));
2572 args = silc_command_get_args(payload);
2574 /* Get the command */
2575 command = silc_command_get(payload);
2578 case SILC_COMMAND_WHOIS:
2579 /* Ignore everything if requested by application */
2580 if (client->internal->params->ignore_requested_attributes)
2583 silc_client_command_process_whois(client, sock, payload, args);
2590 silc_command_payload_free(payload);
2593 void silc_client_command_process_whois(SilcClient client,
2594 SilcSocketConnection sock,
2595 SilcCommandPayload payload,
2596 SilcArgumentPayload args)
2601 SilcBuffer buffer, packet;
2603 SILC_LOG_DEBUG(("Received WHOIS command"));
2605 /* Try to take the Requested Attributes */
2606 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
2610 attrs = silc_attribute_payload_parse(tmp, tmp_len);
2614 /* Process requested attributes */
2615 buffer = silc_client_attributes_process(client, sock, attrs);
2617 silc_attribute_payload_list_free(attrs);
2621 /* Send the attributes back */
2623 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
2625 silc_command_get_ident(payload),
2626 1, 11, buffer->data, buffer->len);
2627 silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
2628 NULL, 0, NULL, NULL, packet->data,
2630 silc_buffer_free(packet);
2631 silc_buffer_free(buffer);