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;
1242 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1248 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1249 SILC_PUT32_MSB(mode, modebuf);
1251 /* Send the command packet. We support sending only one mode at once
1252 that requires an argument. */
1254 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1255 1, idp->data, idp->len,
1256 2, modebuf, sizeof(modebuf));
1257 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1258 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1259 silc_buffer_free(buffer);
1260 silc_buffer_free(idp);
1262 /* Notify application */
1263 COMMAND(SILC_STATUS_OK);
1266 silc_client_command_free(cmd);
1269 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1270 can be set several at once. Those modes that require argument must be set
1271 separately (unless set with modes that does not require arguments). */
1273 SILC_CLIENT_CMD_FUNC(cmode)
1275 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1276 SilcClientConnection conn = cmd->conn;
1277 SilcChannelEntry channel;
1278 SilcBuffer buffer, chidp, auth = NULL;
1279 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1280 SilcUInt32 mode, add, type, len, arg_len = 0;
1284 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1285 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1289 if (cmd->argc < 3) {
1290 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1291 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1292 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1296 if (cmd->argv[1][0] == '*') {
1297 if (!conn->current_channel) {
1298 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1299 "You are not on any channel");
1300 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1304 channel = conn->current_channel;
1306 name = cmd->argv[1];
1308 channel = silc_client_get_channel(cmd->client, conn, name);
1310 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1311 "You are on that channel");
1312 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1317 mode = channel->mode;
1319 /* Are we adding or removing mode */
1320 if (cmd->argv[2][0] == '-')
1325 /* Argument type to be sent to server */
1329 cp = cmd->argv[2] + 1;
1331 for (i = 0; i < len; i++) {
1335 mode |= SILC_CHANNEL_MODE_PRIVATE;
1337 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1341 mode |= SILC_CHANNEL_MODE_SECRET;
1343 mode &= ~SILC_CHANNEL_MODE_SECRET;
1347 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1349 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1353 mode |= SILC_CHANNEL_MODE_INVITE;
1355 mode &= ~SILC_CHANNEL_MODE_INVITE;
1359 mode |= SILC_CHANNEL_MODE_TOPIC;
1361 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1365 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1367 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1371 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1373 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1378 mode |= SILC_CHANNEL_MODE_ULIMIT;
1380 if (cmd->argc < 4) {
1381 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1382 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1383 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1386 ll = atoi(cmd->argv[3]);
1387 SILC_PUT32_MSB(ll, tmp);
1391 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1396 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1398 if (cmd->argc < 4) {
1399 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1400 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1401 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1405 arg_len = cmd->argv_lens[3];
1407 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1412 mode |= SILC_CHANNEL_MODE_CIPHER;
1414 if (cmd->argc < 4) {
1415 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1416 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1417 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1421 arg_len = cmd->argv_lens[3];
1423 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1428 mode |= SILC_CHANNEL_MODE_HMAC;
1430 if (cmd->argc < 4) {
1431 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1432 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1433 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1437 arg_len = cmd->argv_lens[3];
1439 mode &= ~SILC_CHANNEL_MODE_HMAC;
1444 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1447 if (cmd->argc < 4) {
1448 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1449 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1450 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1454 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1455 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1456 cmd->client->private_key,
1462 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1463 cmd->argv[3], cmd->argv_lens[3]);
1467 arg_len = auth->len;
1469 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1473 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1479 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1480 SILC_PUT32_MSB(mode, modebuf);
1482 /* Send the command packet. We support sending only one mode at once
1483 that requires an argument. */
1486 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1487 1, chidp->data, chidp->len,
1488 2, modebuf, sizeof(modebuf),
1489 type, arg, arg_len);
1492 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1493 1, chidp->data, chidp->len,
1494 2, modebuf, sizeof(modebuf));
1497 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1498 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1499 silc_buffer_free(buffer);
1500 silc_buffer_free(chidp);
1502 silc_buffer_free(auth);
1504 /* Notify application */
1505 COMMAND(SILC_STATUS_OK);
1508 silc_client_command_free(cmd);
1511 /* CUMODE command. Changes client's mode on a channel. */
1513 SILC_CLIENT_CMD_FUNC(cumode)
1515 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1516 SilcClient client = cmd->client;
1517 SilcClientConnection conn = cmd->conn;
1518 SilcChannelEntry channel;
1519 SilcChannelUser chu;
1520 SilcClientEntry client_entry;
1521 SilcBuffer buffer, clidp, chidp, auth = NULL;
1522 unsigned char *name, *cp, modebuf[4];
1523 SilcUInt32 mode = 0, add, len;
1524 char *nickname = NULL;
1528 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1529 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1533 if (cmd->argc < 4) {
1534 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1535 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1536 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1540 if (cmd->argv[1][0] == '*') {
1541 if (!conn->current_channel) {
1542 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1543 "You are not on any channel");
1544 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1548 channel = conn->current_channel;
1550 name = cmd->argv[1];
1552 channel = silc_client_get_channel(cmd->client, conn, name);
1554 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1555 "You are on that channel");
1556 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1561 /* Parse the typed nickname. */
1562 if (client->internal->params->nickname_parse)
1563 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1565 nickname = strdup(cmd->argv[3]);
1567 /* Find client entry */
1568 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1569 cmd->argv[3], TRUE);
1570 if (!client_entry) {
1572 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1576 /* Client entry not found, it was requested thus mark this to be
1578 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1580 silc_client_command_cumode,
1581 silc_client_command_dup(cmd));
1586 /* Get the current mode */
1587 chu = silc_client_on_channel(channel, client_entry);
1591 /* Are we adding or removing mode */
1592 if (cmd->argv[2][0] == '-')
1598 cp = cmd->argv[2] + 1;
1600 for (i = 0; i < len; i++) {
1604 mode |= SILC_CHANNEL_UMODE_CHANFO;
1605 mode |= SILC_CHANNEL_UMODE_CHANOP;
1606 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1607 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1608 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1610 mode = SILC_CHANNEL_UMODE_NONE;
1615 if (cmd->argc == 5) {
1616 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1617 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1618 cmd->client->private_key,
1624 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1625 cmd->argv[4], cmd->argv_lens[4]);
1628 mode |= SILC_CHANNEL_UMODE_CHANFO;
1630 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1635 mode |= SILC_CHANNEL_UMODE_CHANOP;
1637 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1641 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1643 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1647 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1649 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1653 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1655 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1658 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1664 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1665 SILC_PUT32_MSB(mode, modebuf);
1666 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1668 /* Send the command packet. We support sending only one mode at once
1669 that requires an argument. */
1670 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1672 1, chidp->data, chidp->len,
1674 3, clidp->data, clidp->len,
1675 4, auth ? auth->data : NULL,
1676 auth ? auth->len : 0);
1678 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1679 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1680 silc_buffer_free(buffer);
1681 silc_buffer_free(chidp);
1682 silc_buffer_free(clidp);
1684 silc_buffer_free(auth);
1686 /* Notify application */
1687 COMMAND(SILC_STATUS_OK);
1690 silc_free(nickname);
1691 silc_client_command_free(cmd);
1694 /* KICK command. Kicks a client out of channel. */
1696 SILC_CLIENT_CMD_FUNC(kick)
1698 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1699 SilcClient client = cmd->client;
1700 SilcClientConnection conn = cmd->conn;
1701 SilcIDCacheEntry id_cache = NULL;
1702 SilcChannelEntry channel;
1703 SilcBuffer buffer, idp, idp2;
1704 SilcClientEntry target;
1706 char *nickname = NULL;
1709 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1710 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1714 if (cmd->argc < 3) {
1715 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1716 "Usage: /KICK <channel> <nickname> [<comment>]");
1717 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1721 if (cmd->argv[1][0] == '*') {
1722 if (!conn->current_channel) {
1723 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1724 "You are not on any channel");
1725 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1728 name = conn->current_channel->channel_name;
1730 name = cmd->argv[1];
1733 if (!conn->current_channel) {
1734 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1735 "You are not on that channel");
1736 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1740 /* Get the Channel ID of the channel */
1741 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1742 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1743 "You are not on that channel");
1744 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1748 channel = (SilcChannelEntry)id_cache->context;
1750 /* Parse the typed nickname. */
1751 if (client->internal->params->nickname_parse)
1752 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1754 nickname = strdup(cmd->argv[2]);
1756 /* Get the target client */
1757 target = silc_idlist_get_client(cmd->client, conn, nickname,
1758 cmd->argv[2], FALSE);
1760 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1761 "No such client: %s", cmd->argv[2]);
1762 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1766 /* Send KICK command to the server */
1767 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1768 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1770 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1771 1, idp->data, idp->len,
1772 2, idp2->data, idp2->len);
1774 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1775 1, idp->data, idp->len,
1776 2, idp2->data, idp2->len,
1778 strlen(cmd->argv[3]));
1779 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1780 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1781 silc_buffer_free(buffer);
1782 silc_buffer_free(idp);
1783 silc_buffer_free(idp2);
1785 /* Notify application */
1786 COMMAND(SILC_STATUS_OK);
1789 silc_free(nickname);
1790 silc_client_command_free(cmd);
1793 static void silc_client_command_oper_send(unsigned char *data,
1794 SilcUInt32 data_len, void *context)
1796 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1797 SilcClientConnection conn = cmd->conn;
1798 SilcBuffer buffer, auth;
1800 if (cmd->argc >= 3) {
1801 /* Encode the public key authentication payload */
1802 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1803 cmd->client->private_key,
1804 cmd->client->rng, conn->hash,
1808 /* Encode the password authentication payload */
1809 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1813 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1815 strlen(cmd->argv[1]),
1816 2, auth->data, auth->len);
1817 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1818 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1820 silc_buffer_free(buffer);
1821 silc_buffer_free(auth);
1823 /* Notify application */
1824 COMMAND(SILC_STATUS_OK);
1827 /* OPER command. Used to obtain server operator privileges. */
1829 SILC_CLIENT_CMD_FUNC(oper)
1831 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1832 SilcClientConnection conn = cmd->conn;
1835 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1836 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1840 if (cmd->argc < 2) {
1841 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1842 "Usage: /OPER <username> [-pubkey]");
1843 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1847 if (cmd->argc < 3) {
1848 /* Get passphrase */
1849 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1850 silc_client_command_oper_send,
1855 silc_client_command_oper_send(NULL, 0, context);
1858 silc_client_command_free(cmd);
1861 static void silc_client_command_silcoper_send(unsigned char *data,
1862 SilcUInt32 data_len,
1865 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1866 SilcClientConnection conn = cmd->conn;
1867 SilcBuffer buffer, auth;
1869 if (cmd->argc >= 3) {
1870 /* Encode the public key authentication payload */
1871 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1872 cmd->client->private_key,
1873 cmd->client->rng, conn->hash,
1877 /* Encode the password authentication payload */
1878 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1882 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1884 strlen(cmd->argv[1]),
1885 2, auth->data, auth->len);
1886 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1887 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1889 silc_buffer_free(buffer);
1890 silc_buffer_free(auth);
1892 /* Notify application */
1893 COMMAND(SILC_STATUS_OK);
1896 /* SILCOPER command. Used to obtain router operator privileges. */
1898 SILC_CLIENT_CMD_FUNC(silcoper)
1900 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1901 SilcClientConnection conn = cmd->conn;
1904 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1905 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1909 if (cmd->argc < 2) {
1910 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1911 "Usage: /SILCOPER <username> [-pubkey]");
1912 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1916 if (cmd->argc < 3) {
1917 /* Get passphrase */
1918 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1919 silc_client_command_silcoper_send,
1924 silc_client_command_silcoper_send(NULL, 0, context);
1927 silc_client_command_free(cmd);
1930 /* Command BAN. This is used to manage the ban list of the channel. */
1932 SILC_CLIENT_CMD_FUNC(ban)
1934 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1935 SilcClientConnection conn = cmd->conn;
1936 SilcChannelEntry channel;
1937 SilcBuffer buffer, chidp;
1939 char *name, *ban = NULL;
1942 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1943 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1947 if (cmd->argc < 2) {
1948 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1949 "Usage: /BAN <channel> "
1950 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1951 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1955 if (cmd->argv[1][0] == '*') {
1956 if (!conn->current_channel) {
1957 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1958 "You are not on any channel");
1959 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1963 channel = conn->current_channel;
1965 name = cmd->argv[1];
1967 channel = silc_client_get_channel(cmd->client, conn, name);
1969 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1970 "You are noton that channel");
1971 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1976 if (cmd->argc == 3) {
1977 if (cmd->argv[2][0] == '+')
1986 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1988 /* Send the command */
1989 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1990 ++conn->cmd_ident, 2,
1991 1, chidp->data, chidp->len,
1992 type, ban, ban ? strlen(ban) : 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);
1996 silc_buffer_free(chidp);
1998 /* Notify application */
1999 COMMAND(SILC_STATUS_OK);
2002 silc_client_command_free(cmd);
2005 /* Command DETACH. This is used to detach from the server */
2007 SILC_CLIENT_CMD_FUNC(detach)
2009 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2010 SilcClientConnection conn = cmd->conn;
2014 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2015 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2019 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
2020 ++conn->cmd_ident, 0);
2021 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2022 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2023 silc_buffer_free(buffer);
2025 /* Notify application */
2026 COMMAND(SILC_STATUS_OK);
2029 silc_client_command_free(cmd);
2032 /* Command WATCH. */
2034 SILC_CLIENT_CMD_FUNC(watch)
2036 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2037 SilcClientConnection conn = cmd->conn;
2038 SilcBuffer buffer, idp = NULL;
2042 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2043 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2047 if (cmd->argc < 3) {
2048 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2052 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2054 if (!strcasecmp(cmd->argv[1], "-add")) {
2056 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2059 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2063 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2064 ++conn->cmd_ident, 2,
2065 1, idp->data, idp->len,
2068 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2069 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2070 silc_buffer_free(buffer);
2072 /* Notify application */
2073 COMMAND(SILC_STATUS_OK);
2077 silc_buffer_free(idp);
2078 silc_client_command_free(cmd);
2081 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2083 SILC_CLIENT_CMD_FUNC(leave)
2085 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2086 SilcClientConnection conn = cmd->conn;
2087 SilcChannelEntry channel;
2088 SilcChannelUser chu;
2089 SilcBuffer buffer, idp;
2093 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2094 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2098 if (cmd->argc != 2) {
2099 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2100 "Usage: /LEAVE <channel>");
2101 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2105 if (cmd->argv[1][0] == '*') {
2106 if (!conn->current_channel) {
2107 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2108 "You are not on any channel");
2109 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2112 name = conn->current_channel->channel_name;
2114 name = cmd->argv[1];
2117 /* Get the channel entry */
2118 channel = silc_client_get_channel(cmd->client, conn, name);
2120 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2121 "You are not on that channel");
2122 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2126 /* Remove us from channel */
2127 chu = silc_client_on_channel(channel, conn->local_entry);
2129 silc_hash_table_del(chu->client->channels, chu->channel);
2130 silc_hash_table_del(chu->channel->user_list, chu->client);
2134 /* Send LEAVE command to the server */
2135 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2136 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2137 1, idp->data, idp->len);
2138 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2139 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2140 silc_buffer_free(buffer);
2141 silc_buffer_free(idp);
2143 /* Notify application */
2144 COMMAND(SILC_STATUS_OK);
2146 if (conn->current_channel == channel)
2147 conn->current_channel = NULL;
2149 silc_client_del_channel(cmd->client, cmd->conn, channel);
2152 silc_client_command_free(cmd);
2155 /* Command USERS. Requests the USERS of the clients joined on requested
2158 SILC_CLIENT_CMD_FUNC(users)
2160 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2161 SilcClientConnection conn = cmd->conn;
2166 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2167 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2171 if (cmd->argc != 2) {
2172 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2173 "Usage: /USERS <channel>");
2174 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2178 if (cmd->argv[1][0] == '*') {
2179 if (!conn->current_channel) {
2180 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2181 "You are not on any channel");
2182 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2185 name = conn->current_channel->channel_name;
2187 name = cmd->argv[1];
2190 /* Send USERS command to the server */
2191 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2192 ++conn->cmd_ident, 1,
2193 2, name, strlen(name));
2194 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2195 NULL, 0, NULL, NULL, buffer->data,
2197 silc_buffer_free(buffer);
2199 /* Notify application */
2200 COMMAND(SILC_STATUS_OK);
2203 silc_client_command_free(cmd);
2206 /* Command GETKEY. Used to fetch remote client's public key. */
2208 SILC_CLIENT_CMD_FUNC(getkey)
2210 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2211 SilcClientConnection conn = cmd->conn;
2212 SilcClient client = cmd->client;
2213 SilcClientEntry client_entry = NULL;
2214 SilcServerEntry server_entry = NULL;
2215 char *nickname = NULL;
2216 SilcBuffer idp, buffer;
2218 SILC_LOG_DEBUG(("Start"));
2221 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2222 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2226 if (cmd->argc < 2) {
2227 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2228 "Usage: /GETKEY <nickname or server name>");
2229 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2233 /* Parse the typed nickname. */
2234 if (client->internal->params->nickname_parse)
2235 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2237 nickname = strdup(cmd->argv[1]);
2239 /* Find client entry */
2240 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2242 if (!client_entry) {
2243 /* Check whether user requested server actually */
2244 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2246 if (!server_entry) {
2247 /* No. what ever user wants we don't have it, so resolve it. We
2248 will first try to resolve the client, and if that fails then
2249 we'll try to resolve the server. */
2251 if (!cmd->pending) {
2252 /* This will send the IDENTIFY command for nickname */
2253 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2254 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2256 silc_client_command_getkey,
2257 silc_client_command_dup(cmd));
2261 SilcClientCommandReplyContext reply =
2262 (SilcClientCommandReplyContext)context2;
2265 /* If nickname was not found, then resolve the server. */
2266 silc_command_get_status(reply->payload, NULL, &error);
2267 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2268 /* This sends the IDENTIFY command to resolve the server. */
2269 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2271 silc_client_command_reply_identify_i, 0,
2273 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2275 2, cmd->argv[1], cmd->argv_lens[1]);
2276 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2278 silc_client_command_getkey,
2279 silc_client_command_dup(cmd));
2283 /* If server was not found, then we've resolved both nickname and
2284 server and did not find anybody. */
2285 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2286 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2287 silc_client_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2288 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2289 silc_client_status_message(error));
2290 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2294 COMMAND_ERROR(error);
2299 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2301 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2304 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2305 1, idp->data, idp->len);
2306 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2307 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2308 silc_buffer_free(buffer);
2309 silc_buffer_free(idp);
2311 /* Notify application */
2312 COMMAND(SILC_STATUS_OK);
2315 silc_free(nickname);
2316 silc_client_command_free(cmd);
2319 /* Register a new command indicated by the `command' to the SILC client.
2320 The `name' is optional command name. If provided the command may be
2321 searched using the silc_client_command_find by that name. The
2322 `command_function' is the function to be called when the command is
2323 executed, and the `command_reply_function' is the function to be
2324 called after the server has sent reply back to the command.
2326 The `ident' is optional identifier for the command. If non-zero
2327 the `command_reply_function' for the command type `command' will be
2328 called only if the command reply sent by server includes the
2329 command identifier `ident'. Application usually does not need it
2330 and set it to zero value. */
2332 bool silc_client_command_register(SilcClient client,
2333 SilcCommand command,
2335 SilcCommandCb command_function,
2336 SilcCommandCb command_reply_function,
2340 SilcClientCommand cmd;
2342 cmd = silc_calloc(1, sizeof(*cmd));
2344 cmd->command = command_function;
2345 cmd->reply = command_reply_function;
2346 cmd->name = name ? strdup(name) : NULL;
2347 cmd->max_args = max_args;
2350 silc_list_add(client->internal->commands, cmd);
2355 /* Unregister a command indicated by the `command' with command function
2356 `command_function' and command reply function `command_reply_function'.
2357 Returns TRUE if the command was found and unregistered. */
2359 bool silc_client_command_unregister(SilcClient client,
2360 SilcCommand command,
2361 SilcCommandCb command_function,
2362 SilcCommandCb command_reply_function,
2365 SilcClientCommand cmd;
2367 silc_list_start(client->internal->commands);
2368 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2369 if (cmd->cmd == command && cmd->command == command_function &&
2370 cmd->reply == command_reply_function && cmd->ident == ident) {
2371 silc_list_del(client->internal->commands, cmd);
2372 silc_free(cmd->name);
2381 /* Private range commands, specific to this implementation (and compatible
2382 with SILC Server). */
2384 /* CONNECT command. Connects the server to another server. */
2386 SILC_CLIENT_CMD_FUNC(connect)
2388 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2389 SilcClientConnection conn = cmd->conn;
2391 unsigned char port[4];
2395 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2396 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2400 if (cmd->argc < 2) {
2401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2402 "Usage: /CONNECT <server> [<port>]");
2403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2407 if (cmd->argc == 3) {
2408 tmp = atoi(cmd->argv[2]);
2409 SILC_PUT32_MSB(tmp, port);
2413 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2415 strlen(cmd->argv[1]),
2418 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2420 strlen(cmd->argv[1]));
2421 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2422 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2423 silc_buffer_free(buffer);
2425 /* Notify application */
2426 COMMAND(SILC_STATUS_OK);
2429 silc_client_command_free(cmd);
2433 /* CLOSE command. Close server connection to the remote server */
2435 SILC_CLIENT_CMD_FUNC(close)
2437 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2438 SilcClientConnection conn = cmd->conn;
2440 unsigned char port[4];
2444 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2445 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2449 if (cmd->argc < 2) {
2450 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2451 "Usage: /CLOSE <server> [<port>]");
2452 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2456 if (cmd->argc == 3) {
2457 tmp = atoi(cmd->argv[2]);
2458 SILC_PUT32_MSB(tmp, port);
2462 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2464 strlen(cmd->argv[1]),
2467 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2469 strlen(cmd->argv[1]));
2470 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2471 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2472 silc_buffer_free(buffer);
2474 /* Notify application */
2475 COMMAND(SILC_STATUS_OK);
2478 silc_client_command_free(cmd);
2481 /* SHUTDOWN command. Shutdowns the server. */
2483 SILC_CLIENT_CMD_FUNC(shutdown)
2485 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2488 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2489 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2493 /* Send the command */
2494 silc_client_command_send(cmd->client, cmd->conn,
2495 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2497 /* Notify application */
2498 COMMAND(SILC_STATUS_OK);
2501 silc_client_command_free(cmd);
2504 /* Register all default commands provided by the client library for the
2507 void silc_client_commands_register(SilcClient client)
2509 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2512 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2513 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2514 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2515 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2516 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2517 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2518 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2519 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2520 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2521 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2522 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2523 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2524 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2525 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2526 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2527 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2528 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2529 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2530 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2531 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2532 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2533 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2534 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2535 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2536 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2538 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2539 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2540 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2543 /* Unregister all commands. */
2545 void silc_client_commands_unregister(SilcClient client)
2547 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2548 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2549 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2550 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2551 SILC_CLIENT_CMDU(list, LIST, "LIST");
2552 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2553 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2554 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2555 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2556 SILC_CLIENT_CMDU(info, INFO, "INFO");
2557 SILC_CLIENT_CMDU(ping, PING, "PING");
2558 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2559 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2560 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2561 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2562 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2563 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2564 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2565 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2566 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2567 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2568 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2569 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2570 SILC_CLIENT_CMDU(users, USERS, "USERS");
2571 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2573 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2574 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2575 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");