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 ? auth->data : NULL,
1764 auth ? auth->len : 0);
1765 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1766 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1768 silc_buffer_free(buffer);
1769 silc_buffer_free(auth);
1771 /* Notify application */
1772 COMMAND(SILC_STATUS_OK);
1775 /* OPER command. Used to obtain server operator privileges. */
1777 SILC_CLIENT_CMD_FUNC(oper)
1779 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1780 SilcClientConnection conn = cmd->conn;
1783 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1784 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1788 if (cmd->argc < 2) {
1789 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1790 "Usage: /OPER <username> [-pubkey]");
1791 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1795 if (cmd->argc < 3) {
1796 /* Get passphrase */
1797 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1798 silc_client_command_oper_send,
1803 silc_client_command_oper_send(NULL, 0, context);
1806 silc_client_command_free(cmd);
1809 static void silc_client_command_silcoper_send(unsigned char *data,
1810 SilcUInt32 data_len,
1813 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1814 SilcClientConnection conn = cmd->conn;
1815 SilcBuffer buffer, auth;
1817 if (cmd->argc >= 3) {
1818 /* Encode the public key authentication payload */
1819 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1820 cmd->client->private_key,
1821 cmd->client->rng, conn->hash,
1825 /* Encode the password authentication payload */
1826 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1830 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1832 strlen(cmd->argv[1]),
1833 2, auth ? auth->data : NULL,
1834 auth ? auth->len : 0);
1835 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1836 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1838 silc_buffer_free(buffer);
1839 silc_buffer_free(auth);
1841 /* Notify application */
1842 COMMAND(SILC_STATUS_OK);
1845 /* SILCOPER command. Used to obtain router operator privileges. */
1847 SILC_CLIENT_CMD_FUNC(silcoper)
1849 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1850 SilcClientConnection conn = cmd->conn;
1853 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1854 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1858 if (cmd->argc < 2) {
1859 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1860 "Usage: /SILCOPER <username> [-pubkey]");
1861 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1865 if (cmd->argc < 3) {
1866 /* Get passphrase */
1867 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1868 silc_client_command_silcoper_send,
1873 silc_client_command_silcoper_send(NULL, 0, context);
1876 silc_client_command_free(cmd);
1879 /* Command BAN. This is used to manage the ban list of the channel. */
1881 SILC_CLIENT_CMD_FUNC(ban)
1883 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1884 SilcClientConnection conn = cmd->conn;
1885 SilcChannelEntry channel;
1886 SilcBuffer buffer, chidp;
1888 char *name, *ban = NULL;
1891 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1892 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1896 if (cmd->argc < 2) {
1897 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1898 "Usage: /BAN <channel> "
1899 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1900 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1904 if (cmd->argv[1][0] == '*') {
1905 if (!conn->current_channel) {
1906 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1907 "You are not on any channel");
1908 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1912 channel = conn->current_channel;
1914 name = cmd->argv[1];
1916 channel = silc_client_get_channel(cmd->client, conn, name);
1918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1919 "You are noton that channel");
1920 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1925 if (cmd->argc == 3) {
1926 if (cmd->argv[2][0] == '+')
1935 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1937 /* Send the command */
1938 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1939 ++conn->cmd_ident, 2,
1940 1, chidp->data, chidp->len,
1941 type, ban, ban ? strlen(ban) : 0);
1942 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1943 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1944 silc_buffer_free(buffer);
1945 silc_buffer_free(chidp);
1947 /* Notify application */
1948 COMMAND(SILC_STATUS_OK);
1951 silc_client_command_free(cmd);
1954 /* Command DETACH. This is used to detach from the server */
1956 SILC_CLIENT_CMD_FUNC(detach)
1958 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1959 SilcClientConnection conn = cmd->conn;
1963 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1964 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1968 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1969 ++conn->cmd_ident, 0);
1970 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1971 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1972 silc_buffer_free(buffer);
1974 /* Notify application */
1975 COMMAND(SILC_STATUS_OK);
1978 silc_client_command_free(cmd);
1981 /* Command WATCH. */
1983 SILC_CLIENT_CMD_FUNC(watch)
1985 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1986 SilcClientConnection conn = cmd->conn;
1987 SilcBuffer buffer, idp = NULL;
1991 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1992 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1996 if (cmd->argc < 3) {
1997 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2001 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2003 if (!strcasecmp(cmd->argv[1], "-add")) {
2005 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2008 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2013 ++conn->cmd_ident, 2,
2014 1, idp->data, idp->len,
2017 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2018 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2019 silc_buffer_free(buffer);
2021 /* Notify application */
2022 COMMAND(SILC_STATUS_OK);
2026 silc_buffer_free(idp);
2027 silc_client_command_free(cmd);
2030 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2032 SILC_CLIENT_CMD_FUNC(leave)
2034 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2035 SilcClientConnection conn = cmd->conn;
2036 SilcChannelEntry channel;
2037 SilcChannelUser chu;
2038 SilcBuffer buffer, idp;
2042 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2043 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2047 if (cmd->argc != 2) {
2048 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2049 "Usage: /LEAVE <channel>");
2050 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2054 if (cmd->argv[1][0] == '*') {
2055 if (!conn->current_channel) {
2056 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2057 "You are not on any channel");
2058 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2061 name = conn->current_channel->channel_name;
2063 name = cmd->argv[1];
2066 /* Get the channel entry */
2067 channel = silc_client_get_channel(cmd->client, conn, name);
2069 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2070 "You are not on that channel");
2071 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2075 /* Remove us from channel */
2076 chu = silc_client_on_channel(channel, conn->local_entry);
2078 silc_hash_table_del(chu->client->channels, chu->channel);
2079 silc_hash_table_del(chu->channel->user_list, chu->client);
2083 /* Send LEAVE command to the server */
2084 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2085 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2086 1, idp->data, idp->len);
2087 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2088 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2089 silc_buffer_free(buffer);
2090 silc_buffer_free(idp);
2092 /* Notify application */
2093 COMMAND(SILC_STATUS_OK);
2095 if (conn->current_channel == channel)
2096 conn->current_channel = NULL;
2098 silc_client_del_channel(cmd->client, cmd->conn, channel);
2101 silc_client_command_free(cmd);
2104 /* Command USERS. Requests the USERS of the clients joined on requested
2107 SILC_CLIENT_CMD_FUNC(users)
2109 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2110 SilcClientConnection conn = cmd->conn;
2115 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2116 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2120 if (cmd->argc != 2) {
2121 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2122 "Usage: /USERS <channel>");
2123 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2127 if (cmd->argv[1][0] == '*') {
2128 if (!conn->current_channel) {
2129 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2130 "You are not on any channel");
2131 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2134 name = conn->current_channel->channel_name;
2136 name = cmd->argv[1];
2139 /* Send USERS command to the server */
2140 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2141 ++conn->cmd_ident, 1,
2142 2, name, strlen(name));
2143 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2144 NULL, 0, NULL, NULL, buffer->data,
2146 silc_buffer_free(buffer);
2148 /* Notify application */
2149 COMMAND(SILC_STATUS_OK);
2152 silc_client_command_free(cmd);
2155 /* Command GETKEY. Used to fetch remote client's public key. */
2157 SILC_CLIENT_CMD_FUNC(getkey)
2159 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2160 SilcClientConnection conn = cmd->conn;
2161 SilcClient client = cmd->client;
2162 SilcClientEntry client_entry = NULL;
2163 SilcServerEntry server_entry = NULL;
2164 char *nickname = NULL;
2165 SilcBuffer idp, buffer;
2167 SILC_LOG_DEBUG(("Start"));
2170 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2171 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2175 if (cmd->argc < 2) {
2176 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2177 "Usage: /GETKEY <nickname or server name>");
2178 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2182 /* Parse the typed nickname. */
2183 if (client->internal->params->nickname_parse)
2184 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2186 nickname = strdup(cmd->argv[1]);
2188 /* Find client entry */
2189 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2191 if (!client_entry) {
2192 /* Check whether user requested server actually */
2193 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2195 if (!server_entry) {
2196 /* No. what ever user wants we don't have it, so resolve it. We
2197 will first try to resolve the client, and if that fails then
2198 we'll try to resolve the server. */
2200 if (!cmd->pending) {
2201 /* This will send the IDENTIFY command for nickname */
2202 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2203 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2205 silc_client_command_getkey,
2206 silc_client_command_dup(cmd));
2210 SilcClientCommandReplyContext reply =
2211 (SilcClientCommandReplyContext)context2;
2214 /* If nickname was not found, then resolve the server. */
2215 silc_command_get_status(reply->payload, NULL, &error);
2216 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2217 /* This sends the IDENTIFY command to resolve the server. */
2218 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2220 silc_client_command_reply_identify_i, 0,
2222 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2224 2, cmd->argv[1], cmd->argv_lens[1]);
2225 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2227 silc_client_command_getkey,
2228 silc_client_command_dup(cmd));
2232 /* If server was not found, then we've resolved both nickname and
2233 server and did not find anybody. */
2234 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2235 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2236 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2237 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2238 silc_get_status_message(error));
2239 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2243 COMMAND_ERROR(error);
2248 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2250 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2253 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2254 1, idp->data, idp->len);
2255 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2256 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2257 silc_buffer_free(buffer);
2258 silc_buffer_free(idp);
2260 /* Notify application */
2261 COMMAND(SILC_STATUS_OK);
2264 silc_free(nickname);
2265 silc_client_command_free(cmd);
2268 /* Register a new command indicated by the `command' to the SILC client.
2269 The `name' is optional command name. If provided the command may be
2270 searched using the silc_client_command_find by that name. The
2271 `command_function' is the function to be called when the command is
2272 executed, and the `command_reply_function' is the function to be
2273 called after the server has sent reply back to the command.
2275 The `ident' is optional identifier for the command. If non-zero
2276 the `command_reply_function' for the command type `command' will be
2277 called only if the command reply sent by server includes the
2278 command identifier `ident'. Application usually does not need it
2279 and set it to zero value. */
2281 bool silc_client_command_register(SilcClient client,
2282 SilcCommand command,
2284 SilcCommandCb command_function,
2285 SilcCommandCb command_reply_function,
2289 SilcClientCommand cmd;
2291 cmd = silc_calloc(1, sizeof(*cmd));
2293 cmd->command = command_function;
2294 cmd->reply = command_reply_function;
2295 cmd->name = name ? strdup(name) : NULL;
2296 cmd->max_args = max_args;
2299 silc_list_add(client->internal->commands, cmd);
2304 /* Unregister a command indicated by the `command' with command function
2305 `command_function' and command reply function `command_reply_function'.
2306 Returns TRUE if the command was found and unregistered. */
2308 bool silc_client_command_unregister(SilcClient client,
2309 SilcCommand command,
2310 SilcCommandCb command_function,
2311 SilcCommandCb command_reply_function,
2314 SilcClientCommand cmd;
2316 silc_list_start(client->internal->commands);
2317 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2318 if (cmd->cmd == command && cmd->command == command_function &&
2319 cmd->reply == command_reply_function && cmd->ident == ident) {
2320 silc_list_del(client->internal->commands, cmd);
2321 silc_free(cmd->name);
2330 /* Private range commands, specific to this implementation (and compatible
2331 with SILC Server). */
2333 /* CONNECT command. Connects the server to another server. */
2335 SILC_CLIENT_CMD_FUNC(connect)
2337 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2338 SilcClientConnection conn = cmd->conn;
2340 unsigned char port[4];
2344 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2345 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2349 if (cmd->argc < 2) {
2350 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2351 "Usage: /CONNECT <server> [<port>]");
2352 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2356 if (cmd->argc == 3) {
2357 tmp = atoi(cmd->argv[2]);
2358 SILC_PUT32_MSB(tmp, port);
2362 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2364 strlen(cmd->argv[1]),
2367 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2369 strlen(cmd->argv[1]));
2370 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2371 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2372 silc_buffer_free(buffer);
2374 /* Notify application */
2375 COMMAND(SILC_STATUS_OK);
2378 silc_client_command_free(cmd);
2382 /* CLOSE command. Close server connection to the remote server */
2384 SILC_CLIENT_CMD_FUNC(close)
2386 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2387 SilcClientConnection conn = cmd->conn;
2389 unsigned char port[4];
2393 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2394 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2398 if (cmd->argc < 2) {
2399 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2400 "Usage: /CLOSE <server> [<port>]");
2401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2405 if (cmd->argc == 3) {
2406 tmp = atoi(cmd->argv[2]);
2407 SILC_PUT32_MSB(tmp, port);
2411 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2413 strlen(cmd->argv[1]),
2416 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2418 strlen(cmd->argv[1]));
2419 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2420 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2421 silc_buffer_free(buffer);
2423 /* Notify application */
2424 COMMAND(SILC_STATUS_OK);
2427 silc_client_command_free(cmd);
2430 /* SHUTDOWN command. Shutdowns the server. */
2432 SILC_CLIENT_CMD_FUNC(shutdown)
2434 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2437 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2438 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2442 /* Send the command */
2443 silc_client_command_send(cmd->client, cmd->conn,
2444 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2446 /* Notify application */
2447 COMMAND(SILC_STATUS_OK);
2450 silc_client_command_free(cmd);
2453 /* Register all default commands provided by the client library for the
2456 void silc_client_commands_register(SilcClient client)
2458 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2461 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2462 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2463 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2464 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2465 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2466 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2467 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2468 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2469 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2470 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2471 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2472 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2473 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2474 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2475 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2476 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2477 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2478 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2479 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2480 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2481 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2482 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2483 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2484 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2485 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2487 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2488 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2489 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2492 /* Unregister all commands. */
2494 void silc_client_commands_unregister(SilcClient client)
2496 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2497 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2498 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2499 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2500 SILC_CLIENT_CMDU(list, LIST, "LIST");
2501 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2502 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2503 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2504 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2505 SILC_CLIENT_CMDU(info, INFO, "INFO");
2506 SILC_CLIENT_CMDU(ping, PING, "PING");
2507 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2508 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2509 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2510 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2511 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2512 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2513 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2514 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2515 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2516 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2517 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2518 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2519 SILC_CLIENT_CMDU(users, USERS, "USERS");
2520 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2522 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2523 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2524 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");