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")) {
995 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
996 cmd->client->private_key,
998 cmd->client->internal->
1004 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1005 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1006 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1007 cmd->argv_lens[i], 0);
1008 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1009 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1010 0, pu8, passphrase_len);
1013 passphrase = strdup(cmd->argv[i]);
1014 passphrase_len = cmd->argv_lens[i];
1019 /* Send JOIN command to the server */
1021 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1022 1, name, strlen(name),
1023 2, idp->data, idp->len,
1024 3, passphrase, passphrase_len,
1025 4, cipher, cipher ? strlen(cipher) : 0,
1026 5, hmac, hmac ? strlen(hmac) : 0,
1027 6, auth ? auth->data : NULL,
1028 auth ? auth->len : 0);
1029 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1030 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1031 silc_buffer_free(buffer);
1032 silc_buffer_free(idp);
1034 silc_buffer_free(auth);
1035 silc_free(passphrase);
1037 /* Notify application */
1038 COMMAND(SILC_STATUS_OK);
1041 silc_client_command_free(cmd);
1044 /* MOTD command. Requests motd from server. */
1046 SILC_CLIENT_CMD_FUNC(motd)
1048 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1049 SilcClientConnection conn = cmd->conn;
1053 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1054 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1058 if (cmd->argc < 1 || cmd->argc > 2) {
1059 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1060 "Usage: /MOTD [<server>]");
1061 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1062 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1066 /* Send TOPIC command to the server */
1068 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1069 1, conn->remote_host,
1070 strlen(conn->remote_host));
1072 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1075 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1076 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1077 silc_buffer_free(buffer);
1079 /* Notify application */
1080 COMMAND(SILC_STATUS_OK);
1083 silc_client_command_free(cmd);
1086 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1087 modes as client cannot set itself server/router operator privileges. */
1089 SILC_CLIENT_CMD_FUNC(umode)
1091 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1092 SilcClientConnection conn = cmd->conn;
1093 SilcBuffer buffer, idp;
1094 unsigned char *cp, modebuf[4];
1095 SilcUInt32 mode, add, len;
1099 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1100 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1104 if (cmd->argc < 2) {
1105 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1106 "Usage: /UMODE +|-<modes>");
1107 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1111 mode = conn->local_entry->mode;
1113 /* Are we adding or removing mode */
1114 if (cmd->argv[1][0] == '-')
1120 cp = cmd->argv[1] + 1;
1122 for (i = 0; i < len; i++) {
1127 mode |= SILC_UMODE_SERVER_OPERATOR;
1128 mode |= SILC_UMODE_ROUTER_OPERATOR;
1129 mode |= SILC_UMODE_GONE;
1130 mode |= SILC_UMODE_INDISPOSED;
1131 mode |= SILC_UMODE_BUSY;
1132 mode |= SILC_UMODE_PAGE;
1133 mode |= SILC_UMODE_HYPER;
1134 mode |= SILC_UMODE_ROBOT;
1135 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1136 mode |= SILC_UMODE_REJECT_WATCHING;
1138 mode = SILC_UMODE_NONE;
1143 mode |= SILC_UMODE_SERVER_OPERATOR;
1145 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1149 mode |= SILC_UMODE_ROUTER_OPERATOR;
1151 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1155 mode |= SILC_UMODE_GONE;
1157 mode &= ~SILC_UMODE_GONE;
1161 mode |= SILC_UMODE_INDISPOSED;
1163 mode &= ~SILC_UMODE_INDISPOSED;
1167 mode |= SILC_UMODE_BUSY;
1169 mode &= ~SILC_UMODE_BUSY;
1173 mode |= SILC_UMODE_PAGE;
1175 mode &= ~SILC_UMODE_PAGE;
1179 mode |= SILC_UMODE_HYPER;
1181 mode &= ~SILC_UMODE_HYPER;
1185 mode |= SILC_UMODE_ROBOT;
1187 mode &= ~SILC_UMODE_ROBOT;
1191 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1193 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1197 mode |= SILC_UMODE_REJECT_WATCHING;
1199 mode &= ~SILC_UMODE_REJECT_WATCHING;
1203 mode |= SILC_UMODE_BLOCK_INVITE;
1205 mode &= ~SILC_UMODE_BLOCK_INVITE;
1208 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1214 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1215 SILC_PUT32_MSB(mode, modebuf);
1217 /* Send the command packet. We support sending only one mode at once
1218 that requires an argument. */
1220 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1221 1, idp->data, idp->len,
1222 2, modebuf, sizeof(modebuf));
1223 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1224 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1225 silc_buffer_free(buffer);
1226 silc_buffer_free(idp);
1228 /* Notify application */
1229 COMMAND(SILC_STATUS_OK);
1232 silc_client_command_free(cmd);
1235 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1236 can be set several at once. Those modes that require argument must be set
1237 separately (unless set with modes that does not require arguments). */
1239 SILC_CLIENT_CMD_FUNC(cmode)
1241 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1242 SilcClientConnection conn = cmd->conn;
1243 SilcChannelEntry channel;
1244 SilcBuffer buffer, chidp, auth = NULL;
1245 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1246 SilcUInt32 mode, add, type, len, arg_len = 0;
1250 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1251 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1255 if (cmd->argc < 3) {
1256 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1257 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1258 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1262 if (cmd->argv[1][0] == '*') {
1263 if (!conn->current_channel) {
1264 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1265 "You are not on any channel");
1266 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1270 channel = conn->current_channel;
1272 name = cmd->argv[1];
1274 channel = silc_client_get_channel(cmd->client, conn, name);
1276 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1277 "You are on that channel");
1278 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1283 mode = channel->mode;
1285 /* Are we adding or removing mode */
1286 if (cmd->argv[2][0] == '-')
1291 /* Argument type to be sent to server */
1295 cp = cmd->argv[2] + 1;
1297 for (i = 0; i < len; i++) {
1301 mode |= SILC_CHANNEL_MODE_PRIVATE;
1303 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1307 mode |= SILC_CHANNEL_MODE_SECRET;
1309 mode &= ~SILC_CHANNEL_MODE_SECRET;
1313 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1315 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1319 mode |= SILC_CHANNEL_MODE_INVITE;
1321 mode &= ~SILC_CHANNEL_MODE_INVITE;
1325 mode |= SILC_CHANNEL_MODE_TOPIC;
1327 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1331 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1333 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1337 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1339 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1344 mode |= SILC_CHANNEL_MODE_ULIMIT;
1346 if (cmd->argc < 4) {
1347 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1348 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1349 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1352 ll = atoi(cmd->argv[3]);
1353 SILC_PUT32_MSB(ll, tmp);
1357 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1362 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1364 if (cmd->argc < 4) {
1365 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1366 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1367 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1371 arg_len = cmd->argv_lens[3];
1373 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1378 mode |= SILC_CHANNEL_MODE_CIPHER;
1380 if (cmd->argc < 4) {
1381 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1382 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1383 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1387 arg_len = cmd->argv_lens[3];
1389 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1394 mode |= SILC_CHANNEL_MODE_HMAC;
1396 if (cmd->argc < 4) {
1397 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1398 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1399 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1403 arg_len = cmd->argv_lens[3];
1405 mode &= ~SILC_CHANNEL_MODE_HMAC;
1410 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1412 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1413 cmd->client->private_key,
1415 cmd->client->internal->
1420 arg_len = auth->len;
1422 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1426 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1432 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1433 SILC_PUT32_MSB(mode, modebuf);
1435 /* Send the command packet. We support sending only one mode at once
1436 that requires an argument. */
1439 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1440 1, chidp->data, chidp->len,
1441 2, modebuf, sizeof(modebuf),
1442 type, arg, arg_len);
1445 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1446 1, chidp->data, chidp->len,
1447 2, modebuf, sizeof(modebuf));
1450 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1451 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1452 silc_buffer_free(buffer);
1453 silc_buffer_free(chidp);
1455 silc_buffer_free(auth);
1457 /* Notify application */
1458 COMMAND(SILC_STATUS_OK);
1461 silc_client_command_free(cmd);
1464 /* CUMODE command. Changes client's mode on a channel. */
1466 SILC_CLIENT_CMD_FUNC(cumode)
1468 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1469 SilcClient client = cmd->client;
1470 SilcClientConnection conn = cmd->conn;
1471 SilcChannelEntry channel;
1472 SilcChannelUser chu;
1473 SilcClientEntry client_entry;
1474 SilcBuffer buffer, clidp, chidp, auth = NULL;
1475 unsigned char *name, *cp, modebuf[4];
1476 SilcUInt32 mode = 0, add, len;
1477 char *nickname = NULL;
1481 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1482 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1486 if (cmd->argc < 4) {
1487 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1488 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1489 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1493 if (cmd->argv[1][0] == '*') {
1494 if (!conn->current_channel) {
1495 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1496 "You are not on any channel");
1497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1501 channel = conn->current_channel;
1503 name = cmd->argv[1];
1505 channel = silc_client_get_channel(cmd->client, conn, name);
1507 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1508 "You are on that channel");
1509 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1514 /* Parse the typed nickname. */
1515 if (client->internal->params->nickname_parse)
1516 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1518 nickname = strdup(cmd->argv[3]);
1520 /* Find client entry */
1521 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1522 cmd->argv[3], TRUE);
1523 if (!client_entry) {
1525 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1529 /* Client entry not found, it was requested thus mark this to be
1531 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1533 silc_client_command_cumode,
1534 silc_client_command_dup(cmd));
1539 /* Get the current mode */
1540 chu = silc_client_on_channel(channel, client_entry);
1544 /* Are we adding or removing mode */
1545 if (cmd->argv[2][0] == '-')
1551 cp = cmd->argv[2] + 1;
1553 for (i = 0; i < len; i++) {
1557 mode |= SILC_CHANNEL_UMODE_CHANFO;
1558 mode |= SILC_CHANNEL_UMODE_CHANOP;
1559 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1560 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1561 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1563 mode = SILC_CHANNEL_UMODE_NONE;
1568 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1569 cmd->client->private_key,
1571 cmd->client->internal->
1575 mode |= SILC_CHANNEL_UMODE_CHANFO;
1577 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1582 mode |= SILC_CHANNEL_UMODE_CHANOP;
1584 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1588 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1590 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1594 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1596 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1600 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1602 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1605 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1611 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1612 SILC_PUT32_MSB(mode, modebuf);
1613 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1615 /* Send the command packet. We support sending only one mode at once
1616 that requires an argument. */
1617 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1619 1, chidp->data, chidp->len,
1621 3, clidp->data, clidp->len,
1622 4, auth ? auth->data : NULL,
1623 auth ? auth->len : 0);
1625 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1626 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1627 silc_buffer_free(buffer);
1628 silc_buffer_free(chidp);
1629 silc_buffer_free(clidp);
1631 silc_buffer_free(auth);
1633 /* Notify application */
1634 COMMAND(SILC_STATUS_OK);
1637 silc_free(nickname);
1638 silc_client_command_free(cmd);
1641 /* KICK command. Kicks a client out of channel. */
1643 SILC_CLIENT_CMD_FUNC(kick)
1645 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1646 SilcClient client = cmd->client;
1647 SilcClientConnection conn = cmd->conn;
1648 SilcIDCacheEntry id_cache = NULL;
1649 SilcChannelEntry channel;
1650 SilcBuffer buffer, idp, idp2;
1651 SilcClientEntry target;
1653 char *nickname = NULL;
1656 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1657 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1661 if (cmd->argc < 3) {
1662 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1663 "Usage: /KICK <channel> <nickname> [<comment>]");
1664 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1668 if (cmd->argv[1][0] == '*') {
1669 if (!conn->current_channel) {
1670 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1671 "You are not on any channel");
1672 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1675 name = conn->current_channel->channel_name;
1677 name = cmd->argv[1];
1680 if (!conn->current_channel) {
1681 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1682 "You are not on that channel");
1683 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1687 /* Get the Channel ID of the channel */
1688 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1689 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1690 "You are not on that channel");
1691 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1695 channel = (SilcChannelEntry)id_cache->context;
1697 /* Parse the typed nickname. */
1698 if (client->internal->params->nickname_parse)
1699 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1701 nickname = strdup(cmd->argv[2]);
1703 /* Get the target client */
1704 target = silc_idlist_get_client(cmd->client, conn, nickname,
1705 cmd->argv[2], FALSE);
1707 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1708 "No such client: %s", cmd->argv[2]);
1709 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1713 /* Send KICK command to the server */
1714 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1715 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1717 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1718 1, idp->data, idp->len,
1719 2, idp2->data, idp2->len);
1721 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1722 1, idp->data, idp->len,
1723 2, idp2->data, idp2->len,
1725 strlen(cmd->argv[3]));
1726 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1727 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1728 silc_buffer_free(buffer);
1729 silc_buffer_free(idp);
1730 silc_buffer_free(idp2);
1732 /* Notify application */
1733 COMMAND(SILC_STATUS_OK);
1736 silc_free(nickname);
1737 silc_client_command_free(cmd);
1740 static void silc_client_command_oper_send(unsigned char *data,
1741 SilcUInt32 data_len, void *context)
1743 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1744 SilcClientConnection conn = cmd->conn;
1745 SilcBuffer buffer, auth;
1747 if (cmd->argc >= 3) {
1748 /* Encode the public key authentication payload */
1749 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1750 cmd->client->private_key,
1751 cmd->client->rng, conn->hash,
1755 /* Encode the password authentication payload */
1756 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1760 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1762 strlen(cmd->argv[1]),
1763 2, auth->data, auth->len);
1764 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1765 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1767 silc_buffer_free(buffer);
1768 silc_buffer_free(auth);
1770 /* Notify application */
1771 COMMAND(SILC_STATUS_OK);
1774 /* OPER command. Used to obtain server operator privileges. */
1776 SILC_CLIENT_CMD_FUNC(oper)
1778 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1779 SilcClientConnection conn = cmd->conn;
1782 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1783 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1787 if (cmd->argc < 2) {
1788 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1789 "Usage: /OPER <username> [-pubkey]");
1790 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1794 if (cmd->argc < 3) {
1795 /* Get passphrase */
1796 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1797 silc_client_command_oper_send,
1802 silc_client_command_oper_send(NULL, 0, context);
1805 silc_client_command_free(cmd);
1808 static void silc_client_command_silcoper_send(unsigned char *data,
1809 SilcUInt32 data_len,
1812 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1813 SilcClientConnection conn = cmd->conn;
1814 SilcBuffer buffer, auth;
1816 if (cmd->argc >= 3) {
1817 /* Encode the public key authentication payload */
1818 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1819 cmd->client->private_key,
1820 cmd->client->rng, conn->hash,
1824 /* Encode the password authentication payload */
1825 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1829 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1831 strlen(cmd->argv[1]),
1832 2, auth->data, auth->len);
1833 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1834 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1836 silc_buffer_free(buffer);
1837 silc_buffer_free(auth);
1839 /* Notify application */
1840 COMMAND(SILC_STATUS_OK);
1843 /* SILCOPER command. Used to obtain router operator privileges. */
1845 SILC_CLIENT_CMD_FUNC(silcoper)
1847 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1848 SilcClientConnection conn = cmd->conn;
1851 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1852 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1856 if (cmd->argc < 2) {
1857 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1858 "Usage: /SILCOPER <username> [-pubkey]");
1859 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1863 if (cmd->argc < 3) {
1864 /* Get passphrase */
1865 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1866 silc_client_command_silcoper_send,
1871 silc_client_command_silcoper_send(NULL, 0, context);
1874 silc_client_command_free(cmd);
1877 /* Command BAN. This is used to manage the ban list of the channel. */
1879 SILC_CLIENT_CMD_FUNC(ban)
1881 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1882 SilcClientConnection conn = cmd->conn;
1883 SilcChannelEntry channel;
1884 SilcBuffer buffer, chidp;
1886 char *name, *ban = NULL;
1889 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1890 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1894 if (cmd->argc < 2) {
1895 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1896 "Usage: /BAN <channel> "
1897 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1898 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1902 if (cmd->argv[1][0] == '*') {
1903 if (!conn->current_channel) {
1904 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1905 "You are not on any channel");
1906 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1910 channel = conn->current_channel;
1912 name = cmd->argv[1];
1914 channel = silc_client_get_channel(cmd->client, conn, name);
1916 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1917 "You are noton that channel");
1918 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1923 if (cmd->argc == 3) {
1924 if (cmd->argv[2][0] == '+')
1933 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1935 /* Send the command */
1936 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1937 ++conn->cmd_ident, 2,
1938 1, chidp->data, chidp->len,
1939 type, ban, ban ? strlen(ban) : 0);
1940 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1941 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1942 silc_buffer_free(buffer);
1943 silc_buffer_free(chidp);
1945 /* Notify application */
1946 COMMAND(SILC_STATUS_OK);
1949 silc_client_command_free(cmd);
1952 /* Command DETACH. This is used to detach from the server */
1954 SILC_CLIENT_CMD_FUNC(detach)
1956 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1957 SilcClientConnection conn = cmd->conn;
1961 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1962 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1966 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1967 ++conn->cmd_ident, 0);
1968 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1969 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1970 silc_buffer_free(buffer);
1972 /* Notify application */
1973 COMMAND(SILC_STATUS_OK);
1976 silc_client_command_free(cmd);
1979 /* Command WATCH. */
1981 SILC_CLIENT_CMD_FUNC(watch)
1983 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1984 SilcClientConnection conn = cmd->conn;
1985 SilcBuffer buffer, idp = NULL;
1989 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1990 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1994 if (cmd->argc < 3) {
1995 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1999 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2001 if (!strcasecmp(cmd->argv[1], "-add")) {
2003 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2006 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2010 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2011 ++conn->cmd_ident, 2,
2012 1, idp->data, idp->len,
2015 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2016 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2017 silc_buffer_free(buffer);
2019 /* Notify application */
2020 COMMAND(SILC_STATUS_OK);
2024 silc_buffer_free(idp);
2025 silc_client_command_free(cmd);
2028 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2030 SILC_CLIENT_CMD_FUNC(leave)
2032 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2033 SilcClientConnection conn = cmd->conn;
2034 SilcChannelEntry channel;
2035 SilcChannelUser chu;
2036 SilcBuffer buffer, idp;
2040 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2041 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2045 if (cmd->argc != 2) {
2046 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2047 "Usage: /LEAVE <channel>");
2048 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2052 if (cmd->argv[1][0] == '*') {
2053 if (!conn->current_channel) {
2054 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2055 "You are not on any channel");
2056 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2059 name = conn->current_channel->channel_name;
2061 name = cmd->argv[1];
2064 /* Get the channel entry */
2065 channel = silc_client_get_channel(cmd->client, conn, name);
2067 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2068 "You are not on that channel");
2069 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2073 /* Remove us from channel */
2074 chu = silc_client_on_channel(channel, conn->local_entry);
2076 silc_hash_table_del(chu->client->channels, chu->channel);
2077 silc_hash_table_del(chu->channel->user_list, chu->client);
2081 /* Send LEAVE command to the server */
2082 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2083 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2084 1, idp->data, idp->len);
2085 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2086 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2087 silc_buffer_free(buffer);
2088 silc_buffer_free(idp);
2090 /* Notify application */
2091 COMMAND(SILC_STATUS_OK);
2093 if (conn->current_channel == channel)
2094 conn->current_channel = NULL;
2096 silc_client_del_channel(cmd->client, cmd->conn, channel);
2099 silc_client_command_free(cmd);
2102 /* Command USERS. Requests the USERS of the clients joined on requested
2105 SILC_CLIENT_CMD_FUNC(users)
2107 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2108 SilcClientConnection conn = cmd->conn;
2113 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2114 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2118 if (cmd->argc != 2) {
2119 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2120 "Usage: /USERS <channel>");
2121 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2125 if (cmd->argv[1][0] == '*') {
2126 if (!conn->current_channel) {
2127 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2128 "You are not on any channel");
2129 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2132 name = conn->current_channel->channel_name;
2134 name = cmd->argv[1];
2137 /* Send USERS command to the server */
2138 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2139 ++conn->cmd_ident, 1,
2140 2, name, strlen(name));
2141 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2142 NULL, 0, NULL, NULL, buffer->data,
2144 silc_buffer_free(buffer);
2146 /* Notify application */
2147 COMMAND(SILC_STATUS_OK);
2150 silc_client_command_free(cmd);
2153 /* Command GETKEY. Used to fetch remote client's public key. */
2155 SILC_CLIENT_CMD_FUNC(getkey)
2157 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2158 SilcClientConnection conn = cmd->conn;
2159 SilcClient client = cmd->client;
2160 SilcClientEntry client_entry = NULL;
2161 SilcServerEntry server_entry = NULL;
2162 char *nickname = NULL;
2163 SilcBuffer idp, buffer;
2165 SILC_LOG_DEBUG(("Start"));
2168 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2169 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2173 if (cmd->argc < 2) {
2174 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2175 "Usage: /GETKEY <nickname or server name>");
2176 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2180 /* Parse the typed nickname. */
2181 if (client->internal->params->nickname_parse)
2182 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2184 nickname = strdup(cmd->argv[1]);
2186 /* Find client entry */
2187 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2189 if (!client_entry) {
2190 /* Check whether user requested server actually */
2191 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2193 if (!server_entry) {
2194 /* No. what ever user wants we don't have it, so resolve it. We
2195 will first try to resolve the client, and if that fails then
2196 we'll try to resolve the server. */
2198 if (!cmd->pending) {
2199 /* This will send the IDENTIFY command for nickname */
2200 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2201 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2203 silc_client_command_getkey,
2204 silc_client_command_dup(cmd));
2208 SilcClientCommandReplyContext reply =
2209 (SilcClientCommandReplyContext)context2;
2212 /* If nickname was not found, then resolve the server. */
2213 silc_command_get_status(reply->payload, NULL, &error);
2214 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2215 /* This sends the IDENTIFY command to resolve the server. */
2216 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2218 silc_client_command_reply_identify_i, 0,
2220 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2222 2, cmd->argv[1], cmd->argv_lens[1]);
2223 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2225 silc_client_command_getkey,
2226 silc_client_command_dup(cmd));
2230 /* If server was not found, then we've resolved both nickname and
2231 server and did not find anybody. */
2232 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2233 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2234 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2235 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2236 silc_get_status_message(error));
2237 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2241 COMMAND_ERROR(error);
2246 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2248 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2251 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2252 1, idp->data, idp->len);
2253 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2254 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2255 silc_buffer_free(buffer);
2256 silc_buffer_free(idp);
2258 /* Notify application */
2259 COMMAND(SILC_STATUS_OK);
2262 silc_free(nickname);
2263 silc_client_command_free(cmd);
2266 /* Register a new command indicated by the `command' to the SILC client.
2267 The `name' is optional command name. If provided the command may be
2268 searched using the silc_client_command_find by that name. The
2269 `command_function' is the function to be called when the command is
2270 executed, and the `command_reply_function' is the function to be
2271 called after the server has sent reply back to the command.
2273 The `ident' is optional identifier for the command. If non-zero
2274 the `command_reply_function' for the command type `command' will be
2275 called only if the command reply sent by server includes the
2276 command identifier `ident'. Application usually does not need it
2277 and set it to zero value. */
2279 bool silc_client_command_register(SilcClient client,
2280 SilcCommand command,
2282 SilcCommandCb command_function,
2283 SilcCommandCb command_reply_function,
2287 SilcClientCommand cmd;
2289 cmd = silc_calloc(1, sizeof(*cmd));
2291 cmd->command = command_function;
2292 cmd->reply = command_reply_function;
2293 cmd->name = name ? strdup(name) : NULL;
2294 cmd->max_args = max_args;
2297 silc_list_add(client->internal->commands, cmd);
2302 /* Unregister a command indicated by the `command' with command function
2303 `command_function' and command reply function `command_reply_function'.
2304 Returns TRUE if the command was found and unregistered. */
2306 bool silc_client_command_unregister(SilcClient client,
2307 SilcCommand command,
2308 SilcCommandCb command_function,
2309 SilcCommandCb command_reply_function,
2312 SilcClientCommand cmd;
2314 silc_list_start(client->internal->commands);
2315 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2316 if (cmd->cmd == command && cmd->command == command_function &&
2317 cmd->reply == command_reply_function && cmd->ident == ident) {
2318 silc_list_del(client->internal->commands, cmd);
2319 silc_free(cmd->name);
2328 /* Private range commands, specific to this implementation (and compatible
2329 with SILC Server). */
2331 /* CONNECT command. Connects the server to another server. */
2333 SILC_CLIENT_CMD_FUNC(connect)
2335 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2336 SilcClientConnection conn = cmd->conn;
2338 unsigned char port[4];
2342 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2343 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2347 if (cmd->argc < 2) {
2348 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2349 "Usage: /CONNECT <server> [<port>]");
2350 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2354 if (cmd->argc == 3) {
2355 tmp = atoi(cmd->argv[2]);
2356 SILC_PUT32_MSB(tmp, port);
2360 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2362 strlen(cmd->argv[1]),
2365 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2367 strlen(cmd->argv[1]));
2368 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2369 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2370 silc_buffer_free(buffer);
2372 /* Notify application */
2373 COMMAND(SILC_STATUS_OK);
2376 silc_client_command_free(cmd);
2380 /* CLOSE command. Close server connection to the remote server */
2382 SILC_CLIENT_CMD_FUNC(close)
2384 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2385 SilcClientConnection conn = cmd->conn;
2387 unsigned char port[4];
2391 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2392 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2396 if (cmd->argc < 2) {
2397 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2398 "Usage: /CLOSE <server> [<port>]");
2399 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2403 if (cmd->argc == 3) {
2404 tmp = atoi(cmd->argv[2]);
2405 SILC_PUT32_MSB(tmp, port);
2409 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2411 strlen(cmd->argv[1]),
2414 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2416 strlen(cmd->argv[1]));
2417 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2418 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2419 silc_buffer_free(buffer);
2421 /* Notify application */
2422 COMMAND(SILC_STATUS_OK);
2425 silc_client_command_free(cmd);
2428 /* SHUTDOWN command. Shutdowns the server. */
2430 SILC_CLIENT_CMD_FUNC(shutdown)
2432 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2435 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2436 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2440 /* Send the command */
2441 silc_client_command_send(cmd->client, cmd->conn,
2442 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2444 /* Notify application */
2445 COMMAND(SILC_STATUS_OK);
2448 silc_client_command_free(cmd);
2451 /* Register all default commands provided by the client library for the
2454 void silc_client_commands_register(SilcClient client)
2456 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2459 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2460 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2461 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2462 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2463 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2464 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2465 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2466 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2467 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2468 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
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(ping, PING, "PING");
2505 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2506 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2507 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2508 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2509 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2510 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2511 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2512 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2513 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2514 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2515 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2516 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2517 SILC_CLIENT_CMDU(users, USERS, "USERS");
2518 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2520 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2521 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2522 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");