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);
135 /* Checks for pending commands and marks callbacks to be called from
136 the command reply function. */
138 SilcClientCommandPendingCallbacks
139 silc_client_command_pending_check(SilcClientConnection conn,
140 SilcClientCommandReplyContext ctx,
143 SilcUInt32 *callbacks_count)
145 SilcClientCommandPending *r;
146 SilcClientCommandPendingCallbacks callbacks = NULL;
149 silc_dlist_start(conn->pending_commands);
150 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
151 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
152 && r->ident == ident) {
153 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
154 callbacks[i].context = r->context;
155 callbacks[i].callback = r->callback;
161 *callbacks_count = i;
165 /* Allocate Command Context */
167 SilcClientCommandContext silc_client_command_alloc(void)
169 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
174 /* Free command context and its internals */
176 void silc_client_command_free(SilcClientCommandContext ctx)
179 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
181 if (ctx->users < 1) {
184 for (i = 0; i < ctx->argc; i++)
185 silc_free(ctx->argv[i]);
186 silc_free(ctx->argv_lens);
187 silc_free(ctx->argv_types);
192 /* Duplicate Command Context by adding reference counter. The context won't
193 be free'd untill it hits zero. */
195 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
198 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
203 /* Command WHOIS. This command is used to query information about
206 SILC_CLIENT_CMD_FUNC(whois)
208 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
209 SilcClientConnection conn = cmd->conn;
211 unsigned char count[4];
214 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
215 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
219 /* Given without arguments fetches client's own information */
221 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
222 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
224 1, 4, buffer->data, buffer->len);
225 silc_buffer_free(buffer);
229 if (cmd->argc == 2) {
230 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
231 ++conn->cmd_ident, 1,
235 int c = atoi(cmd->argv[2]);
236 memset(count, 0, sizeof(count));
237 SILC_PUT32_MSB(c, count);
238 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
239 ++conn->cmd_ident, 2,
240 1, cmd->argv[1], cmd->argv_lens[1],
241 2, count, sizeof(count));
243 silc_client_packet_send(cmd->client, cmd->conn->sock,
244 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
245 buffer->data, buffer->len, TRUE);
246 silc_buffer_free(buffer);
248 /* Notify application */
249 COMMAND(SILC_STATUS_OK);
252 silc_client_command_free(cmd);
255 /* Command WHOWAS. This command is used to query history information about
256 specific user that used to exist in the network. */
258 SILC_CLIENT_CMD_FUNC(whowas)
260 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
261 SilcClientConnection conn = cmd->conn;
263 unsigned char count[4];
266 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
267 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
271 if (cmd->argc < 2 || cmd->argc > 3) {
272 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
273 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
274 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
275 SILC_STATUS_ERR_TOO_MANY_PARAMS));
279 if (cmd->argc == 2) {
280 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
281 ++conn->cmd_ident, 1,
285 int c = atoi(cmd->argv[2]);
286 memset(count, 0, sizeof(count));
287 SILC_PUT32_MSB(c, count);
288 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
289 ++conn->cmd_ident, 2,
290 1, cmd->argv[1], cmd->argv_lens[1],
291 2, count, sizeof(count));
293 silc_client_packet_send(cmd->client, cmd->conn->sock,
294 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
295 buffer->data, buffer->len, TRUE);
296 silc_buffer_free(buffer);
298 /* Notify application */
299 COMMAND(SILC_STATUS_OK);
302 silc_client_command_free(cmd);
305 /* Command IDENTIFY. This command is used to query information about
306 specific user, especially ID's.
308 NOTE: This command is used only internally by the client library
309 and application MUST NOT call this command directly. */
311 SILC_CLIENT_CMD_FUNC(identify)
313 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
314 SilcClientConnection conn = cmd->conn;
316 unsigned char count[4];
319 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
320 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
324 if (cmd->argc < 2 || cmd->argc > 3)
327 if (cmd->argc == 2) {
328 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
329 ++conn->cmd_ident, 1,
333 int c = atoi(cmd->argv[2]);
334 memset(count, 0, sizeof(count));
335 SILC_PUT32_MSB(c, count);
336 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
337 ++conn->cmd_ident, 2,
340 4, count, sizeof(count));
343 silc_client_packet_send(cmd->client, cmd->conn->sock,
344 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
345 buffer->data, buffer->len, TRUE);
346 silc_buffer_free(buffer);
349 silc_client_command_free(cmd);
352 /* Command NICK. Shows current nickname/sets new nickname on current
355 SILC_CLIENT_CMD_FUNC(nick)
357 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
358 SilcClientConnection conn = cmd->conn;
362 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
363 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
368 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
369 "Usage: /NICK <nickname>");
370 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
374 if (!strcmp(conn->nickname, cmd->argv[1]))
377 /* Show current nickname */
380 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
381 "Your nickname is %s on server %s",
382 conn->nickname, conn->remote_host);
384 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
385 "Your nickname is %s", conn->nickname);
388 COMMAND(SILC_STATUS_OK);
392 if (cmd->argv_lens[1] > 128)
393 cmd->argv_lens[1] = 128;
395 /* Send the NICK command */
396 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
400 ++cmd->conn->cmd_ident);
401 silc_client_packet_send(cmd->client, cmd->conn->sock,
402 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
403 buffer->data, buffer->len, TRUE);
404 silc_buffer_free(buffer);
407 silc_client_command_free(cmd);
410 /* Command LIST. Lists channels on the current server. */
412 SILC_CLIENT_CMD_FUNC(list)
414 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
415 SilcClientConnection conn = cmd->conn;
416 SilcIDCacheEntry id_cache = NULL;
417 SilcChannelEntry channel;
418 SilcBuffer buffer, idp = NULL;
422 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
423 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
427 if (cmd->argc == 2) {
430 /* Get the Channel ID of the channel */
431 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
432 channel = (SilcChannelEntry)id_cache->context;
433 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
438 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
439 ++conn->cmd_ident, 0);
441 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
442 ++conn->cmd_ident, 1,
443 1, idp->data, idp->len);
445 silc_client_packet_send(cmd->client, cmd->conn->sock,
446 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
447 buffer->data, buffer->len, TRUE);
448 silc_buffer_free(buffer);
450 silc_buffer_free(idp);
452 /* Notify application */
453 COMMAND(SILC_STATUS_OK);
456 silc_client_command_free(cmd);
459 /* Command TOPIC. Sets/shows topic on a channel. */
461 SILC_CLIENT_CMD_FUNC(topic)
463 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
464 SilcClientConnection conn = cmd->conn;
465 SilcIDCacheEntry id_cache = NULL;
466 SilcChannelEntry channel;
467 SilcBuffer buffer, idp;
471 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
472 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
476 if (cmd->argc < 2 || cmd->argc > 3) {
477 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
478 "Usage: /TOPIC <channel> [<topic>]");
479 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
480 SILC_STATUS_ERR_TOO_MANY_PARAMS));
484 if (cmd->argv[1][0] == '*') {
485 if (!conn->current_channel) {
486 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
489 name = conn->current_channel->channel_name;
494 if (!conn->current_channel) {
495 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
499 /* Get the Channel ID of the channel */
500 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
501 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
505 channel = (SilcChannelEntry)id_cache->context;
507 /* Send TOPIC command to the server */
508 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
510 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
511 ++conn->cmd_ident, 2,
512 1, idp->data, idp->len,
514 strlen(cmd->argv[2]));
516 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
517 ++conn->cmd_ident, 1,
518 1, idp->data, idp->len);
519 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
520 0, NULL, NULL, buffer->data, buffer->len, TRUE);
521 silc_buffer_free(buffer);
522 silc_buffer_free(idp);
524 /* Notify application */
525 COMMAND(SILC_STATUS_OK);
528 silc_client_command_free(cmd);
531 /* Command INVITE. Invites specific client to join a channel. This is
532 also used to mange the invite list of the channel. */
534 SILC_CLIENT_CMD_FUNC(invite)
536 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
537 SilcClient client = cmd->client;
538 SilcClientConnection conn = cmd->conn;
539 SilcClientEntry client_entry = NULL;
540 SilcChannelEntry channel;
541 SilcBuffer buffer, clidp, chidp;
543 char *nickname = NULL, *name;
547 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
548 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
553 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
554 "Usage: /INVITE <channel> [<nickname>[@server>]"
555 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
556 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
560 if (cmd->argv[1][0] == '*') {
561 if (!conn->current_channel) {
562 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
566 channel = conn->current_channel;
570 channel = silc_client_get_channel(cmd->client, conn, name);
572 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
577 /* Parse the typed nickname. */
578 if (cmd->argc == 3) {
579 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
580 if (client->internal->params->nickname_parse)
581 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
583 nickname = strdup(cmd->argv[2]);
585 /* Find client entry */
586 client_entry = silc_idlist_get_client(client, conn, nickname,
590 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
594 /* Client entry not found, it was requested thus mark this to be
596 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
598 silc_client_command_invite,
599 silc_client_command_dup(cmd));
604 invite = cmd->argv[2];
606 if (cmd->argv[2][0] == '+')
613 /* Send the command */
614 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
616 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
617 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
618 ++conn->cmd_ident, 3,
619 1, chidp->data, chidp->len,
620 2, clidp->data, clidp->len,
621 type, invite, invite ?
623 silc_buffer_free(clidp);
625 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
626 ++conn->cmd_ident, 2,
627 1, chidp->data, chidp->len,
628 type, invite, invite ?
632 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
633 0, NULL, NULL, buffer->data, buffer->len, TRUE);
634 silc_buffer_free(buffer);
635 silc_buffer_free(chidp);
637 /* Notify application */
638 COMMAND(SILC_STATUS_OK);
642 silc_client_command_free(cmd);
647 SilcClientConnection conn;
650 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
652 QuitInternal q = (QuitInternal)context;
654 /* Close connection */
655 q->client->internal->ops->disconnect(q->client, q->conn, 0, NULL);
656 silc_client_close_connection(q->client, q->conn->sock->user_data);
661 /* Command QUIT. Closes connection with current server. */
663 SILC_CLIENT_CMD_FUNC(quit)
665 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
670 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
671 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
676 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
677 &cmd->argv[1], &cmd->argv_lens[1],
678 &cmd->argv_types[1], 0);
680 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
681 NULL, NULL, NULL, 0);
682 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
684 buffer->data, buffer->len, TRUE);
685 silc_buffer_free(buffer);
687 q = silc_calloc(1, sizeof(*q));
688 q->client = cmd->client;
691 /* Sleep for a while */
694 /* We quit the connection with little timeout */
695 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
696 silc_client_command_quit_cb, (void *)q,
697 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
699 /* Notify application */
700 COMMAND(SILC_STATUS_OK);
703 silc_client_command_free(cmd);
706 /* Timeout callback to remove the killed client from cache */
708 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
710 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
711 SilcClient client = cmd->client;
712 SilcClientConnection conn = cmd->conn;
713 SilcClientEntry target;
714 char *nickname = NULL;
716 /* Parse the typed nickname. */
717 if (client->internal->params->nickname_parse)
718 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
720 nickname = strdup(cmd->argv[1]);
722 /* Get the target client */
723 target = silc_idlist_get_client(cmd->client, conn, nickname,
724 cmd->argv[1], FALSE);
726 /* Remove the client from all channels and free it */
727 silc_client_del_client(client, conn, target);
730 silc_client_command_free(cmd);
733 /* Kill command's pending command callback to actually remove the killed
734 client from our local cache. */
736 SILC_CLIENT_CMD_FUNC(kill_remove)
738 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
739 SilcClientCommandReplyContext reply =
740 (SilcClientCommandReplyContext)context2;
743 silc_command_get_status(reply->payload, &status, NULL);
744 if (status == SILC_STATUS_OK) {
745 /* Remove with timeout */
746 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
747 silc_client_command_kill_remove_later, context,
748 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
752 silc_client_command_free(cmd);
755 /* Command KILL. Router operator can use this command to remove an client
756 fromthe SILC Network. */
758 SILC_CLIENT_CMD_FUNC(kill)
760 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
761 SilcClient client = cmd->client;
762 SilcClientConnection conn = cmd->conn;
763 SilcBuffer buffer, idp;
764 SilcClientEntry target;
765 char *nickname = NULL;
768 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
769 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
774 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
775 "Usage: /KILL <nickname> [<comment>]");
776 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
780 /* Parse the typed nickname. */
781 if (client->internal->params->nickname_parse)
782 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
784 nickname = strdup(cmd->argv[1]);
786 /* Get the target client */
787 target = silc_idlist_get_client(cmd->client, conn, nickname,
791 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
795 /* Client entry not found, it was requested thus mark this to be
797 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
799 silc_client_command_kill,
800 silc_client_command_dup(cmd));
805 /* Send the KILL command to the server */
806 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
808 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
809 ++conn->cmd_ident, 1,
810 1, idp->data, idp->len);
812 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
813 ++conn->cmd_ident, 2,
814 1, idp->data, idp->len,
816 strlen(cmd->argv[2]));
817 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
818 0, NULL, NULL, buffer->data, buffer->len, TRUE);
819 silc_buffer_free(buffer);
820 silc_buffer_free(idp);
822 /* Notify application */
823 COMMAND(SILC_STATUS_OK);
825 /* Register a pending callback that will actually remove the killed
826 client from our cache. */
827 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
828 silc_client_command_kill_remove,
829 silc_client_command_dup(cmd));
833 silc_client_command_free(cmd);
836 /* Command INFO. Request information about specific server. If specific
837 server is not provided the current server is used. */
839 SILC_CLIENT_CMD_FUNC(info)
841 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
842 SilcClientConnection conn = cmd->conn;
847 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
848 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
853 name = strdup(cmd->argv[1]);
855 /* Send the command */
857 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
858 1, name, strlen(name));
860 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
861 NULL, NULL, NULL, 0);
862 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
863 0, NULL, NULL, buffer->data, buffer->len, TRUE);
864 silc_buffer_free(buffer);
868 /* Notify application */
869 COMMAND(SILC_STATUS_OK);
872 silc_client_command_free(cmd);
875 /* Command PING. Sends ping to server. This is used to test the
876 communication channel. */
878 SILC_CLIENT_CMD_FUNC(ping)
880 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
881 SilcClientConnection conn = cmd->conn;
887 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
888 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
892 /* Send the command */
893 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
894 1, conn->remote_id_data,
895 silc_id_get_len(conn->remote_id,
897 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
898 0, NULL, NULL, buffer->data, buffer->len, TRUE);
899 silc_buffer_free(buffer);
901 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
904 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
905 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
909 /* Start counting time */
910 for (i = 0; i < conn->ping_count; i++) {
911 if (conn->ping[i].dest_id == NULL) {
912 conn->ping[i].start_time = time(NULL);
913 conn->ping[i].dest_id = id;
914 conn->ping[i].dest_name = strdup(conn->remote_host);
918 if (i >= conn->ping_count) {
919 i = conn->ping_count;
920 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
921 conn->ping[i].start_time = time(NULL);
922 conn->ping[i].dest_id = id;
923 conn->ping[i].dest_name = strdup(conn->remote_host);
927 /* Notify application */
928 COMMAND(SILC_STATUS_OK);
931 silc_client_command_free(cmd);
934 /* Command JOIN. Joins to a channel. */
936 SILC_CLIENT_CMD_FUNC(join)
938 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
939 SilcClientConnection conn = cmd->conn;
940 SilcChannelEntry channel;
941 SilcBuffer buffer, idp, auth = NULL;
942 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
943 int i, passphrase_len = 0;
946 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
947 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
952 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
956 /* See if we have joined to the requested channel already */
957 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
958 if (channel && silc_client_on_channel(channel, conn->local_entry))
961 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
963 if (cmd->argv_lens[1] > 256)
964 cmd->argv_lens[1] = 256;
968 for (i = 2; i < cmd->argc; i++) {
969 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
970 cipher = cmd->argv[i + 1];
972 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
973 hmac = cmd->argv[i + 1];
975 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
976 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
977 cmd->client->private_key,
979 cmd->client->internal->
985 /* Passphrases must be UTF-8 encoded, so encode if it is not */
986 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
987 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
988 cmd->argv_lens[i], 0);
989 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
990 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
991 0, pu8, passphrase_len);
994 passphrase = strdup(cmd->argv[i]);
995 passphrase_len = cmd->argv_lens[i];
1000 /* Send JOIN command to the server */
1002 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1003 1, name, strlen(name),
1004 2, idp->data, idp->len,
1005 3, passphrase, passphrase_len,
1006 4, cipher, cipher ? strlen(cipher) : 0,
1007 5, hmac, hmac ? strlen(hmac) : 0,
1008 6, auth ? auth->data : NULL,
1009 auth ? auth->len : 0);
1010 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1011 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1012 silc_buffer_free(buffer);
1013 silc_buffer_free(idp);
1015 silc_buffer_free(auth);
1016 silc_free(passphrase);
1018 /* Notify application */
1019 COMMAND(SILC_STATUS_OK);
1022 silc_client_command_free(cmd);
1025 /* MOTD command. Requests motd from server. */
1027 SILC_CLIENT_CMD_FUNC(motd)
1029 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1030 SilcClientConnection conn = cmd->conn;
1034 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1035 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1039 if (cmd->argc < 1 || cmd->argc > 2) {
1040 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1041 "Usage: /MOTD [<server>]");
1042 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1043 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1047 /* Send TOPIC command to the server */
1049 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1050 1, conn->remote_host,
1051 strlen(conn->remote_host));
1053 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1056 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1057 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1058 silc_buffer_free(buffer);
1060 /* Notify application */
1061 COMMAND(SILC_STATUS_OK);
1064 silc_client_command_free(cmd);
1067 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1068 modes as client cannot set itself server/router operator privileges. */
1070 SILC_CLIENT_CMD_FUNC(umode)
1072 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1073 SilcClientConnection conn = cmd->conn;
1074 SilcBuffer buffer, idp;
1075 unsigned char *cp, modebuf[4];
1076 SilcUInt32 mode, add, len;
1080 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1081 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1085 if (cmd->argc < 2) {
1086 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1087 "Usage: /UMODE +|-<modes>");
1088 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1092 mode = conn->local_entry->mode;
1094 /* Are we adding or removing mode */
1095 if (cmd->argv[1][0] == '-')
1101 cp = cmd->argv[1] + 1;
1103 for (i = 0; i < len; i++) {
1108 mode |= SILC_UMODE_SERVER_OPERATOR;
1109 mode |= SILC_UMODE_ROUTER_OPERATOR;
1110 mode |= SILC_UMODE_GONE;
1111 mode |= SILC_UMODE_INDISPOSED;
1112 mode |= SILC_UMODE_BUSY;
1113 mode |= SILC_UMODE_PAGE;
1114 mode |= SILC_UMODE_HYPER;
1115 mode |= SILC_UMODE_ROBOT;
1116 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1117 mode |= SILC_UMODE_REJECT_WATCHING;
1119 mode = SILC_UMODE_NONE;
1124 mode |= SILC_UMODE_SERVER_OPERATOR;
1126 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1130 mode |= SILC_UMODE_ROUTER_OPERATOR;
1132 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1136 mode |= SILC_UMODE_GONE;
1138 mode &= ~SILC_UMODE_GONE;
1142 mode |= SILC_UMODE_INDISPOSED;
1144 mode &= ~SILC_UMODE_INDISPOSED;
1148 mode |= SILC_UMODE_BUSY;
1150 mode &= ~SILC_UMODE_BUSY;
1154 mode |= SILC_UMODE_PAGE;
1156 mode &= ~SILC_UMODE_PAGE;
1160 mode |= SILC_UMODE_HYPER;
1162 mode &= ~SILC_UMODE_HYPER;
1166 mode |= SILC_UMODE_ROBOT;
1168 mode &= ~SILC_UMODE_ROBOT;
1172 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1174 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1178 mode |= SILC_UMODE_REJECT_WATCHING;
1180 mode &= ~SILC_UMODE_REJECT_WATCHING;
1184 mode |= SILC_UMODE_BLOCK_INVITE;
1186 mode &= ~SILC_UMODE_BLOCK_INVITE;
1189 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1195 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1196 SILC_PUT32_MSB(mode, modebuf);
1198 /* Send the command packet. We support sending only one mode at once
1199 that requires an argument. */
1201 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1202 1, idp->data, idp->len,
1203 2, modebuf, sizeof(modebuf));
1204 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1205 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1206 silc_buffer_free(buffer);
1207 silc_buffer_free(idp);
1209 /* Notify application */
1210 COMMAND(SILC_STATUS_OK);
1213 silc_client_command_free(cmd);
1216 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1217 can be set several at once. Those modes that require argument must be set
1218 separately (unless set with modes that does not require arguments). */
1220 SILC_CLIENT_CMD_FUNC(cmode)
1222 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1223 SilcClientConnection conn = cmd->conn;
1224 SilcChannelEntry channel;
1225 SilcBuffer buffer, chidp, auth = NULL;
1226 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1227 SilcUInt32 mode, add, type, len, arg_len = 0;
1231 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1232 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1236 if (cmd->argc < 3) {
1237 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1238 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1239 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1243 if (cmd->argv[1][0] == '*') {
1244 if (!conn->current_channel) {
1245 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1249 channel = conn->current_channel;
1251 name = cmd->argv[1];
1253 channel = silc_client_get_channel(cmd->client, conn, name);
1255 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1260 mode = channel->mode;
1262 /* Are we adding or removing mode */
1263 if (cmd->argv[2][0] == '-')
1268 /* Argument type to be sent to server */
1272 cp = cmd->argv[2] + 1;
1274 for (i = 0; i < len; i++) {
1278 mode |= SILC_CHANNEL_MODE_PRIVATE;
1280 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1284 mode |= SILC_CHANNEL_MODE_SECRET;
1286 mode &= ~SILC_CHANNEL_MODE_SECRET;
1290 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1292 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1296 mode |= SILC_CHANNEL_MODE_INVITE;
1298 mode &= ~SILC_CHANNEL_MODE_INVITE;
1302 mode |= SILC_CHANNEL_MODE_TOPIC;
1304 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1308 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1310 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1314 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1316 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1321 mode |= SILC_CHANNEL_MODE_ULIMIT;
1323 if (cmd->argc < 4) {
1324 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1325 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1326 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1329 ll = atoi(cmd->argv[3]);
1330 SILC_PUT32_MSB(ll, tmp);
1334 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1339 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1341 if (cmd->argc < 4) {
1342 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1343 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1344 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1348 arg_len = cmd->argv_lens[3];
1350 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1355 mode |= SILC_CHANNEL_MODE_CIPHER;
1357 if (cmd->argc < 4) {
1358 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1359 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1360 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1364 arg_len = cmd->argv_lens[3];
1366 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1371 mode |= SILC_CHANNEL_MODE_HMAC;
1373 if (cmd->argc < 4) {
1374 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1375 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1376 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1380 arg_len = cmd->argv_lens[3];
1382 mode &= ~SILC_CHANNEL_MODE_HMAC;
1387 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1389 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1390 cmd->client->private_key,
1392 cmd->client->internal->
1397 arg_len = auth->len;
1399 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1403 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1409 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1410 SILC_PUT32_MSB(mode, modebuf);
1412 /* Send the command packet. We support sending only one mode at once
1413 that requires an argument. */
1416 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1417 1, chidp->data, chidp->len,
1418 2, modebuf, sizeof(modebuf),
1419 type, arg, arg_len);
1422 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1423 1, chidp->data, chidp->len,
1424 2, modebuf, sizeof(modebuf));
1427 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1428 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1429 silc_buffer_free(buffer);
1430 silc_buffer_free(chidp);
1432 silc_buffer_free(auth);
1434 /* Notify application */
1435 COMMAND(SILC_STATUS_OK);
1438 silc_client_command_free(cmd);
1441 /* CUMODE command. Changes client's mode on a channel. */
1443 SILC_CLIENT_CMD_FUNC(cumode)
1445 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1446 SilcClient client = cmd->client;
1447 SilcClientConnection conn = cmd->conn;
1448 SilcChannelEntry channel;
1449 SilcChannelUser chu;
1450 SilcClientEntry client_entry;
1451 SilcBuffer buffer, clidp, chidp, auth = NULL;
1452 unsigned char *name, *cp, modebuf[4];
1453 SilcUInt32 mode = 0, add, len;
1454 char *nickname = NULL;
1458 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1459 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1463 if (cmd->argc < 4) {
1464 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1465 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1466 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1470 if (cmd->argv[1][0] == '*') {
1471 if (!conn->current_channel) {
1472 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1476 channel = conn->current_channel;
1478 name = cmd->argv[1];
1480 channel = silc_client_get_channel(cmd->client, conn, name);
1482 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1487 /* Parse the typed nickname. */
1488 if (client->internal->params->nickname_parse)
1489 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1491 nickname = strdup(cmd->argv[3]);
1493 /* Find client entry */
1494 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1495 cmd->argv[3], TRUE);
1496 if (!client_entry) {
1498 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1502 /* Client entry not found, it was requested thus mark this to be
1504 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1506 silc_client_command_cumode,
1507 silc_client_command_dup(cmd));
1512 /* Get the current mode */
1513 chu = silc_client_on_channel(channel, client_entry);
1517 /* Are we adding or removing mode */
1518 if (cmd->argv[2][0] == '-')
1524 cp = cmd->argv[2] + 1;
1526 for (i = 0; i < len; i++) {
1530 mode |= SILC_CHANNEL_UMODE_CHANFO;
1531 mode |= SILC_CHANNEL_UMODE_CHANOP;
1532 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1533 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1534 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1536 mode = SILC_CHANNEL_UMODE_NONE;
1541 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1542 cmd->client->private_key,
1544 cmd->client->internal->
1548 mode |= SILC_CHANNEL_UMODE_CHANFO;
1550 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1555 mode |= SILC_CHANNEL_UMODE_CHANOP;
1557 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1561 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1563 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1567 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1569 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1573 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1575 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1579 mode |= SILC_CHANNEL_UMODE_QUIET;
1581 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1584 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1590 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1591 SILC_PUT32_MSB(mode, modebuf);
1592 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1594 /* Send the command packet. We support sending only one mode at once
1595 that requires an argument. */
1596 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1598 1, chidp->data, chidp->len,
1600 3, clidp->data, clidp->len,
1601 4, auth ? auth->data : NULL,
1602 auth ? auth->len : 0);
1604 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1605 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1606 silc_buffer_free(buffer);
1607 silc_buffer_free(chidp);
1608 silc_buffer_free(clidp);
1610 silc_buffer_free(auth);
1612 /* Notify application */
1613 COMMAND(SILC_STATUS_OK);
1616 silc_free(nickname);
1617 silc_client_command_free(cmd);
1620 /* KICK command. Kicks a client out of channel. */
1622 SILC_CLIENT_CMD_FUNC(kick)
1624 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1625 SilcClient client = cmd->client;
1626 SilcClientConnection conn = cmd->conn;
1627 SilcIDCacheEntry id_cache = NULL;
1628 SilcChannelEntry channel;
1629 SilcBuffer buffer, idp, idp2;
1630 SilcClientEntry target;
1632 char *nickname = NULL;
1635 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1636 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1640 if (cmd->argc < 3) {
1641 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1642 "Usage: /KICK <channel> <nickname> [<comment>]");
1643 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1647 if (cmd->argv[1][0] == '*') {
1648 if (!conn->current_channel) {
1649 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1652 name = conn->current_channel->channel_name;
1654 name = cmd->argv[1];
1657 if (!conn->current_channel) {
1658 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1662 /* Get the Channel ID of the channel */
1663 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1664 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1668 channel = (SilcChannelEntry)id_cache->context;
1670 /* Parse the typed nickname. */
1671 if (client->internal->params->nickname_parse)
1672 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1674 nickname = strdup(cmd->argv[2]);
1676 /* Get the target client */
1677 target = silc_idlist_get_client(cmd->client, conn, nickname,
1678 cmd->argv[2], FALSE);
1680 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1681 "No such client: %s", cmd->argv[2]);
1682 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1686 /* Send KICK command to the server */
1687 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1688 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1690 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1691 1, idp->data, idp->len,
1692 2, idp2->data, idp2->len);
1694 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1695 1, idp->data, idp->len,
1696 2, idp2->data, idp2->len,
1698 strlen(cmd->argv[3]));
1699 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1700 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1701 silc_buffer_free(buffer);
1702 silc_buffer_free(idp);
1703 silc_buffer_free(idp2);
1705 /* Notify application */
1706 COMMAND(SILC_STATUS_OK);
1709 silc_free(nickname);
1710 silc_client_command_free(cmd);
1713 static void silc_client_command_oper_send(unsigned char *data,
1714 SilcUInt32 data_len, void *context)
1716 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1717 SilcClientConnection conn = cmd->conn;
1718 SilcBuffer buffer, auth;
1720 if (cmd->argc >= 3) {
1721 /* Encode the public key authentication payload */
1722 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1723 cmd->client->private_key,
1724 cmd->client->rng, conn->hash,
1728 /* Encode the password authentication payload */
1729 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1733 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1735 strlen(cmd->argv[1]),
1736 2, auth ? auth->data : NULL,
1737 auth ? auth->len : 0);
1738 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1739 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1741 silc_buffer_free(buffer);
1742 silc_buffer_free(auth);
1744 /* Notify application */
1745 COMMAND(SILC_STATUS_OK);
1748 /* OPER command. Used to obtain server operator privileges. */
1750 SILC_CLIENT_CMD_FUNC(oper)
1752 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1753 SilcClientConnection conn = cmd->conn;
1756 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1757 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1761 if (cmd->argc < 2) {
1762 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1763 "Usage: /OPER <username> [-pubkey]");
1764 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1768 if (cmd->argc < 3) {
1769 /* Get passphrase */
1770 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1771 silc_client_command_oper_send,
1776 silc_client_command_oper_send(NULL, 0, context);
1779 silc_client_command_free(cmd);
1782 static void silc_client_command_silcoper_send(unsigned char *data,
1783 SilcUInt32 data_len,
1786 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1787 SilcClientConnection conn = cmd->conn;
1788 SilcBuffer buffer, auth;
1790 if (cmd->argc >= 3) {
1791 /* Encode the public key authentication payload */
1792 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1793 cmd->client->private_key,
1794 cmd->client->rng, conn->hash,
1798 /* Encode the password authentication payload */
1799 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1803 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1805 strlen(cmd->argv[1]),
1806 2, auth ? auth->data : NULL,
1807 auth ? auth->len : 0);
1808 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1809 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1811 silc_buffer_free(buffer);
1812 silc_buffer_free(auth);
1814 /* Notify application */
1815 COMMAND(SILC_STATUS_OK);
1818 /* SILCOPER command. Used to obtain router operator privileges. */
1820 SILC_CLIENT_CMD_FUNC(silcoper)
1822 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1823 SilcClientConnection conn = cmd->conn;
1826 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1827 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1831 if (cmd->argc < 2) {
1832 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1833 "Usage: /SILCOPER <username> [-pubkey]");
1834 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1838 if (cmd->argc < 3) {
1839 /* Get passphrase */
1840 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1841 silc_client_command_silcoper_send,
1846 silc_client_command_silcoper_send(NULL, 0, context);
1849 silc_client_command_free(cmd);
1852 /* Command BAN. This is used to manage the ban list of the channel. */
1854 SILC_CLIENT_CMD_FUNC(ban)
1856 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1857 SilcClientConnection conn = cmd->conn;
1858 SilcChannelEntry channel;
1859 SilcBuffer buffer, chidp;
1861 char *name, *ban = NULL;
1864 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1865 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1869 if (cmd->argc < 2) {
1870 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1871 "Usage: /BAN <channel> "
1872 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1873 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1877 if (cmd->argv[1][0] == '*') {
1878 if (!conn->current_channel) {
1879 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1883 channel = conn->current_channel;
1885 name = cmd->argv[1];
1887 channel = silc_client_get_channel(cmd->client, conn, name);
1889 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1894 if (cmd->argc == 3) {
1895 if (cmd->argv[2][0] == '+')
1904 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1906 /* Send the command */
1907 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1908 ++conn->cmd_ident, 2,
1909 1, chidp->data, chidp->len,
1910 type, ban, ban ? strlen(ban) : 0);
1911 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1912 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1913 silc_buffer_free(buffer);
1914 silc_buffer_free(chidp);
1916 /* Notify application */
1917 COMMAND(SILC_STATUS_OK);
1920 silc_client_command_free(cmd);
1923 /* Command DETACH. This is used to detach from the server */
1925 SILC_CLIENT_CMD_FUNC(detach)
1927 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1928 SilcClientConnection conn = cmd->conn;
1932 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1933 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1937 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1938 ++conn->cmd_ident, 0);
1939 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1940 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1941 silc_buffer_free(buffer);
1943 /* Notify application */
1944 COMMAND(SILC_STATUS_OK);
1947 silc_client_command_free(cmd);
1950 /* Command WATCH. */
1952 SILC_CLIENT_CMD_FUNC(watch)
1954 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1955 SilcClientConnection conn = cmd->conn;
1956 SilcBuffer buffer, idp = NULL;
1960 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1961 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1965 if (cmd->argc < 3) {
1966 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1970 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1972 if (!strcasecmp(cmd->argv[1], "-add")) {
1974 } else if (!strcasecmp(cmd->argv[1], "-del")) {
1977 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1981 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
1982 ++conn->cmd_ident, 2,
1983 1, idp->data, idp->len,
1986 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1987 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1988 silc_buffer_free(buffer);
1990 /* Notify application */
1991 COMMAND(SILC_STATUS_OK);
1995 silc_buffer_free(idp);
1996 silc_client_command_free(cmd);
1999 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2001 SILC_CLIENT_CMD_FUNC(leave)
2003 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2004 SilcClientConnection conn = cmd->conn;
2005 SilcChannelEntry channel;
2006 SilcChannelUser chu;
2007 SilcBuffer buffer, idp;
2011 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2012 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2016 if (cmd->argc != 2) {
2017 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2018 "Usage: /LEAVE <channel>");
2019 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2023 if (cmd->argv[1][0] == '*') {
2024 if (!conn->current_channel) {
2025 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2028 name = conn->current_channel->channel_name;
2030 name = cmd->argv[1];
2033 /* Get the channel entry */
2034 channel = silc_client_get_channel(cmd->client, conn, name);
2036 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2040 /* Remove us from channel */
2041 chu = silc_client_on_channel(channel, conn->local_entry);
2043 silc_hash_table_del(chu->client->channels, chu->channel);
2044 silc_hash_table_del(chu->channel->user_list, chu->client);
2048 /* Send LEAVE command to the server */
2049 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2050 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2051 1, idp->data, idp->len);
2052 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2053 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2054 silc_buffer_free(buffer);
2055 silc_buffer_free(idp);
2057 /* Notify application */
2058 COMMAND(SILC_STATUS_OK);
2060 if (conn->current_channel == channel)
2061 conn->current_channel = NULL;
2063 silc_client_del_channel(cmd->client, cmd->conn, channel);
2066 silc_client_command_free(cmd);
2069 /* Command USERS. Requests the USERS of the clients joined on requested
2072 SILC_CLIENT_CMD_FUNC(users)
2074 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2075 SilcClientConnection conn = cmd->conn;
2080 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2081 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2085 if (cmd->argc != 2) {
2086 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2087 "Usage: /USERS <channel>");
2088 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2092 if (cmd->argv[1][0] == '*') {
2093 if (!conn->current_channel) {
2094 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2097 name = conn->current_channel->channel_name;
2099 name = cmd->argv[1];
2102 /* Send USERS command to the server */
2103 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2104 ++conn->cmd_ident, 1,
2105 2, name, strlen(name));
2106 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2107 NULL, 0, NULL, NULL, buffer->data,
2109 silc_buffer_free(buffer);
2111 /* Notify application */
2112 COMMAND(SILC_STATUS_OK);
2115 silc_client_command_free(cmd);
2118 /* Command GETKEY. Used to fetch remote client's public key. */
2120 SILC_CLIENT_CMD_FUNC(getkey)
2122 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2123 SilcClientConnection conn = cmd->conn;
2124 SilcClient client = cmd->client;
2125 SilcClientEntry client_entry = NULL;
2126 SilcServerEntry server_entry = NULL;
2127 char *nickname = NULL;
2128 SilcBuffer idp, buffer;
2130 SILC_LOG_DEBUG(("Start"));
2133 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2134 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2138 if (cmd->argc < 2) {
2139 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2140 "Usage: /GETKEY <nickname or server name>");
2141 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2145 /* Parse the typed nickname. */
2146 if (client->internal->params->nickname_parse)
2147 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2149 nickname = strdup(cmd->argv[1]);
2151 /* Find client entry */
2152 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2154 if (!client_entry) {
2155 /* Check whether user requested server actually */
2156 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2158 if (!server_entry) {
2159 /* No. what ever user wants we don't have it, so resolve it. We
2160 will first try to resolve the client, and if that fails then
2161 we'll try to resolve the server. */
2163 if (!cmd->pending) {
2164 /* This will send the IDENTIFY command for nickname */
2165 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2166 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2168 silc_client_command_getkey,
2169 silc_client_command_dup(cmd));
2173 SilcClientCommandReplyContext reply =
2174 (SilcClientCommandReplyContext)context2;
2177 /* If nickname was not found, then resolve the server. */
2178 silc_command_get_status(reply->payload, NULL, &error);
2179 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2180 /* This sends the IDENTIFY command to resolve the server. */
2181 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2183 silc_client_command_reply_identify_i, 0,
2185 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2187 2, cmd->argv[1], cmd->argv_lens[1]);
2188 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2190 silc_client_command_getkey,
2191 silc_client_command_dup(cmd));
2195 /* If server was not found, then we've resolved both nickname and
2196 server and did not find anybody. */
2197 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2198 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2199 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2200 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2201 silc_get_status_message(error));
2202 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2206 COMMAND_ERROR(error);
2211 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2213 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2216 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2217 1, idp->data, idp->len);
2218 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2219 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2220 silc_buffer_free(buffer);
2221 silc_buffer_free(idp);
2223 /* Notify application */
2224 COMMAND(SILC_STATUS_OK);
2227 silc_free(nickname);
2228 silc_client_command_free(cmd);
2231 /* Register a new command indicated by the `command' to the SILC client.
2232 The `name' is optional command name. If provided the command may be
2233 searched using the silc_client_command_find by that name. The
2234 `command_function' is the function to be called when the command is
2235 executed, and the `command_reply_function' is the function to be
2236 called after the server has sent reply back to the command.
2238 The `ident' is optional identifier for the command. If non-zero
2239 the `command_reply_function' for the command type `command' will be
2240 called only if the command reply sent by server includes the
2241 command identifier `ident'. Application usually does not need it
2242 and set it to zero value. */
2244 bool silc_client_command_register(SilcClient client,
2245 SilcCommand command,
2247 SilcCommandCb command_function,
2248 SilcCommandCb command_reply_function,
2252 SilcClientCommand cmd;
2254 cmd = silc_calloc(1, sizeof(*cmd));
2256 cmd->command = command_function;
2257 cmd->reply = command_reply_function;
2258 cmd->name = name ? strdup(name) : NULL;
2259 cmd->max_args = max_args;
2262 silc_list_add(client->internal->commands, cmd);
2267 /* Unregister a command indicated by the `command' with command function
2268 `command_function' and command reply function `command_reply_function'.
2269 Returns TRUE if the command was found and unregistered. */
2271 bool silc_client_command_unregister(SilcClient client,
2272 SilcCommand command,
2273 SilcCommandCb command_function,
2274 SilcCommandCb command_reply_function,
2277 SilcClientCommand cmd;
2279 silc_list_start(client->internal->commands);
2280 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2281 if (cmd->cmd == command && cmd->command == command_function &&
2282 cmd->reply == command_reply_function && cmd->ident == ident) {
2283 silc_list_del(client->internal->commands, cmd);
2284 silc_free(cmd->name);
2293 /* Private range commands, specific to this implementation (and compatible
2294 with SILC Server). */
2296 /* CONNECT command. Connects the server to another server. */
2298 SILC_CLIENT_CMD_FUNC(connect)
2300 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2301 SilcClientConnection conn = cmd->conn;
2303 unsigned char port[4];
2307 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2308 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2312 if (cmd->argc < 2) {
2313 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2314 "Usage: /CONNECT <server> [<port>]");
2315 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2319 if (cmd->argc == 3) {
2320 tmp = atoi(cmd->argv[2]);
2321 SILC_PUT32_MSB(tmp, port);
2325 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2327 strlen(cmd->argv[1]),
2330 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2332 strlen(cmd->argv[1]));
2333 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2334 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2335 silc_buffer_free(buffer);
2337 /* Notify application */
2338 COMMAND(SILC_STATUS_OK);
2341 silc_client_command_free(cmd);
2345 /* CLOSE command. Close server connection to the remote server */
2347 SILC_CLIENT_CMD_FUNC(close)
2349 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2350 SilcClientConnection conn = cmd->conn;
2352 unsigned char port[4];
2356 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2357 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2361 if (cmd->argc < 2) {
2362 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2363 "Usage: /CLOSE <server> [<port>]");
2364 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2368 if (cmd->argc == 3) {
2369 tmp = atoi(cmd->argv[2]);
2370 SILC_PUT32_MSB(tmp, port);
2374 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2376 strlen(cmd->argv[1]),
2379 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2381 strlen(cmd->argv[1]));
2382 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2383 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2384 silc_buffer_free(buffer);
2386 /* Notify application */
2387 COMMAND(SILC_STATUS_OK);
2390 silc_client_command_free(cmd);
2393 /* SHUTDOWN command. Shutdowns the server. */
2395 SILC_CLIENT_CMD_FUNC(shutdown)
2397 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2400 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2405 /* Send the command */
2406 silc_client_command_send(cmd->client, cmd->conn,
2407 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2409 /* Notify application */
2410 COMMAND(SILC_STATUS_OK);
2413 silc_client_command_free(cmd);
2416 /* Register all default commands provided by the client library for the
2419 void silc_client_commands_register(SilcClient client)
2421 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2424 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2425 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2426 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2427 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2428 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2429 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2430 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2431 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2432 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2433 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2434 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2435 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2436 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2437 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2438 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2439 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2440 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2441 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2442 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2443 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2444 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2445 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2446 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2447 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2448 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2450 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2451 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2452 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2455 /* Unregister all commands. */
2457 void silc_client_commands_unregister(SilcClient client)
2459 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2460 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2461 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2462 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2463 SILC_CLIENT_CMDU(list, LIST, "LIST");
2464 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2465 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2466 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2467 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2468 SILC_CLIENT_CMDU(info, INFO, "INFO");
2469 SILC_CLIENT_CMDU(ping, PING, "PING");
2470 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2471 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2472 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2473 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2474 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2475 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2476 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2477 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2478 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2479 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2480 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2481 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2482 SILC_CLIENT_CMDU(users, USERS, "USERS");
2483 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2485 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2486 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2487 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");