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 /* Check whether identical pending already exists for same command,
107 ident, callback and callback context. If it does then it would be
108 error to register it again. */
109 silc_dlist_start(conn->pending_commands);
110 while ((reply = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
111 if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
112 reply->callback == callback && reply->context == context)
116 reply = silc_calloc(1, sizeof(*reply));
117 reply->reply_cmd = reply_cmd;
118 reply->ident = ident;
119 reply->context = context;
120 reply->callback = callback;
121 silc_dlist_add(conn->pending_commands, reply);
124 /* Deletes pending command by reply command type. */
126 void silc_client_command_pending_del(SilcClientConnection conn,
127 SilcCommand reply_cmd,
130 SilcClientCommandPending *r;
132 if (!conn->pending_commands)
135 silc_dlist_start(conn->pending_commands);
136 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
137 if (r->reply_cmd == reply_cmd && r->ident == ident) {
138 silc_dlist_del(conn->pending_commands, r);
144 /* Checks for pending commands and marks callbacks to be called from
145 the command reply function. */
147 SilcClientCommandPendingCallbacks
148 silc_client_command_pending_check(SilcClientConnection conn,
149 SilcClientCommandReplyContext ctx,
152 SilcUInt32 *callbacks_count)
154 SilcClientCommandPending *r;
155 SilcClientCommandPendingCallbacks callbacks = NULL;
158 silc_dlist_start(conn->pending_commands);
159 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
160 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
161 && r->ident == ident) {
162 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
163 callbacks[i].context = r->context;
164 callbacks[i].callback = r->callback;
170 *callbacks_count = i;
174 /* Allocate Command Context */
176 SilcClientCommandContext silc_client_command_alloc(void)
178 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
183 /* Free command context and its internals */
185 void silc_client_command_free(SilcClientCommandContext ctx)
188 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
190 if (ctx->users < 1) {
193 for (i = 0; i < ctx->argc; i++)
194 silc_free(ctx->argv[i]);
195 silc_free(ctx->argv_lens);
196 silc_free(ctx->argv_types);
201 /* Duplicate Command Context by adding reference counter. The context won't
202 be free'd untill it hits zero. */
204 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
207 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
212 /* Command WHOIS. This command is used to query information about
215 SILC_CLIENT_CMD_FUNC(whois)
217 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
218 SilcClientConnection conn = cmd->conn;
220 unsigned char count[4];
223 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
224 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
228 /* Given without arguments fetches client's own information */
230 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
231 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
233 1, 4, buffer->data, buffer->len);
234 silc_buffer_free(buffer);
238 if (cmd->argc == 2) {
239 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
240 ++conn->cmd_ident, 1,
244 int c = atoi(cmd->argv[2]);
245 memset(count, 0, sizeof(count));
246 SILC_PUT32_MSB(c, count);
247 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
248 ++conn->cmd_ident, 2,
249 1, cmd->argv[1], cmd->argv_lens[1],
250 2, count, sizeof(count));
252 silc_client_packet_send(cmd->client, cmd->conn->sock,
253 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
254 buffer->data, buffer->len, TRUE);
255 silc_buffer_free(buffer);
257 /* Notify application */
258 COMMAND(SILC_STATUS_OK);
261 silc_client_command_free(cmd);
264 /* Command WHOWAS. This command is used to query history information about
265 specific user that used to exist in the network. */
267 SILC_CLIENT_CMD_FUNC(whowas)
269 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
270 SilcClientConnection conn = cmd->conn;
272 unsigned char count[4];
275 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
276 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
280 if (cmd->argc < 2 || cmd->argc > 3) {
281 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
282 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
283 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
284 SILC_STATUS_ERR_TOO_MANY_PARAMS));
288 if (cmd->argc == 2) {
289 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
290 ++conn->cmd_ident, 1,
294 int c = atoi(cmd->argv[2]);
295 memset(count, 0, sizeof(count));
296 SILC_PUT32_MSB(c, count);
297 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
298 ++conn->cmd_ident, 2,
299 1, cmd->argv[1], cmd->argv_lens[1],
300 2, count, sizeof(count));
302 silc_client_packet_send(cmd->client, cmd->conn->sock,
303 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
304 buffer->data, buffer->len, TRUE);
305 silc_buffer_free(buffer);
307 /* Notify application */
308 COMMAND(SILC_STATUS_OK);
311 silc_client_command_free(cmd);
314 /* Command IDENTIFY. This command is used to query information about
315 specific user, especially ID's.
317 NOTE: This command is used only internally by the client library
318 and application MUST NOT call this command directly. */
320 SILC_CLIENT_CMD_FUNC(identify)
322 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
323 SilcClientConnection conn = cmd->conn;
325 unsigned char count[4];
328 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
329 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
333 if (cmd->argc < 2 || cmd->argc > 3)
336 if (cmd->argc == 2) {
337 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
338 ++conn->cmd_ident, 1,
342 int c = atoi(cmd->argv[2]);
343 memset(count, 0, sizeof(count));
344 SILC_PUT32_MSB(c, count);
345 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
346 ++conn->cmd_ident, 2,
349 4, count, sizeof(count));
352 silc_client_packet_send(cmd->client, cmd->conn->sock,
353 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
354 buffer->data, buffer->len, TRUE);
355 silc_buffer_free(buffer);
358 silc_client_command_free(cmd);
361 /* Command NICK. Shows current nickname/sets new nickname on current
364 SILC_CLIENT_CMD_FUNC(nick)
366 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
367 SilcClientConnection conn = cmd->conn;
371 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
372 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
378 "Usage: /NICK <nickname>");
379 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
383 if (!strcmp(conn->nickname, cmd->argv[1]))
386 /* Show current nickname */
389 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
390 "Your nickname is %s on server %s",
391 conn->nickname, conn->remote_host);
393 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
394 "Your nickname is %s", conn->nickname);
397 COMMAND(SILC_STATUS_OK);
401 if (cmd->argv_lens[1] > 128)
402 cmd->argv_lens[1] = 128;
404 /* Send the NICK command */
405 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
409 ++cmd->conn->cmd_ident);
410 silc_client_packet_send(cmd->client, cmd->conn->sock,
411 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
412 buffer->data, buffer->len, TRUE);
413 silc_buffer_free(buffer);
416 silc_client_command_free(cmd);
419 /* Command LIST. Lists channels on the current server. */
421 SILC_CLIENT_CMD_FUNC(list)
423 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
424 SilcClientConnection conn = cmd->conn;
425 SilcIDCacheEntry id_cache = NULL;
426 SilcChannelEntry channel;
427 SilcBuffer buffer, idp = NULL;
431 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
432 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
436 if (cmd->argc == 2) {
439 /* Get the Channel ID of the channel */
440 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
441 channel = (SilcChannelEntry)id_cache->context;
442 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
447 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
448 ++conn->cmd_ident, 0);
450 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
451 ++conn->cmd_ident, 1,
452 1, idp->data, idp->len);
454 silc_client_packet_send(cmd->client, cmd->conn->sock,
455 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
456 buffer->data, buffer->len, TRUE);
457 silc_buffer_free(buffer);
459 silc_buffer_free(idp);
461 /* Notify application */
462 COMMAND(SILC_STATUS_OK);
465 silc_client_command_free(cmd);
468 /* Command TOPIC. Sets/shows topic on a channel. */
470 SILC_CLIENT_CMD_FUNC(topic)
472 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
473 SilcClientConnection conn = cmd->conn;
474 SilcIDCacheEntry id_cache = NULL;
475 SilcChannelEntry channel;
476 SilcBuffer buffer, idp;
480 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
481 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
485 if (cmd->argc < 2 || cmd->argc > 3) {
486 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
487 "Usage: /TOPIC <channel> [<topic>]");
488 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
489 SILC_STATUS_ERR_TOO_MANY_PARAMS));
493 if (cmd->argv[1][0] == '*') {
494 if (!conn->current_channel) {
495 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
496 "You are not on any channel");
497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
500 name = conn->current_channel->channel_name;
505 if (!conn->current_channel) {
506 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
507 "You are not on that channel");
508 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
512 /* Get the Channel ID of the channel */
513 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
514 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
515 "You are not on that channel");
516 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
520 channel = (SilcChannelEntry)id_cache->context;
522 /* Send TOPIC command to the server */
523 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
525 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
526 ++conn->cmd_ident, 2,
527 1, idp->data, idp->len,
529 strlen(cmd->argv[2]));
531 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
532 ++conn->cmd_ident, 1,
533 1, idp->data, idp->len);
534 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
535 0, NULL, NULL, buffer->data, buffer->len, TRUE);
536 silc_buffer_free(buffer);
537 silc_buffer_free(idp);
539 /* Notify application */
540 COMMAND(SILC_STATUS_OK);
543 silc_client_command_free(cmd);
546 /* Command INVITE. Invites specific client to join a channel. This is
547 also used to mange the invite list of the channel. */
549 SILC_CLIENT_CMD_FUNC(invite)
551 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
552 SilcClient client = cmd->client;
553 SilcClientConnection conn = cmd->conn;
554 SilcClientEntry client_entry = NULL;
555 SilcChannelEntry channel;
556 SilcBuffer buffer, clidp, chidp;
558 char *nickname = NULL, *name;
562 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
563 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
568 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
569 "Usage: /INVITE <channel> [<nickname>[@server>]"
570 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
571 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
575 if (cmd->argv[1][0] == '*') {
576 if (!conn->current_channel) {
577 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
578 "You are not on any channel");
579 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
583 channel = conn->current_channel;
587 channel = silc_client_get_channel(cmd->client, conn, name);
589 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
590 "You are on that channel");
591 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
596 /* Parse the typed nickname. */
597 if (cmd->argc == 3) {
598 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
599 if (client->internal->params->nickname_parse)
600 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
602 nickname = strdup(cmd->argv[2]);
604 /* Find client entry */
605 client_entry = silc_idlist_get_client(client, conn, nickname,
609 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
613 /* Client entry not found, it was requested thus mark this to be
615 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
617 silc_client_command_invite,
618 silc_client_command_dup(cmd));
623 invite = cmd->argv[2];
625 if (cmd->argv[2][0] == '+')
632 /* Send the command */
633 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
635 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
636 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
637 ++conn->cmd_ident, 3,
638 1, chidp->data, chidp->len,
639 2, clidp->data, clidp->len,
640 type, invite, invite ?
642 silc_buffer_free(clidp);
644 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
645 ++conn->cmd_ident, 2,
646 1, chidp->data, chidp->len,
647 type, invite, invite ?
651 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
652 0, NULL, NULL, buffer->data, buffer->len, TRUE);
653 silc_buffer_free(buffer);
654 silc_buffer_free(chidp);
656 /* Notify application */
657 COMMAND(SILC_STATUS_OK);
661 silc_client_command_free(cmd);
666 SilcClientConnection conn;
669 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
671 QuitInternal q = (QuitInternal)context;
673 /* Close connection */
674 q->client->internal->ops->disconnect(q->client, q->conn);
675 silc_client_close_connection(q->client, q->conn->sock->user_data);
680 /* Command QUIT. Closes connection with current server. */
682 SILC_CLIENT_CMD_FUNC(quit)
684 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
689 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
690 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
695 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
696 &cmd->argv[1], &cmd->argv_lens[1],
697 &cmd->argv_types[1], 0);
699 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
700 NULL, NULL, NULL, 0);
701 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
703 buffer->data, buffer->len, TRUE);
704 silc_buffer_free(buffer);
706 q = silc_calloc(1, sizeof(*q));
707 q->client = cmd->client;
710 /* Sleep for a while */
713 /* We quit the connection with little timeout */
714 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
715 silc_client_command_quit_cb, (void *)q,
716 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
718 /* Notify application */
719 COMMAND(SILC_STATUS_OK);
722 silc_client_command_free(cmd);
725 /* Timeout callback to remove the killed client from cache */
727 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
729 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
730 SilcClient client = cmd->client;
731 SilcClientConnection conn = cmd->conn;
732 SilcClientEntry target;
733 char *nickname = NULL;
735 /* Parse the typed nickname. */
736 if (client->internal->params->nickname_parse)
737 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
739 nickname = strdup(cmd->argv[1]);
741 /* Get the target client */
742 target = silc_idlist_get_client(cmd->client, conn, nickname,
743 cmd->argv[1], FALSE);
745 /* Remove the client from all channels and free it */
746 silc_client_del_client(client, conn, target);
749 silc_client_command_free(cmd);
752 /* Kill command's pending command callback to actually remove the killed
753 client from our local cache. */
755 SILC_CLIENT_CMD_FUNC(kill_remove)
757 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
758 SilcClientCommandReplyContext reply =
759 (SilcClientCommandReplyContext)context2;
762 silc_command_get_status(reply->payload, &status, NULL);
763 if (status == SILC_STATUS_OK) {
764 /* Remove with timeout */
765 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
766 silc_client_command_kill_remove_later, context,
767 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
771 silc_client_command_free(cmd);
774 /* Command KILL. Router operator can use this command to remove an client
775 fromthe SILC Network. */
777 SILC_CLIENT_CMD_FUNC(kill)
779 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
780 SilcClient client = cmd->client;
781 SilcClientConnection conn = cmd->conn;
782 SilcBuffer buffer, idp;
783 SilcClientEntry target;
784 char *nickname = NULL;
787 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
788 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
793 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
794 "Usage: /KILL <nickname> [<comment>]");
795 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 /* Parse the typed nickname. */
800 if (client->internal->params->nickname_parse)
801 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
803 nickname = strdup(cmd->argv[1]);
805 /* Get the target client */
806 target = silc_idlist_get_client(cmd->client, conn, nickname,
810 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
814 /* Client entry not found, it was requested thus mark this to be
816 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
818 silc_client_command_kill,
819 silc_client_command_dup(cmd));
824 /* Send the KILL command to the server */
825 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
827 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
828 ++conn->cmd_ident, 1,
829 1, idp->data, idp->len);
831 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
832 ++conn->cmd_ident, 2,
833 1, idp->data, idp->len,
835 strlen(cmd->argv[2]));
836 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
837 0, NULL, NULL, buffer->data, buffer->len, TRUE);
838 silc_buffer_free(buffer);
839 silc_buffer_free(idp);
841 /* Notify application */
842 COMMAND(SILC_STATUS_OK);
844 /* Register a pending callback that will actually remove the killed
845 client from our cache. */
846 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
847 silc_client_command_kill_remove,
848 silc_client_command_dup(cmd));
852 silc_client_command_free(cmd);
855 /* Command INFO. Request information about specific server. If specific
856 server is not provided the current server is used. */
858 SILC_CLIENT_CMD_FUNC(info)
860 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
861 SilcClientConnection conn = cmd->conn;
866 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
867 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
872 name = strdup(cmd->argv[1]);
874 /* Send the command */
876 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
877 1, name, strlen(name));
879 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
880 NULL, NULL, NULL, 0);
881 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
882 0, NULL, NULL, buffer->data, buffer->len, TRUE);
883 silc_buffer_free(buffer);
887 /* Notify application */
888 COMMAND(SILC_STATUS_OK);
891 silc_client_command_free(cmd);
894 /* Command PING. Sends ping to server. This is used to test the
895 communication channel. */
897 SILC_CLIENT_CMD_FUNC(ping)
899 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
900 SilcClientConnection conn = cmd->conn;
906 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
907 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
911 /* Send the command */
912 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
913 1, conn->remote_id_data,
914 silc_id_get_len(conn->remote_id,
916 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
917 0, NULL, NULL, buffer->data, buffer->len, TRUE);
918 silc_buffer_free(buffer);
920 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
923 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
924 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
928 /* Start counting time */
929 for (i = 0; i < conn->ping_count; i++) {
930 if (conn->ping[i].dest_id == NULL) {
931 conn->ping[i].start_time = time(NULL);
932 conn->ping[i].dest_id = id;
933 conn->ping[i].dest_name = strdup(conn->remote_host);
937 if (i >= conn->ping_count) {
938 i = conn->ping_count;
939 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
940 conn->ping[i].start_time = time(NULL);
941 conn->ping[i].dest_id = id;
942 conn->ping[i].dest_name = strdup(conn->remote_host);
946 /* Notify application */
947 COMMAND(SILC_STATUS_OK);
950 silc_client_command_free(cmd);
953 /* Command JOIN. Joins to a channel. */
955 SILC_CLIENT_CMD_FUNC(join)
957 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
958 SilcClientConnection conn = cmd->conn;
959 SilcChannelEntry channel;
960 SilcBuffer buffer, idp, auth = NULL;
961 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
962 int i, passphrase_len = 0;
965 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
966 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
971 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
975 /* See if we have joined to the requested channel already */
976 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
977 if (channel && silc_client_on_channel(channel, conn->local_entry))
980 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
982 if (cmd->argv_lens[1] > 256)
983 cmd->argv_lens[1] = 256;
987 for (i = 2; i < cmd->argc; i++) {
988 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
989 cipher = cmd->argv[i + 1];
991 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
992 hmac = cmd->argv[i + 1];
994 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
995 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
996 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
997 cmd->client->private_key,
998 cmd->client->rng, conn->hash,
1002 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1004 cmd->argv_lens[i + 1]);
1008 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1009 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1010 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1011 cmd->argv_lens[i], 0);
1012 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1013 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1014 0, pu8, passphrase_len);
1017 passphrase = strdup(cmd->argv[i]);
1018 passphrase_len = cmd->argv_lens[i];
1023 /* Send JOIN command to the server */
1025 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1026 1, name, strlen(name),
1027 2, idp->data, idp->len,
1028 3, passphrase, passphrase_len,
1029 4, cipher, cipher ? strlen(cipher) : 0,
1030 5, hmac, hmac ? strlen(hmac) : 0,
1031 6, auth ? auth->data : NULL,
1032 auth ? auth->len : 0);
1033 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1034 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1035 silc_buffer_free(buffer);
1036 silc_buffer_free(idp);
1038 silc_buffer_free(auth);
1039 silc_free(passphrase);
1041 /* Notify application */
1042 COMMAND(SILC_STATUS_OK);
1045 silc_client_command_free(cmd);
1048 /* MOTD command. Requests motd from server. */
1050 SILC_CLIENT_CMD_FUNC(motd)
1052 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1053 SilcClientConnection conn = cmd->conn;
1057 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1058 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1062 if (cmd->argc < 1 || cmd->argc > 2) {
1063 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1064 "Usage: /MOTD [<server>]");
1065 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1066 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1070 /* Send TOPIC command to the server */
1072 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1073 1, conn->remote_host,
1074 strlen(conn->remote_host));
1076 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1079 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1080 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1081 silc_buffer_free(buffer);
1083 /* Notify application */
1084 COMMAND(SILC_STATUS_OK);
1087 silc_client_command_free(cmd);
1090 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1091 modes as client cannot set itself server/router operator privileges. */
1093 SILC_CLIENT_CMD_FUNC(umode)
1095 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1096 SilcClientConnection conn = cmd->conn;
1097 SilcBuffer buffer, idp;
1098 unsigned char *cp, modebuf[4];
1099 SilcUInt32 mode, add, len;
1103 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1104 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1108 if (cmd->argc < 2) {
1109 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1110 "Usage: /UMODE +|-<modes>");
1111 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1115 mode = conn->local_entry->mode;
1117 /* Are we adding or removing mode */
1118 if (cmd->argv[1][0] == '-')
1124 cp = cmd->argv[1] + 1;
1126 for (i = 0; i < len; i++) {
1131 mode |= SILC_UMODE_SERVER_OPERATOR;
1132 mode |= SILC_UMODE_ROUTER_OPERATOR;
1133 mode |= SILC_UMODE_GONE;
1134 mode |= SILC_UMODE_INDISPOSED;
1135 mode |= SILC_UMODE_BUSY;
1136 mode |= SILC_UMODE_PAGE;
1137 mode |= SILC_UMODE_HYPER;
1138 mode |= SILC_UMODE_ROBOT;
1139 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1140 mode |= SILC_UMODE_REJECT_WATCHING;
1142 mode = SILC_UMODE_NONE;
1147 mode |= SILC_UMODE_SERVER_OPERATOR;
1149 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1153 mode |= SILC_UMODE_ROUTER_OPERATOR;
1155 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1159 mode |= SILC_UMODE_GONE;
1161 mode &= ~SILC_UMODE_GONE;
1165 mode |= SILC_UMODE_INDISPOSED;
1167 mode &= ~SILC_UMODE_INDISPOSED;
1171 mode |= SILC_UMODE_BUSY;
1173 mode &= ~SILC_UMODE_BUSY;
1177 mode |= SILC_UMODE_PAGE;
1179 mode &= ~SILC_UMODE_PAGE;
1183 mode |= SILC_UMODE_HYPER;
1185 mode &= ~SILC_UMODE_HYPER;
1189 mode |= SILC_UMODE_ROBOT;
1191 mode &= ~SILC_UMODE_ROBOT;
1195 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1197 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1201 mode |= SILC_UMODE_REJECT_WATCHING;
1203 mode &= ~SILC_UMODE_REJECT_WATCHING;
1207 mode |= SILC_UMODE_BLOCK_INVITE;
1209 mode &= ~SILC_UMODE_BLOCK_INVITE;
1212 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1218 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1219 SILC_PUT32_MSB(mode, modebuf);
1221 /* Send the command packet. We support sending only one mode at once
1222 that requires an argument. */
1224 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1225 1, idp->data, idp->len,
1226 2, modebuf, sizeof(modebuf));
1227 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1228 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1229 silc_buffer_free(buffer);
1230 silc_buffer_free(idp);
1232 /* Notify application */
1233 COMMAND(SILC_STATUS_OK);
1236 silc_client_command_free(cmd);
1239 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1240 can be set several at once. Those modes that require argument must be set
1241 separately (unless set with modes that does not require arguments). */
1243 SILC_CLIENT_CMD_FUNC(cmode)
1245 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1246 SilcClientConnection conn = cmd->conn;
1247 SilcChannelEntry channel;
1248 SilcBuffer buffer, chidp, auth = NULL;
1249 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1250 SilcUInt32 mode, add, type, len, arg_len = 0;
1254 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1255 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1259 if (cmd->argc < 3) {
1260 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1261 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1262 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1266 if (cmd->argv[1][0] == '*') {
1267 if (!conn->current_channel) {
1268 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1269 "You are not on any channel");
1270 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1274 channel = conn->current_channel;
1276 name = cmd->argv[1];
1278 channel = silc_client_get_channel(cmd->client, conn, name);
1280 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1281 "You are on that channel");
1282 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1287 mode = channel->mode;
1289 /* Are we adding or removing mode */
1290 if (cmd->argv[2][0] == '-')
1295 /* Argument type to be sent to server */
1299 cp = cmd->argv[2] + 1;
1301 for (i = 0; i < len; i++) {
1305 mode |= SILC_CHANNEL_MODE_PRIVATE;
1307 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1311 mode |= SILC_CHANNEL_MODE_SECRET;
1313 mode &= ~SILC_CHANNEL_MODE_SECRET;
1317 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1319 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1323 mode |= SILC_CHANNEL_MODE_INVITE;
1325 mode &= ~SILC_CHANNEL_MODE_INVITE;
1329 mode |= SILC_CHANNEL_MODE_TOPIC;
1331 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1335 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1337 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1341 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1343 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1348 mode |= SILC_CHANNEL_MODE_ULIMIT;
1350 if (cmd->argc < 4) {
1351 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1352 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1353 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1356 ll = atoi(cmd->argv[3]);
1357 SILC_PUT32_MSB(ll, tmp);
1361 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1366 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1368 if (cmd->argc < 4) {
1369 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1370 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1371 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1375 arg_len = cmd->argv_lens[3];
1377 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1382 mode |= SILC_CHANNEL_MODE_CIPHER;
1384 if (cmd->argc < 4) {
1385 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1386 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1387 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1391 arg_len = cmd->argv_lens[3];
1393 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1398 mode |= SILC_CHANNEL_MODE_HMAC;
1400 if (cmd->argc < 4) {
1401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1402 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1407 arg_len = cmd->argv_lens[3];
1409 mode &= ~SILC_CHANNEL_MODE_HMAC;
1414 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1416 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1417 cmd->client->private_key,
1423 arg_len = auth->len;
1425 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1429 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1435 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1436 SILC_PUT32_MSB(mode, modebuf);
1438 /* Send the command packet. We support sending only one mode at once
1439 that requires an argument. */
1442 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1443 1, chidp->data, chidp->len,
1444 2, modebuf, sizeof(modebuf),
1445 type, arg, arg_len);
1448 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1449 1, chidp->data, chidp->len,
1450 2, modebuf, sizeof(modebuf));
1453 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1454 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1455 silc_buffer_free(buffer);
1456 silc_buffer_free(chidp);
1458 silc_buffer_free(auth);
1460 /* Notify application */
1461 COMMAND(SILC_STATUS_OK);
1464 silc_client_command_free(cmd);
1467 /* CUMODE command. Changes client's mode on a channel. */
1469 SILC_CLIENT_CMD_FUNC(cumode)
1471 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1472 SilcClient client = cmd->client;
1473 SilcClientConnection conn = cmd->conn;
1474 SilcChannelEntry channel;
1475 SilcChannelUser chu;
1476 SilcClientEntry client_entry;
1477 SilcBuffer buffer, clidp, chidp, auth = NULL;
1478 unsigned char *name, *cp, modebuf[4];
1479 SilcUInt32 mode = 0, add, len;
1480 char *nickname = NULL;
1484 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1485 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1489 if (cmd->argc < 4) {
1490 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1491 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1492 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1496 if (cmd->argv[1][0] == '*') {
1497 if (!conn->current_channel) {
1498 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1499 "You are not on any channel");
1500 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1504 channel = conn->current_channel;
1506 name = cmd->argv[1];
1508 channel = silc_client_get_channel(cmd->client, conn, name);
1510 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1511 "You are on that channel");
1512 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1517 /* Parse the typed nickname. */
1518 if (client->internal->params->nickname_parse)
1519 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1521 nickname = strdup(cmd->argv[3]);
1523 /* Find client entry */
1524 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1525 cmd->argv[3], TRUE);
1526 if (!client_entry) {
1528 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1532 /* Client entry not found, it was requested thus mark this to be
1534 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1536 silc_client_command_cumode,
1537 silc_client_command_dup(cmd));
1542 /* Get the current mode */
1543 chu = silc_client_on_channel(channel, client_entry);
1547 /* Are we adding or removing mode */
1548 if (cmd->argv[2][0] == '-')
1554 cp = cmd->argv[2] + 1;
1556 for (i = 0; i < len; i++) {
1560 mode |= SILC_CHANNEL_UMODE_CHANFO;
1561 mode |= SILC_CHANNEL_UMODE_CHANOP;
1562 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1563 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1564 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1566 mode = SILC_CHANNEL_UMODE_NONE;
1571 if (cmd->argc == 5) {
1572 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1573 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1574 cmd->client->private_key,
1580 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1581 cmd->argv[4], cmd->argv_lens[4]);
1584 mode |= SILC_CHANNEL_UMODE_CHANFO;
1586 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1591 mode |= SILC_CHANNEL_UMODE_CHANOP;
1593 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1597 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1599 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1603 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1605 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1609 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1611 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1614 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1620 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1621 SILC_PUT32_MSB(mode, modebuf);
1622 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1624 /* Send the command packet. We support sending only one mode at once
1625 that requires an argument. */
1626 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1628 1, chidp->data, chidp->len,
1630 3, clidp->data, clidp->len,
1631 4, auth ? auth->data : NULL,
1632 auth ? auth->len : 0);
1634 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1635 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1636 silc_buffer_free(buffer);
1637 silc_buffer_free(chidp);
1638 silc_buffer_free(clidp);
1640 silc_buffer_free(auth);
1642 /* Notify application */
1643 COMMAND(SILC_STATUS_OK);
1646 silc_free(nickname);
1647 silc_client_command_free(cmd);
1650 /* KICK command. Kicks a client out of channel. */
1652 SILC_CLIENT_CMD_FUNC(kick)
1654 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1655 SilcClient client = cmd->client;
1656 SilcClientConnection conn = cmd->conn;
1657 SilcIDCacheEntry id_cache = NULL;
1658 SilcChannelEntry channel;
1659 SilcBuffer buffer, idp, idp2;
1660 SilcClientEntry target;
1662 char *nickname = NULL;
1665 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1666 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1670 if (cmd->argc < 3) {
1671 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1672 "Usage: /KICK <channel> <nickname> [<comment>]");
1673 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1677 if (cmd->argv[1][0] == '*') {
1678 if (!conn->current_channel) {
1679 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1680 "You are not on any channel");
1681 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1684 name = conn->current_channel->channel_name;
1686 name = cmd->argv[1];
1689 if (!conn->current_channel) {
1690 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1691 "You are not on that 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 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1699 "You are not on that channel");
1700 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1704 channel = (SilcChannelEntry)id_cache->context;
1706 /* Parse the typed nickname. */
1707 if (client->internal->params->nickname_parse)
1708 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1710 nickname = strdup(cmd->argv[2]);
1712 /* Get the target client */
1713 target = silc_idlist_get_client(cmd->client, conn, nickname,
1714 cmd->argv[2], FALSE);
1716 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1717 "No such client: %s", cmd->argv[2]);
1718 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1722 /* Send KICK command to the server */
1723 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1724 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1726 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1727 1, idp->data, idp->len,
1728 2, idp2->data, idp2->len);
1730 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1731 1, idp->data, idp->len,
1732 2, idp2->data, idp2->len,
1734 strlen(cmd->argv[3]));
1735 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1736 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1737 silc_buffer_free(buffer);
1738 silc_buffer_free(idp);
1739 silc_buffer_free(idp2);
1741 /* Notify application */
1742 COMMAND(SILC_STATUS_OK);
1745 silc_free(nickname);
1746 silc_client_command_free(cmd);
1749 static void silc_client_command_oper_send(unsigned char *data,
1750 SilcUInt32 data_len, void *context)
1752 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1753 SilcClientConnection conn = cmd->conn;
1754 SilcBuffer buffer, auth;
1756 if (cmd->argc >= 3) {
1757 /* Encode the public key authentication payload */
1758 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1759 cmd->client->private_key,
1760 cmd->client->rng, conn->hash,
1764 /* Encode the password authentication payload */
1765 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1769 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1771 strlen(cmd->argv[1]),
1772 2, auth->data, auth->len);
1773 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1774 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1776 silc_buffer_free(buffer);
1777 silc_buffer_free(auth);
1779 /* Notify application */
1780 COMMAND(SILC_STATUS_OK);
1783 /* OPER command. Used to obtain server operator privileges. */
1785 SILC_CLIENT_CMD_FUNC(oper)
1787 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1788 SilcClientConnection conn = cmd->conn;
1791 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1792 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1796 if (cmd->argc < 2) {
1797 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1798 "Usage: /OPER <username> [-pubkey]");
1799 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1803 if (cmd->argc < 3) {
1804 /* Get passphrase */
1805 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1806 silc_client_command_oper_send,
1811 silc_client_command_oper_send(NULL, 0, context);
1814 silc_client_command_free(cmd);
1817 static void silc_client_command_silcoper_send(unsigned char *data,
1818 SilcUInt32 data_len,
1821 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1822 SilcClientConnection conn = cmd->conn;
1823 SilcBuffer buffer, auth;
1825 if (cmd->argc >= 3) {
1826 /* Encode the public key authentication payload */
1827 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1828 cmd->client->private_key,
1829 cmd->client->rng, conn->hash,
1833 /* Encode the password authentication payload */
1834 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1838 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1840 strlen(cmd->argv[1]),
1841 2, auth->data, auth->len);
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 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1914 "You are not on any channel");
1915 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1919 channel = conn->current_channel;
1921 name = cmd->argv[1];
1923 channel = silc_client_get_channel(cmd->client, conn, name);
1925 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1926 "You are noton that channel");
1927 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1932 if (cmd->argc == 3) {
1933 if (cmd->argv[2][0] == '+')
1942 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1944 /* Send the command */
1945 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1946 ++conn->cmd_ident, 2,
1947 1, chidp->data, chidp->len,
1948 type, ban, ban ? strlen(ban) : 0);
1949 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1950 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1951 silc_buffer_free(buffer);
1952 silc_buffer_free(chidp);
1954 /* Notify application */
1955 COMMAND(SILC_STATUS_OK);
1958 silc_client_command_free(cmd);
1961 /* Command DETACH. This is used to detach from the server */
1963 SILC_CLIENT_CMD_FUNC(detach)
1965 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1966 SilcClientConnection conn = cmd->conn;
1970 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1971 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1975 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1976 ++conn->cmd_ident, 0);
1977 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1978 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1979 silc_buffer_free(buffer);
1981 /* Notify application */
1982 COMMAND(SILC_STATUS_OK);
1985 silc_client_command_free(cmd);
1988 /* Command WATCH. */
1990 SILC_CLIENT_CMD_FUNC(watch)
1992 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1993 SilcClientConnection conn = cmd->conn;
1994 SilcBuffer buffer, idp = NULL;
1998 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1999 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2003 if (cmd->argc < 3) {
2004 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2008 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2010 if (!strcasecmp(cmd->argv[1], "-add")) {
2012 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2015 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2019 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2020 ++conn->cmd_ident, 2,
2021 1, idp->data, idp->len,
2024 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2025 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2026 silc_buffer_free(buffer);
2028 /* Notify application */
2029 COMMAND(SILC_STATUS_OK);
2033 silc_buffer_free(idp);
2034 silc_client_command_free(cmd);
2037 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2039 SILC_CLIENT_CMD_FUNC(leave)
2041 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2042 SilcClientConnection conn = cmd->conn;
2043 SilcChannelEntry channel;
2044 SilcChannelUser chu;
2045 SilcBuffer buffer, idp;
2049 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2050 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2054 if (cmd->argc != 2) {
2055 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2056 "Usage: /LEAVE <channel>");
2057 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2061 if (cmd->argv[1][0] == '*') {
2062 if (!conn->current_channel) {
2063 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2064 "You are not on any channel");
2065 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2068 name = conn->current_channel->channel_name;
2070 name = cmd->argv[1];
2073 /* Get the channel entry */
2074 channel = silc_client_get_channel(cmd->client, conn, name);
2076 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2077 "You are not on that channel");
2078 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2082 /* Remove us from channel */
2083 chu = silc_client_on_channel(channel, conn->local_entry);
2085 silc_hash_table_del(chu->client->channels, chu->channel);
2086 silc_hash_table_del(chu->channel->user_list, chu->client);
2090 /* Send LEAVE command to the server */
2091 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2092 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2093 1, idp->data, idp->len);
2094 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2095 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2096 silc_buffer_free(buffer);
2097 silc_buffer_free(idp);
2099 /* Notify application */
2100 COMMAND(SILC_STATUS_OK);
2102 if (conn->current_channel == channel)
2103 conn->current_channel = NULL;
2105 silc_client_del_channel(cmd->client, cmd->conn, channel);
2108 silc_client_command_free(cmd);
2111 /* Command USERS. Requests the USERS of the clients joined on requested
2114 SILC_CLIENT_CMD_FUNC(users)
2116 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2117 SilcClientConnection conn = cmd->conn;
2122 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2123 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2127 if (cmd->argc != 2) {
2128 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2129 "Usage: /USERS <channel>");
2130 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2134 if (cmd->argv[1][0] == '*') {
2135 if (!conn->current_channel) {
2136 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2137 "You are not on any channel");
2138 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2141 name = conn->current_channel->channel_name;
2143 name = cmd->argv[1];
2146 /* Send USERS command to the server */
2147 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2148 ++conn->cmd_ident, 1,
2149 2, name, strlen(name));
2150 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2151 NULL, 0, NULL, NULL, buffer->data,
2153 silc_buffer_free(buffer);
2155 /* Notify application */
2156 COMMAND(SILC_STATUS_OK);
2159 silc_client_command_free(cmd);
2162 /* Command GETKEY. Used to fetch remote client's public key. */
2164 SILC_CLIENT_CMD_FUNC(getkey)
2166 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2167 SilcClientConnection conn = cmd->conn;
2168 SilcClient client = cmd->client;
2169 SilcClientEntry client_entry = NULL;
2170 SilcServerEntry server_entry = NULL;
2171 char *nickname = NULL;
2172 SilcBuffer idp, buffer;
2174 SILC_LOG_DEBUG(("Start"));
2177 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2178 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2182 if (cmd->argc < 2) {
2183 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2184 "Usage: /GETKEY <nickname or server name>");
2185 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2189 /* Parse the typed nickname. */
2190 if (client->internal->params->nickname_parse)
2191 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2193 nickname = strdup(cmd->argv[1]);
2195 /* Find client entry */
2196 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2198 if (!client_entry) {
2199 /* Check whether user requested server actually */
2200 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2202 if (!server_entry) {
2203 /* No. what ever user wants we don't have it, so resolve it. We
2204 will first try to resolve the client, and if that fails then
2205 we'll try to resolve the server. */
2207 if (!cmd->pending) {
2208 /* This will send the IDENTIFY command for nickname */
2209 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2210 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2212 silc_client_command_getkey,
2213 silc_client_command_dup(cmd));
2217 SilcClientCommandReplyContext reply =
2218 (SilcClientCommandReplyContext)context2;
2221 /* If nickname was not found, then resolve the server. */
2222 silc_command_get_status(reply->payload, NULL, &error);
2223 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2224 /* This sends the IDENTIFY command to resolve the server. */
2225 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2227 silc_client_command_reply_identify_i, 0,
2229 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2231 2, cmd->argv[1], cmd->argv_lens[1]);
2232 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2234 silc_client_command_getkey,
2235 silc_client_command_dup(cmd));
2239 /* If server was not found, then we've resolved both nickname and
2240 server and did not find anybody. */
2241 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2242 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2243 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2244 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2245 silc_get_status_message(error));
2246 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2250 COMMAND_ERROR(error);
2255 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2257 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2260 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2261 1, idp->data, idp->len);
2262 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2263 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2264 silc_buffer_free(buffer);
2265 silc_buffer_free(idp);
2267 /* Notify application */
2268 COMMAND(SILC_STATUS_OK);
2271 silc_free(nickname);
2272 silc_client_command_free(cmd);
2275 /* Register a new command indicated by the `command' to the SILC client.
2276 The `name' is optional command name. If provided the command may be
2277 searched using the silc_client_command_find by that name. The
2278 `command_function' is the function to be called when the command is
2279 executed, and the `command_reply_function' is the function to be
2280 called after the server has sent reply back to the command.
2282 The `ident' is optional identifier for the command. If non-zero
2283 the `command_reply_function' for the command type `command' will be
2284 called only if the command reply sent by server includes the
2285 command identifier `ident'. Application usually does not need it
2286 and set it to zero value. */
2288 bool silc_client_command_register(SilcClient client,
2289 SilcCommand command,
2291 SilcCommandCb command_function,
2292 SilcCommandCb command_reply_function,
2296 SilcClientCommand cmd;
2298 cmd = silc_calloc(1, sizeof(*cmd));
2300 cmd->command = command_function;
2301 cmd->reply = command_reply_function;
2302 cmd->name = name ? strdup(name) : NULL;
2303 cmd->max_args = max_args;
2306 silc_list_add(client->internal->commands, cmd);
2311 /* Unregister a command indicated by the `command' with command function
2312 `command_function' and command reply function `command_reply_function'.
2313 Returns TRUE if the command was found and unregistered. */
2315 bool silc_client_command_unregister(SilcClient client,
2316 SilcCommand command,
2317 SilcCommandCb command_function,
2318 SilcCommandCb command_reply_function,
2321 SilcClientCommand cmd;
2323 silc_list_start(client->internal->commands);
2324 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2325 if (cmd->cmd == command && cmd->command == command_function &&
2326 cmd->reply == command_reply_function && cmd->ident == ident) {
2327 silc_list_del(client->internal->commands, cmd);
2328 silc_free(cmd->name);
2337 /* Private range commands, specific to this implementation (and compatible
2338 with SILC Server). */
2340 /* CONNECT command. Connects the server to another server. */
2342 SILC_CLIENT_CMD_FUNC(connect)
2344 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2345 SilcClientConnection conn = cmd->conn;
2347 unsigned char port[4];
2351 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2352 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2356 if (cmd->argc < 2) {
2357 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2358 "Usage: /CONNECT <server> [<port>]");
2359 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2363 if (cmd->argc == 3) {
2364 tmp = atoi(cmd->argv[2]);
2365 SILC_PUT32_MSB(tmp, port);
2369 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2371 strlen(cmd->argv[1]),
2374 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2376 strlen(cmd->argv[1]));
2377 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2378 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2379 silc_buffer_free(buffer);
2381 /* Notify application */
2382 COMMAND(SILC_STATUS_OK);
2385 silc_client_command_free(cmd);
2389 /* CLOSE command. Close server connection to the remote server */
2391 SILC_CLIENT_CMD_FUNC(close)
2393 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2394 SilcClientConnection conn = cmd->conn;
2396 unsigned char port[4];
2400 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2405 if (cmd->argc < 2) {
2406 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2407 "Usage: /CLOSE <server> [<port>]");
2408 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2412 if (cmd->argc == 3) {
2413 tmp = atoi(cmd->argv[2]);
2414 SILC_PUT32_MSB(tmp, port);
2418 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2420 strlen(cmd->argv[1]),
2423 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2425 strlen(cmd->argv[1]));
2426 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2427 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2428 silc_buffer_free(buffer);
2430 /* Notify application */
2431 COMMAND(SILC_STATUS_OK);
2434 silc_client_command_free(cmd);
2437 /* SHUTDOWN command. Shutdowns the server. */
2439 SILC_CLIENT_CMD_FUNC(shutdown)
2441 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2444 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2445 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2449 /* Send the command */
2450 silc_client_command_send(cmd->client, cmd->conn,
2451 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2453 /* Notify application */
2454 COMMAND(SILC_STATUS_OK);
2457 silc_client_command_free(cmd);
2460 /* Register all default commands provided by the client library for the
2463 void silc_client_commands_register(SilcClient client)
2465 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2468 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2469 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2470 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2471 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2472 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2473 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2474 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2475 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2476 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2477 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2478 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2479 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2480 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2481 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2482 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2483 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2484 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2485 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2486 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2487 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2488 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2489 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2490 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2491 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2492 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2494 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2495 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2496 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2499 /* Unregister all commands. */
2501 void silc_client_commands_unregister(SilcClient client)
2503 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2504 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2505 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2506 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2507 SILC_CLIENT_CMDU(list, LIST, "LIST");
2508 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2509 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2510 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2511 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2512 SILC_CLIENT_CMDU(info, INFO, "INFO");
2513 SILC_CLIENT_CMDU(ping, PING, "PING");
2514 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2515 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2516 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2517 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2518 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2519 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2520 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2521 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2522 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2523 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2524 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2525 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2526 SILC_CLIENT_CMDU(users, USERS, "USERS");
2527 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2529 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2530 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2531 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");