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 STATS. Shows server and network statistics. */
879 SILC_CLIENT_CMD_FUNC(stats)
881 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
882 SilcClientConnection conn = cmd->conn;
883 SilcBuffer buffer, idp = NULL;
886 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
887 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
891 idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
893 /* Send the command */
894 buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
895 ++conn->cmd_ident, 1,
896 SILC_ID_SERVER, idp->data, idp->len);
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);
900 silc_buffer_free(idp);
902 /* Notify application */
903 COMMAND(SILC_STATUS_OK);
906 silc_client_command_free(cmd);
909 /* Command PING. Sends ping to server. This is used to test the
910 communication channel. */
912 SILC_CLIENT_CMD_FUNC(ping)
914 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
915 SilcClientConnection conn = cmd->conn;
921 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
922 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
926 /* Send the command */
927 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
928 1, conn->remote_id_data,
929 silc_id_get_len(conn->remote_id,
931 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
932 0, NULL, NULL, buffer->data, buffer->len, TRUE);
933 silc_buffer_free(buffer);
935 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
938 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
939 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
943 /* Start counting time */
944 for (i = 0; i < conn->ping_count; i++) {
945 if (conn->ping[i].dest_id == NULL) {
946 conn->ping[i].start_time = time(NULL);
947 conn->ping[i].dest_id = id;
948 conn->ping[i].dest_name = strdup(conn->remote_host);
952 if (i >= conn->ping_count) {
953 i = conn->ping_count;
954 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
955 conn->ping[i].start_time = time(NULL);
956 conn->ping[i].dest_id = id;
957 conn->ping[i].dest_name = strdup(conn->remote_host);
961 /* Notify application */
962 COMMAND(SILC_STATUS_OK);
965 silc_client_command_free(cmd);
968 /* Command JOIN. Joins to a channel. */
970 SILC_CLIENT_CMD_FUNC(join)
972 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
973 SilcClientConnection conn = cmd->conn;
974 SilcChannelEntry channel;
975 SilcBuffer buffer, idp, auth = NULL;
976 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
977 int i, passphrase_len = 0;
980 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
981 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
986 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
990 /* See if we have joined to the requested channel already */
991 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
992 if (channel && silc_client_on_channel(channel, conn->local_entry))
995 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
997 if (cmd->argv_lens[1] > 256)
998 cmd->argv_lens[1] = 256;
1000 name = cmd->argv[1];
1002 for (i = 2; i < cmd->argc; i++) {
1003 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1004 cipher = cmd->argv[i + 1];
1006 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1007 hmac = cmd->argv[i + 1];
1009 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
1010 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1011 cmd->client->private_key,
1013 cmd->client->internal->
1019 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1020 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1021 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1022 cmd->argv_lens[i], 0);
1023 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1024 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1025 0, pu8, passphrase_len);
1028 passphrase = strdup(cmd->argv[i]);
1029 passphrase_len = cmd->argv_lens[i];
1034 /* Send JOIN command to the server */
1036 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1037 1, name, strlen(name),
1038 2, idp->data, idp->len,
1039 3, passphrase, passphrase_len,
1040 4, cipher, cipher ? strlen(cipher) : 0,
1041 5, hmac, hmac ? strlen(hmac) : 0,
1042 6, auth ? auth->data : NULL,
1043 auth ? auth->len : 0);
1044 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1045 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1046 silc_buffer_free(buffer);
1047 silc_buffer_free(idp);
1049 silc_buffer_free(auth);
1050 silc_free(passphrase);
1052 /* Notify application */
1053 COMMAND(SILC_STATUS_OK);
1056 silc_client_command_free(cmd);
1059 /* MOTD command. Requests motd from server. */
1061 SILC_CLIENT_CMD_FUNC(motd)
1063 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1064 SilcClientConnection conn = cmd->conn;
1068 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1069 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1073 if (cmd->argc < 1 || cmd->argc > 2) {
1074 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1075 "Usage: /MOTD [<server>]");
1076 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1077 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1081 /* Send TOPIC command to the server */
1083 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1084 1, conn->remote_host,
1085 strlen(conn->remote_host));
1087 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1090 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1091 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1092 silc_buffer_free(buffer);
1094 /* Notify application */
1095 COMMAND(SILC_STATUS_OK);
1098 silc_client_command_free(cmd);
1101 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1102 modes as client cannot set itself server/router operator privileges. */
1104 SILC_CLIENT_CMD_FUNC(umode)
1106 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1107 SilcClientConnection conn = cmd->conn;
1108 SilcBuffer buffer, idp;
1109 unsigned char *cp, modebuf[4];
1110 SilcUInt32 mode, add, len;
1114 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1115 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1119 if (cmd->argc < 2) {
1120 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1121 "Usage: /UMODE +|-<modes>");
1122 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1126 mode = conn->local_entry->mode;
1128 /* Are we adding or removing mode */
1129 if (cmd->argv[1][0] == '-')
1135 cp = cmd->argv[1] + 1;
1137 for (i = 0; i < len; i++) {
1142 mode |= SILC_UMODE_SERVER_OPERATOR;
1143 mode |= SILC_UMODE_ROUTER_OPERATOR;
1144 mode |= SILC_UMODE_GONE;
1145 mode |= SILC_UMODE_INDISPOSED;
1146 mode |= SILC_UMODE_BUSY;
1147 mode |= SILC_UMODE_PAGE;
1148 mode |= SILC_UMODE_HYPER;
1149 mode |= SILC_UMODE_ROBOT;
1150 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1151 mode |= SILC_UMODE_REJECT_WATCHING;
1153 mode = SILC_UMODE_NONE;
1158 mode |= SILC_UMODE_SERVER_OPERATOR;
1160 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1164 mode |= SILC_UMODE_ROUTER_OPERATOR;
1166 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1170 mode |= SILC_UMODE_GONE;
1172 mode &= ~SILC_UMODE_GONE;
1176 mode |= SILC_UMODE_INDISPOSED;
1178 mode &= ~SILC_UMODE_INDISPOSED;
1182 mode |= SILC_UMODE_BUSY;
1184 mode &= ~SILC_UMODE_BUSY;
1188 mode |= SILC_UMODE_PAGE;
1190 mode &= ~SILC_UMODE_PAGE;
1194 mode |= SILC_UMODE_HYPER;
1196 mode &= ~SILC_UMODE_HYPER;
1200 mode |= SILC_UMODE_ROBOT;
1202 mode &= ~SILC_UMODE_ROBOT;
1206 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1208 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1212 mode |= SILC_UMODE_REJECT_WATCHING;
1214 mode &= ~SILC_UMODE_REJECT_WATCHING;
1218 mode |= SILC_UMODE_BLOCK_INVITE;
1220 mode &= ~SILC_UMODE_BLOCK_INVITE;
1223 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1229 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1230 SILC_PUT32_MSB(mode, modebuf);
1232 /* Send the command packet. We support sending only one mode at once
1233 that requires an argument. */
1235 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1236 1, idp->data, idp->len,
1237 2, modebuf, sizeof(modebuf));
1238 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1239 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1240 silc_buffer_free(buffer);
1241 silc_buffer_free(idp);
1243 /* Notify application */
1244 COMMAND(SILC_STATUS_OK);
1247 silc_client_command_free(cmd);
1250 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1251 can be set several at once. Those modes that require argument must be set
1252 separately (unless set with modes that does not require arguments). */
1254 SILC_CLIENT_CMD_FUNC(cmode)
1256 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1257 SilcClientConnection conn = cmd->conn;
1258 SilcChannelEntry channel;
1259 SilcBuffer buffer, chidp, auth = NULL;
1260 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1261 SilcUInt32 mode, add, type, len, arg_len = 0;
1265 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1266 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1270 if (cmd->argc < 3) {
1271 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1272 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1273 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1277 if (cmd->argv[1][0] == '*') {
1278 if (!conn->current_channel) {
1279 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1283 channel = conn->current_channel;
1285 name = cmd->argv[1];
1287 channel = silc_client_get_channel(cmd->client, conn, name);
1289 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1294 mode = channel->mode;
1296 /* Are we adding or removing mode */
1297 if (cmd->argv[2][0] == '-')
1302 /* Argument type to be sent to server */
1306 cp = cmd->argv[2] + 1;
1308 for (i = 0; i < len; i++) {
1312 mode |= SILC_CHANNEL_MODE_PRIVATE;
1314 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1318 mode |= SILC_CHANNEL_MODE_SECRET;
1320 mode &= ~SILC_CHANNEL_MODE_SECRET;
1324 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1326 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1330 mode |= SILC_CHANNEL_MODE_INVITE;
1332 mode &= ~SILC_CHANNEL_MODE_INVITE;
1336 mode |= SILC_CHANNEL_MODE_TOPIC;
1338 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1342 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1344 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1348 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1350 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1355 mode |= SILC_CHANNEL_MODE_ULIMIT;
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);
1363 ll = atoi(cmd->argv[3]);
1364 SILC_PUT32_MSB(ll, tmp);
1368 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1373 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
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_PASSPHRASE;
1389 mode |= SILC_CHANNEL_MODE_CIPHER;
1391 if (cmd->argc < 4) {
1392 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1393 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1394 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1398 arg_len = cmd->argv_lens[3];
1400 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1405 mode |= SILC_CHANNEL_MODE_HMAC;
1407 if (cmd->argc < 4) {
1408 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1409 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1410 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1414 arg_len = cmd->argv_lens[3];
1416 mode &= ~SILC_CHANNEL_MODE_HMAC;
1421 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1423 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1424 cmd->client->private_key,
1426 cmd->client->internal->
1431 arg_len = auth->len;
1433 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1437 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1443 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1444 SILC_PUT32_MSB(mode, modebuf);
1446 /* Send the command packet. We support sending only one mode at once
1447 that requires an argument. */
1450 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1451 1, chidp->data, chidp->len,
1452 2, modebuf, sizeof(modebuf),
1453 type, arg, arg_len);
1456 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1457 1, chidp->data, chidp->len,
1458 2, modebuf, sizeof(modebuf));
1461 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1462 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1463 silc_buffer_free(buffer);
1464 silc_buffer_free(chidp);
1466 silc_buffer_free(auth);
1468 /* Notify application */
1469 COMMAND(SILC_STATUS_OK);
1472 silc_client_command_free(cmd);
1475 /* CUMODE command. Changes client's mode on a channel. */
1477 SILC_CLIENT_CMD_FUNC(cumode)
1479 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1480 SilcClient client = cmd->client;
1481 SilcClientConnection conn = cmd->conn;
1482 SilcChannelEntry channel;
1483 SilcChannelUser chu;
1484 SilcClientEntry client_entry;
1485 SilcBuffer buffer, clidp, chidp, auth = NULL;
1486 unsigned char *name, *cp, modebuf[4];
1487 SilcUInt32 mode = 0, add, len;
1488 char *nickname = NULL;
1492 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1493 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1497 if (cmd->argc < 4) {
1498 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1499 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1500 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1504 if (cmd->argv[1][0] == '*') {
1505 if (!conn->current_channel) {
1506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1510 channel = conn->current_channel;
1512 name = cmd->argv[1];
1514 channel = silc_client_get_channel(cmd->client, conn, name);
1516 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1521 /* Parse the typed nickname. */
1522 if (client->internal->params->nickname_parse)
1523 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1525 nickname = strdup(cmd->argv[3]);
1527 /* Find client entry */
1528 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1529 cmd->argv[3], TRUE);
1530 if (!client_entry) {
1532 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1536 /* Client entry not found, it was requested thus mark this to be
1538 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1540 silc_client_command_cumode,
1541 silc_client_command_dup(cmd));
1546 /* Get the current mode */
1547 chu = silc_client_on_channel(channel, client_entry);
1551 /* Are we adding or removing mode */
1552 if (cmd->argv[2][0] == '-')
1558 cp = cmd->argv[2] + 1;
1560 for (i = 0; i < len; i++) {
1564 mode |= SILC_CHANNEL_UMODE_CHANFO;
1565 mode |= SILC_CHANNEL_UMODE_CHANOP;
1566 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1567 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1568 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1570 mode = SILC_CHANNEL_UMODE_NONE;
1575 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1576 cmd->client->private_key,
1578 cmd->client->internal->
1582 mode |= SILC_CHANNEL_UMODE_CHANFO;
1584 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1589 mode |= SILC_CHANNEL_UMODE_CHANOP;
1591 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1595 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1597 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1601 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1603 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1607 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1609 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1613 mode |= SILC_CHANNEL_UMODE_QUIET;
1615 mode &= ~SILC_CHANNEL_UMODE_QUIET;
1618 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1624 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1625 SILC_PUT32_MSB(mode, modebuf);
1626 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1628 /* Send the command packet. We support sending only one mode at once
1629 that requires an argument. */
1630 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1632 1, chidp->data, chidp->len,
1634 3, clidp->data, clidp->len,
1635 4, auth ? auth->data : NULL,
1636 auth ? auth->len : 0);
1638 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1639 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1640 silc_buffer_free(buffer);
1641 silc_buffer_free(chidp);
1642 silc_buffer_free(clidp);
1644 silc_buffer_free(auth);
1646 /* Notify application */
1647 COMMAND(SILC_STATUS_OK);
1650 silc_free(nickname);
1651 silc_client_command_free(cmd);
1654 /* KICK command. Kicks a client out of channel. */
1656 SILC_CLIENT_CMD_FUNC(kick)
1658 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1659 SilcClient client = cmd->client;
1660 SilcClientConnection conn = cmd->conn;
1661 SilcIDCacheEntry id_cache = NULL;
1662 SilcChannelEntry channel;
1663 SilcBuffer buffer, idp, idp2;
1664 SilcClientEntry target;
1666 char *nickname = NULL;
1669 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1670 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1674 if (cmd->argc < 3) {
1675 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1676 "Usage: /KICK <channel> <nickname> [<comment>]");
1677 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1681 if (cmd->argv[1][0] == '*') {
1682 if (!conn->current_channel) {
1683 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1686 name = conn->current_channel->channel_name;
1688 name = cmd->argv[1];
1691 if (!conn->current_channel) {
1692 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1696 /* Get the Channel ID of the channel */
1697 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1698 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1702 channel = (SilcChannelEntry)id_cache->context;
1704 /* Parse the typed nickname. */
1705 if (client->internal->params->nickname_parse)
1706 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1708 nickname = strdup(cmd->argv[2]);
1710 /* Get the target client */
1711 target = silc_idlist_get_client(cmd->client, conn, nickname,
1712 cmd->argv[2], FALSE);
1714 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1715 "No such client: %s", cmd->argv[2]);
1716 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1720 /* Send KICK command to the server */
1721 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1722 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1724 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1725 1, idp->data, idp->len,
1726 2, idp2->data, idp2->len);
1728 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1729 1, idp->data, idp->len,
1730 2, idp2->data, idp2->len,
1732 strlen(cmd->argv[3]));
1733 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1734 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1735 silc_buffer_free(buffer);
1736 silc_buffer_free(idp);
1737 silc_buffer_free(idp2);
1739 /* Notify application */
1740 COMMAND(SILC_STATUS_OK);
1743 silc_free(nickname);
1744 silc_client_command_free(cmd);
1747 static void silc_client_command_oper_send(unsigned char *data,
1748 SilcUInt32 data_len, void *context)
1750 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1751 SilcClientConnection conn = cmd->conn;
1752 SilcBuffer buffer, auth;
1754 if (cmd->argc >= 3) {
1755 /* Encode the public key authentication payload */
1756 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1757 cmd->client->private_key,
1758 cmd->client->rng, conn->hash,
1762 /* Encode the password authentication payload */
1763 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1767 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1769 strlen(cmd->argv[1]),
1770 2, auth ? auth->data : NULL,
1771 auth ? auth->len : 0);
1772 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1773 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1775 silc_buffer_free(buffer);
1776 silc_buffer_free(auth);
1778 /* Notify application */
1779 COMMAND(SILC_STATUS_OK);
1782 /* OPER command. Used to obtain server operator privileges. */
1784 SILC_CLIENT_CMD_FUNC(oper)
1786 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1787 SilcClientConnection conn = cmd->conn;
1790 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1791 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1795 if (cmd->argc < 2) {
1796 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1797 "Usage: /OPER <username> [-pubkey]");
1798 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1802 if (cmd->argc < 3) {
1803 /* Get passphrase */
1804 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1805 silc_client_command_oper_send,
1810 silc_client_command_oper_send(NULL, 0, context);
1813 silc_client_command_free(cmd);
1816 static void silc_client_command_silcoper_send(unsigned char *data,
1817 SilcUInt32 data_len,
1820 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1821 SilcClientConnection conn = cmd->conn;
1822 SilcBuffer buffer, auth;
1824 if (cmd->argc >= 3) {
1825 /* Encode the public key authentication payload */
1826 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1827 cmd->client->private_key,
1828 cmd->client->rng, conn->hash,
1832 /* Encode the password authentication payload */
1833 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1837 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1839 strlen(cmd->argv[1]),
1840 2, auth ? auth->data : NULL,
1841 auth ? auth->len : 0);
1842 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1843 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1845 silc_buffer_free(buffer);
1846 silc_buffer_free(auth);
1848 /* Notify application */
1849 COMMAND(SILC_STATUS_OK);
1852 /* SILCOPER command. Used to obtain router operator privileges. */
1854 SILC_CLIENT_CMD_FUNC(silcoper)
1856 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1857 SilcClientConnection conn = cmd->conn;
1860 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1861 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1865 if (cmd->argc < 2) {
1866 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1867 "Usage: /SILCOPER <username> [-pubkey]");
1868 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1872 if (cmd->argc < 3) {
1873 /* Get passphrase */
1874 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1875 silc_client_command_silcoper_send,
1880 silc_client_command_silcoper_send(NULL, 0, context);
1883 silc_client_command_free(cmd);
1886 /* Command BAN. This is used to manage the ban list of the channel. */
1888 SILC_CLIENT_CMD_FUNC(ban)
1890 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1891 SilcClientConnection conn = cmd->conn;
1892 SilcChannelEntry channel;
1893 SilcBuffer buffer, chidp;
1895 char *name, *ban = NULL;
1898 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1899 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1903 if (cmd->argc < 2) {
1904 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1905 "Usage: /BAN <channel> "
1906 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1907 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1911 if (cmd->argv[1][0] == '*') {
1912 if (!conn->current_channel) {
1913 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1917 channel = conn->current_channel;
1919 name = cmd->argv[1];
1921 channel = silc_client_get_channel(cmd->client, conn, name);
1923 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1928 if (cmd->argc == 3) {
1929 if (cmd->argv[2][0] == '+')
1938 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1940 /* Send the command */
1941 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1942 ++conn->cmd_ident, 2,
1943 1, chidp->data, chidp->len,
1944 type, ban, ban ? strlen(ban) : 0);
1945 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1946 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1947 silc_buffer_free(buffer);
1948 silc_buffer_free(chidp);
1950 /* Notify application */
1951 COMMAND(SILC_STATUS_OK);
1954 silc_client_command_free(cmd);
1957 /* Command DETACH. This is used to detach from the server */
1959 SILC_CLIENT_CMD_FUNC(detach)
1961 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1962 SilcClientConnection conn = cmd->conn;
1966 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1967 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1971 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1972 ++conn->cmd_ident, 0);
1973 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1974 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1975 silc_buffer_free(buffer);
1977 /* Notify application */
1978 COMMAND(SILC_STATUS_OK);
1981 silc_client_command_free(cmd);
1984 /* Command WATCH. */
1986 SILC_CLIENT_CMD_FUNC(watch)
1988 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1989 SilcClientConnection conn = cmd->conn;
1990 SilcBuffer buffer, idp = NULL;
1994 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1995 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1999 if (cmd->argc < 3) {
2000 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2004 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2006 if (!strcasecmp(cmd->argv[1], "-add")) {
2008 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2011 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2015 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2016 ++conn->cmd_ident, 2,
2017 1, idp->data, idp->len,
2020 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2021 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2022 silc_buffer_free(buffer);
2024 /* Notify application */
2025 COMMAND(SILC_STATUS_OK);
2029 silc_buffer_free(idp);
2030 silc_client_command_free(cmd);
2033 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2035 SILC_CLIENT_CMD_FUNC(leave)
2037 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2038 SilcClientConnection conn = cmd->conn;
2039 SilcChannelEntry channel;
2040 SilcChannelUser chu;
2041 SilcBuffer buffer, idp;
2045 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2046 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2050 if (cmd->argc != 2) {
2051 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2052 "Usage: /LEAVE <channel>");
2053 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2057 if (cmd->argv[1][0] == '*') {
2058 if (!conn->current_channel) {
2059 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2062 name = conn->current_channel->channel_name;
2064 name = cmd->argv[1];
2067 /* Get the channel entry */
2068 channel = silc_client_get_channel(cmd->client, conn, name);
2070 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2074 /* Remove us from channel */
2075 chu = silc_client_on_channel(channel, conn->local_entry);
2077 silc_hash_table_del(chu->client->channels, chu->channel);
2078 silc_hash_table_del(chu->channel->user_list, chu->client);
2082 /* Send LEAVE command to the server */
2083 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2084 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2085 1, idp->data, idp->len);
2086 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2087 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2088 silc_buffer_free(buffer);
2089 silc_buffer_free(idp);
2091 /* Notify application */
2092 COMMAND(SILC_STATUS_OK);
2094 if (conn->current_channel == channel)
2095 conn->current_channel = NULL;
2097 silc_client_del_channel(cmd->client, cmd->conn, channel);
2100 silc_client_command_free(cmd);
2103 /* Command USERS. Requests the USERS of the clients joined on requested
2106 SILC_CLIENT_CMD_FUNC(users)
2108 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2109 SilcClientConnection conn = cmd->conn;
2114 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2115 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2119 if (cmd->argc != 2) {
2120 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2121 "Usage: /USERS <channel>");
2122 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2126 if (cmd->argv[1][0] == '*') {
2127 if (!conn->current_channel) {
2128 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2131 name = conn->current_channel->channel_name;
2133 name = cmd->argv[1];
2136 /* Send USERS command to the server */
2137 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2138 ++conn->cmd_ident, 1,
2139 2, name, strlen(name));
2140 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2141 NULL, 0, NULL, NULL, buffer->data,
2143 silc_buffer_free(buffer);
2145 /* Notify application */
2146 COMMAND(SILC_STATUS_OK);
2149 silc_client_command_free(cmd);
2152 /* Command GETKEY. Used to fetch remote client's public key. */
2154 SILC_CLIENT_CMD_FUNC(getkey)
2156 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2157 SilcClientConnection conn = cmd->conn;
2158 SilcClient client = cmd->client;
2159 SilcClientEntry client_entry = NULL;
2160 SilcServerEntry server_entry = NULL;
2161 char *nickname = NULL;
2162 SilcBuffer idp, buffer;
2164 SILC_LOG_DEBUG(("Start"));
2167 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2168 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2172 if (cmd->argc < 2) {
2173 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2174 "Usage: /GETKEY <nickname or server name>");
2175 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2179 /* Parse the typed nickname. */
2180 if (client->internal->params->nickname_parse)
2181 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2183 nickname = strdup(cmd->argv[1]);
2185 /* Find client entry */
2186 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2188 if (!client_entry) {
2189 /* Check whether user requested server actually */
2190 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2192 if (!server_entry) {
2193 /* No. what ever user wants we don't have it, so resolve it. We
2194 will first try to resolve the client, and if that fails then
2195 we'll try to resolve the server. */
2197 if (!cmd->pending) {
2198 /* This will send the IDENTIFY command for nickname */
2199 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2200 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2202 silc_client_command_getkey,
2203 silc_client_command_dup(cmd));
2207 SilcClientCommandReplyContext reply =
2208 (SilcClientCommandReplyContext)context2;
2211 /* If nickname was not found, then resolve the server. */
2212 silc_command_get_status(reply->payload, NULL, &error);
2213 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2214 /* This sends the IDENTIFY command to resolve the server. */
2215 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2217 silc_client_command_reply_identify_i, 0,
2219 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2221 2, cmd->argv[1], cmd->argv_lens[1]);
2222 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2224 silc_client_command_getkey,
2225 silc_client_command_dup(cmd));
2229 /* If server was not found, then we've resolved both nickname and
2230 server and did not find anybody. */
2231 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2232 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2233 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2234 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2235 silc_get_status_message(error));
2236 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2240 COMMAND_ERROR(error);
2245 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2247 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2250 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2251 1, idp->data, idp->len);
2252 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2253 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2254 silc_buffer_free(buffer);
2255 silc_buffer_free(idp);
2257 /* Notify application */
2258 COMMAND(SILC_STATUS_OK);
2261 silc_free(nickname);
2262 silc_client_command_free(cmd);
2265 /* Register a new command indicated by the `command' to the SILC client.
2266 The `name' is optional command name. If provided the command may be
2267 searched using the silc_client_command_find by that name. The
2268 `command_function' is the function to be called when the command is
2269 executed, and the `command_reply_function' is the function to be
2270 called after the server has sent reply back to the command.
2272 The `ident' is optional identifier for the command. If non-zero
2273 the `command_reply_function' for the command type `command' will be
2274 called only if the command reply sent by server includes the
2275 command identifier `ident'. Application usually does not need it
2276 and set it to zero value. */
2278 bool silc_client_command_register(SilcClient client,
2279 SilcCommand command,
2281 SilcCommandCb command_function,
2282 SilcCommandCb command_reply_function,
2286 SilcClientCommand cmd;
2288 cmd = silc_calloc(1, sizeof(*cmd));
2290 cmd->command = command_function;
2291 cmd->reply = command_reply_function;
2292 cmd->name = name ? strdup(name) : NULL;
2293 cmd->max_args = max_args;
2296 silc_list_add(client->internal->commands, cmd);
2301 /* Unregister a command indicated by the `command' with command function
2302 `command_function' and command reply function `command_reply_function'.
2303 Returns TRUE if the command was found and unregistered. */
2305 bool silc_client_command_unregister(SilcClient client,
2306 SilcCommand command,
2307 SilcCommandCb command_function,
2308 SilcCommandCb command_reply_function,
2311 SilcClientCommand cmd;
2313 silc_list_start(client->internal->commands);
2314 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2315 if (cmd->cmd == command && cmd->command == command_function &&
2316 cmd->reply == command_reply_function && cmd->ident == ident) {
2317 silc_list_del(client->internal->commands, cmd);
2318 silc_free(cmd->name);
2327 /* Private range commands, specific to this implementation (and compatible
2328 with SILC Server). */
2330 /* CONNECT command. Connects the server to another server. */
2332 SILC_CLIENT_CMD_FUNC(connect)
2334 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2335 SilcClientConnection conn = cmd->conn;
2337 unsigned char port[4];
2341 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2342 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2346 if (cmd->argc < 2) {
2347 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2348 "Usage: /CONNECT <server> [<port>]");
2349 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2353 if (cmd->argc == 3) {
2354 tmp = atoi(cmd->argv[2]);
2355 SILC_PUT32_MSB(tmp, port);
2359 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2361 strlen(cmd->argv[1]),
2364 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2366 strlen(cmd->argv[1]));
2367 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2368 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2369 silc_buffer_free(buffer);
2371 /* Notify application */
2372 COMMAND(SILC_STATUS_OK);
2375 silc_client_command_free(cmd);
2379 /* CLOSE command. Close server connection to the remote server */
2381 SILC_CLIENT_CMD_FUNC(close)
2383 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2384 SilcClientConnection conn = cmd->conn;
2386 unsigned char port[4];
2390 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2391 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2395 if (cmd->argc < 2) {
2396 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2397 "Usage: /CLOSE <server> [<port>]");
2398 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2402 if (cmd->argc == 3) {
2403 tmp = atoi(cmd->argv[2]);
2404 SILC_PUT32_MSB(tmp, port);
2408 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2410 strlen(cmd->argv[1]),
2413 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2415 strlen(cmd->argv[1]));
2416 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2417 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2418 silc_buffer_free(buffer);
2420 /* Notify application */
2421 COMMAND(SILC_STATUS_OK);
2424 silc_client_command_free(cmd);
2427 /* SHUTDOWN command. Shutdowns the server. */
2429 SILC_CLIENT_CMD_FUNC(shutdown)
2431 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2434 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2435 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2439 /* Send the command */
2440 silc_client_command_send(cmd->client, cmd->conn,
2441 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2443 /* Notify application */
2444 COMMAND(SILC_STATUS_OK);
2447 silc_client_command_free(cmd);
2450 /* Register all default commands provided by the client library for the
2453 void silc_client_commands_register(SilcClient client)
2455 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2458 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2459 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2460 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2461 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2462 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2463 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2464 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2465 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2466 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2467 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2468 SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
2469 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2470 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2471 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2472 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2473 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2474 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2475 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2476 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2477 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2478 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2479 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2480 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2481 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2482 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2483 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2485 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2486 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2487 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2490 /* Unregister all commands. */
2492 void silc_client_commands_unregister(SilcClient client)
2494 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2495 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2496 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2497 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2498 SILC_CLIENT_CMDU(list, LIST, "LIST");
2499 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2500 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2501 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2502 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2503 SILC_CLIENT_CMDU(info, INFO, "INFO");
2504 SILC_CLIENT_CMDU(stats, STATS, "STATS");
2505 SILC_CLIENT_CMDU(ping, PING, "PING");
2506 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2507 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2508 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2509 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2510 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2511 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2512 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2513 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2514 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2515 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2516 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2517 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2518 SILC_CLIENT_CMDU(users, USERS, "USERS");
2519 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2521 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2522 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2523 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");