5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, use /SERVER to connect");
29 /* Command operation that is called at the end of all commands.
30 Usage: COMMAND(status); */
31 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
32 cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
34 /* Error to application. Usage: COMMAND_ERROR(status); */
35 #define COMMAND_ERROR(status) \
36 cmd->client->internal->ops->command(cmd->client, \
37 cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
39 #define SAY cmd->client->internal->ops->say
41 /* Generic function to send any command. The arguments must be sent already
42 encoded into correct form and in correct order. */
44 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
45 SilcCommand command, SilcUInt16 ident,
53 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
54 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
55 NULL, 0, NULL, NULL, packet->data,
57 silc_buffer_free(packet);
60 /* Finds and returns a pointer to the command list. Return NULL if the
61 command is not found. */
63 SilcClientCommand silc_client_command_find(SilcClient client,
66 SilcClientCommand cmd;
68 silc_list_start(client->internal->commands);
69 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
70 if (cmd->name && !strcmp(cmd->name, name))
77 /* Calls the command (executes it). Application can call this after
78 it has allocated the SilcClientCommandContext with the function
79 silc_client_command_alloc and found the command from the client
80 library by calling silc_client_command_find. This will execute
83 void silc_client_command_call(SilcClientCommand command,
84 SilcClientCommandContext cmd)
86 (*command->command)((void *)cmd, NULL);
89 /* Add new pending command to be executed when reply to a command has been
90 received. The `reply_cmd' is the command that will call the `callback'
91 with `context' when reply has been received. It can be SILC_COMMAND_NONE
92 to match any command with the `ident'. If `ident' is non-zero
93 the `callback' will be executed when received reply with command
94 identifier `ident'. If there already exists pending command for the
95 specified command, ident, callback and context this function has no
98 void silc_client_command_pending(SilcClientConnection conn,
99 SilcCommand reply_cmd,
101 SilcCommandCb callback,
104 SilcClientCommandPending *reply;
106 reply = silc_calloc(1, sizeof(*reply));
107 reply->reply_cmd = reply_cmd;
108 reply->ident = ident;
109 reply->context = context;
110 reply->callback = callback;
111 silc_dlist_add(conn->pending_commands, reply);
114 /* Deletes pending command by reply command type. */
116 void silc_client_command_pending_del(SilcClientConnection conn,
117 SilcCommand reply_cmd,
120 SilcClientCommandPending *r;
122 if (!conn->pending_commands)
125 silc_dlist_start(conn->pending_commands);
126 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
127 if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
129 && r->ident == ident) {
130 silc_dlist_del(conn->pending_commands, r);
136 /* Checks for pending commands and marks callbacks to be called from
137 the command reply function. */
139 SilcClientCommandPendingCallbacks
140 silc_client_command_pending_check(SilcClientConnection conn,
141 SilcClientCommandReplyContext ctx,
144 SilcUInt32 *callbacks_count)
146 SilcClientCommandPending *r;
147 SilcClientCommandPendingCallbacks callbacks = NULL;
150 silc_dlist_start(conn->pending_commands);
151 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
152 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
153 && r->ident == ident) {
154 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
155 callbacks[i].context = r->context;
156 callbacks[i].callback = r->callback;
157 r->reply_check = TRUE;
163 *callbacks_count = i;
167 /* Allocate Command Context */
169 SilcClientCommandContext silc_client_command_alloc(void)
171 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
176 /* Free command context and its internals */
178 void silc_client_command_free(SilcClientCommandContext ctx)
181 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
183 if (ctx->users < 1) {
186 for (i = 0; i < ctx->argc; i++)
187 silc_free(ctx->argv[i]);
188 silc_free(ctx->argv_lens);
189 silc_free(ctx->argv_types);
194 /* Duplicate Command Context by adding reference counter. The context won't
195 be free'd untill it hits zero. */
197 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
200 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
205 /* Command WHOIS. This command is used to query information about
208 SILC_CLIENT_CMD_FUNC(whois)
210 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
211 SilcClientConnection conn = cmd->conn;
213 unsigned char count[4];
216 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
217 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
221 /* Given without arguments fetches client's own information */
223 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
224 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
226 1, 4, buffer->data, buffer->len);
227 silc_buffer_free(buffer);
231 if (cmd->argc == 2) {
232 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
233 ++conn->cmd_ident, 1,
237 int c = atoi(cmd->argv[2]);
238 memset(count, 0, sizeof(count));
239 SILC_PUT32_MSB(c, count);
240 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
241 ++conn->cmd_ident, 2,
242 1, cmd->argv[1], cmd->argv_lens[1],
243 2, count, sizeof(count));
245 silc_client_packet_send(cmd->client, cmd->conn->sock,
246 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
247 buffer->data, buffer->len, TRUE);
248 silc_buffer_free(buffer);
250 /* Notify application */
251 COMMAND(SILC_STATUS_OK);
254 silc_client_command_free(cmd);
257 /* Command WHOWAS. This command is used to query history information about
258 specific user that used to exist in the network. */
260 SILC_CLIENT_CMD_FUNC(whowas)
262 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
263 SilcClientConnection conn = cmd->conn;
265 unsigned char count[4];
268 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
269 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
273 if (cmd->argc < 2 || cmd->argc > 3) {
274 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
275 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
276 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
277 SILC_STATUS_ERR_TOO_MANY_PARAMS));
281 if (cmd->argc == 2) {
282 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
283 ++conn->cmd_ident, 1,
287 int c = atoi(cmd->argv[2]);
288 memset(count, 0, sizeof(count));
289 SILC_PUT32_MSB(c, count);
290 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
291 ++conn->cmd_ident, 2,
292 1, cmd->argv[1], cmd->argv_lens[1],
293 2, count, sizeof(count));
295 silc_client_packet_send(cmd->client, cmd->conn->sock,
296 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
297 buffer->data, buffer->len, TRUE);
298 silc_buffer_free(buffer);
300 /* Notify application */
301 COMMAND(SILC_STATUS_OK);
304 silc_client_command_free(cmd);
307 /* Command IDENTIFY. This command is used to query information about
308 specific user, especially ID's.
310 NOTE: This command is used only internally by the client library
311 and application MUST NOT call this command directly. */
313 SILC_CLIENT_CMD_FUNC(identify)
315 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
316 SilcClientConnection conn = cmd->conn;
318 unsigned char count[4];
321 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
322 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
326 if (cmd->argc < 2 || cmd->argc > 3)
329 if (cmd->argc == 2) {
330 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
331 ++conn->cmd_ident, 1,
335 int c = atoi(cmd->argv[2]);
336 memset(count, 0, sizeof(count));
337 SILC_PUT32_MSB(c, count);
338 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
339 ++conn->cmd_ident, 2,
342 4, count, sizeof(count));
345 silc_client_packet_send(cmd->client, cmd->conn->sock,
346 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
347 buffer->data, buffer->len, TRUE);
348 silc_buffer_free(buffer);
351 silc_client_command_free(cmd);
354 /* Command NICK. Shows current nickname/sets new nickname on current
357 SILC_CLIENT_CMD_FUNC(nick)
359 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
360 SilcClientConnection conn = cmd->conn;
364 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
365 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
370 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
371 "Usage: /NICK <nickname>");
372 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
376 if (!strcmp(conn->nickname, cmd->argv[1]))
379 /* Show current nickname */
382 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
383 "Your nickname is %s on server %s",
384 conn->nickname, conn->remote_host);
386 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
387 "Your nickname is %s", conn->nickname);
390 COMMAND(SILC_STATUS_OK);
394 if (cmd->argv_lens[1] > 128)
395 cmd->argv_lens[1] = 128;
397 /* Send the NICK command */
398 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
402 ++cmd->conn->cmd_ident);
403 silc_client_packet_send(cmd->client, cmd->conn->sock,
404 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
405 buffer->data, buffer->len, TRUE);
406 silc_buffer_free(buffer);
409 silc_client_command_free(cmd);
412 /* Command LIST. Lists channels on the current server. */
414 SILC_CLIENT_CMD_FUNC(list)
416 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
417 SilcClientConnection conn = cmd->conn;
418 SilcIDCacheEntry id_cache = NULL;
419 SilcChannelEntry channel;
420 SilcBuffer buffer, idp = NULL;
424 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
425 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
429 if (cmd->argc == 2) {
432 /* Get the Channel ID of the channel */
433 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
434 channel = (SilcChannelEntry)id_cache->context;
435 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
440 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
441 ++conn->cmd_ident, 0);
443 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
444 ++conn->cmd_ident, 1,
445 1, idp->data, idp->len);
447 silc_client_packet_send(cmd->client, cmd->conn->sock,
448 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
449 buffer->data, buffer->len, TRUE);
450 silc_buffer_free(buffer);
452 silc_buffer_free(idp);
454 /* Notify application */
455 COMMAND(SILC_STATUS_OK);
458 silc_client_command_free(cmd);
461 /* Command TOPIC. Sets/shows topic on a channel. */
463 SILC_CLIENT_CMD_FUNC(topic)
465 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
466 SilcClientConnection conn = cmd->conn;
467 SilcIDCacheEntry id_cache = NULL;
468 SilcChannelEntry channel;
469 SilcBuffer buffer, idp;
473 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
474 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
478 if (cmd->argc < 2 || cmd->argc > 3) {
479 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
480 "Usage: /TOPIC <channel> [<topic>]");
481 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
482 SILC_STATUS_ERR_TOO_MANY_PARAMS));
486 if (cmd->argv[1][0] == '*') {
487 if (!conn->current_channel) {
488 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
491 name = conn->current_channel->channel_name;
496 if (!conn->current_channel) {
497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
501 /* Get the Channel ID of the channel */
502 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
503 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
507 channel = (SilcChannelEntry)id_cache->context;
509 /* Send TOPIC command to the server */
510 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
512 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
513 ++conn->cmd_ident, 2,
514 1, idp->data, idp->len,
516 strlen(cmd->argv[2]));
518 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
519 ++conn->cmd_ident, 1,
520 1, idp->data, idp->len);
521 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
522 0, NULL, NULL, buffer->data, buffer->len, TRUE);
523 silc_buffer_free(buffer);
524 silc_buffer_free(idp);
526 /* Notify application */
527 COMMAND(SILC_STATUS_OK);
530 silc_client_command_free(cmd);
533 /* Command INVITE. Invites specific client to join a channel. This is
534 also used to mange the invite list of the channel. */
536 SILC_CLIENT_CMD_FUNC(invite)
538 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
539 SilcClient client = cmd->client;
540 SilcClientConnection conn = cmd->conn;
541 SilcClientEntry client_entry = NULL;
542 SilcChannelEntry channel;
543 SilcBuffer buffer, clidp, chidp;
545 char *nickname = NULL, *name;
549 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
550 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
555 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
556 "Usage: /INVITE <channel> [<nickname>[@server>]"
557 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
558 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
562 if (cmd->argv[1][0] == '*') {
563 if (!conn->current_channel) {
564 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
568 channel = conn->current_channel;
572 channel = silc_client_get_channel(cmd->client, conn, name);
574 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
579 /* Parse the typed nickname. */
580 if (cmd->argc == 3) {
581 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
582 if (client->internal->params->nickname_parse)
583 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
585 nickname = strdup(cmd->argv[2]);
587 /* Find client entry */
588 client_entry = silc_idlist_get_client(client, conn, nickname,
592 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
596 /* Client entry not found, it was requested thus mark this to be
598 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
600 silc_client_command_invite,
601 silc_client_command_dup(cmd));
606 invite = cmd->argv[2];
608 if (cmd->argv[2][0] == '+')
615 /* Send the command */
616 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
618 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
619 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
620 ++conn->cmd_ident, 3,
621 1, chidp->data, chidp->len,
622 2, clidp->data, clidp->len,
623 type, invite, invite ?
625 silc_buffer_free(clidp);
627 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
628 ++conn->cmd_ident, 2,
629 1, chidp->data, chidp->len,
630 type, invite, invite ?
634 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
635 0, NULL, NULL, buffer->data, buffer->len, TRUE);
636 silc_buffer_free(buffer);
637 silc_buffer_free(chidp);
639 /* Notify application */
640 COMMAND(SILC_STATUS_OK);
644 silc_client_command_free(cmd);
649 SilcClientConnection conn;
652 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
654 QuitInternal q = (QuitInternal)context;
656 /* Close connection */
657 q->client->internal->ops->disconnect(q->client, q->conn, 0, NULL);
658 silc_client_close_connection(q->client, q->conn->sock->user_data);
663 /* Command QUIT. Closes connection with current server. */
665 SILC_CLIENT_CMD_FUNC(quit)
667 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
672 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
673 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
678 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
679 &cmd->argv[1], &cmd->argv_lens[1],
680 &cmd->argv_types[1], 0);
682 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
683 NULL, NULL, NULL, 0);
684 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
686 buffer->data, buffer->len, TRUE);
687 silc_buffer_free(buffer);
689 q = silc_calloc(1, sizeof(*q));
690 q->client = cmd->client;
693 /* Sleep for a while */
696 /* We quit the connection with little timeout */
697 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
698 silc_client_command_quit_cb, (void *)q,
699 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
701 /* Notify application */
702 COMMAND(SILC_STATUS_OK);
705 silc_client_command_free(cmd);
708 /* Timeout callback to remove the killed client from cache */
710 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
712 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
713 SilcClient client = cmd->client;
714 SilcClientConnection conn = cmd->conn;
715 SilcClientEntry target;
716 char *nickname = NULL;
718 /* Parse the typed nickname. */
719 if (client->internal->params->nickname_parse)
720 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
722 nickname = strdup(cmd->argv[1]);
724 /* Get the target client */
725 target = silc_idlist_get_client(cmd->client, conn, nickname,
726 cmd->argv[1], FALSE);
728 /* Remove the client from all channels and free it */
729 silc_client_del_client(client, conn, target);
732 silc_client_command_free(cmd);
735 /* Kill command's pending command callback to actually remove the killed
736 client from our local cache. */
738 SILC_CLIENT_CMD_FUNC(kill_remove)
740 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
741 SilcClientCommandReplyContext reply =
742 (SilcClientCommandReplyContext)context2;
745 silc_command_get_status(reply->payload, &status, NULL);
746 if (status == SILC_STATUS_OK) {
747 /* Remove with timeout */
748 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
749 silc_client_command_kill_remove_later, context,
750 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
754 silc_client_command_free(cmd);
757 /* Command KILL. Router operator can use this command to remove an client
758 fromthe SILC Network. */
760 SILC_CLIENT_CMD_FUNC(kill)
762 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
763 SilcClient client = cmd->client;
764 SilcClientConnection conn = cmd->conn;
765 SilcBuffer buffer, idp;
766 SilcClientEntry target;
767 char *nickname = NULL;
770 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
771 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
776 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
777 "Usage: /KILL <nickname> [<comment>]");
778 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
782 /* Parse the typed nickname. */
783 if (client->internal->params->nickname_parse)
784 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
786 nickname = strdup(cmd->argv[1]);
788 /* Get the target client */
789 target = silc_idlist_get_client(cmd->client, conn, nickname,
793 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
797 /* Client entry not found, it was requested thus mark this to be
799 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
801 silc_client_command_kill,
802 silc_client_command_dup(cmd));
807 /* Send the KILL command to the server */
808 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
810 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
811 ++conn->cmd_ident, 1,
812 1, idp->data, idp->len);
814 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
815 ++conn->cmd_ident, 2,
816 1, idp->data, idp->len,
818 strlen(cmd->argv[2]));
819 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
820 0, NULL, NULL, buffer->data, buffer->len, TRUE);
821 silc_buffer_free(buffer);
822 silc_buffer_free(idp);
824 /* Notify application */
825 COMMAND(SILC_STATUS_OK);
827 /* Register a pending callback that will actually remove the killed
828 client from our cache. */
829 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
830 silc_client_command_kill_remove,
831 silc_client_command_dup(cmd));
835 silc_client_command_free(cmd);
838 /* Command INFO. Request information about specific server. If specific
839 server is not provided the current server is used. */
841 SILC_CLIENT_CMD_FUNC(info)
843 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
844 SilcClientConnection conn = cmd->conn;
849 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
850 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
855 name = strdup(cmd->argv[1]);
857 /* Send the command */
859 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
860 1, name, strlen(name));
862 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
863 NULL, NULL, NULL, 0);
864 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
865 0, NULL, NULL, buffer->data, buffer->len, TRUE);
866 silc_buffer_free(buffer);
870 /* Notify application */
871 COMMAND(SILC_STATUS_OK);
874 silc_client_command_free(cmd);
877 /* Command PING. Sends ping to server. This is used to test the
878 communication channel. */
880 SILC_CLIENT_CMD_FUNC(ping)
882 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
883 SilcClientConnection conn = cmd->conn;
889 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
890 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
894 /* Send the command */
895 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
896 1, conn->remote_id_data,
897 silc_id_get_len(conn->remote_id,
899 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
900 0, NULL, NULL, buffer->data, buffer->len, TRUE);
901 silc_buffer_free(buffer);
903 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
906 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
907 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
911 /* Start counting time */
912 for (i = 0; i < conn->ping_count; i++) {
913 if (conn->ping[i].dest_id == NULL) {
914 conn->ping[i].start_time = time(NULL);
915 conn->ping[i].dest_id = id;
916 conn->ping[i].dest_name = strdup(conn->remote_host);
920 if (i >= conn->ping_count) {
921 i = conn->ping_count;
922 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
923 conn->ping[i].start_time = time(NULL);
924 conn->ping[i].dest_id = id;
925 conn->ping[i].dest_name = strdup(conn->remote_host);
929 /* Notify application */
930 COMMAND(SILC_STATUS_OK);
933 silc_client_command_free(cmd);
936 /* Command JOIN. Joins to a channel. */
938 SILC_CLIENT_CMD_FUNC(join)
940 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
941 SilcClientConnection conn = cmd->conn;
942 SilcChannelEntry channel;
943 SilcBuffer buffer, idp, auth = NULL;
944 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
945 int i, passphrase_len = 0;
948 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
949 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
954 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
958 /* See if we have joined to the requested channel already */
959 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
960 if (channel && silc_client_on_channel(channel, conn->local_entry))
963 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
965 if (cmd->argv_lens[1] > 256)
966 cmd->argv_lens[1] = 256;
970 for (i = 2; i < cmd->argc; i++) {
971 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
972 cipher = cmd->argv[i + 1];
974 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
975 hmac = cmd->argv[i + 1];
977 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
978 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
979 cmd->client->private_key,
981 cmd->client->internal->
987 /* Passphrases must be UTF-8 encoded, so encode if it is not */
988 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
989 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
990 cmd->argv_lens[i], 0);
991 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
992 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
993 0, pu8, passphrase_len);
996 passphrase = strdup(cmd->argv[i]);
997 passphrase_len = cmd->argv_lens[i];
1002 /* Send JOIN command to the server */
1004 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1005 1, name, strlen(name),
1006 2, idp->data, idp->len,
1007 3, passphrase, passphrase_len,
1008 4, cipher, cipher ? strlen(cipher) : 0,
1009 5, hmac, hmac ? strlen(hmac) : 0,
1010 6, auth ? auth->data : NULL,
1011 auth ? auth->len : 0);
1012 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1013 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1014 silc_buffer_free(buffer);
1015 silc_buffer_free(idp);
1017 silc_buffer_free(auth);
1018 silc_free(passphrase);
1020 /* Notify application */
1021 COMMAND(SILC_STATUS_OK);
1024 silc_client_command_free(cmd);
1027 /* MOTD command. Requests motd from server. */
1029 SILC_CLIENT_CMD_FUNC(motd)
1031 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1032 SilcClientConnection conn = cmd->conn;
1036 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1037 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1041 if (cmd->argc < 1 || cmd->argc > 2) {
1042 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1043 "Usage: /MOTD [<server>]");
1044 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1045 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1049 /* Send TOPIC command to the server */
1051 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1052 1, conn->remote_host,
1053 strlen(conn->remote_host));
1055 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1058 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1059 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1060 silc_buffer_free(buffer);
1062 /* Notify application */
1063 COMMAND(SILC_STATUS_OK);
1066 silc_client_command_free(cmd);
1069 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1070 modes as client cannot set itself server/router operator privileges. */
1072 SILC_CLIENT_CMD_FUNC(umode)
1074 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1075 SilcClientConnection conn = cmd->conn;
1076 SilcBuffer buffer, idp;
1077 unsigned char *cp, modebuf[4];
1078 SilcUInt32 mode, add, len;
1082 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1083 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1087 if (cmd->argc < 2) {
1088 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1089 "Usage: /UMODE +|-<modes>");
1090 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1094 mode = conn->local_entry->mode;
1096 /* Are we adding or removing mode */
1097 if (cmd->argv[1][0] == '-')
1103 cp = cmd->argv[1] + 1;
1105 for (i = 0; i < len; i++) {
1110 mode |= SILC_UMODE_SERVER_OPERATOR;
1111 mode |= SILC_UMODE_ROUTER_OPERATOR;
1112 mode |= SILC_UMODE_GONE;
1113 mode |= SILC_UMODE_INDISPOSED;
1114 mode |= SILC_UMODE_BUSY;
1115 mode |= SILC_UMODE_PAGE;
1116 mode |= SILC_UMODE_HYPER;
1117 mode |= SILC_UMODE_ROBOT;
1118 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1119 mode |= SILC_UMODE_REJECT_WATCHING;
1121 mode = SILC_UMODE_NONE;
1126 mode |= SILC_UMODE_SERVER_OPERATOR;
1128 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1132 mode |= SILC_UMODE_ROUTER_OPERATOR;
1134 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1138 mode |= SILC_UMODE_GONE;
1140 mode &= ~SILC_UMODE_GONE;
1144 mode |= SILC_UMODE_INDISPOSED;
1146 mode &= ~SILC_UMODE_INDISPOSED;
1150 mode |= SILC_UMODE_BUSY;
1152 mode &= ~SILC_UMODE_BUSY;
1156 mode |= SILC_UMODE_PAGE;
1158 mode &= ~SILC_UMODE_PAGE;
1162 mode |= SILC_UMODE_HYPER;
1164 mode &= ~SILC_UMODE_HYPER;
1168 mode |= SILC_UMODE_ROBOT;
1170 mode &= ~SILC_UMODE_ROBOT;
1174 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1176 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1180 mode |= SILC_UMODE_REJECT_WATCHING;
1182 mode &= ~SILC_UMODE_REJECT_WATCHING;
1186 mode |= SILC_UMODE_BLOCK_INVITE;
1188 mode &= ~SILC_UMODE_BLOCK_INVITE;
1191 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1197 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1198 SILC_PUT32_MSB(mode, modebuf);
1200 /* Send the command packet. We support sending only one mode at once
1201 that requires an argument. */
1203 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1204 1, idp->data, idp->len,
1205 2, modebuf, sizeof(modebuf));
1206 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1207 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1208 silc_buffer_free(buffer);
1209 silc_buffer_free(idp);
1211 /* Notify application */
1212 COMMAND(SILC_STATUS_OK);
1215 silc_client_command_free(cmd);
1218 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1219 can be set several at once. Those modes that require argument must be set
1220 separately (unless set with modes that does not require arguments). */
1222 SILC_CLIENT_CMD_FUNC(cmode)
1224 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1225 SilcClientConnection conn = cmd->conn;
1226 SilcChannelEntry channel;
1227 SilcBuffer buffer, chidp, auth = NULL;
1228 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1229 SilcUInt32 mode, add, type, len, arg_len = 0;
1233 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1234 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1238 if (cmd->argc < 3) {
1239 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1240 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1241 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1245 if (cmd->argv[1][0] == '*') {
1246 if (!conn->current_channel) {
1247 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1251 channel = conn->current_channel;
1253 name = cmd->argv[1];
1255 channel = silc_client_get_channel(cmd->client, conn, name);
1257 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1262 mode = channel->mode;
1264 /* Are we adding or removing mode */
1265 if (cmd->argv[2][0] == '-')
1270 /* Argument type to be sent to server */
1274 cp = cmd->argv[2] + 1;
1276 for (i = 0; i < len; i++) {
1280 mode |= SILC_CHANNEL_MODE_PRIVATE;
1282 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1286 mode |= SILC_CHANNEL_MODE_SECRET;
1288 mode &= ~SILC_CHANNEL_MODE_SECRET;
1292 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1294 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1298 mode |= SILC_CHANNEL_MODE_INVITE;
1300 mode &= ~SILC_CHANNEL_MODE_INVITE;
1304 mode |= SILC_CHANNEL_MODE_TOPIC;
1306 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1310 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1312 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1316 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1318 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1323 mode |= SILC_CHANNEL_MODE_ULIMIT;
1325 if (cmd->argc < 4) {
1326 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1327 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1328 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1331 ll = atoi(cmd->argv[3]);
1332 SILC_PUT32_MSB(ll, tmp);
1336 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1341 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1343 if (cmd->argc < 4) {
1344 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1345 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1346 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1350 arg_len = cmd->argv_lens[3];
1352 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1357 mode |= SILC_CHANNEL_MODE_CIPHER;
1359 if (cmd->argc < 4) {
1360 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1361 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1362 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1366 arg_len = cmd->argv_lens[3];
1368 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1373 mode |= SILC_CHANNEL_MODE_HMAC;
1375 if (cmd->argc < 4) {
1376 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1377 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1378 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1382 arg_len = cmd->argv_lens[3];
1384 mode &= ~SILC_CHANNEL_MODE_HMAC;
1389 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1391 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1392 cmd->client->private_key,
1394 cmd->client->internal->
1399 arg_len = auth->len;
1401 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1405 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1411 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1412 SILC_PUT32_MSB(mode, modebuf);
1414 /* Send the command packet. We support sending only one mode at once
1415 that requires an argument. */
1418 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1419 1, chidp->data, chidp->len,
1420 2, modebuf, sizeof(modebuf),
1421 type, arg, arg_len);
1424 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1425 1, chidp->data, chidp->len,
1426 2, modebuf, sizeof(modebuf));
1429 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1430 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1431 silc_buffer_free(buffer);
1432 silc_buffer_free(chidp);
1434 silc_buffer_free(auth);
1436 /* Notify application */
1437 COMMAND(SILC_STATUS_OK);
1440 silc_client_command_free(cmd);
1443 /* CUMODE command. Changes client's mode on a channel. */
1445 SILC_CLIENT_CMD_FUNC(cumode)
1447 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1448 SilcClient client = cmd->client;
1449 SilcClientConnection conn = cmd->conn;
1450 SilcChannelEntry channel;
1451 SilcChannelUser chu;
1452 SilcClientEntry client_entry;
1453 SilcBuffer buffer, clidp, chidp, auth = NULL;
1454 unsigned char *name, *cp, modebuf[4];
1455 SilcUInt32 mode = 0, add, len;
1456 char *nickname = NULL;
1460 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1461 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1465 if (cmd->argc < 4) {
1466 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1467 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1468 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1472 if (cmd->argv[1][0] == '*') {
1473 if (!conn->current_channel) {
1474 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1478 channel = conn->current_channel;
1480 name = cmd->argv[1];
1482 channel = silc_client_get_channel(cmd->client, conn, name);
1484 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1489 /* Parse the typed nickname. */
1490 if (client->internal->params->nickname_parse)
1491 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1493 nickname = strdup(cmd->argv[3]);
1495 /* Find client entry */
1496 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1497 cmd->argv[3], TRUE);
1498 if (!client_entry) {
1500 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1504 /* Client entry not found, it was requested thus mark this to be
1506 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1508 silc_client_command_cumode,
1509 silc_client_command_dup(cmd));
1514 /* Get the current mode */
1515 chu = silc_client_on_channel(channel, client_entry);
1519 /* Are we adding or removing mode */
1520 if (cmd->argv[2][0] == '-')
1526 cp = cmd->argv[2] + 1;
1528 for (i = 0; i < len; i++) {
1532 mode |= SILC_CHANNEL_UMODE_CHANFO;
1533 mode |= SILC_CHANNEL_UMODE_CHANOP;
1534 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1535 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1536 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1538 mode = SILC_CHANNEL_UMODE_NONE;
1543 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1544 cmd->client->private_key,
1546 cmd->client->internal->
1550 mode |= SILC_CHANNEL_UMODE_CHANFO;
1552 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1557 mode |= SILC_CHANNEL_UMODE_CHANOP;
1559 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1563 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1565 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1569 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1571 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1575 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1577 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1581 mode |= SILC_CHANNEL_UMODE_QUIET;
1583 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1586 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1592 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1593 SILC_PUT32_MSB(mode, modebuf);
1594 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1596 /* Send the command packet. We support sending only one mode at once
1597 that requires an argument. */
1598 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1600 1, chidp->data, chidp->len,
1602 3, clidp->data, clidp->len,
1603 4, auth ? auth->data : NULL,
1604 auth ? auth->len : 0);
1606 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1607 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1608 silc_buffer_free(buffer);
1609 silc_buffer_free(chidp);
1610 silc_buffer_free(clidp);
1612 silc_buffer_free(auth);
1614 /* Notify application */
1615 COMMAND(SILC_STATUS_OK);
1618 silc_free(nickname);
1619 silc_client_command_free(cmd);
1622 /* KICK command. Kicks a client out of channel. */
1624 SILC_CLIENT_CMD_FUNC(kick)
1626 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1627 SilcClient client = cmd->client;
1628 SilcClientConnection conn = cmd->conn;
1629 SilcIDCacheEntry id_cache = NULL;
1630 SilcChannelEntry channel;
1631 SilcBuffer buffer, idp, idp2;
1632 SilcClientEntry target;
1634 char *nickname = NULL;
1637 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1638 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1642 if (cmd->argc < 3) {
1643 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1644 "Usage: /KICK <channel> <nickname> [<comment>]");
1645 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1649 if (cmd->argv[1][0] == '*') {
1650 if (!conn->current_channel) {
1651 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1654 name = conn->current_channel->channel_name;
1656 name = cmd->argv[1];
1659 if (!conn->current_channel) {
1660 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1664 /* Get the Channel ID of the channel */
1665 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1666 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1670 channel = (SilcChannelEntry)id_cache->context;
1672 /* Parse the typed nickname. */
1673 if (client->internal->params->nickname_parse)
1674 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1676 nickname = strdup(cmd->argv[2]);
1678 /* Get the target client */
1679 target = silc_idlist_get_client(cmd->client, conn, nickname,
1680 cmd->argv[2], FALSE);
1682 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1683 "No such client: %s", cmd->argv[2]);
1684 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1688 /* Send KICK command to the server */
1689 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1690 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1692 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1693 1, idp->data, idp->len,
1694 2, idp2->data, idp2->len);
1696 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1697 1, idp->data, idp->len,
1698 2, idp2->data, idp2->len,
1700 strlen(cmd->argv[3]));
1701 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1702 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1703 silc_buffer_free(buffer);
1704 silc_buffer_free(idp);
1705 silc_buffer_free(idp2);
1707 /* Notify application */
1708 COMMAND(SILC_STATUS_OK);
1711 silc_free(nickname);
1712 silc_client_command_free(cmd);
1715 static void silc_client_command_oper_send(unsigned char *data,
1716 SilcUInt32 data_len, void *context)
1718 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1719 SilcClientConnection conn = cmd->conn;
1720 SilcBuffer buffer, auth;
1722 if (cmd->argc >= 3) {
1723 /* Encode the public key authentication payload */
1724 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1725 cmd->client->private_key,
1726 cmd->client->rng, conn->hash,
1730 /* Encode the password authentication payload */
1731 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1735 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1737 strlen(cmd->argv[1]),
1738 2, auth ? auth->data : NULL,
1739 auth ? auth->len : 0);
1740 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1741 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1743 silc_buffer_free(buffer);
1744 silc_buffer_free(auth);
1746 /* Notify application */
1747 COMMAND(SILC_STATUS_OK);
1750 /* OPER command. Used to obtain server operator privileges. */
1752 SILC_CLIENT_CMD_FUNC(oper)
1754 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1755 SilcClientConnection conn = cmd->conn;
1758 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1759 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1763 if (cmd->argc < 2) {
1764 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1765 "Usage: /OPER <username> [-pubkey]");
1766 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1770 if (cmd->argc < 3) {
1771 /* Get passphrase */
1772 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1773 silc_client_command_oper_send,
1778 silc_client_command_oper_send(NULL, 0, context);
1781 silc_client_command_free(cmd);
1784 static void silc_client_command_silcoper_send(unsigned char *data,
1785 SilcUInt32 data_len,
1788 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1789 SilcClientConnection conn = cmd->conn;
1790 SilcBuffer buffer, auth;
1792 if (cmd->argc >= 3) {
1793 /* Encode the public key authentication payload */
1794 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1795 cmd->client->private_key,
1796 cmd->client->rng, conn->hash,
1800 /* Encode the password authentication payload */
1801 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1805 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1807 strlen(cmd->argv[1]),
1808 2, auth ? auth->data : NULL,
1809 auth ? auth->len : 0);
1810 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1811 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1813 silc_buffer_free(buffer);
1814 silc_buffer_free(auth);
1816 /* Notify application */
1817 COMMAND(SILC_STATUS_OK);
1820 /* SILCOPER command. Used to obtain router operator privileges. */
1822 SILC_CLIENT_CMD_FUNC(silcoper)
1824 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1825 SilcClientConnection conn = cmd->conn;
1828 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1829 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1833 if (cmd->argc < 2) {
1834 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1835 "Usage: /SILCOPER <username> [-pubkey]");
1836 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1840 if (cmd->argc < 3) {
1841 /* Get passphrase */
1842 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1843 silc_client_command_silcoper_send,
1848 silc_client_command_silcoper_send(NULL, 0, context);
1851 silc_client_command_free(cmd);
1854 /* Command BAN. This is used to manage the ban list of the channel. */
1856 SILC_CLIENT_CMD_FUNC(ban)
1858 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1859 SilcClientConnection conn = cmd->conn;
1860 SilcChannelEntry channel;
1861 SilcBuffer buffer, chidp;
1863 char *name, *ban = NULL;
1866 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1867 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1871 if (cmd->argc < 2) {
1872 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1873 "Usage: /BAN <channel> "
1874 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1875 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1879 if (cmd->argv[1][0] == '*') {
1880 if (!conn->current_channel) {
1881 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1885 channel = conn->current_channel;
1887 name = cmd->argv[1];
1889 channel = silc_client_get_channel(cmd->client, conn, name);
1891 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1896 if (cmd->argc == 3) {
1897 if (cmd->argv[2][0] == '+')
1906 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1908 /* Send the command */
1909 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1910 ++conn->cmd_ident, 2,
1911 1, chidp->data, chidp->len,
1912 type, ban, ban ? strlen(ban) : 0);
1913 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1914 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1915 silc_buffer_free(buffer);
1916 silc_buffer_free(chidp);
1918 /* Notify application */
1919 COMMAND(SILC_STATUS_OK);
1922 silc_client_command_free(cmd);
1925 /* Command DETACH. This is used to detach from the server */
1927 SILC_CLIENT_CMD_FUNC(detach)
1929 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1930 SilcClientConnection conn = cmd->conn;
1934 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1935 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1939 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1940 ++conn->cmd_ident, 0);
1941 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1942 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1943 silc_buffer_free(buffer);
1945 /* Notify application */
1946 COMMAND(SILC_STATUS_OK);
1949 silc_client_command_free(cmd);
1952 /* Command WATCH. */
1954 SILC_CLIENT_CMD_FUNC(watch)
1956 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1957 SilcClientConnection conn = cmd->conn;
1958 SilcBuffer buffer, idp = NULL;
1962 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1963 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1967 if (cmd->argc < 3) {
1968 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1972 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1974 if (!strcasecmp(cmd->argv[1], "-add")) {
1976 } else if (!strcasecmp(cmd->argv[1], "-del")) {
1979 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1983 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
1984 ++conn->cmd_ident, 2,
1985 1, idp->data, idp->len,
1988 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1989 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1990 silc_buffer_free(buffer);
1992 /* Notify application */
1993 COMMAND(SILC_STATUS_OK);
1997 silc_buffer_free(idp);
1998 silc_client_command_free(cmd);
2001 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2003 SILC_CLIENT_CMD_FUNC(leave)
2005 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2006 SilcClientConnection conn = cmd->conn;
2007 SilcChannelEntry channel;
2008 SilcChannelUser chu;
2009 SilcBuffer buffer, idp;
2013 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2014 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2018 if (cmd->argc != 2) {
2019 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2020 "Usage: /LEAVE <channel>");
2021 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2025 if (cmd->argv[1][0] == '*') {
2026 if (!conn->current_channel) {
2027 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2030 name = conn->current_channel->channel_name;
2032 name = cmd->argv[1];
2035 /* Get the channel entry */
2036 channel = silc_client_get_channel(cmd->client, conn, name);
2038 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2042 /* Remove us from channel */
2043 chu = silc_client_on_channel(channel, conn->local_entry);
2045 silc_hash_table_del(chu->client->channels, chu->channel);
2046 silc_hash_table_del(chu->channel->user_list, chu->client);
2050 /* Send LEAVE command to the server */
2051 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2052 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2053 1, idp->data, idp->len);
2054 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2055 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2056 silc_buffer_free(buffer);
2057 silc_buffer_free(idp);
2059 /* Notify application */
2060 COMMAND(SILC_STATUS_OK);
2062 if (conn->current_channel == channel)
2063 conn->current_channel = NULL;
2065 silc_client_del_channel(cmd->client, cmd->conn, channel);
2068 silc_client_command_free(cmd);
2071 /* Command USERS. Requests the USERS of the clients joined on requested
2074 SILC_CLIENT_CMD_FUNC(users)
2076 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2077 SilcClientConnection conn = cmd->conn;
2082 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2083 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2087 if (cmd->argc != 2) {
2088 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2089 "Usage: /USERS <channel>");
2090 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2094 if (cmd->argv[1][0] == '*') {
2095 if (!conn->current_channel) {
2096 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2099 name = conn->current_channel->channel_name;
2101 name = cmd->argv[1];
2104 /* Send USERS command to the server */
2105 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2106 ++conn->cmd_ident, 1,
2107 2, name, strlen(name));
2108 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2109 NULL, 0, NULL, NULL, buffer->data,
2111 silc_buffer_free(buffer);
2113 /* Notify application */
2114 COMMAND(SILC_STATUS_OK);
2117 silc_client_command_free(cmd);
2120 /* Command GETKEY. Used to fetch remote client's public key. */
2122 SILC_CLIENT_CMD_FUNC(getkey)
2124 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2125 SilcClientConnection conn = cmd->conn;
2126 SilcClient client = cmd->client;
2127 SilcClientEntry client_entry = NULL;
2128 SilcServerEntry server_entry = NULL;
2129 char *nickname = NULL;
2130 SilcBuffer idp, buffer;
2132 SILC_LOG_DEBUG(("Start"));
2135 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2136 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2140 if (cmd->argc < 2) {
2141 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2142 "Usage: /GETKEY <nickname or server name>");
2143 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2147 /* Parse the typed nickname. */
2148 if (client->internal->params->nickname_parse)
2149 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2151 nickname = strdup(cmd->argv[1]);
2153 /* Find client entry */
2154 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2156 if (!client_entry) {
2157 /* Check whether user requested server actually */
2158 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2160 if (!server_entry) {
2161 /* No. what ever user wants we don't have it, so resolve it. We
2162 will first try to resolve the client, and if that fails then
2163 we'll try to resolve the server. */
2165 if (!cmd->pending) {
2166 /* This will send the IDENTIFY command for nickname */
2167 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2168 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2170 silc_client_command_getkey,
2171 silc_client_command_dup(cmd));
2175 SilcClientCommandReplyContext reply =
2176 (SilcClientCommandReplyContext)context2;
2179 /* If nickname was not found, then resolve the server. */
2180 silc_command_get_status(reply->payload, NULL, &error);
2181 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2182 /* This sends the IDENTIFY command to resolve the server. */
2183 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2185 silc_client_command_reply_identify_i, 0,
2187 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2189 2, cmd->argv[1], cmd->argv_lens[1]);
2190 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2192 silc_client_command_getkey,
2193 silc_client_command_dup(cmd));
2197 /* If server was not found, then we've resolved both nickname and
2198 server and did not find anybody. */
2199 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2200 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2201 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2202 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2203 silc_get_status_message(error));
2204 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2208 COMMAND_ERROR(error);
2213 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2215 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2218 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2219 1, idp->data, idp->len);
2220 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2221 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2222 silc_buffer_free(buffer);
2223 silc_buffer_free(idp);
2225 /* Notify application */
2226 COMMAND(SILC_STATUS_OK);
2229 silc_free(nickname);
2230 silc_client_command_free(cmd);
2233 /* Register a new command indicated by the `command' to the SILC client.
2234 The `name' is optional command name. If provided the command may be
2235 searched using the silc_client_command_find by that name. The
2236 `command_function' is the function to be called when the command is
2237 executed, and the `command_reply_function' is the function to be
2238 called after the server has sent reply back to the command.
2240 The `ident' is optional identifier for the command. If non-zero
2241 the `command_reply_function' for the command type `command' will be
2242 called only if the command reply sent by server includes the
2243 command identifier `ident'. Application usually does not need it
2244 and set it to zero value. */
2246 bool silc_client_command_register(SilcClient client,
2247 SilcCommand command,
2249 SilcCommandCb command_function,
2250 SilcCommandCb command_reply_function,
2254 SilcClientCommand cmd;
2256 cmd = silc_calloc(1, sizeof(*cmd));
2258 cmd->command = command_function;
2259 cmd->reply = command_reply_function;
2260 cmd->name = name ? strdup(name) : NULL;
2261 cmd->max_args = max_args;
2264 silc_list_add(client->internal->commands, cmd);
2269 /* Unregister a command indicated by the `command' with command function
2270 `command_function' and command reply function `command_reply_function'.
2271 Returns TRUE if the command was found and unregistered. */
2273 bool silc_client_command_unregister(SilcClient client,
2274 SilcCommand command,
2275 SilcCommandCb command_function,
2276 SilcCommandCb command_reply_function,
2279 SilcClientCommand cmd;
2281 silc_list_start(client->internal->commands);
2282 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2283 if (cmd->cmd == command && cmd->command == command_function &&
2284 cmd->reply == command_reply_function && cmd->ident == ident) {
2285 silc_list_del(client->internal->commands, cmd);
2286 silc_free(cmd->name);
2295 /* Private range commands, specific to this implementation (and compatible
2296 with SILC Server). */
2298 /* CONNECT command. Connects the server to another server. */
2300 SILC_CLIENT_CMD_FUNC(connect)
2302 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2303 SilcClientConnection conn = cmd->conn;
2305 unsigned char port[4];
2309 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2310 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2314 if (cmd->argc < 2) {
2315 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2316 "Usage: /CONNECT <server> [<port>]");
2317 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2321 if (cmd->argc == 3) {
2322 tmp = atoi(cmd->argv[2]);
2323 SILC_PUT32_MSB(tmp, port);
2327 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2329 strlen(cmd->argv[1]),
2332 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2334 strlen(cmd->argv[1]));
2335 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2336 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2337 silc_buffer_free(buffer);
2339 /* Notify application */
2340 COMMAND(SILC_STATUS_OK);
2343 silc_client_command_free(cmd);
2347 /* CLOSE command. Close server connection to the remote server */
2349 SILC_CLIENT_CMD_FUNC(close)
2351 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2352 SilcClientConnection conn = cmd->conn;
2354 unsigned char port[4];
2358 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2359 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2363 if (cmd->argc < 2) {
2364 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2365 "Usage: /CLOSE <server> [<port>]");
2366 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2370 if (cmd->argc == 3) {
2371 tmp = atoi(cmd->argv[2]);
2372 SILC_PUT32_MSB(tmp, port);
2376 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2378 strlen(cmd->argv[1]),
2381 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2383 strlen(cmd->argv[1]));
2384 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2385 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2386 silc_buffer_free(buffer);
2388 /* Notify application */
2389 COMMAND(SILC_STATUS_OK);
2392 silc_client_command_free(cmd);
2395 /* SHUTDOWN command. Shutdowns the server. */
2397 SILC_CLIENT_CMD_FUNC(shutdown)
2399 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2402 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2407 /* Send the command */
2408 silc_client_command_send(cmd->client, cmd->conn,
2409 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2411 /* Notify application */
2412 COMMAND(SILC_STATUS_OK);
2415 silc_client_command_free(cmd);
2418 /* Register all default commands provided by the client library for the
2421 void silc_client_commands_register(SilcClient client)
2423 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2426 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2427 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2428 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2429 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2430 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2431 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2432 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2433 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2434 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2435 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2436 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2437 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2438 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2439 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2440 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2441 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2442 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2443 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2444 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2445 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2446 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2447 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2448 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2449 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2450 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2452 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2453 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2454 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2457 /* Unregister all commands. */
2459 void silc_client_commands_unregister(SilcClient client)
2461 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2462 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2463 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2464 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2465 SILC_CLIENT_CMDU(list, LIST, "LIST");
2466 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2467 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2468 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2469 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2470 SILC_CLIENT_CMDU(info, INFO, "INFO");
2471 SILC_CLIENT_CMDU(ping, PING, "PING");
2472 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2473 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2474 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2475 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2476 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2477 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2478 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2479 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2480 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2481 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2482 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2483 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2484 SILC_CLIENT_CMDU(users, USERS, "USERS");
2485 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2487 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2488 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2489 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");