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->ident == ident) {
128 silc_dlist_del(conn->pending_commands, r);
134 /* Checks for pending commands and marks callbacks to be called from
135 the command reply function. */
137 SilcClientCommandPendingCallbacks
138 silc_client_command_pending_check(SilcClientConnection conn,
139 SilcClientCommandReplyContext ctx,
142 SilcUInt32 *callbacks_count)
144 SilcClientCommandPending *r;
145 SilcClientCommandPendingCallbacks callbacks = NULL;
148 silc_dlist_start(conn->pending_commands);
149 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
150 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
151 && r->ident == ident) {
152 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
153 callbacks[i].context = r->context;
154 callbacks[i].callback = r->callback;
160 *callbacks_count = i;
164 /* Allocate Command Context */
166 SilcClientCommandContext silc_client_command_alloc(void)
168 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
173 /* Free command context and its internals */
175 void silc_client_command_free(SilcClientCommandContext ctx)
178 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
180 if (ctx->users < 1) {
183 for (i = 0; i < ctx->argc; i++)
184 silc_free(ctx->argv[i]);
185 silc_free(ctx->argv_lens);
186 silc_free(ctx->argv_types);
191 /* Duplicate Command Context by adding reference counter. The context won't
192 be free'd untill it hits zero. */
194 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
197 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
202 /* Command WHOIS. This command is used to query information about
205 SILC_CLIENT_CMD_FUNC(whois)
207 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
208 SilcClientConnection conn = cmd->conn;
210 unsigned char count[4];
213 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
214 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
218 /* Given without arguments fetches client's own information */
220 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
221 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
223 1, 4, buffer->data, buffer->len);
224 silc_buffer_free(buffer);
228 if (cmd->argc == 2) {
229 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
230 ++conn->cmd_ident, 1,
234 int c = atoi(cmd->argv[2]);
235 memset(count, 0, sizeof(count));
236 SILC_PUT32_MSB(c, count);
237 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
238 ++conn->cmd_ident, 2,
239 1, cmd->argv[1], cmd->argv_lens[1],
240 2, count, sizeof(count));
242 silc_client_packet_send(cmd->client, cmd->conn->sock,
243 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
244 buffer->data, buffer->len, TRUE);
245 silc_buffer_free(buffer);
247 /* Notify application */
248 COMMAND(SILC_STATUS_OK);
251 silc_client_command_free(cmd);
254 /* Command WHOWAS. This command is used to query history information about
255 specific user that used to exist in the network. */
257 SILC_CLIENT_CMD_FUNC(whowas)
259 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
260 SilcClientConnection conn = cmd->conn;
262 unsigned char count[4];
265 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
266 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
270 if (cmd->argc < 2 || cmd->argc > 3) {
271 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
272 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
273 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
274 SILC_STATUS_ERR_TOO_MANY_PARAMS));
278 if (cmd->argc == 2) {
279 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
280 ++conn->cmd_ident, 1,
284 int c = atoi(cmd->argv[2]);
285 memset(count, 0, sizeof(count));
286 SILC_PUT32_MSB(c, count);
287 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
288 ++conn->cmd_ident, 2,
289 1, cmd->argv[1], cmd->argv_lens[1],
290 2, count, sizeof(count));
292 silc_client_packet_send(cmd->client, cmd->conn->sock,
293 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
294 buffer->data, buffer->len, TRUE);
295 silc_buffer_free(buffer);
297 /* Notify application */
298 COMMAND(SILC_STATUS_OK);
301 silc_client_command_free(cmd);
304 /* Command IDENTIFY. This command is used to query information about
305 specific user, especially ID's.
307 NOTE: This command is used only internally by the client library
308 and application MUST NOT call this command directly. */
310 SILC_CLIENT_CMD_FUNC(identify)
312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
313 SilcClientConnection conn = cmd->conn;
315 unsigned char count[4];
318 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
319 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
323 if (cmd->argc < 2 || cmd->argc > 3)
326 if (cmd->argc == 2) {
327 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
328 ++conn->cmd_ident, 1,
332 int c = atoi(cmd->argv[2]);
333 memset(count, 0, sizeof(count));
334 SILC_PUT32_MSB(c, count);
335 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
336 ++conn->cmd_ident, 2,
339 4, count, sizeof(count));
342 silc_client_packet_send(cmd->client, cmd->conn->sock,
343 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
344 buffer->data, buffer->len, TRUE);
345 silc_buffer_free(buffer);
348 silc_client_command_free(cmd);
351 /* Command NICK. Shows current nickname/sets new nickname on current
354 SILC_CLIENT_CMD_FUNC(nick)
356 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
357 SilcClientConnection conn = cmd->conn;
361 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
362 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
368 "Usage: /NICK <nickname>");
369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
373 if (!strcmp(conn->nickname, cmd->argv[1]))
376 /* Show current nickname */
379 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
380 "Your nickname is %s on server %s",
381 conn->nickname, conn->remote_host);
383 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
384 "Your nickname is %s", conn->nickname);
387 COMMAND(SILC_STATUS_OK);
391 if (cmd->argv_lens[1] > 128)
392 cmd->argv_lens[1] = 128;
394 /* Send the NICK command */
395 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
399 ++cmd->conn->cmd_ident);
400 silc_client_packet_send(cmd->client, cmd->conn->sock,
401 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
402 buffer->data, buffer->len, TRUE);
403 silc_buffer_free(buffer);
406 silc_client_command_free(cmd);
409 /* Command LIST. Lists channels on the current server. */
411 SILC_CLIENT_CMD_FUNC(list)
413 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
414 SilcClientConnection conn = cmd->conn;
415 SilcIDCacheEntry id_cache = NULL;
416 SilcChannelEntry channel;
417 SilcBuffer buffer, idp = NULL;
421 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
422 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
426 if (cmd->argc == 2) {
429 /* Get the Channel ID of the channel */
430 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
431 channel = (SilcChannelEntry)id_cache->context;
432 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
437 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
438 ++conn->cmd_ident, 0);
440 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
441 ++conn->cmd_ident, 1,
442 1, idp->data, idp->len);
444 silc_client_packet_send(cmd->client, cmd->conn->sock,
445 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
446 buffer->data, buffer->len, TRUE);
447 silc_buffer_free(buffer);
449 silc_buffer_free(idp);
451 /* Notify application */
452 COMMAND(SILC_STATUS_OK);
455 silc_client_command_free(cmd);
458 /* Command TOPIC. Sets/shows topic on a channel. */
460 SILC_CLIENT_CMD_FUNC(topic)
462 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
463 SilcClientConnection conn = cmd->conn;
464 SilcIDCacheEntry id_cache = NULL;
465 SilcChannelEntry channel;
466 SilcBuffer buffer, idp;
470 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
471 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
475 if (cmd->argc < 2 || cmd->argc > 3) {
476 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
477 "Usage: /TOPIC <channel> [<topic>]");
478 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
479 SILC_STATUS_ERR_TOO_MANY_PARAMS));
483 if (cmd->argv[1][0] == '*') {
484 if (!conn->current_channel) {
485 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
488 name = conn->current_channel->channel_name;
493 if (!conn->current_channel) {
494 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
498 /* Get the Channel ID of the channel */
499 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
500 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
504 channel = (SilcChannelEntry)id_cache->context;
506 /* Send TOPIC command to the server */
507 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
509 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
510 ++conn->cmd_ident, 2,
511 1, idp->data, idp->len,
513 strlen(cmd->argv[2]));
515 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
516 ++conn->cmd_ident, 1,
517 1, idp->data, idp->len);
518 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
519 0, NULL, NULL, buffer->data, buffer->len, TRUE);
520 silc_buffer_free(buffer);
521 silc_buffer_free(idp);
523 /* Notify application */
524 COMMAND(SILC_STATUS_OK);
527 silc_client_command_free(cmd);
530 /* Command INVITE. Invites specific client to join a channel. This is
531 also used to mange the invite list of the channel. */
533 SILC_CLIENT_CMD_FUNC(invite)
535 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
536 SilcClient client = cmd->client;
537 SilcClientConnection conn = cmd->conn;
538 SilcClientEntry client_entry = NULL;
539 SilcChannelEntry channel;
540 SilcBuffer buffer, clidp, chidp;
542 char *nickname = NULL, *name;
546 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
547 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
552 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
553 "Usage: /INVITE <channel> [<nickname>[@server>]"
554 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
555 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
559 if (cmd->argv[1][0] == '*') {
560 if (!conn->current_channel) {
561 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
565 channel = conn->current_channel;
569 channel = silc_client_get_channel(cmd->client, conn, name);
571 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
576 /* Parse the typed nickname. */
577 if (cmd->argc == 3) {
578 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
579 if (client->internal->params->nickname_parse)
580 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
582 nickname = strdup(cmd->argv[2]);
584 /* Find client entry */
585 client_entry = silc_idlist_get_client(client, conn, nickname,
589 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
593 /* Client entry not found, it was requested thus mark this to be
595 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
597 silc_client_command_invite,
598 silc_client_command_dup(cmd));
603 invite = cmd->argv[2];
605 if (cmd->argv[2][0] == '+')
612 /* Send the command */
613 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
615 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
616 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
617 ++conn->cmd_ident, 3,
618 1, chidp->data, chidp->len,
619 2, clidp->data, clidp->len,
620 type, invite, invite ?
622 silc_buffer_free(clidp);
624 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
625 ++conn->cmd_ident, 2,
626 1, chidp->data, chidp->len,
627 type, invite, invite ?
631 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
632 0, NULL, NULL, buffer->data, buffer->len, TRUE);
633 silc_buffer_free(buffer);
634 silc_buffer_free(chidp);
636 /* Notify application */
637 COMMAND(SILC_STATUS_OK);
641 silc_client_command_free(cmd);
646 SilcClientConnection conn;
649 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
651 QuitInternal q = (QuitInternal)context;
653 /* Close connection */
654 q->client->internal->ops->disconnect(q->client, q->conn, 0, NULL);
655 silc_client_close_connection(q->client, q->conn->sock->user_data);
660 /* Command QUIT. Closes connection with current server. */
662 SILC_CLIENT_CMD_FUNC(quit)
664 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
669 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
670 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
675 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
676 &cmd->argv[1], &cmd->argv_lens[1],
677 &cmd->argv_types[1], 0);
679 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
680 NULL, NULL, NULL, 0);
681 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
683 buffer->data, buffer->len, TRUE);
684 silc_buffer_free(buffer);
686 q = silc_calloc(1, sizeof(*q));
687 q->client = cmd->client;
690 /* Sleep for a while */
693 /* We quit the connection with little timeout */
694 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
695 silc_client_command_quit_cb, (void *)q,
696 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
698 /* Notify application */
699 COMMAND(SILC_STATUS_OK);
702 silc_client_command_free(cmd);
705 /* Timeout callback to remove the killed client from cache */
707 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
709 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
710 SilcClient client = cmd->client;
711 SilcClientConnection conn = cmd->conn;
712 SilcClientEntry target;
713 char *nickname = NULL;
715 /* Parse the typed nickname. */
716 if (client->internal->params->nickname_parse)
717 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
719 nickname = strdup(cmd->argv[1]);
721 /* Get the target client */
722 target = silc_idlist_get_client(cmd->client, conn, nickname,
723 cmd->argv[1], FALSE);
725 /* Remove the client from all channels and free it */
726 silc_client_del_client(client, conn, target);
729 silc_client_command_free(cmd);
732 /* Kill command's pending command callback to actually remove the killed
733 client from our local cache. */
735 SILC_CLIENT_CMD_FUNC(kill_remove)
737 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
738 SilcClientCommandReplyContext reply =
739 (SilcClientCommandReplyContext)context2;
742 silc_command_get_status(reply->payload, &status, NULL);
743 if (status == SILC_STATUS_OK) {
744 /* Remove with timeout */
745 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
746 silc_client_command_kill_remove_later, context,
747 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
751 silc_client_command_free(cmd);
754 /* Command KILL. Router operator can use this command to remove an client
755 fromthe SILC Network. */
757 SILC_CLIENT_CMD_FUNC(kill)
759 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
760 SilcClient client = cmd->client;
761 SilcClientConnection conn = cmd->conn;
762 SilcBuffer buffer, idp;
763 SilcClientEntry target;
764 char *nickname = NULL;
767 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
768 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
773 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
774 "Usage: /KILL <nickname> [<comment>]");
775 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
779 /* Parse the typed nickname. */
780 if (client->internal->params->nickname_parse)
781 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
783 nickname = strdup(cmd->argv[1]);
785 /* Get the target client */
786 target = silc_idlist_get_client(cmd->client, conn, nickname,
790 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
794 /* Client entry not found, it was requested thus mark this to be
796 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
798 silc_client_command_kill,
799 silc_client_command_dup(cmd));
804 /* Send the KILL command to the server */
805 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
807 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
808 ++conn->cmd_ident, 1,
809 1, idp->data, idp->len);
811 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
812 ++conn->cmd_ident, 2,
813 1, idp->data, idp->len,
815 strlen(cmd->argv[2]));
816 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
817 0, NULL, NULL, buffer->data, buffer->len, TRUE);
818 silc_buffer_free(buffer);
819 silc_buffer_free(idp);
821 /* Notify application */
822 COMMAND(SILC_STATUS_OK);
824 /* Register a pending callback that will actually remove the killed
825 client from our cache. */
826 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
827 silc_client_command_kill_remove,
828 silc_client_command_dup(cmd));
832 silc_client_command_free(cmd);
835 /* Command INFO. Request information about specific server. If specific
836 server is not provided the current server is used. */
838 SILC_CLIENT_CMD_FUNC(info)
840 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
841 SilcClientConnection conn = cmd->conn;
846 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
847 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
852 name = strdup(cmd->argv[1]);
854 /* Send the command */
856 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
857 1, name, strlen(name));
859 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
860 NULL, NULL, NULL, 0);
861 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
862 0, NULL, NULL, buffer->data, buffer->len, TRUE);
863 silc_buffer_free(buffer);
867 /* Notify application */
868 COMMAND(SILC_STATUS_OK);
871 silc_client_command_free(cmd);
874 /* Command PING. Sends ping to server. This is used to test the
875 communication channel. */
877 SILC_CLIENT_CMD_FUNC(ping)
879 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
880 SilcClientConnection conn = cmd->conn;
886 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
887 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
891 /* Send the command */
892 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
893 1, conn->remote_id_data,
894 silc_id_get_len(conn->remote_id,
896 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
897 0, NULL, NULL, buffer->data, buffer->len, TRUE);
898 silc_buffer_free(buffer);
900 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
903 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
904 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
908 /* Start counting time */
909 for (i = 0; i < conn->ping_count; i++) {
910 if (conn->ping[i].dest_id == NULL) {
911 conn->ping[i].start_time = time(NULL);
912 conn->ping[i].dest_id = id;
913 conn->ping[i].dest_name = strdup(conn->remote_host);
917 if (i >= conn->ping_count) {
918 i = conn->ping_count;
919 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
920 conn->ping[i].start_time = time(NULL);
921 conn->ping[i].dest_id = id;
922 conn->ping[i].dest_name = strdup(conn->remote_host);
926 /* Notify application */
927 COMMAND(SILC_STATUS_OK);
930 silc_client_command_free(cmd);
933 /* Command JOIN. Joins to a channel. */
935 SILC_CLIENT_CMD_FUNC(join)
937 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
938 SilcClientConnection conn = cmd->conn;
939 SilcChannelEntry channel;
940 SilcBuffer buffer, idp, auth = NULL;
941 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
942 int i, passphrase_len = 0;
945 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
946 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
951 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
955 /* See if we have joined to the requested channel already */
956 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
957 if (channel && silc_client_on_channel(channel, conn->local_entry))
960 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
962 if (cmd->argv_lens[1] > 256)
963 cmd->argv_lens[1] = 256;
967 for (i = 2; i < cmd->argc; i++) {
968 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
969 cipher = cmd->argv[i + 1];
971 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
972 hmac = cmd->argv[i + 1];
974 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
975 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
976 cmd->client->private_key,
978 cmd->client->internal->
984 /* Passphrases must be UTF-8 encoded, so encode if it is not */
985 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
986 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
987 cmd->argv_lens[i], 0);
988 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
989 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
990 0, pu8, passphrase_len);
993 passphrase = strdup(cmd->argv[i]);
994 passphrase_len = cmd->argv_lens[i];
999 /* Send JOIN command to the server */
1001 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1002 1, name, strlen(name),
1003 2, idp->data, idp->len,
1004 3, passphrase, passphrase_len,
1005 4, cipher, cipher ? strlen(cipher) : 0,
1006 5, hmac, hmac ? strlen(hmac) : 0,
1007 6, auth ? auth->data : NULL,
1008 auth ? auth->len : 0);
1009 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1010 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1011 silc_buffer_free(buffer);
1012 silc_buffer_free(idp);
1014 silc_buffer_free(auth);
1015 silc_free(passphrase);
1017 /* Notify application */
1018 COMMAND(SILC_STATUS_OK);
1021 silc_client_command_free(cmd);
1024 /* MOTD command. Requests motd from server. */
1026 SILC_CLIENT_CMD_FUNC(motd)
1028 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1029 SilcClientConnection conn = cmd->conn;
1033 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1034 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1038 if (cmd->argc < 1 || cmd->argc > 2) {
1039 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1040 "Usage: /MOTD [<server>]");
1041 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1042 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1046 /* Send TOPIC command to the server */
1048 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1049 1, conn->remote_host,
1050 strlen(conn->remote_host));
1052 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1055 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1056 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1057 silc_buffer_free(buffer);
1059 /* Notify application */
1060 COMMAND(SILC_STATUS_OK);
1063 silc_client_command_free(cmd);
1066 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1067 modes as client cannot set itself server/router operator privileges. */
1069 SILC_CLIENT_CMD_FUNC(umode)
1071 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1072 SilcClientConnection conn = cmd->conn;
1073 SilcBuffer buffer, idp;
1074 unsigned char *cp, modebuf[4];
1075 SilcUInt32 mode, add, len;
1079 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1080 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1084 if (cmd->argc < 2) {
1085 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1086 "Usage: /UMODE +|-<modes>");
1087 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1091 mode = conn->local_entry->mode;
1093 /* Are we adding or removing mode */
1094 if (cmd->argv[1][0] == '-')
1100 cp = cmd->argv[1] + 1;
1102 for (i = 0; i < len; i++) {
1107 mode |= SILC_UMODE_SERVER_OPERATOR;
1108 mode |= SILC_UMODE_ROUTER_OPERATOR;
1109 mode |= SILC_UMODE_GONE;
1110 mode |= SILC_UMODE_INDISPOSED;
1111 mode |= SILC_UMODE_BUSY;
1112 mode |= SILC_UMODE_PAGE;
1113 mode |= SILC_UMODE_HYPER;
1114 mode |= SILC_UMODE_ROBOT;
1115 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1116 mode |= SILC_UMODE_REJECT_WATCHING;
1118 mode = SILC_UMODE_NONE;
1123 mode |= SILC_UMODE_SERVER_OPERATOR;
1125 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1129 mode |= SILC_UMODE_ROUTER_OPERATOR;
1131 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1135 mode |= SILC_UMODE_GONE;
1137 mode &= ~SILC_UMODE_GONE;
1141 mode |= SILC_UMODE_INDISPOSED;
1143 mode &= ~SILC_UMODE_INDISPOSED;
1147 mode |= SILC_UMODE_BUSY;
1149 mode &= ~SILC_UMODE_BUSY;
1153 mode |= SILC_UMODE_PAGE;
1155 mode &= ~SILC_UMODE_PAGE;
1159 mode |= SILC_UMODE_HYPER;
1161 mode &= ~SILC_UMODE_HYPER;
1165 mode |= SILC_UMODE_ROBOT;
1167 mode &= ~SILC_UMODE_ROBOT;
1171 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1173 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1177 mode |= SILC_UMODE_REJECT_WATCHING;
1179 mode &= ~SILC_UMODE_REJECT_WATCHING;
1183 mode |= SILC_UMODE_BLOCK_INVITE;
1185 mode &= ~SILC_UMODE_BLOCK_INVITE;
1188 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1194 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1195 SILC_PUT32_MSB(mode, modebuf);
1197 /* Send the command packet. We support sending only one mode at once
1198 that requires an argument. */
1200 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1201 1, idp->data, idp->len,
1202 2, modebuf, sizeof(modebuf));
1203 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1204 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1205 silc_buffer_free(buffer);
1206 silc_buffer_free(idp);
1208 /* Notify application */
1209 COMMAND(SILC_STATUS_OK);
1212 silc_client_command_free(cmd);
1215 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1216 can be set several at once. Those modes that require argument must be set
1217 separately (unless set with modes that does not require arguments). */
1219 SILC_CLIENT_CMD_FUNC(cmode)
1221 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1222 SilcClientConnection conn = cmd->conn;
1223 SilcChannelEntry channel;
1224 SilcBuffer buffer, chidp, auth = NULL;
1225 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1226 SilcUInt32 mode, add, type, len, arg_len = 0;
1230 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1231 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1235 if (cmd->argc < 3) {
1236 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1237 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1238 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1242 if (cmd->argv[1][0] == '*') {
1243 if (!conn->current_channel) {
1244 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1248 channel = conn->current_channel;
1250 name = cmd->argv[1];
1252 channel = silc_client_get_channel(cmd->client, conn, name);
1254 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1259 mode = channel->mode;
1261 /* Are we adding or removing mode */
1262 if (cmd->argv[2][0] == '-')
1267 /* Argument type to be sent to server */
1271 cp = cmd->argv[2] + 1;
1273 for (i = 0; i < len; i++) {
1277 mode |= SILC_CHANNEL_MODE_PRIVATE;
1279 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1283 mode |= SILC_CHANNEL_MODE_SECRET;
1285 mode &= ~SILC_CHANNEL_MODE_SECRET;
1289 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1291 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1295 mode |= SILC_CHANNEL_MODE_INVITE;
1297 mode &= ~SILC_CHANNEL_MODE_INVITE;
1301 mode |= SILC_CHANNEL_MODE_TOPIC;
1303 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1307 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1309 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1313 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1315 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1320 mode |= SILC_CHANNEL_MODE_ULIMIT;
1322 if (cmd->argc < 4) {
1323 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1324 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1325 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1328 ll = atoi(cmd->argv[3]);
1329 SILC_PUT32_MSB(ll, tmp);
1333 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1338 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1340 if (cmd->argc < 4) {
1341 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1342 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1343 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1347 arg_len = cmd->argv_lens[3];
1349 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1354 mode |= SILC_CHANNEL_MODE_CIPHER;
1356 if (cmd->argc < 4) {
1357 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1358 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1359 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1363 arg_len = cmd->argv_lens[3];
1365 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1370 mode |= SILC_CHANNEL_MODE_HMAC;
1372 if (cmd->argc < 4) {
1373 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1374 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1375 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1379 arg_len = cmd->argv_lens[3];
1381 mode &= ~SILC_CHANNEL_MODE_HMAC;
1386 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1388 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1389 cmd->client->private_key,
1391 cmd->client->internal->
1396 arg_len = auth->len;
1398 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1402 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1408 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1409 SILC_PUT32_MSB(mode, modebuf);
1411 /* Send the command packet. We support sending only one mode at once
1412 that requires an argument. */
1415 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1416 1, chidp->data, chidp->len,
1417 2, modebuf, sizeof(modebuf),
1418 type, arg, arg_len);
1421 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1422 1, chidp->data, chidp->len,
1423 2, modebuf, sizeof(modebuf));
1426 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1427 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1428 silc_buffer_free(buffer);
1429 silc_buffer_free(chidp);
1431 silc_buffer_free(auth);
1433 /* Notify application */
1434 COMMAND(SILC_STATUS_OK);
1437 silc_client_command_free(cmd);
1440 /* CUMODE command. Changes client's mode on a channel. */
1442 SILC_CLIENT_CMD_FUNC(cumode)
1444 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1445 SilcClient client = cmd->client;
1446 SilcClientConnection conn = cmd->conn;
1447 SilcChannelEntry channel;
1448 SilcChannelUser chu;
1449 SilcClientEntry client_entry;
1450 SilcBuffer buffer, clidp, chidp, auth = NULL;
1451 unsigned char *name, *cp, modebuf[4];
1452 SilcUInt32 mode = 0, add, len;
1453 char *nickname = NULL;
1457 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1458 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1462 if (cmd->argc < 4) {
1463 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1464 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1465 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1469 if (cmd->argv[1][0] == '*') {
1470 if (!conn->current_channel) {
1471 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1475 channel = conn->current_channel;
1477 name = cmd->argv[1];
1479 channel = silc_client_get_channel(cmd->client, conn, name);
1481 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1486 /* Parse the typed nickname. */
1487 if (client->internal->params->nickname_parse)
1488 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1490 nickname = strdup(cmd->argv[3]);
1492 /* Find client entry */
1493 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1494 cmd->argv[3], TRUE);
1495 if (!client_entry) {
1497 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1501 /* Client entry not found, it was requested thus mark this to be
1503 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1505 silc_client_command_cumode,
1506 silc_client_command_dup(cmd));
1511 /* Get the current mode */
1512 chu = silc_client_on_channel(channel, client_entry);
1516 /* Are we adding or removing mode */
1517 if (cmd->argv[2][0] == '-')
1523 cp = cmd->argv[2] + 1;
1525 for (i = 0; i < len; i++) {
1529 mode |= SILC_CHANNEL_UMODE_CHANFO;
1530 mode |= SILC_CHANNEL_UMODE_CHANOP;
1531 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1532 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1533 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1535 mode = SILC_CHANNEL_UMODE_NONE;
1540 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1541 cmd->client->private_key,
1543 cmd->client->internal->
1547 mode |= SILC_CHANNEL_UMODE_CHANFO;
1549 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1554 mode |= SILC_CHANNEL_UMODE_CHANOP;
1556 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1560 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1562 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1566 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1568 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1572 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1574 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1578 mode |= SILC_CHANNEL_UMODE_QUIET;
1580 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1583 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1589 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1590 SILC_PUT32_MSB(mode, modebuf);
1591 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1593 /* Send the command packet. We support sending only one mode at once
1594 that requires an argument. */
1595 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1597 1, chidp->data, chidp->len,
1599 3, clidp->data, clidp->len,
1600 4, auth ? auth->data : NULL,
1601 auth ? auth->len : 0);
1603 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1604 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1605 silc_buffer_free(buffer);
1606 silc_buffer_free(chidp);
1607 silc_buffer_free(clidp);
1609 silc_buffer_free(auth);
1611 /* Notify application */
1612 COMMAND(SILC_STATUS_OK);
1615 silc_free(nickname);
1616 silc_client_command_free(cmd);
1619 /* KICK command. Kicks a client out of channel. */
1621 SILC_CLIENT_CMD_FUNC(kick)
1623 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1624 SilcClient client = cmd->client;
1625 SilcClientConnection conn = cmd->conn;
1626 SilcIDCacheEntry id_cache = NULL;
1627 SilcChannelEntry channel;
1628 SilcBuffer buffer, idp, idp2;
1629 SilcClientEntry target;
1631 char *nickname = NULL;
1634 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1635 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1639 if (cmd->argc < 3) {
1640 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1641 "Usage: /KICK <channel> <nickname> [<comment>]");
1642 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1646 if (cmd->argv[1][0] == '*') {
1647 if (!conn->current_channel) {
1648 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1651 name = conn->current_channel->channel_name;
1653 name = cmd->argv[1];
1656 if (!conn->current_channel) {
1657 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1661 /* Get the Channel ID of the channel */
1662 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1663 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1667 channel = (SilcChannelEntry)id_cache->context;
1669 /* Parse the typed nickname. */
1670 if (client->internal->params->nickname_parse)
1671 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1673 nickname = strdup(cmd->argv[2]);
1675 /* Get the target client */
1676 target = silc_idlist_get_client(cmd->client, conn, nickname,
1677 cmd->argv[2], FALSE);
1679 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1680 "No such client: %s", cmd->argv[2]);
1681 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1685 /* Send KICK command to the server */
1686 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1687 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1689 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1690 1, idp->data, idp->len,
1691 2, idp2->data, idp2->len);
1693 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1694 1, idp->data, idp->len,
1695 2, idp2->data, idp2->len,
1697 strlen(cmd->argv[3]));
1698 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1699 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1700 silc_buffer_free(buffer);
1701 silc_buffer_free(idp);
1702 silc_buffer_free(idp2);
1704 /* Notify application */
1705 COMMAND(SILC_STATUS_OK);
1708 silc_free(nickname);
1709 silc_client_command_free(cmd);
1712 static void silc_client_command_oper_send(unsigned char *data,
1713 SilcUInt32 data_len, void *context)
1715 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1716 SilcClientConnection conn = cmd->conn;
1717 SilcBuffer buffer, auth;
1719 if (cmd->argc >= 3) {
1720 /* Encode the public key authentication payload */
1721 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1722 cmd->client->private_key,
1723 cmd->client->rng, conn->hash,
1727 /* Encode the password authentication payload */
1728 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1732 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1734 strlen(cmd->argv[1]),
1735 2, auth ? auth->data : NULL,
1736 auth ? auth->len : 0);
1737 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1738 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1740 silc_buffer_free(buffer);
1741 silc_buffer_free(auth);
1743 /* Notify application */
1744 COMMAND(SILC_STATUS_OK);
1747 /* OPER command. Used to obtain server operator privileges. */
1749 SILC_CLIENT_CMD_FUNC(oper)
1751 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1752 SilcClientConnection conn = cmd->conn;
1755 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1756 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1760 if (cmd->argc < 2) {
1761 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1762 "Usage: /OPER <username> [-pubkey]");
1763 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1767 if (cmd->argc < 3) {
1768 /* Get passphrase */
1769 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1770 silc_client_command_oper_send,
1775 silc_client_command_oper_send(NULL, 0, context);
1778 silc_client_command_free(cmd);
1781 static void silc_client_command_silcoper_send(unsigned char *data,
1782 SilcUInt32 data_len,
1785 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1786 SilcClientConnection conn = cmd->conn;
1787 SilcBuffer buffer, auth;
1789 if (cmd->argc >= 3) {
1790 /* Encode the public key authentication payload */
1791 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1792 cmd->client->private_key,
1793 cmd->client->rng, conn->hash,
1797 /* Encode the password authentication payload */
1798 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1802 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1804 strlen(cmd->argv[1]),
1805 2, auth ? auth->data : NULL,
1806 auth ? auth->len : 0);
1807 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1808 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1810 silc_buffer_free(buffer);
1811 silc_buffer_free(auth);
1813 /* Notify application */
1814 COMMAND(SILC_STATUS_OK);
1817 /* SILCOPER command. Used to obtain router operator privileges. */
1819 SILC_CLIENT_CMD_FUNC(silcoper)
1821 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1822 SilcClientConnection conn = cmd->conn;
1825 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1826 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1830 if (cmd->argc < 2) {
1831 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1832 "Usage: /SILCOPER <username> [-pubkey]");
1833 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1837 if (cmd->argc < 3) {
1838 /* Get passphrase */
1839 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1840 silc_client_command_silcoper_send,
1845 silc_client_command_silcoper_send(NULL, 0, context);
1848 silc_client_command_free(cmd);
1851 /* Command BAN. This is used to manage the ban list of the channel. */
1853 SILC_CLIENT_CMD_FUNC(ban)
1855 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1856 SilcClientConnection conn = cmd->conn;
1857 SilcChannelEntry channel;
1858 SilcBuffer buffer, chidp;
1860 char *name, *ban = NULL;
1863 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1864 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1868 if (cmd->argc < 2) {
1869 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1870 "Usage: /BAN <channel> "
1871 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1872 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1876 if (cmd->argv[1][0] == '*') {
1877 if (!conn->current_channel) {
1878 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1882 channel = conn->current_channel;
1884 name = cmd->argv[1];
1886 channel = silc_client_get_channel(cmd->client, conn, name);
1888 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1893 if (cmd->argc == 3) {
1894 if (cmd->argv[2][0] == '+')
1903 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1905 /* Send the command */
1906 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1907 ++conn->cmd_ident, 2,
1908 1, chidp->data, chidp->len,
1909 type, ban, ban ? strlen(ban) : 0);
1910 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1911 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1912 silc_buffer_free(buffer);
1913 silc_buffer_free(chidp);
1915 /* Notify application */
1916 COMMAND(SILC_STATUS_OK);
1919 silc_client_command_free(cmd);
1922 /* Command DETACH. This is used to detach from the server */
1924 SILC_CLIENT_CMD_FUNC(detach)
1926 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1927 SilcClientConnection conn = cmd->conn;
1931 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1932 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1936 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1937 ++conn->cmd_ident, 0);
1938 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1939 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1940 silc_buffer_free(buffer);
1942 /* Notify application */
1943 COMMAND(SILC_STATUS_OK);
1946 silc_client_command_free(cmd);
1949 /* Command WATCH. */
1951 SILC_CLIENT_CMD_FUNC(watch)
1953 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1954 SilcClientConnection conn = cmd->conn;
1955 SilcBuffer buffer, idp = NULL;
1959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1960 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1964 if (cmd->argc < 3) {
1965 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1969 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1971 if (!strcasecmp(cmd->argv[1], "-add")) {
1973 } else if (!strcasecmp(cmd->argv[1], "-del")) {
1976 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1980 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
1981 ++conn->cmd_ident, 2,
1982 1, idp->data, idp->len,
1985 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1986 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1987 silc_buffer_free(buffer);
1989 /* Notify application */
1990 COMMAND(SILC_STATUS_OK);
1994 silc_buffer_free(idp);
1995 silc_client_command_free(cmd);
1998 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2000 SILC_CLIENT_CMD_FUNC(leave)
2002 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2003 SilcClientConnection conn = cmd->conn;
2004 SilcChannelEntry channel;
2005 SilcChannelUser chu;
2006 SilcBuffer buffer, idp;
2010 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2011 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2015 if (cmd->argc != 2) {
2016 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2017 "Usage: /LEAVE <channel>");
2018 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2022 if (cmd->argv[1][0] == '*') {
2023 if (!conn->current_channel) {
2024 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2027 name = conn->current_channel->channel_name;
2029 name = cmd->argv[1];
2032 /* Get the channel entry */
2033 channel = silc_client_get_channel(cmd->client, conn, name);
2035 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2039 /* Remove us from channel */
2040 chu = silc_client_on_channel(channel, conn->local_entry);
2042 silc_hash_table_del(chu->client->channels, chu->channel);
2043 silc_hash_table_del(chu->channel->user_list, chu->client);
2047 /* Send LEAVE command to the server */
2048 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2049 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2050 1, idp->data, idp->len);
2051 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2052 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2053 silc_buffer_free(buffer);
2054 silc_buffer_free(idp);
2056 /* Notify application */
2057 COMMAND(SILC_STATUS_OK);
2059 if (conn->current_channel == channel)
2060 conn->current_channel = NULL;
2062 silc_client_del_channel(cmd->client, cmd->conn, channel);
2065 silc_client_command_free(cmd);
2068 /* Command USERS. Requests the USERS of the clients joined on requested
2071 SILC_CLIENT_CMD_FUNC(users)
2073 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2074 SilcClientConnection conn = cmd->conn;
2079 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2080 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2084 if (cmd->argc != 2) {
2085 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2086 "Usage: /USERS <channel>");
2087 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2091 if (cmd->argv[1][0] == '*') {
2092 if (!conn->current_channel) {
2093 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2096 name = conn->current_channel->channel_name;
2098 name = cmd->argv[1];
2101 /* Send USERS command to the server */
2102 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2103 ++conn->cmd_ident, 1,
2104 2, name, strlen(name));
2105 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2106 NULL, 0, NULL, NULL, buffer->data,
2108 silc_buffer_free(buffer);
2110 /* Notify application */
2111 COMMAND(SILC_STATUS_OK);
2114 silc_client_command_free(cmd);
2117 /* Command GETKEY. Used to fetch remote client's public key. */
2119 SILC_CLIENT_CMD_FUNC(getkey)
2121 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2122 SilcClientConnection conn = cmd->conn;
2123 SilcClient client = cmd->client;
2124 SilcClientEntry client_entry = NULL;
2125 SilcServerEntry server_entry = NULL;
2126 char *nickname = NULL;
2127 SilcBuffer idp, buffer;
2129 SILC_LOG_DEBUG(("Start"));
2132 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2133 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2137 if (cmd->argc < 2) {
2138 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2139 "Usage: /GETKEY <nickname or server name>");
2140 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2144 /* Parse the typed nickname. */
2145 if (client->internal->params->nickname_parse)
2146 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2148 nickname = strdup(cmd->argv[1]);
2150 /* Find client entry */
2151 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2153 if (!client_entry) {
2154 /* Check whether user requested server actually */
2155 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2157 if (!server_entry) {
2158 /* No. what ever user wants we don't have it, so resolve it. We
2159 will first try to resolve the client, and if that fails then
2160 we'll try to resolve the server. */
2162 if (!cmd->pending) {
2163 /* This will send the IDENTIFY command for nickname */
2164 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2165 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2167 silc_client_command_getkey,
2168 silc_client_command_dup(cmd));
2172 SilcClientCommandReplyContext reply =
2173 (SilcClientCommandReplyContext)context2;
2176 /* If nickname was not found, then resolve the server. */
2177 silc_command_get_status(reply->payload, NULL, &error);
2178 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2179 /* This sends the IDENTIFY command to resolve the server. */
2180 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2182 silc_client_command_reply_identify_i, 0,
2184 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2186 2, cmd->argv[1], cmd->argv_lens[1]);
2187 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2189 silc_client_command_getkey,
2190 silc_client_command_dup(cmd));
2194 /* If server was not found, then we've resolved both nickname and
2195 server and did not find anybody. */
2196 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2197 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2198 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2199 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2200 silc_get_status_message(error));
2201 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2205 COMMAND_ERROR(error);
2210 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2212 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2215 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2216 1, idp->data, idp->len);
2217 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2218 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2219 silc_buffer_free(buffer);
2220 silc_buffer_free(idp);
2222 /* Notify application */
2223 COMMAND(SILC_STATUS_OK);
2226 silc_free(nickname);
2227 silc_client_command_free(cmd);
2230 /* Register a new command indicated by the `command' to the SILC client.
2231 The `name' is optional command name. If provided the command may be
2232 searched using the silc_client_command_find by that name. The
2233 `command_function' is the function to be called when the command is
2234 executed, and the `command_reply_function' is the function to be
2235 called after the server has sent reply back to the command.
2237 The `ident' is optional identifier for the command. If non-zero
2238 the `command_reply_function' for the command type `command' will be
2239 called only if the command reply sent by server includes the
2240 command identifier `ident'. Application usually does not need it
2241 and set it to zero value. */
2243 bool silc_client_command_register(SilcClient client,
2244 SilcCommand command,
2246 SilcCommandCb command_function,
2247 SilcCommandCb command_reply_function,
2251 SilcClientCommand cmd;
2253 cmd = silc_calloc(1, sizeof(*cmd));
2255 cmd->command = command_function;
2256 cmd->reply = command_reply_function;
2257 cmd->name = name ? strdup(name) : NULL;
2258 cmd->max_args = max_args;
2261 silc_list_add(client->internal->commands, cmd);
2266 /* Unregister a command indicated by the `command' with command function
2267 `command_function' and command reply function `command_reply_function'.
2268 Returns TRUE if the command was found and unregistered. */
2270 bool silc_client_command_unregister(SilcClient client,
2271 SilcCommand command,
2272 SilcCommandCb command_function,
2273 SilcCommandCb command_reply_function,
2276 SilcClientCommand cmd;
2278 silc_list_start(client->internal->commands);
2279 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2280 if (cmd->cmd == command && cmd->command == command_function &&
2281 cmd->reply == command_reply_function && cmd->ident == ident) {
2282 silc_list_del(client->internal->commands, cmd);
2283 silc_free(cmd->name);
2292 /* Private range commands, specific to this implementation (and compatible
2293 with SILC Server). */
2295 /* CONNECT command. Connects the server to another server. */
2297 SILC_CLIENT_CMD_FUNC(connect)
2299 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2300 SilcClientConnection conn = cmd->conn;
2302 unsigned char port[4];
2306 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2307 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2311 if (cmd->argc < 2) {
2312 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2313 "Usage: /CONNECT <server> [<port>]");
2314 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2318 if (cmd->argc == 3) {
2319 tmp = atoi(cmd->argv[2]);
2320 SILC_PUT32_MSB(tmp, port);
2324 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2326 strlen(cmd->argv[1]),
2329 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2331 strlen(cmd->argv[1]));
2332 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2333 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2334 silc_buffer_free(buffer);
2336 /* Notify application */
2337 COMMAND(SILC_STATUS_OK);
2340 silc_client_command_free(cmd);
2344 /* CLOSE command. Close server connection to the remote server */
2346 SILC_CLIENT_CMD_FUNC(close)
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: /CLOSE <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_CLOSE, 0, 2,
2375 strlen(cmd->argv[1]),
2378 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 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);
2392 /* SHUTDOWN command. Shutdowns the server. */
2394 SILC_CLIENT_CMD_FUNC(shutdown)
2396 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2399 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2400 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2404 /* Send the command */
2405 silc_client_command_send(cmd->client, cmd->conn,
2406 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2408 /* Notify application */
2409 COMMAND(SILC_STATUS_OK);
2412 silc_client_command_free(cmd);
2415 /* Register all default commands provided by the client library for the
2418 void silc_client_commands_register(SilcClient client)
2420 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2423 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2424 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2425 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2426 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2427 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2428 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2429 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2430 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2431 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2432 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2433 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2434 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2435 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2436 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2437 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2438 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2439 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2440 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2441 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2442 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2443 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2444 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2445 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2446 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2447 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2449 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2450 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2451 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2454 /* Unregister all commands. */
2456 void silc_client_commands_unregister(SilcClient client)
2458 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2459 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2460 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2461 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2462 SILC_CLIENT_CMDU(list, LIST, "LIST");
2463 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2464 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2465 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2466 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2467 SILC_CLIENT_CMDU(info, INFO, "INFO");
2468 SILC_CLIENT_CMDU(ping, PING, "PING");
2469 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2470 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2471 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2472 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2473 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2474 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2475 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2476 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2477 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2478 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2479 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2480 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2481 SILC_CLIENT_CMDU(users, USERS, "USERS");
2482 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2484 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2485 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2486 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");