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 silc_dlist_start(conn->pending_commands);
133 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
134 if (r->reply_cmd == reply_cmd && r->ident == ident) {
135 silc_dlist_del(conn->pending_commands, r);
141 /* Checks for pending commands and marks callbacks to be called from
142 the command reply function. */
144 SilcClientCommandPendingCallbacks
145 silc_client_command_pending_check(SilcClientConnection conn,
146 SilcClientCommandReplyContext ctx,
149 SilcUInt32 *callbacks_count)
151 SilcClientCommandPending *r;
152 SilcClientCommandPendingCallbacks callbacks = NULL;
155 silc_dlist_start(conn->pending_commands);
156 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
157 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
158 && r->ident == ident) {
159 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
160 callbacks[i].context = r->context;
161 callbacks[i].callback = r->callback;
167 *callbacks_count = i;
171 /* Allocate Command Context */
173 SilcClientCommandContext silc_client_command_alloc(void)
175 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
180 /* Free command context and its internals */
182 void silc_client_command_free(SilcClientCommandContext ctx)
185 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
187 if (ctx->users < 1) {
190 for (i = 0; i < ctx->argc; i++)
191 silc_free(ctx->argv[i]);
192 silc_free(ctx->argv_lens);
193 silc_free(ctx->argv_types);
198 /* Duplicate Command Context by adding reference counter. The context won't
199 be free'd untill it hits zero. */
201 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
204 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
209 /* Command WHOIS. This command is used to query information about
212 SILC_CLIENT_CMD_FUNC(whois)
214 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
215 SilcClientConnection conn = cmd->conn;
217 unsigned char count[4];
220 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
221 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
225 /* Given without arguments fetches client's own information */
227 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
228 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
230 1, 3, buffer->data, buffer->len);
231 silc_buffer_free(buffer);
235 if (cmd->argc == 2) {
236 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
237 ++conn->cmd_ident, 1,
241 int c = atoi(cmd->argv[2]);
242 memset(count, 0, sizeof(count));
243 SILC_PUT32_MSB(c, count);
244 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
245 ++conn->cmd_ident, 2,
246 1, cmd->argv[1], cmd->argv_lens[1],
247 2, count, sizeof(count));
249 silc_client_packet_send(cmd->client, cmd->conn->sock,
250 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
251 buffer->data, buffer->len, TRUE);
252 silc_buffer_free(buffer);
254 /* Notify application */
255 COMMAND(SILC_STATUS_OK);
258 silc_client_command_free(cmd);
261 /* Command WHOWAS. This command is used to query history information about
262 specific user that used to exist in the network. */
264 SILC_CLIENT_CMD_FUNC(whowas)
266 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
267 SilcClientConnection conn = cmd->conn;
269 unsigned char count[4];
272 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
273 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
277 if (cmd->argc < 2 || cmd->argc > 3) {
278 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
279 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
280 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
281 SILC_STATUS_ERR_TOO_MANY_PARAMS));
285 if (cmd->argc == 2) {
286 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
287 ++conn->cmd_ident, 1,
291 int c = atoi(cmd->argv[2]);
292 memset(count, 0, sizeof(count));
293 SILC_PUT32_MSB(c, count);
294 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
295 ++conn->cmd_ident, 2,
296 1, cmd->argv[1], cmd->argv_lens[1],
297 2, count, sizeof(count));
299 silc_client_packet_send(cmd->client, cmd->conn->sock,
300 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
301 buffer->data, buffer->len, TRUE);
302 silc_buffer_free(buffer);
304 /* Notify application */
305 COMMAND(SILC_STATUS_OK);
308 silc_client_command_free(cmd);
311 /* Command IDENTIFY. This command is used to query information about
312 specific user, especially ID's.
314 NOTE: This command is used only internally by the client library
315 and application MUST NOT call this command directly. */
317 SILC_CLIENT_CMD_FUNC(identify)
319 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
320 SilcClientConnection conn = cmd->conn;
322 unsigned char count[4];
325 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
326 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
330 if (cmd->argc < 2 || cmd->argc > 3)
333 if (cmd->argc == 2) {
334 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
335 ++conn->cmd_ident, 1,
339 int c = atoi(cmd->argv[2]);
340 memset(count, 0, sizeof(count));
341 SILC_PUT32_MSB(c, count);
342 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
343 ++conn->cmd_ident, 2,
346 4, count, sizeof(count));
349 silc_client_packet_send(cmd->client, cmd->conn->sock,
350 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
351 buffer->data, buffer->len, TRUE);
352 silc_buffer_free(buffer);
355 silc_client_command_free(cmd);
358 /* Pending callbcak that will be called after the NICK command was
359 replied by the server. This sets the nickname if there were no
362 SILC_CLIENT_CMD_FUNC(nick_change)
364 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
365 SilcClientConnection conn = cmd->conn;
366 SilcClientCommandReplyContext reply =
367 (SilcClientCommandReplyContext)context2;
370 silc_command_get_status(reply->payload, &status, NULL);
371 if (status == SILC_STATUS_OK) {
372 /* Set the nickname */
373 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
375 silc_free(conn->nickname);
376 conn->nickname = strdup(cmd->argv[1]);
377 conn->local_entry->nickname = conn->nickname;
378 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
379 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
380 conn->local_entry->id, conn->local_entry, 0, NULL);
381 COMMAND(SILC_STATUS_OK);
383 COMMAND_ERROR(status);
386 silc_client_command_free(cmd);
389 /* Command NICK. Shows current nickname/sets new nickname on current
392 SILC_CLIENT_CMD_FUNC(nick)
394 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
395 SilcClientConnection conn = cmd->conn;
399 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
400 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
405 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
406 "Usage: /NICK <nickname>");
407 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
411 if (!strcmp(conn->nickname, cmd->argv[1]))
414 /* Show current nickname */
417 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
418 "Your nickname is %s on server %s",
419 conn->nickname, conn->remote_host);
421 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
422 "Your nickname is %s", conn->nickname);
425 COMMAND(SILC_STATUS_OK);
429 if (cmd->argv_lens[1] > 128)
430 cmd->argv_lens[1] = 128;
432 /* Send the NICK command */
433 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
437 ++cmd->conn->cmd_ident);
438 silc_client_packet_send(cmd->client, cmd->conn->sock,
439 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
440 buffer->data, buffer->len, TRUE);
441 silc_buffer_free(buffer);
443 /* Register pending callback that will actually set the new nickname
444 if there were no errors returned by the server. */
445 silc_client_command_pending(conn, SILC_COMMAND_NICK,
446 cmd->conn->cmd_ident,
447 silc_client_command_nick_change,
448 silc_client_command_dup(cmd));
452 silc_client_command_free(cmd);
455 /* Command LIST. Lists channels on the current server. */
457 SILC_CLIENT_CMD_FUNC(list)
459 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
460 SilcClientConnection conn = cmd->conn;
461 SilcIDCacheEntry id_cache = NULL;
462 SilcChannelEntry channel;
463 SilcBuffer buffer, idp = NULL;
467 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
468 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
472 if (cmd->argc == 2) {
475 /* Get the Channel ID of the channel */
476 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
477 channel = (SilcChannelEntry)id_cache->context;
478 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
483 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
484 ++conn->cmd_ident, 0);
486 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
487 ++conn->cmd_ident, 1,
488 1, idp->data, idp->len);
490 silc_client_packet_send(cmd->client, cmd->conn->sock,
491 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
492 buffer->data, buffer->len, TRUE);
493 silc_buffer_free(buffer);
495 silc_buffer_free(idp);
497 /* Notify application */
498 COMMAND(SILC_STATUS_OK);
501 silc_client_command_free(cmd);
504 /* Command TOPIC. Sets/shows topic on a channel. */
506 SILC_CLIENT_CMD_FUNC(topic)
508 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
509 SilcClientConnection conn = cmd->conn;
510 SilcIDCacheEntry id_cache = NULL;
511 SilcChannelEntry channel;
512 SilcBuffer buffer, idp;
516 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
517 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
521 if (cmd->argc < 2 || cmd->argc > 3) {
522 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
523 "Usage: /TOPIC <channel> [<topic>]");
524 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
525 SILC_STATUS_ERR_TOO_MANY_PARAMS));
529 if (cmd->argv[1][0] == '*') {
530 if (!conn->current_channel) {
531 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
532 "You are not on any channel");
533 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
536 name = conn->current_channel->channel_name;
541 if (!conn->current_channel) {
542 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
543 "You are not on that channel");
544 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
548 /* Get the Channel ID of the channel */
549 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
550 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
551 "You are not on that channel");
552 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
556 channel = (SilcChannelEntry)id_cache->context;
558 /* Send TOPIC command to the server */
559 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
561 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
562 ++conn->cmd_ident, 2,
563 1, idp->data, idp->len,
565 strlen(cmd->argv[2]));
567 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
568 ++conn->cmd_ident, 1,
569 1, idp->data, idp->len);
570 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
571 0, NULL, NULL, buffer->data, buffer->len, TRUE);
572 silc_buffer_free(buffer);
573 silc_buffer_free(idp);
575 /* Notify application */
576 COMMAND(SILC_STATUS_OK);
579 silc_client_command_free(cmd);
582 /* Command INVITE. Invites specific client to join a channel. This is
583 also used to mange the invite list of the channel. */
585 SILC_CLIENT_CMD_FUNC(invite)
587 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
588 SilcClient client = cmd->client;
589 SilcClientConnection conn = cmd->conn;
590 SilcClientEntry client_entry = NULL;
591 SilcChannelEntry channel;
592 SilcBuffer buffer, clidp, chidp;
594 char *nickname = NULL, *name;
598 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
599 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
604 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
605 "Usage: /INVITE <channel> [<nickname>[@server>]"
606 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
607 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
611 if (cmd->argv[1][0] == '*') {
612 if (!conn->current_channel) {
613 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
614 "You are not on any channel");
615 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
619 channel = conn->current_channel;
623 channel = silc_client_get_channel(cmd->client, conn, name);
625 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
626 "You are on that channel");
627 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
632 /* Parse the typed nickname. */
633 if (cmd->argc == 3) {
634 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
635 if (client->internal->params->nickname_parse)
636 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
638 nickname = strdup(cmd->argv[2]);
640 /* Find client entry */
641 client_entry = silc_idlist_get_client(client, conn, nickname,
645 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
649 /* Client entry not found, it was requested thus mark this to be
651 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
653 silc_client_command_invite,
654 silc_client_command_dup(cmd));
659 invite = cmd->argv[2];
661 if (cmd->argv[2][0] == '+')
668 /* Send the command */
669 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
671 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
672 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
673 ++conn->cmd_ident, 3,
674 1, chidp->data, chidp->len,
675 2, clidp->data, clidp->len,
676 type, invite, invite ?
678 silc_buffer_free(clidp);
680 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
681 ++conn->cmd_ident, 2,
682 1, chidp->data, chidp->len,
683 type, invite, invite ?
687 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
688 0, NULL, NULL, buffer->data, buffer->len, TRUE);
689 silc_buffer_free(buffer);
690 silc_buffer_free(chidp);
692 /* Notify application */
693 COMMAND(SILC_STATUS_OK);
697 silc_client_command_free(cmd);
702 SilcClientConnection conn;
705 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
707 QuitInternal q = (QuitInternal)context;
709 /* Close connection */
710 q->client->internal->ops->disconnect(q->client, q->conn);
711 silc_client_close_connection(q->client, q->conn->sock->user_data);
716 /* Command QUIT. Closes connection with current server. */
718 SILC_CLIENT_CMD_FUNC(quit)
720 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
725 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
726 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
731 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
732 &cmd->argv[1], &cmd->argv_lens[1],
733 &cmd->argv_types[1], 0);
735 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
736 NULL, NULL, NULL, 0);
737 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
739 buffer->data, buffer->len, TRUE);
740 silc_buffer_free(buffer);
742 q = silc_calloc(1, sizeof(*q));
743 q->client = cmd->client;
746 /* Sleep for a while */
749 /* We quit the connection with little timeout */
750 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
751 silc_client_command_quit_cb, (void *)q,
752 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
754 /* Notify application */
755 COMMAND(SILC_STATUS_OK);
758 silc_client_command_free(cmd);
761 /* Timeout callback to remove the killed client from cache */
763 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
765 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
766 SilcClient client = cmd->client;
767 SilcClientConnection conn = cmd->conn;
768 SilcClientEntry target;
769 char *nickname = NULL;
771 /* Parse the typed nickname. */
772 if (client->internal->params->nickname_parse)
773 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
775 nickname = strdup(cmd->argv[1]);
777 /* Get the target client */
778 target = silc_idlist_get_client(cmd->client, conn, nickname,
779 cmd->argv[1], FALSE);
781 /* Remove the client from all channels and free it */
782 silc_client_del_client(client, conn, target);
785 silc_client_command_free(cmd);
788 /* Kill command's pending command callback to actually remove the killed
789 client from our local cache. */
791 SILC_CLIENT_CMD_FUNC(kill_remove)
793 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
794 SilcClientCommandReplyContext reply =
795 (SilcClientCommandReplyContext)context2;
798 silc_command_get_status(reply->payload, &status, NULL);
799 if (status == SILC_STATUS_OK) {
800 /* Remove with timeout */
801 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
802 silc_client_command_kill_remove_later, context,
803 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
807 silc_client_command_free(cmd);
810 /* Command KILL. Router operator can use this command to remove an client
811 fromthe SILC Network. */
813 SILC_CLIENT_CMD_FUNC(kill)
815 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
816 SilcClient client = cmd->client;
817 SilcClientConnection conn = cmd->conn;
818 SilcBuffer buffer, idp;
819 SilcClientEntry target;
820 char *nickname = NULL;
823 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
824 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
829 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
830 "Usage: /KILL <nickname> [<comment>]");
831 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
835 /* Parse the typed nickname. */
836 if (client->internal->params->nickname_parse)
837 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
839 nickname = strdup(cmd->argv[1]);
841 /* Get the target client */
842 target = silc_idlist_get_client(cmd->client, conn, nickname,
846 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
850 /* Client entry not found, it was requested thus mark this to be
852 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
854 silc_client_command_kill,
855 silc_client_command_dup(cmd));
860 /* Send the KILL command to the server */
861 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
863 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
864 ++conn->cmd_ident, 1,
865 1, idp->data, idp->len);
867 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
868 ++conn->cmd_ident, 2,
869 1, idp->data, idp->len,
871 strlen(cmd->argv[2]));
872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
874 silc_buffer_free(buffer);
875 silc_buffer_free(idp);
877 /* Notify application */
878 COMMAND(SILC_STATUS_OK);
880 /* Register a pending callback that will actually remove the killed
881 client from our cache. */
882 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
883 silc_client_command_kill_remove,
884 silc_client_command_dup(cmd));
888 silc_client_command_free(cmd);
891 /* Command INFO. Request information about specific server. If specific
892 server is not provided the current server is used. */
894 SILC_CLIENT_CMD_FUNC(info)
896 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
897 SilcClientConnection conn = cmd->conn;
902 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
903 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
908 name = strdup(cmd->argv[1]);
910 /* Send the command */
912 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
913 1, name, strlen(name));
915 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
916 NULL, NULL, NULL, 0);
917 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
918 0, NULL, NULL, buffer->data, buffer->len, TRUE);
919 silc_buffer_free(buffer);
923 /* Notify application */
924 COMMAND(SILC_STATUS_OK);
927 silc_client_command_free(cmd);
930 /* Command PING. Sends ping to server. This is used to test the
931 communication channel. */
933 SILC_CLIENT_CMD_FUNC(ping)
935 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
936 SilcClientConnection conn = cmd->conn;
942 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
947 /* Send the command */
948 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
949 1, conn->remote_id_data,
950 silc_id_get_len(conn->remote_id,
952 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
953 0, NULL, NULL, buffer->data, buffer->len, TRUE);
954 silc_buffer_free(buffer);
956 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
960 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
964 /* Start counting time */
965 for (i = 0; i < conn->ping_count; i++) {
966 if (conn->ping[i].dest_id == NULL) {
967 conn->ping[i].start_time = time(NULL);
968 conn->ping[i].dest_id = id;
969 conn->ping[i].dest_name = strdup(conn->remote_host);
973 if (i >= conn->ping_count) {
974 i = conn->ping_count;
975 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
976 conn->ping[i].start_time = time(NULL);
977 conn->ping[i].dest_id = id;
978 conn->ping[i].dest_name = strdup(conn->remote_host);
982 /* Notify application */
983 COMMAND(SILC_STATUS_OK);
986 silc_client_command_free(cmd);
989 /* Command JOIN. Joins to a channel. */
991 SILC_CLIENT_CMD_FUNC(join)
993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
994 SilcClientConnection conn = cmd->conn;
995 SilcChannelEntry channel;
996 SilcBuffer buffer, idp, auth = NULL;
997 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
998 int i, passphrase_len = 0;
1001 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1002 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1006 if (cmd->argc < 2) {
1007 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1011 /* See if we have joined to the requested channel already */
1012 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
1013 if (channel && silc_client_on_channel(channel, conn->local_entry))
1016 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1018 if (cmd->argv_lens[1] > 256)
1019 cmd->argv_lens[1] = 256;
1021 name = cmd->argv[1];
1023 for (i = 2; i < cmd->argc; i++) {
1024 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1025 cipher = cmd->argv[i + 1];
1027 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1028 hmac = cmd->argv[i + 1];
1030 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
1031 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
1032 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1033 cmd->client->private_key,
1034 cmd->client->rng, conn->hash,
1038 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1040 cmd->argv_lens[i + 1]);
1044 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1045 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1046 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1047 cmd->argv_lens[i], 0);
1048 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1049 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1050 0, pu8, passphrase_len);
1053 passphrase = strdup(cmd->argv[i]);
1054 passphrase_len = cmd->argv_lens[i];
1059 /* Send JOIN command to the server */
1061 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1062 1, name, strlen(name),
1063 2, idp->data, idp->len,
1064 3, passphrase, passphrase_len,
1065 4, cipher, cipher ? strlen(cipher) : 0,
1066 5, hmac, hmac ? strlen(hmac) : 0,
1067 6, auth ? auth->data : NULL,
1068 auth ? auth->len : 0);
1069 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1070 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1071 silc_buffer_free(buffer);
1072 silc_buffer_free(idp);
1074 silc_buffer_free(auth);
1075 silc_free(passphrase);
1077 /* Notify application */
1078 COMMAND(SILC_STATUS_OK);
1081 silc_client_command_free(cmd);
1084 /* MOTD command. Requests motd from server. */
1086 SILC_CLIENT_CMD_FUNC(motd)
1088 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1089 SilcClientConnection conn = cmd->conn;
1093 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1094 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1098 if (cmd->argc < 1 || cmd->argc > 2) {
1099 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1100 "Usage: /MOTD [<server>]");
1101 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1102 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1106 /* Send TOPIC command to the server */
1108 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1109 1, conn->remote_host,
1110 strlen(conn->remote_host));
1112 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1115 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1116 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1117 silc_buffer_free(buffer);
1119 /* Notify application */
1120 COMMAND(SILC_STATUS_OK);
1123 silc_client_command_free(cmd);
1126 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1127 modes as client cannot set itself server/router operator privileges. */
1129 SILC_CLIENT_CMD_FUNC(umode)
1131 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1132 SilcClientConnection conn = cmd->conn;
1133 SilcBuffer buffer, idp;
1134 unsigned char *cp, modebuf[4];
1135 SilcUInt32 mode, add, len;
1139 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1140 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1144 if (cmd->argc < 2) {
1145 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1146 "Usage: /UMODE +|-<modes>");
1147 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1151 mode = conn->local_entry->mode;
1153 /* Are we adding or removing mode */
1154 if (cmd->argv[1][0] == '-')
1160 cp = cmd->argv[1] + 1;
1162 for (i = 0; i < len; i++) {
1167 mode |= SILC_UMODE_SERVER_OPERATOR;
1168 mode |= SILC_UMODE_ROUTER_OPERATOR;
1170 mode = SILC_UMODE_NONE;
1175 mode |= SILC_UMODE_SERVER_OPERATOR;
1177 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1181 mode |= SILC_UMODE_ROUTER_OPERATOR;
1183 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1187 mode |= SILC_UMODE_GONE;
1189 mode &= ~SILC_UMODE_GONE;
1193 mode |= SILC_UMODE_INDISPOSED;
1195 mode &= ~SILC_UMODE_INDISPOSED;
1199 mode |= SILC_UMODE_BUSY;
1201 mode &= ~SILC_UMODE_BUSY;
1205 mode |= SILC_UMODE_PAGE;
1207 mode &= ~SILC_UMODE_PAGE;
1211 mode |= SILC_UMODE_HYPER;
1213 mode &= ~SILC_UMODE_HYPER;
1217 mode |= SILC_UMODE_ROBOT;
1219 mode &= ~SILC_UMODE_ROBOT;
1223 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1225 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1228 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1234 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1235 SILC_PUT32_MSB(mode, modebuf);
1237 /* Send the command packet. We support sending only one mode at once
1238 that requires an argument. */
1240 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1241 1, idp->data, idp->len,
1242 2, modebuf, sizeof(modebuf));
1243 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1244 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1245 silc_buffer_free(buffer);
1246 silc_buffer_free(idp);
1248 /* Notify application */
1249 COMMAND(SILC_STATUS_OK);
1252 silc_client_command_free(cmd);
1255 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1256 can be set several at once. Those modes that require argument must be set
1257 separately (unless set with modes that does not require arguments). */
1259 SILC_CLIENT_CMD_FUNC(cmode)
1261 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1262 SilcClientConnection conn = cmd->conn;
1263 SilcChannelEntry channel;
1264 SilcBuffer buffer, chidp, auth = NULL;
1265 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1266 SilcUInt32 mode, add, type, len, arg_len = 0;
1270 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1271 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1275 if (cmd->argc < 3) {
1276 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1277 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1278 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1282 if (cmd->argv[1][0] == '*') {
1283 if (!conn->current_channel) {
1284 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1285 "You are not on any channel");
1286 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1290 channel = conn->current_channel;
1292 name = cmd->argv[1];
1294 channel = silc_client_get_channel(cmd->client, conn, name);
1296 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1297 "You are on that channel");
1298 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1303 mode = channel->mode;
1305 /* Are we adding or removing mode */
1306 if (cmd->argv[2][0] == '-')
1311 /* Argument type to be sent to server */
1315 cp = cmd->argv[2] + 1;
1317 for (i = 0; i < len; i++) {
1321 mode |= SILC_CHANNEL_MODE_PRIVATE;
1323 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1327 mode |= SILC_CHANNEL_MODE_SECRET;
1329 mode &= ~SILC_CHANNEL_MODE_SECRET;
1333 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1335 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1339 mode |= SILC_CHANNEL_MODE_INVITE;
1341 mode &= ~SILC_CHANNEL_MODE_INVITE;
1345 mode |= SILC_CHANNEL_MODE_TOPIC;
1347 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1351 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1353 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1357 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1359 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1364 mode |= SILC_CHANNEL_MODE_ULIMIT;
1366 if (cmd->argc < 4) {
1367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1368 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1372 ll = atoi(cmd->argv[3]);
1373 SILC_PUT32_MSB(ll, tmp);
1377 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1382 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1384 if (cmd->argc < 4) {
1385 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1386 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1387 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1391 arg_len = cmd->argv_lens[3];
1393 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1398 mode |= SILC_CHANNEL_MODE_CIPHER;
1400 if (cmd->argc < 4) {
1401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1402 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1407 arg_len = cmd->argv_lens[3];
1409 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1414 mode |= SILC_CHANNEL_MODE_HMAC;
1416 if (cmd->argc < 4) {
1417 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1418 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1419 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1423 arg_len = cmd->argv_lens[3];
1425 mode &= ~SILC_CHANNEL_MODE_HMAC;
1430 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1433 if (cmd->argc < 4) {
1434 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1435 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1436 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1440 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1441 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1442 cmd->client->private_key,
1448 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1449 cmd->argv[3], cmd->argv_lens[3]);
1453 arg_len = auth->len;
1455 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1459 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1465 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1466 SILC_PUT32_MSB(mode, modebuf);
1468 /* Send the command packet. We support sending only one mode at once
1469 that requires an argument. */
1472 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1473 1, chidp->data, chidp->len,
1474 2, modebuf, sizeof(modebuf),
1475 type, arg, arg_len);
1478 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1479 1, chidp->data, chidp->len,
1480 2, modebuf, sizeof(modebuf));
1483 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1484 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1485 silc_buffer_free(buffer);
1486 silc_buffer_free(chidp);
1488 silc_buffer_free(auth);
1490 /* Notify application */
1491 COMMAND(SILC_STATUS_OK);
1494 silc_client_command_free(cmd);
1497 /* CUMODE command. Changes client's mode on a channel. */
1499 SILC_CLIENT_CMD_FUNC(cumode)
1501 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1502 SilcClient client = cmd->client;
1503 SilcClientConnection conn = cmd->conn;
1504 SilcChannelEntry channel;
1505 SilcChannelUser chu;
1506 SilcClientEntry client_entry;
1507 SilcBuffer buffer, clidp, chidp, auth = NULL;
1508 unsigned char *name, *cp, modebuf[4];
1509 SilcUInt32 mode = 0, add, len;
1510 char *nickname = NULL;
1514 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1515 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1519 if (cmd->argc < 4) {
1520 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1521 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1522 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1526 if (cmd->argv[1][0] == '*') {
1527 if (!conn->current_channel) {
1528 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1529 "You are not on any channel");
1530 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1534 channel = conn->current_channel;
1536 name = cmd->argv[1];
1538 channel = silc_client_get_channel(cmd->client, conn, name);
1540 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1541 "You are on that channel");
1542 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1547 /* Parse the typed nickname. */
1548 if (client->internal->params->nickname_parse)
1549 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1551 nickname = strdup(cmd->argv[3]);
1553 /* Find client entry */
1554 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1555 cmd->argv[3], TRUE);
1556 if (!client_entry) {
1558 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1562 /* Client entry not found, it was requested thus mark this to be
1564 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1566 silc_client_command_cumode,
1567 silc_client_command_dup(cmd));
1572 /* Get the current mode */
1573 chu = silc_client_on_channel(channel, client_entry);
1577 /* Are we adding or removing mode */
1578 if (cmd->argv[2][0] == '-')
1584 cp = cmd->argv[2] + 1;
1586 for (i = 0; i < len; i++) {
1590 mode |= SILC_CHANNEL_UMODE_CHANFO;
1591 mode |= SILC_CHANNEL_UMODE_CHANOP;
1592 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1594 mode = SILC_CHANNEL_UMODE_NONE;
1599 if (cmd->argc == 5) {
1600 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1601 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1602 cmd->client->private_key,
1608 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1609 cmd->argv[4], cmd->argv_lens[4]);
1612 mode |= SILC_CHANNEL_UMODE_CHANFO;
1614 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1619 mode |= SILC_CHANNEL_UMODE_CHANOP;
1621 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1625 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1627 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1630 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1636 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1637 SILC_PUT32_MSB(mode, modebuf);
1638 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1640 /* Send the command packet. We support sending only one mode at once
1641 that requires an argument. */
1642 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1644 1, chidp->data, chidp->len,
1646 3, clidp->data, clidp->len,
1647 4, auth ? auth->data : NULL,
1648 auth ? auth->len : 0);
1650 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1651 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1652 silc_buffer_free(buffer);
1653 silc_buffer_free(chidp);
1654 silc_buffer_free(clidp);
1656 silc_buffer_free(auth);
1658 /* Notify application */
1659 COMMAND(SILC_STATUS_OK);
1662 silc_free(nickname);
1663 silc_client_command_free(cmd);
1666 /* KICK command. Kicks a client out of channel. */
1668 SILC_CLIENT_CMD_FUNC(kick)
1670 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1671 SilcClient client = cmd->client;
1672 SilcClientConnection conn = cmd->conn;
1673 SilcIDCacheEntry id_cache = NULL;
1674 SilcChannelEntry channel;
1675 SilcBuffer buffer, idp, idp2;
1676 SilcClientEntry target;
1678 char *nickname = NULL;
1681 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1682 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1686 if (cmd->argc < 3) {
1687 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1688 "Usage: /KICK <channel> <nickname> [<comment>]");
1689 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1693 if (cmd->argv[1][0] == '*') {
1694 if (!conn->current_channel) {
1695 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1696 "You are not on any channel");
1697 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1700 name = conn->current_channel->channel_name;
1702 name = cmd->argv[1];
1705 if (!conn->current_channel) {
1706 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1707 "You are not on that channel");
1708 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1712 /* Get the Channel ID of the channel */
1713 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1714 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1715 "You are not on that channel");
1716 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1720 channel = (SilcChannelEntry)id_cache->context;
1722 /* Parse the typed nickname. */
1723 if (client->internal->params->nickname_parse)
1724 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1726 nickname = strdup(cmd->argv[2]);
1728 /* Get the target client */
1729 target = silc_idlist_get_client(cmd->client, conn, nickname,
1730 cmd->argv[2], FALSE);
1732 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1733 "No such client: %s", cmd->argv[2]);
1734 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1738 /* Send KICK command to the server */
1739 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1740 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1742 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1743 1, idp->data, idp->len,
1744 2, idp2->data, idp2->len);
1746 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1747 1, idp->data, idp->len,
1748 2, idp2->data, idp2->len,
1750 strlen(cmd->argv[3]));
1751 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1752 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1753 silc_buffer_free(buffer);
1754 silc_buffer_free(idp);
1755 silc_buffer_free(idp2);
1757 /* Notify application */
1758 COMMAND(SILC_STATUS_OK);
1761 silc_free(nickname);
1762 silc_client_command_free(cmd);
1765 static void silc_client_command_oper_send(unsigned char *data,
1766 SilcUInt32 data_len, void *context)
1768 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1769 SilcClientConnection conn = cmd->conn;
1770 SilcBuffer buffer, auth;
1772 if (cmd->argc >= 3) {
1773 /* Encode the public key authentication payload */
1774 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1775 cmd->client->private_key,
1776 cmd->client->rng, conn->hash,
1780 /* Encode the password authentication payload */
1781 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1785 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1787 strlen(cmd->argv[1]),
1788 2, auth->data, auth->len);
1789 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1790 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1792 silc_buffer_free(buffer);
1793 silc_buffer_free(auth);
1795 /* Notify application */
1796 COMMAND(SILC_STATUS_OK);
1799 /* OPER command. Used to obtain server operator privileges. */
1801 SILC_CLIENT_CMD_FUNC(oper)
1803 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1804 SilcClientConnection conn = cmd->conn;
1807 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1808 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1812 if (cmd->argc < 2) {
1813 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1814 "Usage: /OPER <username> [-pubkey]");
1815 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1819 if (cmd->argc < 3) {
1820 /* Get passphrase */
1821 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1822 silc_client_command_oper_send,
1827 silc_client_command_oper_send(NULL, 0, context);
1830 silc_client_command_free(cmd);
1833 static void silc_client_command_silcoper_send(unsigned char *data,
1834 SilcUInt32 data_len,
1837 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1838 SilcClientConnection conn = cmd->conn;
1839 SilcBuffer buffer, auth;
1841 if (cmd->argc >= 3) {
1842 /* Encode the public key authentication payload */
1843 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1844 cmd->client->private_key,
1845 cmd->client->rng, conn->hash,
1849 /* Encode the password authentication payload */
1850 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1854 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1856 strlen(cmd->argv[1]),
1857 2, auth->data, auth->len);
1858 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1859 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1861 silc_buffer_free(buffer);
1862 silc_buffer_free(auth);
1864 /* Notify application */
1865 COMMAND(SILC_STATUS_OK);
1868 /* SILCOPER command. Used to obtain router operator privileges. */
1870 SILC_CLIENT_CMD_FUNC(silcoper)
1872 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1873 SilcClientConnection conn = cmd->conn;
1876 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1877 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1881 if (cmd->argc < 2) {
1882 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1883 "Usage: /SILCOPER <username> [-pubkey]");
1884 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1888 if (cmd->argc < 3) {
1889 /* Get passphrase */
1890 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1891 silc_client_command_silcoper_send,
1896 silc_client_command_silcoper_send(NULL, 0, context);
1899 silc_client_command_free(cmd);
1902 /* Command BAN. This is used to manage the ban list of the channel. */
1904 SILC_CLIENT_CMD_FUNC(ban)
1906 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1907 SilcClientConnection conn = cmd->conn;
1908 SilcChannelEntry channel;
1909 SilcBuffer buffer, chidp;
1911 char *name, *ban = NULL;
1914 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1915 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1919 if (cmd->argc < 2) {
1920 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1921 "Usage: /BAN <channel> "
1922 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1923 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1927 if (cmd->argv[1][0] == '*') {
1928 if (!conn->current_channel) {
1929 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1930 "You are not on any channel");
1931 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1935 channel = conn->current_channel;
1937 name = cmd->argv[1];
1939 channel = silc_client_get_channel(cmd->client, conn, name);
1941 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1942 "You are noton that channel");
1943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1948 if (cmd->argc == 3) {
1949 if (cmd->argv[2][0] == '+')
1958 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1960 /* Send the command */
1961 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1962 ++conn->cmd_ident, 2,
1963 1, chidp->data, chidp->len,
1964 type, ban, ban ? strlen(ban) : 0);
1965 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1966 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1967 silc_buffer_free(buffer);
1968 silc_buffer_free(chidp);
1970 /* Notify application */
1971 COMMAND(SILC_STATUS_OK);
1974 silc_client_command_free(cmd);
1977 /* Command DETACH. This is used to detach from the server */
1979 SILC_CLIENT_CMD_FUNC(detach)
1981 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1982 SilcClientConnection conn = cmd->conn;
1986 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1987 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1991 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1992 ++conn->cmd_ident, 0);
1993 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1994 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1995 silc_buffer_free(buffer);
1997 /* Notify application */
1998 COMMAND(SILC_STATUS_OK);
2001 silc_client_command_free(cmd);
2004 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2006 SILC_CLIENT_CMD_FUNC(leave)
2008 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2009 SilcClientConnection conn = cmd->conn;
2010 SilcChannelEntry channel;
2011 SilcChannelUser chu;
2012 SilcBuffer buffer, idp;
2016 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2017 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2021 if (cmd->argc != 2) {
2022 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2023 "Usage: /LEAVE <channel>");
2024 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2028 if (cmd->argv[1][0] == '*') {
2029 if (!conn->current_channel) {
2030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "You are not on any channel");
2032 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2035 name = conn->current_channel->channel_name;
2037 name = cmd->argv[1];
2040 /* Get the channel entry */
2041 channel = silc_client_get_channel(cmd->client, conn, name);
2043 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2044 "You are not on that channel");
2045 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2049 /* Remove us from channel */
2050 chu = silc_client_on_channel(channel, conn->local_entry);
2052 silc_hash_table_del(chu->client->channels, chu->channel);
2053 silc_hash_table_del(chu->channel->user_list, chu->client);
2057 /* Send LEAVE command to the server */
2058 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2059 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2060 1, idp->data, idp->len);
2061 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2062 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2063 silc_buffer_free(buffer);
2064 silc_buffer_free(idp);
2066 /* Notify application */
2067 COMMAND(SILC_STATUS_OK);
2069 if (conn->current_channel == channel)
2070 conn->current_channel = NULL;
2072 silc_client_del_channel(cmd->client, cmd->conn, channel);
2075 silc_client_command_free(cmd);
2078 /* Command USERS. Requests the USERS of the clients joined on requested
2081 SILC_CLIENT_CMD_FUNC(users)
2083 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2084 SilcClientConnection conn = cmd->conn;
2089 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2090 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2094 if (cmd->argc != 2) {
2095 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2096 "Usage: /USERS <channel>");
2097 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2101 if (cmd->argv[1][0] == '*') {
2102 if (!conn->current_channel) {
2103 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2104 "You are not on any channel");
2105 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2108 name = conn->current_channel->channel_name;
2110 name = cmd->argv[1];
2113 /* Send USERS command to the server */
2114 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2115 ++conn->cmd_ident, 1,
2116 2, name, strlen(name));
2117 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2118 NULL, 0, NULL, NULL, buffer->data,
2120 silc_buffer_free(buffer);
2122 /* Notify application */
2123 COMMAND(SILC_STATUS_OK);
2126 silc_client_command_free(cmd);
2129 /* Command GETKEY. Used to fetch remote client's public key. */
2131 SILC_CLIENT_CMD_FUNC(getkey)
2133 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2134 SilcClientConnection conn = cmd->conn;
2135 SilcClient client = cmd->client;
2136 SilcClientEntry client_entry = NULL;
2137 SilcServerEntry server_entry = NULL;
2138 char *nickname = NULL;
2139 SilcBuffer idp, buffer;
2141 SILC_LOG_DEBUG(("Start"));
2144 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2145 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2149 if (cmd->argc < 2) {
2150 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2151 "Usage: /GETKEY <nickname or server name>");
2152 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2156 /* Parse the typed nickname. */
2157 if (client->internal->params->nickname_parse)
2158 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2160 nickname = strdup(cmd->argv[1]);
2162 /* Find client entry */
2163 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2165 if (!client_entry) {
2166 /* Check whether user requested server actually */
2167 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2169 if (!server_entry) {
2170 /* No. what ever user wants we don't have it, so resolve it. We
2171 will first try to resolve the client, and if that fails then
2172 we'll try to resolve the server. */
2174 if (!cmd->pending) {
2175 /* This will send the IDENTIFY command for nickname */
2176 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2177 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2179 silc_client_command_getkey,
2180 silc_client_command_dup(cmd));
2184 SilcClientCommandReplyContext reply =
2185 (SilcClientCommandReplyContext)context2;
2188 /* If nickname was not found, then resolve the server. */
2189 silc_command_get_status(reply->payload, NULL, &error);
2190 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2191 /* This sends the IDENTIFY command to resolve the server. */
2192 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2194 silc_client_command_reply_identify_i, 0,
2196 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2198 2, cmd->argv[1], cmd->argv_lens[1]);
2199 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2201 silc_client_command_getkey,
2202 silc_client_command_dup(cmd));
2206 /* If server was not found, then we've resolved both nickname and
2207 server and did not find anybody. */
2208 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2209 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2210 silc_client_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2211 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2212 silc_client_status_message(error));
2213 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2217 COMMAND_ERROR(error);
2222 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2224 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2227 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2228 1, idp->data, idp->len);
2229 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2230 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2231 silc_buffer_free(buffer);
2232 silc_buffer_free(idp);
2234 /* Notify application */
2235 COMMAND(SILC_STATUS_OK);
2238 silc_free(nickname);
2239 silc_client_command_free(cmd);
2242 /* Register a new command indicated by the `command' to the SILC client.
2243 The `name' is optional command name. If provided the command may be
2244 searched using the silc_client_command_find by that name. The
2245 `command_function' is the function to be called when the command is
2246 executed, and the `command_reply_function' is the function to be
2247 called after the server has sent reply back to the command.
2249 The `ident' is optional identifier for the command. If non-zero
2250 the `command_reply_function' for the command type `command' will be
2251 called only if the command reply sent by server includes the
2252 command identifier `ident'. Application usually does not need it
2253 and set it to zero value. */
2255 bool silc_client_command_register(SilcClient client,
2256 SilcCommand command,
2258 SilcCommandCb command_function,
2259 SilcCommandCb command_reply_function,
2263 SilcClientCommand cmd;
2265 cmd = silc_calloc(1, sizeof(*cmd));
2267 cmd->command = command_function;
2268 cmd->reply = command_reply_function;
2269 cmd->name = name ? strdup(name) : NULL;
2270 cmd->max_args = max_args;
2273 silc_list_add(client->internal->commands, cmd);
2278 /* Unregister a command indicated by the `command' with command function
2279 `command_function' and command reply function `command_reply_function'.
2280 Returns TRUE if the command was found and unregistered. */
2282 bool silc_client_command_unregister(SilcClient client,
2283 SilcCommand command,
2284 SilcCommandCb command_function,
2285 SilcCommandCb command_reply_function,
2288 SilcClientCommand cmd;
2290 silc_list_start(client->internal->commands);
2291 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2292 if (cmd->cmd == command && cmd->command == command_function &&
2293 cmd->reply == command_reply_function && cmd->ident == ident) {
2294 silc_list_del(client->internal->commands, cmd);
2295 silc_free(cmd->name);
2304 /* Private range commands, specific to this implementation (and compatible
2305 with SILC Server). */
2307 /* CONNECT command. Connects the server to another server. */
2309 SILC_CLIENT_CMD_FUNC(connect)
2311 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2312 SilcClientConnection conn = cmd->conn;
2314 unsigned char port[4];
2318 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2319 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2323 if (cmd->argc < 2) {
2324 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2325 "Usage: /CONNECT <server> [<port>]");
2326 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2330 if (cmd->argc == 3) {
2331 tmp = atoi(cmd->argv[2]);
2332 SILC_PUT32_MSB(tmp, port);
2336 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2338 strlen(cmd->argv[1]),
2341 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2343 strlen(cmd->argv[1]));
2344 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2345 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2346 silc_buffer_free(buffer);
2348 /* Notify application */
2349 COMMAND(SILC_STATUS_OK);
2352 silc_client_command_free(cmd);
2356 /* CLOSE command. Close server connection to the remote server */
2358 SILC_CLIENT_CMD_FUNC(close)
2360 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2361 SilcClientConnection conn = cmd->conn;
2363 unsigned char port[4];
2367 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2368 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2372 if (cmd->argc < 2) {
2373 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2374 "Usage: /CLOSE <server> [<port>]");
2375 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2379 if (cmd->argc == 3) {
2380 tmp = atoi(cmd->argv[2]);
2381 SILC_PUT32_MSB(tmp, port);
2385 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2387 strlen(cmd->argv[1]),
2390 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2392 strlen(cmd->argv[1]));
2393 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2394 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2395 silc_buffer_free(buffer);
2397 /* Notify application */
2398 COMMAND(SILC_STATUS_OK);
2401 silc_client_command_free(cmd);
2404 /* SHUTDOWN command. Shutdowns the server. */
2406 SILC_CLIENT_CMD_FUNC(shutdown)
2408 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2411 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2412 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2416 /* Send the command */
2417 silc_client_command_send(cmd->client, cmd->conn,
2418 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2420 /* Notify application */
2421 COMMAND(SILC_STATUS_OK);
2424 silc_client_command_free(cmd);
2427 /* Register all default commands provided by the client library for the
2430 void silc_client_commands_register(SilcClient client)
2432 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2435 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2436 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2437 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2438 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2439 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2440 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2441 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2442 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2443 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2444 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2445 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2446 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2447 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2448 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2449 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2450 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2451 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2452 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2453 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2454 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2455 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2456 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2457 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2458 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2460 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2461 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2462 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2465 /* Unregister all commands. */
2467 void silc_client_commands_unregister(SilcClient client)
2469 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2470 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2471 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2472 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2473 SILC_CLIENT_CMDU(list, LIST, "LIST");
2474 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2475 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2476 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2477 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2478 SILC_CLIENT_CMDU(info, INFO, "INFO");
2479 SILC_CLIENT_CMDU(ping, PING, "PING");
2480 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2481 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2482 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2483 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2484 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2485 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2486 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2487 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2488 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2489 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2490 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2491 SILC_CLIENT_CMDU(users, USERS, "USERS");
2492 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2494 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2495 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2496 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");