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;
1169 mode |= SILC_UMODE_GONE;
1170 mode |= SILC_UMODE_INDISPOSED;
1171 mode |= SILC_UMODE_BUSY;
1172 mode |= SILC_UMODE_PAGE;
1173 mode |= SILC_UMODE_HYPER;
1174 mode |= SILC_UMODE_ROBOT;
1175 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1176 mode |= SILC_UMODE_REJECT_WATCHING;
1178 mode = SILC_UMODE_NONE;
1183 mode |= SILC_UMODE_SERVER_OPERATOR;
1185 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1189 mode |= SILC_UMODE_ROUTER_OPERATOR;
1191 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1195 mode |= SILC_UMODE_GONE;
1197 mode &= ~SILC_UMODE_GONE;
1201 mode |= SILC_UMODE_INDISPOSED;
1203 mode &= ~SILC_UMODE_INDISPOSED;
1207 mode |= SILC_UMODE_BUSY;
1209 mode &= ~SILC_UMODE_BUSY;
1213 mode |= SILC_UMODE_PAGE;
1215 mode &= ~SILC_UMODE_PAGE;
1219 mode |= SILC_UMODE_HYPER;
1221 mode &= ~SILC_UMODE_HYPER;
1225 mode |= SILC_UMODE_ROBOT;
1227 mode &= ~SILC_UMODE_ROBOT;
1231 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1233 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1237 mode |= SILC_UMODE_REJECT_WATCHING;
1239 mode &= ~SILC_UMODE_REJECT_WATCHING;
1243 mode |= SILC_UMODE_BLOCK_INVITE;
1245 mode &= ~SILC_UMODE_BLOCK_INVITE;
1248 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1254 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1255 SILC_PUT32_MSB(mode, modebuf);
1257 /* Send the command packet. We support sending only one mode at once
1258 that requires an argument. */
1260 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1261 1, idp->data, idp->len,
1262 2, modebuf, sizeof(modebuf));
1263 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1264 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1265 silc_buffer_free(buffer);
1266 silc_buffer_free(idp);
1268 /* Notify application */
1269 COMMAND(SILC_STATUS_OK);
1272 silc_client_command_free(cmd);
1275 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1276 can be set several at once. Those modes that require argument must be set
1277 separately (unless set with modes that does not require arguments). */
1279 SILC_CLIENT_CMD_FUNC(cmode)
1281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1282 SilcClientConnection conn = cmd->conn;
1283 SilcChannelEntry channel;
1284 SilcBuffer buffer, chidp, auth = NULL;
1285 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1286 SilcUInt32 mode, add, type, len, arg_len = 0;
1290 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1291 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1295 if (cmd->argc < 3) {
1296 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1297 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1298 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1302 if (cmd->argv[1][0] == '*') {
1303 if (!conn->current_channel) {
1304 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1305 "You are not on any channel");
1306 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1310 channel = conn->current_channel;
1312 name = cmd->argv[1];
1314 channel = silc_client_get_channel(cmd->client, conn, name);
1316 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1317 "You are on that channel");
1318 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1323 mode = channel->mode;
1325 /* Are we adding or removing mode */
1326 if (cmd->argv[2][0] == '-')
1331 /* Argument type to be sent to server */
1335 cp = cmd->argv[2] + 1;
1337 for (i = 0; i < len; i++) {
1341 mode |= SILC_CHANNEL_MODE_PRIVATE;
1343 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1347 mode |= SILC_CHANNEL_MODE_SECRET;
1349 mode &= ~SILC_CHANNEL_MODE_SECRET;
1353 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1355 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1359 mode |= SILC_CHANNEL_MODE_INVITE;
1361 mode &= ~SILC_CHANNEL_MODE_INVITE;
1365 mode |= SILC_CHANNEL_MODE_TOPIC;
1367 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1371 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1373 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1377 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1379 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1384 mode |= SILC_CHANNEL_MODE_ULIMIT;
1386 if (cmd->argc < 4) {
1387 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1388 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1389 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1392 ll = atoi(cmd->argv[3]);
1393 SILC_PUT32_MSB(ll, tmp);
1397 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1402 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1404 if (cmd->argc < 4) {
1405 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1406 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1407 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1411 arg_len = cmd->argv_lens[3];
1413 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1418 mode |= SILC_CHANNEL_MODE_CIPHER;
1420 if (cmd->argc < 4) {
1421 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1422 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1423 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1427 arg_len = cmd->argv_lens[3];
1429 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1434 mode |= SILC_CHANNEL_MODE_HMAC;
1436 if (cmd->argc < 4) {
1437 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1438 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1439 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1443 arg_len = cmd->argv_lens[3];
1445 mode &= ~SILC_CHANNEL_MODE_HMAC;
1450 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1453 if (cmd->argc < 4) {
1454 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1455 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1456 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1460 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1461 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1462 cmd->client->private_key,
1468 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1469 cmd->argv[3], cmd->argv_lens[3]);
1473 arg_len = auth->len;
1475 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1479 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1485 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1486 SILC_PUT32_MSB(mode, modebuf);
1488 /* Send the command packet. We support sending only one mode at once
1489 that requires an argument. */
1492 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1493 1, chidp->data, chidp->len,
1494 2, modebuf, sizeof(modebuf),
1495 type, arg, arg_len);
1498 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1499 1, chidp->data, chidp->len,
1500 2, modebuf, sizeof(modebuf));
1503 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1504 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1505 silc_buffer_free(buffer);
1506 silc_buffer_free(chidp);
1508 silc_buffer_free(auth);
1510 /* Notify application */
1511 COMMAND(SILC_STATUS_OK);
1514 silc_client_command_free(cmd);
1517 /* CUMODE command. Changes client's mode on a channel. */
1519 SILC_CLIENT_CMD_FUNC(cumode)
1521 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1522 SilcClient client = cmd->client;
1523 SilcClientConnection conn = cmd->conn;
1524 SilcChannelEntry channel;
1525 SilcChannelUser chu;
1526 SilcClientEntry client_entry;
1527 SilcBuffer buffer, clidp, chidp, auth = NULL;
1528 unsigned char *name, *cp, modebuf[4];
1529 SilcUInt32 mode = 0, add, len;
1530 char *nickname = NULL;
1534 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1535 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1539 if (cmd->argc < 4) {
1540 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1541 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1542 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1546 if (cmd->argv[1][0] == '*') {
1547 if (!conn->current_channel) {
1548 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1549 "You are not on any channel");
1550 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1554 channel = conn->current_channel;
1556 name = cmd->argv[1];
1558 channel = silc_client_get_channel(cmd->client, conn, name);
1560 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1561 "You are on that channel");
1562 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1567 /* Parse the typed nickname. */
1568 if (client->internal->params->nickname_parse)
1569 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1571 nickname = strdup(cmd->argv[3]);
1573 /* Find client entry */
1574 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1575 cmd->argv[3], TRUE);
1576 if (!client_entry) {
1578 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1582 /* Client entry not found, it was requested thus mark this to be
1584 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1586 silc_client_command_cumode,
1587 silc_client_command_dup(cmd));
1592 /* Get the current mode */
1593 chu = silc_client_on_channel(channel, client_entry);
1597 /* Are we adding or removing mode */
1598 if (cmd->argv[2][0] == '-')
1604 cp = cmd->argv[2] + 1;
1606 for (i = 0; i < len; i++) {
1610 mode |= SILC_CHANNEL_UMODE_CHANFO;
1611 mode |= SILC_CHANNEL_UMODE_CHANOP;
1612 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1613 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1614 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1616 mode = SILC_CHANNEL_UMODE_NONE;
1621 if (cmd->argc == 5) {
1622 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1623 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1624 cmd->client->private_key,
1630 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1631 cmd->argv[4], cmd->argv_lens[4]);
1634 mode |= SILC_CHANNEL_UMODE_CHANFO;
1636 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1641 mode |= SILC_CHANNEL_UMODE_CHANOP;
1643 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1647 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1649 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1653 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1655 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1659 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1661 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1664 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1670 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1671 SILC_PUT32_MSB(mode, modebuf);
1672 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1674 /* Send the command packet. We support sending only one mode at once
1675 that requires an argument. */
1676 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1678 1, chidp->data, chidp->len,
1680 3, clidp->data, clidp->len,
1681 4, auth ? auth->data : NULL,
1682 auth ? auth->len : 0);
1684 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1685 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1686 silc_buffer_free(buffer);
1687 silc_buffer_free(chidp);
1688 silc_buffer_free(clidp);
1690 silc_buffer_free(auth);
1692 /* Notify application */
1693 COMMAND(SILC_STATUS_OK);
1696 silc_free(nickname);
1697 silc_client_command_free(cmd);
1700 /* KICK command. Kicks a client out of channel. */
1702 SILC_CLIENT_CMD_FUNC(kick)
1704 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1705 SilcClient client = cmd->client;
1706 SilcClientConnection conn = cmd->conn;
1707 SilcIDCacheEntry id_cache = NULL;
1708 SilcChannelEntry channel;
1709 SilcBuffer buffer, idp, idp2;
1710 SilcClientEntry target;
1712 char *nickname = NULL;
1715 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1716 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1720 if (cmd->argc < 3) {
1721 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1722 "Usage: /KICK <channel> <nickname> [<comment>]");
1723 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1727 if (cmd->argv[1][0] == '*') {
1728 if (!conn->current_channel) {
1729 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1730 "You are not on any channel");
1731 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1734 name = conn->current_channel->channel_name;
1736 name = cmd->argv[1];
1739 if (!conn->current_channel) {
1740 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1741 "You are not on that channel");
1742 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1746 /* Get the Channel ID of the channel */
1747 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1748 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1749 "You are not on that channel");
1750 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1754 channel = (SilcChannelEntry)id_cache->context;
1756 /* Parse the typed nickname. */
1757 if (client->internal->params->nickname_parse)
1758 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1760 nickname = strdup(cmd->argv[2]);
1762 /* Get the target client */
1763 target = silc_idlist_get_client(cmd->client, conn, nickname,
1764 cmd->argv[2], FALSE);
1766 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1767 "No such client: %s", cmd->argv[2]);
1768 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1772 /* Send KICK command to the server */
1773 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1774 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1776 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1777 1, idp->data, idp->len,
1778 2, idp2->data, idp2->len);
1780 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1781 1, idp->data, idp->len,
1782 2, idp2->data, idp2->len,
1784 strlen(cmd->argv[3]));
1785 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1786 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1787 silc_buffer_free(buffer);
1788 silc_buffer_free(idp);
1789 silc_buffer_free(idp2);
1791 /* Notify application */
1792 COMMAND(SILC_STATUS_OK);
1795 silc_free(nickname);
1796 silc_client_command_free(cmd);
1799 static void silc_client_command_oper_send(unsigned char *data,
1800 SilcUInt32 data_len, void *context)
1802 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1803 SilcClientConnection conn = cmd->conn;
1804 SilcBuffer buffer, auth;
1806 if (cmd->argc >= 3) {
1807 /* Encode the public key authentication payload */
1808 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1809 cmd->client->private_key,
1810 cmd->client->rng, conn->hash,
1814 /* Encode the password authentication payload */
1815 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1819 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1821 strlen(cmd->argv[1]),
1822 2, auth->data, auth->len);
1823 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1824 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1826 silc_buffer_free(buffer);
1827 silc_buffer_free(auth);
1829 /* Notify application */
1830 COMMAND(SILC_STATUS_OK);
1833 /* OPER command. Used to obtain server operator privileges. */
1835 SILC_CLIENT_CMD_FUNC(oper)
1837 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1838 SilcClientConnection conn = cmd->conn;
1841 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1842 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1846 if (cmd->argc < 2) {
1847 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1848 "Usage: /OPER <username> [-pubkey]");
1849 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1853 if (cmd->argc < 3) {
1854 /* Get passphrase */
1855 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1856 silc_client_command_oper_send,
1861 silc_client_command_oper_send(NULL, 0, context);
1864 silc_client_command_free(cmd);
1867 static void silc_client_command_silcoper_send(unsigned char *data,
1868 SilcUInt32 data_len,
1871 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1872 SilcClientConnection conn = cmd->conn;
1873 SilcBuffer buffer, auth;
1875 if (cmd->argc >= 3) {
1876 /* Encode the public key authentication payload */
1877 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1878 cmd->client->private_key,
1879 cmd->client->rng, conn->hash,
1883 /* Encode the password authentication payload */
1884 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1888 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1890 strlen(cmd->argv[1]),
1891 2, auth->data, auth->len);
1892 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1893 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1895 silc_buffer_free(buffer);
1896 silc_buffer_free(auth);
1898 /* Notify application */
1899 COMMAND(SILC_STATUS_OK);
1902 /* SILCOPER command. Used to obtain router operator privileges. */
1904 SILC_CLIENT_CMD_FUNC(silcoper)
1906 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1907 SilcClientConnection conn = cmd->conn;
1910 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1911 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1915 if (cmd->argc < 2) {
1916 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1917 "Usage: /SILCOPER <username> [-pubkey]");
1918 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1922 if (cmd->argc < 3) {
1923 /* Get passphrase */
1924 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1925 silc_client_command_silcoper_send,
1930 silc_client_command_silcoper_send(NULL, 0, context);
1933 silc_client_command_free(cmd);
1936 /* Command BAN. This is used to manage the ban list of the channel. */
1938 SILC_CLIENT_CMD_FUNC(ban)
1940 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1941 SilcClientConnection conn = cmd->conn;
1942 SilcChannelEntry channel;
1943 SilcBuffer buffer, chidp;
1945 char *name, *ban = NULL;
1948 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1949 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1953 if (cmd->argc < 2) {
1954 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1955 "Usage: /BAN <channel> "
1956 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1957 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1961 if (cmd->argv[1][0] == '*') {
1962 if (!conn->current_channel) {
1963 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1964 "You are not on any channel");
1965 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1969 channel = conn->current_channel;
1971 name = cmd->argv[1];
1973 channel = silc_client_get_channel(cmd->client, conn, name);
1975 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1976 "You are noton that channel");
1977 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1982 if (cmd->argc == 3) {
1983 if (cmd->argv[2][0] == '+')
1992 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1994 /* Send the command */
1995 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1996 ++conn->cmd_ident, 2,
1997 1, chidp->data, chidp->len,
1998 type, ban, ban ? strlen(ban) : 0);
1999 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2000 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2001 silc_buffer_free(buffer);
2002 silc_buffer_free(chidp);
2004 /* Notify application */
2005 COMMAND(SILC_STATUS_OK);
2008 silc_client_command_free(cmd);
2011 /* Command DETACH. This is used to detach from the server */
2013 SILC_CLIENT_CMD_FUNC(detach)
2015 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2016 SilcClientConnection conn = cmd->conn;
2020 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2021 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2025 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2026 ++conn->cmd_ident, 0);
2027 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2028 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2029 silc_buffer_free(buffer);
2031 /* Notify application */
2032 COMMAND(SILC_STATUS_OK);
2035 silc_client_command_free(cmd);
2038 /* Command WATCH. */
2040 SILC_CLIENT_CMD_FUNC(watch)
2042 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2043 SilcClientConnection conn = cmd->conn;
2044 SilcBuffer buffer, idp = NULL;
2048 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2049 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2053 if (cmd->argc < 3) {
2054 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2058 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2060 if (!strcasecmp(cmd->argv[1], "-add")) {
2062 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2065 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2069 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2070 ++conn->cmd_ident, 2,
2071 1, idp->data, idp->len,
2074 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2075 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2076 silc_buffer_free(buffer);
2078 /* Notify application */
2079 COMMAND(SILC_STATUS_OK);
2083 silc_buffer_free(idp);
2084 silc_client_command_free(cmd);
2087 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2089 SILC_CLIENT_CMD_FUNC(leave)
2091 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2092 SilcClientConnection conn = cmd->conn;
2093 SilcChannelEntry channel;
2094 SilcChannelUser chu;
2095 SilcBuffer buffer, idp;
2099 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2100 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2104 if (cmd->argc != 2) {
2105 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2106 "Usage: /LEAVE <channel>");
2107 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2111 if (cmd->argv[1][0] == '*') {
2112 if (!conn->current_channel) {
2113 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2114 "You are not on any channel");
2115 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2118 name = conn->current_channel->channel_name;
2120 name = cmd->argv[1];
2123 /* Get the channel entry */
2124 channel = silc_client_get_channel(cmd->client, conn, name);
2126 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2127 "You are not on that channel");
2128 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2132 /* Remove us from channel */
2133 chu = silc_client_on_channel(channel, conn->local_entry);
2135 silc_hash_table_del(chu->client->channels, chu->channel);
2136 silc_hash_table_del(chu->channel->user_list, chu->client);
2140 /* Send LEAVE command to the server */
2141 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2142 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2143 1, idp->data, idp->len);
2144 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2145 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2146 silc_buffer_free(buffer);
2147 silc_buffer_free(idp);
2149 /* Notify application */
2150 COMMAND(SILC_STATUS_OK);
2152 if (conn->current_channel == channel)
2153 conn->current_channel = NULL;
2155 silc_client_del_channel(cmd->client, cmd->conn, channel);
2158 silc_client_command_free(cmd);
2161 /* Command USERS. Requests the USERS of the clients joined on requested
2164 SILC_CLIENT_CMD_FUNC(users)
2166 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2167 SilcClientConnection conn = cmd->conn;
2172 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2173 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2177 if (cmd->argc != 2) {
2178 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2179 "Usage: /USERS <channel>");
2180 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2184 if (cmd->argv[1][0] == '*') {
2185 if (!conn->current_channel) {
2186 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2187 "You are not on any channel");
2188 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2191 name = conn->current_channel->channel_name;
2193 name = cmd->argv[1];
2196 /* Send USERS command to the server */
2197 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2198 ++conn->cmd_ident, 1,
2199 2, name, strlen(name));
2200 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2201 NULL, 0, NULL, NULL, buffer->data,
2203 silc_buffer_free(buffer);
2205 /* Notify application */
2206 COMMAND(SILC_STATUS_OK);
2209 silc_client_command_free(cmd);
2212 /* Command GETKEY. Used to fetch remote client's public key. */
2214 SILC_CLIENT_CMD_FUNC(getkey)
2216 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2217 SilcClientConnection conn = cmd->conn;
2218 SilcClient client = cmd->client;
2219 SilcClientEntry client_entry = NULL;
2220 SilcServerEntry server_entry = NULL;
2221 char *nickname = NULL;
2222 SilcBuffer idp, buffer;
2224 SILC_LOG_DEBUG(("Start"));
2227 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2228 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2232 if (cmd->argc < 2) {
2233 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2234 "Usage: /GETKEY <nickname or server name>");
2235 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2239 /* Parse the typed nickname. */
2240 if (client->internal->params->nickname_parse)
2241 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2243 nickname = strdup(cmd->argv[1]);
2245 /* Find client entry */
2246 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2248 if (!client_entry) {
2249 /* Check whether user requested server actually */
2250 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2252 if (!server_entry) {
2253 /* No. what ever user wants we don't have it, so resolve it. We
2254 will first try to resolve the client, and if that fails then
2255 we'll try to resolve the server. */
2257 if (!cmd->pending) {
2258 /* This will send the IDENTIFY command for nickname */
2259 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2260 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2262 silc_client_command_getkey,
2263 silc_client_command_dup(cmd));
2267 SilcClientCommandReplyContext reply =
2268 (SilcClientCommandReplyContext)context2;
2271 /* If nickname was not found, then resolve the server. */
2272 silc_command_get_status(reply->payload, NULL, &error);
2273 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2274 /* This sends the IDENTIFY command to resolve the server. */
2275 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2277 silc_client_command_reply_identify_i, 0,
2279 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2281 2, cmd->argv[1], cmd->argv_lens[1]);
2282 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2284 silc_client_command_getkey,
2285 silc_client_command_dup(cmd));
2289 /* If server was not found, then we've resolved both nickname and
2290 server and did not find anybody. */
2291 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2292 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2293 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2294 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2295 silc_get_status_message(error));
2296 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2300 COMMAND_ERROR(error);
2305 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2307 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2310 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2311 1, idp->data, idp->len);
2312 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2313 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2314 silc_buffer_free(buffer);
2315 silc_buffer_free(idp);
2317 /* Notify application */
2318 COMMAND(SILC_STATUS_OK);
2321 silc_free(nickname);
2322 silc_client_command_free(cmd);
2325 /* Register a new command indicated by the `command' to the SILC client.
2326 The `name' is optional command name. If provided the command may be
2327 searched using the silc_client_command_find by that name. The
2328 `command_function' is the function to be called when the command is
2329 executed, and the `command_reply_function' is the function to be
2330 called after the server has sent reply back to the command.
2332 The `ident' is optional identifier for the command. If non-zero
2333 the `command_reply_function' for the command type `command' will be
2334 called only if the command reply sent by server includes the
2335 command identifier `ident'. Application usually does not need it
2336 and set it to zero value. */
2338 bool silc_client_command_register(SilcClient client,
2339 SilcCommand command,
2341 SilcCommandCb command_function,
2342 SilcCommandCb command_reply_function,
2346 SilcClientCommand cmd;
2348 cmd = silc_calloc(1, sizeof(*cmd));
2350 cmd->command = command_function;
2351 cmd->reply = command_reply_function;
2352 cmd->name = name ? strdup(name) : NULL;
2353 cmd->max_args = max_args;
2356 silc_list_add(client->internal->commands, cmd);
2361 /* Unregister a command indicated by the `command' with command function
2362 `command_function' and command reply function `command_reply_function'.
2363 Returns TRUE if the command was found and unregistered. */
2365 bool silc_client_command_unregister(SilcClient client,
2366 SilcCommand command,
2367 SilcCommandCb command_function,
2368 SilcCommandCb command_reply_function,
2371 SilcClientCommand cmd;
2373 silc_list_start(client->internal->commands);
2374 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2375 if (cmd->cmd == command && cmd->command == command_function &&
2376 cmd->reply == command_reply_function && cmd->ident == ident) {
2377 silc_list_del(client->internal->commands, cmd);
2378 silc_free(cmd->name);
2387 /* Private range commands, specific to this implementation (and compatible
2388 with SILC Server). */
2390 /* CONNECT command. Connects the server to another server. */
2392 SILC_CLIENT_CMD_FUNC(connect)
2394 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2395 SilcClientConnection conn = cmd->conn;
2397 unsigned char port[4];
2401 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2402 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2406 if (cmd->argc < 2) {
2407 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2408 "Usage: /CONNECT <server> [<port>]");
2409 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2413 if (cmd->argc == 3) {
2414 tmp = atoi(cmd->argv[2]);
2415 SILC_PUT32_MSB(tmp, port);
2419 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2421 strlen(cmd->argv[1]),
2424 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2426 strlen(cmd->argv[1]));
2427 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2428 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2429 silc_buffer_free(buffer);
2431 /* Notify application */
2432 COMMAND(SILC_STATUS_OK);
2435 silc_client_command_free(cmd);
2439 /* CLOSE command. Close server connection to the remote server */
2441 SILC_CLIENT_CMD_FUNC(close)
2443 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2444 SilcClientConnection conn = cmd->conn;
2446 unsigned char port[4];
2450 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2451 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2455 if (cmd->argc < 2) {
2456 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2457 "Usage: /CLOSE <server> [<port>]");
2458 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2462 if (cmd->argc == 3) {
2463 tmp = atoi(cmd->argv[2]);
2464 SILC_PUT32_MSB(tmp, port);
2468 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2470 strlen(cmd->argv[1]),
2473 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2475 strlen(cmd->argv[1]));
2476 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2477 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2478 silc_buffer_free(buffer);
2480 /* Notify application */
2481 COMMAND(SILC_STATUS_OK);
2484 silc_client_command_free(cmd);
2487 /* SHUTDOWN command. Shutdowns the server. */
2489 SILC_CLIENT_CMD_FUNC(shutdown)
2491 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2494 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2495 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2499 /* Send the command */
2500 silc_client_command_send(cmd->client, cmd->conn,
2501 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2503 /* Notify application */
2504 COMMAND(SILC_STATUS_OK);
2507 silc_client_command_free(cmd);
2510 /* Register all default commands provided by the client library for the
2513 void silc_client_commands_register(SilcClient client)
2515 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2518 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2519 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2520 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2521 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2522 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2523 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2524 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2525 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2526 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2527 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2528 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2529 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2530 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2531 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2532 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2533 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2534 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2535 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2536 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2537 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2538 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2539 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2540 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2541 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2542 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2544 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2545 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2546 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2549 /* Unregister all commands. */
2551 void silc_client_commands_unregister(SilcClient client)
2553 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2554 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2555 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2556 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2557 SILC_CLIENT_CMDU(list, LIST, "LIST");
2558 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2559 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2560 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2561 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2562 SILC_CLIENT_CMDU(info, INFO, "INFO");
2563 SILC_CLIENT_CMDU(ping, PING, "PING");
2564 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2565 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2566 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2567 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2568 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2569 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2570 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2571 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2572 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2573 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2574 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2575 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2576 SILC_CLIENT_CMDU(users, USERS, "USERS");
2577 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2579 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2580 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2581 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");