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 /* Command NICK. Shows current nickname/sets new nickname on current
361 SILC_CLIENT_CMD_FUNC(nick)
363 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
364 SilcClientConnection conn = cmd->conn;
368 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
374 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
375 "Usage: /NICK <nickname>");
376 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
380 if (!strcmp(conn->nickname, cmd->argv[1]))
383 /* Show current nickname */
386 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
387 "Your nickname is %s on server %s",
388 conn->nickname, conn->remote_host);
390 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
391 "Your nickname is %s", conn->nickname);
394 COMMAND(SILC_STATUS_OK);
398 if (cmd->argv_lens[1] > 128)
399 cmd->argv_lens[1] = 128;
401 /* Send the NICK command */
402 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
406 ++cmd->conn->cmd_ident);
407 silc_client_packet_send(cmd->client, cmd->conn->sock,
408 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
409 buffer->data, buffer->len, TRUE);
410 silc_buffer_free(buffer);
413 silc_client_command_free(cmd);
416 /* Command LIST. Lists channels on the current server. */
418 SILC_CLIENT_CMD_FUNC(list)
420 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
421 SilcClientConnection conn = cmd->conn;
422 SilcIDCacheEntry id_cache = NULL;
423 SilcChannelEntry channel;
424 SilcBuffer buffer, idp = NULL;
428 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
429 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
433 if (cmd->argc == 2) {
436 /* Get the Channel ID of the channel */
437 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
438 channel = (SilcChannelEntry)id_cache->context;
439 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
444 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
445 ++conn->cmd_ident, 0);
447 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
448 ++conn->cmd_ident, 1,
449 1, idp->data, idp->len);
451 silc_client_packet_send(cmd->client, cmd->conn->sock,
452 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
453 buffer->data, buffer->len, TRUE);
454 silc_buffer_free(buffer);
456 silc_buffer_free(idp);
458 /* Notify application */
459 COMMAND(SILC_STATUS_OK);
462 silc_client_command_free(cmd);
465 /* Command TOPIC. Sets/shows topic on a channel. */
467 SILC_CLIENT_CMD_FUNC(topic)
469 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
470 SilcClientConnection conn = cmd->conn;
471 SilcIDCacheEntry id_cache = NULL;
472 SilcChannelEntry channel;
473 SilcBuffer buffer, idp;
477 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
478 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
482 if (cmd->argc < 2 || cmd->argc > 3) {
483 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
484 "Usage: /TOPIC <channel> [<topic>]");
485 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
486 SILC_STATUS_ERR_TOO_MANY_PARAMS));
490 if (cmd->argv[1][0] == '*') {
491 if (!conn->current_channel) {
492 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
493 "You are not on any channel");
494 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
497 name = conn->current_channel->channel_name;
502 if (!conn->current_channel) {
503 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
504 "You are not on that channel");
505 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
509 /* Get the Channel ID of the channel */
510 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
511 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
512 "You are not on that channel");
513 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
517 channel = (SilcChannelEntry)id_cache->context;
519 /* Send TOPIC command to the server */
520 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
522 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
523 ++conn->cmd_ident, 2,
524 1, idp->data, idp->len,
526 strlen(cmd->argv[2]));
528 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
529 ++conn->cmd_ident, 1,
530 1, idp->data, idp->len);
531 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
532 0, NULL, NULL, buffer->data, buffer->len, TRUE);
533 silc_buffer_free(buffer);
534 silc_buffer_free(idp);
536 /* Notify application */
537 COMMAND(SILC_STATUS_OK);
540 silc_client_command_free(cmd);
543 /* Command INVITE. Invites specific client to join a channel. This is
544 also used to mange the invite list of the channel. */
546 SILC_CLIENT_CMD_FUNC(invite)
548 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
549 SilcClient client = cmd->client;
550 SilcClientConnection conn = cmd->conn;
551 SilcClientEntry client_entry = NULL;
552 SilcChannelEntry channel;
553 SilcBuffer buffer, clidp, chidp;
555 char *nickname = NULL, *name;
559 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
560 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
565 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
566 "Usage: /INVITE <channel> [<nickname>[@server>]"
567 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
568 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
572 if (cmd->argv[1][0] == '*') {
573 if (!conn->current_channel) {
574 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
575 "You are not on any channel");
576 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
580 channel = conn->current_channel;
584 channel = silc_client_get_channel(cmd->client, conn, name);
586 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
587 "You are on that channel");
588 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
593 /* Parse the typed nickname. */
594 if (cmd->argc == 3) {
595 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
596 if (client->internal->params->nickname_parse)
597 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
599 nickname = strdup(cmd->argv[2]);
601 /* Find client entry */
602 client_entry = silc_idlist_get_client(client, conn, nickname,
606 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
610 /* Client entry not found, it was requested thus mark this to be
612 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
614 silc_client_command_invite,
615 silc_client_command_dup(cmd));
620 invite = cmd->argv[2];
622 if (cmd->argv[2][0] == '+')
629 /* Send the command */
630 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
632 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
633 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
634 ++conn->cmd_ident, 3,
635 1, chidp->data, chidp->len,
636 2, clidp->data, clidp->len,
637 type, invite, invite ?
639 silc_buffer_free(clidp);
641 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
642 ++conn->cmd_ident, 2,
643 1, chidp->data, chidp->len,
644 type, invite, invite ?
648 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
649 0, NULL, NULL, buffer->data, buffer->len, TRUE);
650 silc_buffer_free(buffer);
651 silc_buffer_free(chidp);
653 /* Notify application */
654 COMMAND(SILC_STATUS_OK);
658 silc_client_command_free(cmd);
663 SilcClientConnection conn;
666 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
668 QuitInternal q = (QuitInternal)context;
670 /* Close connection */
671 q->client->internal->ops->disconnect(q->client, q->conn);
672 silc_client_close_connection(q->client, q->conn->sock->user_data);
677 /* Command QUIT. Closes connection with current server. */
679 SILC_CLIENT_CMD_FUNC(quit)
681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
686 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
687 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
692 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
693 &cmd->argv[1], &cmd->argv_lens[1],
694 &cmd->argv_types[1], 0);
696 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
697 NULL, NULL, NULL, 0);
698 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
700 buffer->data, buffer->len, TRUE);
701 silc_buffer_free(buffer);
703 q = silc_calloc(1, sizeof(*q));
704 q->client = cmd->client;
707 /* Sleep for a while */
710 /* We quit the connection with little timeout */
711 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
712 silc_client_command_quit_cb, (void *)q,
713 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
715 /* Notify application */
716 COMMAND(SILC_STATUS_OK);
719 silc_client_command_free(cmd);
722 /* Timeout callback to remove the killed client from cache */
724 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
726 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
727 SilcClient client = cmd->client;
728 SilcClientConnection conn = cmd->conn;
729 SilcClientEntry target;
730 char *nickname = NULL;
732 /* Parse the typed nickname. */
733 if (client->internal->params->nickname_parse)
734 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
736 nickname = strdup(cmd->argv[1]);
738 /* Get the target client */
739 target = silc_idlist_get_client(cmd->client, conn, nickname,
740 cmd->argv[1], FALSE);
742 /* Remove the client from all channels and free it */
743 silc_client_del_client(client, conn, target);
746 silc_client_command_free(cmd);
749 /* Kill command's pending command callback to actually remove the killed
750 client from our local cache. */
752 SILC_CLIENT_CMD_FUNC(kill_remove)
754 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
755 SilcClientCommandReplyContext reply =
756 (SilcClientCommandReplyContext)context2;
759 silc_command_get_status(reply->payload, &status, NULL);
760 if (status == SILC_STATUS_OK) {
761 /* Remove with timeout */
762 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
763 silc_client_command_kill_remove_later, context,
764 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
768 silc_client_command_free(cmd);
771 /* Command KILL. Router operator can use this command to remove an client
772 fromthe SILC Network. */
774 SILC_CLIENT_CMD_FUNC(kill)
776 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
777 SilcClient client = cmd->client;
778 SilcClientConnection conn = cmd->conn;
779 SilcBuffer buffer, idp;
780 SilcClientEntry target;
781 char *nickname = NULL;
784 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
785 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
790 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
791 "Usage: /KILL <nickname> [<comment>]");
792 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
796 /* Parse the typed nickname. */
797 if (client->internal->params->nickname_parse)
798 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
800 nickname = strdup(cmd->argv[1]);
802 /* Get the target client */
803 target = silc_idlist_get_client(cmd->client, conn, nickname,
807 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
811 /* Client entry not found, it was requested thus mark this to be
813 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
815 silc_client_command_kill,
816 silc_client_command_dup(cmd));
821 /* Send the KILL command to the server */
822 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
824 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
825 ++conn->cmd_ident, 1,
826 1, idp->data, idp->len);
828 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
829 ++conn->cmd_ident, 2,
830 1, idp->data, idp->len,
832 strlen(cmd->argv[2]));
833 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
834 0, NULL, NULL, buffer->data, buffer->len, TRUE);
835 silc_buffer_free(buffer);
836 silc_buffer_free(idp);
838 /* Notify application */
839 COMMAND(SILC_STATUS_OK);
841 /* Register a pending callback that will actually remove the killed
842 client from our cache. */
843 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
844 silc_client_command_kill_remove,
845 silc_client_command_dup(cmd));
849 silc_client_command_free(cmd);
852 /* Command INFO. Request information about specific server. If specific
853 server is not provided the current server is used. */
855 SILC_CLIENT_CMD_FUNC(info)
857 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
858 SilcClientConnection conn = cmd->conn;
863 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
864 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
869 name = strdup(cmd->argv[1]);
871 /* Send the command */
873 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
874 1, name, strlen(name));
876 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
877 NULL, NULL, NULL, 0);
878 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
879 0, NULL, NULL, buffer->data, buffer->len, TRUE);
880 silc_buffer_free(buffer);
884 /* Notify application */
885 COMMAND(SILC_STATUS_OK);
888 silc_client_command_free(cmd);
891 /* Command PING. Sends ping to server. This is used to test the
892 communication channel. */
894 SILC_CLIENT_CMD_FUNC(ping)
896 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
897 SilcClientConnection conn = cmd->conn;
903 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
904 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
908 /* Send the command */
909 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
910 1, conn->remote_id_data,
911 silc_id_get_len(conn->remote_id,
913 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
914 0, NULL, NULL, buffer->data, buffer->len, TRUE);
915 silc_buffer_free(buffer);
917 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
920 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
921 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
925 /* Start counting time */
926 for (i = 0; i < conn->ping_count; i++) {
927 if (conn->ping[i].dest_id == NULL) {
928 conn->ping[i].start_time = time(NULL);
929 conn->ping[i].dest_id = id;
930 conn->ping[i].dest_name = strdup(conn->remote_host);
934 if (i >= conn->ping_count) {
935 i = conn->ping_count;
936 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
937 conn->ping[i].start_time = time(NULL);
938 conn->ping[i].dest_id = id;
939 conn->ping[i].dest_name = strdup(conn->remote_host);
943 /* Notify application */
944 COMMAND(SILC_STATUS_OK);
947 silc_client_command_free(cmd);
950 /* Command JOIN. Joins to a channel. */
952 SILC_CLIENT_CMD_FUNC(join)
954 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
955 SilcClientConnection conn = cmd->conn;
956 SilcChannelEntry channel;
957 SilcBuffer buffer, idp, auth = NULL;
958 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
959 int i, passphrase_len = 0;
962 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
963 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
968 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
972 /* See if we have joined to the requested channel already */
973 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
974 if (channel && silc_client_on_channel(channel, conn->local_entry))
977 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
979 if (cmd->argv_lens[1] > 256)
980 cmd->argv_lens[1] = 256;
984 for (i = 2; i < cmd->argc; i++) {
985 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
986 cipher = cmd->argv[i + 1];
988 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
989 hmac = cmd->argv[i + 1];
991 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
992 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
993 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
994 cmd->client->private_key,
995 cmd->client->rng, conn->hash,
999 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1001 cmd->argv_lens[i + 1]);
1005 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1006 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1007 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1008 cmd->argv_lens[i], 0);
1009 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1010 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1011 0, pu8, passphrase_len);
1014 passphrase = strdup(cmd->argv[i]);
1015 passphrase_len = cmd->argv_lens[i];
1020 /* Send JOIN command to the server */
1022 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1023 1, name, strlen(name),
1024 2, idp->data, idp->len,
1025 3, passphrase, passphrase_len,
1026 4, cipher, cipher ? strlen(cipher) : 0,
1027 5, hmac, hmac ? strlen(hmac) : 0,
1028 6, auth ? auth->data : NULL,
1029 auth ? auth->len : 0);
1030 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1031 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1032 silc_buffer_free(buffer);
1033 silc_buffer_free(idp);
1035 silc_buffer_free(auth);
1036 silc_free(passphrase);
1038 /* Notify application */
1039 COMMAND(SILC_STATUS_OK);
1042 silc_client_command_free(cmd);
1045 /* MOTD command. Requests motd from server. */
1047 SILC_CLIENT_CMD_FUNC(motd)
1049 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1050 SilcClientConnection conn = cmd->conn;
1054 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1055 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1059 if (cmd->argc < 1 || cmd->argc > 2) {
1060 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1061 "Usage: /MOTD [<server>]");
1062 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1063 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1067 /* Send TOPIC command to the server */
1069 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1070 1, conn->remote_host,
1071 strlen(conn->remote_host));
1073 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1076 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1077 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1078 silc_buffer_free(buffer);
1080 /* Notify application */
1081 COMMAND(SILC_STATUS_OK);
1084 silc_client_command_free(cmd);
1087 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1088 modes as client cannot set itself server/router operator privileges. */
1090 SILC_CLIENT_CMD_FUNC(umode)
1092 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1093 SilcClientConnection conn = cmd->conn;
1094 SilcBuffer buffer, idp;
1095 unsigned char *cp, modebuf[4];
1096 SilcUInt32 mode, add, len;
1100 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1101 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1105 if (cmd->argc < 2) {
1106 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1107 "Usage: /UMODE +|-<modes>");
1108 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1112 mode = conn->local_entry->mode;
1114 /* Are we adding or removing mode */
1115 if (cmd->argv[1][0] == '-')
1121 cp = cmd->argv[1] + 1;
1123 for (i = 0; i < len; i++) {
1128 mode |= SILC_UMODE_SERVER_OPERATOR;
1129 mode |= SILC_UMODE_ROUTER_OPERATOR;
1130 mode |= SILC_UMODE_GONE;
1131 mode |= SILC_UMODE_INDISPOSED;
1132 mode |= SILC_UMODE_BUSY;
1133 mode |= SILC_UMODE_PAGE;
1134 mode |= SILC_UMODE_HYPER;
1135 mode |= SILC_UMODE_ROBOT;
1136 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1137 mode |= SILC_UMODE_REJECT_WATCHING;
1139 mode = SILC_UMODE_NONE;
1144 mode |= SILC_UMODE_SERVER_OPERATOR;
1146 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1150 mode |= SILC_UMODE_ROUTER_OPERATOR;
1152 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1156 mode |= SILC_UMODE_GONE;
1158 mode &= ~SILC_UMODE_GONE;
1162 mode |= SILC_UMODE_INDISPOSED;
1164 mode &= ~SILC_UMODE_INDISPOSED;
1168 mode |= SILC_UMODE_BUSY;
1170 mode &= ~SILC_UMODE_BUSY;
1174 mode |= SILC_UMODE_PAGE;
1176 mode &= ~SILC_UMODE_PAGE;
1180 mode |= SILC_UMODE_HYPER;
1182 mode &= ~SILC_UMODE_HYPER;
1186 mode |= SILC_UMODE_ROBOT;
1188 mode &= ~SILC_UMODE_ROBOT;
1192 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1194 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1198 mode |= SILC_UMODE_REJECT_WATCHING;
1200 mode &= ~SILC_UMODE_REJECT_WATCHING;
1204 mode |= SILC_UMODE_BLOCK_INVITE;
1206 mode &= ~SILC_UMODE_BLOCK_INVITE;
1209 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1215 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1216 SILC_PUT32_MSB(mode, modebuf);
1218 /* Send the command packet. We support sending only one mode at once
1219 that requires an argument. */
1221 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1222 1, idp->data, idp->len,
1223 2, modebuf, sizeof(modebuf));
1224 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1225 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1226 silc_buffer_free(buffer);
1227 silc_buffer_free(idp);
1229 /* Notify application */
1230 COMMAND(SILC_STATUS_OK);
1233 silc_client_command_free(cmd);
1236 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1237 can be set several at once. Those modes that require argument must be set
1238 separately (unless set with modes that does not require arguments). */
1240 SILC_CLIENT_CMD_FUNC(cmode)
1242 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1243 SilcClientConnection conn = cmd->conn;
1244 SilcChannelEntry channel;
1245 SilcBuffer buffer, chidp, auth = NULL;
1246 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1247 SilcUInt32 mode, add, type, len, arg_len = 0;
1251 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1252 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1256 if (cmd->argc < 3) {
1257 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1258 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1259 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1263 if (cmd->argv[1][0] == '*') {
1264 if (!conn->current_channel) {
1265 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1266 "You are not on any channel");
1267 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1271 channel = conn->current_channel;
1273 name = cmd->argv[1];
1275 channel = silc_client_get_channel(cmd->client, conn, name);
1277 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1278 "You are on that channel");
1279 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1284 mode = channel->mode;
1286 /* Are we adding or removing mode */
1287 if (cmd->argv[2][0] == '-')
1292 /* Argument type to be sent to server */
1296 cp = cmd->argv[2] + 1;
1298 for (i = 0; i < len; i++) {
1302 mode |= SILC_CHANNEL_MODE_PRIVATE;
1304 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1308 mode |= SILC_CHANNEL_MODE_SECRET;
1310 mode &= ~SILC_CHANNEL_MODE_SECRET;
1314 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1316 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1320 mode |= SILC_CHANNEL_MODE_INVITE;
1322 mode &= ~SILC_CHANNEL_MODE_INVITE;
1326 mode |= SILC_CHANNEL_MODE_TOPIC;
1328 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1332 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1334 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1338 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1340 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1345 mode |= SILC_CHANNEL_MODE_ULIMIT;
1347 if (cmd->argc < 4) {
1348 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1349 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1350 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1353 ll = atoi(cmd->argv[3]);
1354 SILC_PUT32_MSB(ll, tmp);
1358 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1363 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1365 if (cmd->argc < 4) {
1366 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1367 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1368 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1372 arg_len = cmd->argv_lens[3];
1374 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1379 mode |= SILC_CHANNEL_MODE_CIPHER;
1381 if (cmd->argc < 4) {
1382 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1383 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1384 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1388 arg_len = cmd->argv_lens[3];
1390 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1395 mode |= SILC_CHANNEL_MODE_HMAC;
1397 if (cmd->argc < 4) {
1398 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1399 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1400 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1404 arg_len = cmd->argv_lens[3];
1406 mode &= ~SILC_CHANNEL_MODE_HMAC;
1411 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
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 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1422 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1423 cmd->client->private_key,
1429 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1430 cmd->argv[3], cmd->argv_lens[3]);
1434 arg_len = auth->len;
1436 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1440 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1446 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1447 SILC_PUT32_MSB(mode, modebuf);
1449 /* Send the command packet. We support sending only one mode at once
1450 that requires an argument. */
1453 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1454 1, chidp->data, chidp->len,
1455 2, modebuf, sizeof(modebuf),
1456 type, arg, arg_len);
1459 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1460 1, chidp->data, chidp->len,
1461 2, modebuf, sizeof(modebuf));
1464 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1465 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1466 silc_buffer_free(buffer);
1467 silc_buffer_free(chidp);
1469 silc_buffer_free(auth);
1471 /* Notify application */
1472 COMMAND(SILC_STATUS_OK);
1475 silc_client_command_free(cmd);
1478 /* CUMODE command. Changes client's mode on a channel. */
1480 SILC_CLIENT_CMD_FUNC(cumode)
1482 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1483 SilcClient client = cmd->client;
1484 SilcClientConnection conn = cmd->conn;
1485 SilcChannelEntry channel;
1486 SilcChannelUser chu;
1487 SilcClientEntry client_entry;
1488 SilcBuffer buffer, clidp, chidp, auth = NULL;
1489 unsigned char *name, *cp, modebuf[4];
1490 SilcUInt32 mode = 0, add, len;
1491 char *nickname = NULL;
1495 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1496 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1500 if (cmd->argc < 4) {
1501 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1502 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1503 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1507 if (cmd->argv[1][0] == '*') {
1508 if (!conn->current_channel) {
1509 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1510 "You are not on any channel");
1511 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1515 channel = conn->current_channel;
1517 name = cmd->argv[1];
1519 channel = silc_client_get_channel(cmd->client, conn, name);
1521 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1522 "You are on that channel");
1523 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1528 /* Parse the typed nickname. */
1529 if (client->internal->params->nickname_parse)
1530 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1532 nickname = strdup(cmd->argv[3]);
1534 /* Find client entry */
1535 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1536 cmd->argv[3], TRUE);
1537 if (!client_entry) {
1539 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1543 /* Client entry not found, it was requested thus mark this to be
1545 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1547 silc_client_command_cumode,
1548 silc_client_command_dup(cmd));
1553 /* Get the current mode */
1554 chu = silc_client_on_channel(channel, client_entry);
1558 /* Are we adding or removing mode */
1559 if (cmd->argv[2][0] == '-')
1565 cp = cmd->argv[2] + 1;
1567 for (i = 0; i < len; i++) {
1571 mode |= SILC_CHANNEL_UMODE_CHANFO;
1572 mode |= SILC_CHANNEL_UMODE_CHANOP;
1573 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1574 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1575 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1577 mode = SILC_CHANNEL_UMODE_NONE;
1582 if (cmd->argc == 5) {
1583 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1584 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1585 cmd->client->private_key,
1591 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1592 cmd->argv[4], cmd->argv_lens[4]);
1595 mode |= SILC_CHANNEL_UMODE_CHANFO;
1597 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1602 mode |= SILC_CHANNEL_UMODE_CHANOP;
1604 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1608 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1610 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1614 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1616 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1620 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1622 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1625 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1631 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1632 SILC_PUT32_MSB(mode, modebuf);
1633 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1635 /* Send the command packet. We support sending only one mode at once
1636 that requires an argument. */
1637 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1639 1, chidp->data, chidp->len,
1641 3, clidp->data, clidp->len,
1642 4, auth ? auth->data : NULL,
1643 auth ? auth->len : 0);
1645 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1646 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1647 silc_buffer_free(buffer);
1648 silc_buffer_free(chidp);
1649 silc_buffer_free(clidp);
1651 silc_buffer_free(auth);
1653 /* Notify application */
1654 COMMAND(SILC_STATUS_OK);
1657 silc_free(nickname);
1658 silc_client_command_free(cmd);
1661 /* KICK command. Kicks a client out of channel. */
1663 SILC_CLIENT_CMD_FUNC(kick)
1665 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1666 SilcClient client = cmd->client;
1667 SilcClientConnection conn = cmd->conn;
1668 SilcIDCacheEntry id_cache = NULL;
1669 SilcChannelEntry channel;
1670 SilcBuffer buffer, idp, idp2;
1671 SilcClientEntry target;
1673 char *nickname = NULL;
1676 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1677 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1681 if (cmd->argc < 3) {
1682 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1683 "Usage: /KICK <channel> <nickname> [<comment>]");
1684 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1688 if (cmd->argv[1][0] == '*') {
1689 if (!conn->current_channel) {
1690 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1691 "You are not on any channel");
1692 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1695 name = conn->current_channel->channel_name;
1697 name = cmd->argv[1];
1700 if (!conn->current_channel) {
1701 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1702 "You are not on that channel");
1703 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1707 /* Get the Channel ID of the channel */
1708 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1709 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1710 "You are not on that channel");
1711 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1715 channel = (SilcChannelEntry)id_cache->context;
1717 /* Parse the typed nickname. */
1718 if (client->internal->params->nickname_parse)
1719 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1721 nickname = strdup(cmd->argv[2]);
1723 /* Get the target client */
1724 target = silc_idlist_get_client(cmd->client, conn, nickname,
1725 cmd->argv[2], FALSE);
1727 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1728 "No such client: %s", cmd->argv[2]);
1729 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1733 /* Send KICK command to the server */
1734 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1735 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1737 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1738 1, idp->data, idp->len,
1739 2, idp2->data, idp2->len);
1741 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1742 1, idp->data, idp->len,
1743 2, idp2->data, idp2->len,
1745 strlen(cmd->argv[3]));
1746 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1747 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1748 silc_buffer_free(buffer);
1749 silc_buffer_free(idp);
1750 silc_buffer_free(idp2);
1752 /* Notify application */
1753 COMMAND(SILC_STATUS_OK);
1756 silc_free(nickname);
1757 silc_client_command_free(cmd);
1760 static void silc_client_command_oper_send(unsigned char *data,
1761 SilcUInt32 data_len, void *context)
1763 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1764 SilcClientConnection conn = cmd->conn;
1765 SilcBuffer buffer, auth;
1767 if (cmd->argc >= 3) {
1768 /* Encode the public key authentication payload */
1769 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1770 cmd->client->private_key,
1771 cmd->client->rng, conn->hash,
1775 /* Encode the password authentication payload */
1776 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1780 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1782 strlen(cmd->argv[1]),
1783 2, auth->data, auth->len);
1784 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1785 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1787 silc_buffer_free(buffer);
1788 silc_buffer_free(auth);
1790 /* Notify application */
1791 COMMAND(SILC_STATUS_OK);
1794 /* OPER command. Used to obtain server operator privileges. */
1796 SILC_CLIENT_CMD_FUNC(oper)
1798 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1799 SilcClientConnection conn = cmd->conn;
1802 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1803 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1807 if (cmd->argc < 2) {
1808 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1809 "Usage: /OPER <username> [-pubkey]");
1810 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1814 if (cmd->argc < 3) {
1815 /* Get passphrase */
1816 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1817 silc_client_command_oper_send,
1822 silc_client_command_oper_send(NULL, 0, context);
1825 silc_client_command_free(cmd);
1828 static void silc_client_command_silcoper_send(unsigned char *data,
1829 SilcUInt32 data_len,
1832 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1833 SilcClientConnection conn = cmd->conn;
1834 SilcBuffer buffer, auth;
1836 if (cmd->argc >= 3) {
1837 /* Encode the public key authentication payload */
1838 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1839 cmd->client->private_key,
1840 cmd->client->rng, conn->hash,
1844 /* Encode the password authentication payload */
1845 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1849 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1851 strlen(cmd->argv[1]),
1852 2, auth->data, auth->len);
1853 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1854 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1856 silc_buffer_free(buffer);
1857 silc_buffer_free(auth);
1859 /* Notify application */
1860 COMMAND(SILC_STATUS_OK);
1863 /* SILCOPER command. Used to obtain router operator privileges. */
1865 SILC_CLIENT_CMD_FUNC(silcoper)
1867 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1868 SilcClientConnection conn = cmd->conn;
1871 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1872 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1876 if (cmd->argc < 2) {
1877 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1878 "Usage: /SILCOPER <username> [-pubkey]");
1879 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1883 if (cmd->argc < 3) {
1884 /* Get passphrase */
1885 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1886 silc_client_command_silcoper_send,
1891 silc_client_command_silcoper_send(NULL, 0, context);
1894 silc_client_command_free(cmd);
1897 /* Command BAN. This is used to manage the ban list of the channel. */
1899 SILC_CLIENT_CMD_FUNC(ban)
1901 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1902 SilcClientConnection conn = cmd->conn;
1903 SilcChannelEntry channel;
1904 SilcBuffer buffer, chidp;
1906 char *name, *ban = NULL;
1909 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1910 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1914 if (cmd->argc < 2) {
1915 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1916 "Usage: /BAN <channel> "
1917 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1918 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1922 if (cmd->argv[1][0] == '*') {
1923 if (!conn->current_channel) {
1924 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1925 "You are not on any channel");
1926 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1930 channel = conn->current_channel;
1932 name = cmd->argv[1];
1934 channel = silc_client_get_channel(cmd->client, conn, name);
1936 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1937 "You are noton that channel");
1938 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1943 if (cmd->argc == 3) {
1944 if (cmd->argv[2][0] == '+')
1953 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1955 /* Send the command */
1956 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1957 ++conn->cmd_ident, 2,
1958 1, chidp->data, chidp->len,
1959 type, ban, ban ? strlen(ban) : 0);
1960 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1961 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1962 silc_buffer_free(buffer);
1963 silc_buffer_free(chidp);
1965 /* Notify application */
1966 COMMAND(SILC_STATUS_OK);
1969 silc_client_command_free(cmd);
1972 /* Command DETACH. This is used to detach from the server */
1974 SILC_CLIENT_CMD_FUNC(detach)
1976 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1977 SilcClientConnection conn = cmd->conn;
1981 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1982 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1986 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1987 ++conn->cmd_ident, 0);
1988 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1989 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1990 silc_buffer_free(buffer);
1992 /* Notify application */
1993 COMMAND(SILC_STATUS_OK);
1996 silc_client_command_free(cmd);
1999 /* Command WATCH. */
2001 SILC_CLIENT_CMD_FUNC(watch)
2003 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2004 SilcClientConnection conn = cmd->conn;
2005 SilcBuffer buffer, idp = NULL;
2009 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2010 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2014 if (cmd->argc < 3) {
2015 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2019 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2021 if (!strcasecmp(cmd->argv[1], "-add")) {
2023 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2026 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2030 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2031 ++conn->cmd_ident, 2,
2032 1, idp->data, idp->len,
2035 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2036 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2037 silc_buffer_free(buffer);
2039 /* Notify application */
2040 COMMAND(SILC_STATUS_OK);
2044 silc_buffer_free(idp);
2045 silc_client_command_free(cmd);
2048 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2050 SILC_CLIENT_CMD_FUNC(leave)
2052 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2053 SilcClientConnection conn = cmd->conn;
2054 SilcChannelEntry channel;
2055 SilcChannelUser chu;
2056 SilcBuffer buffer, idp;
2060 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2061 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2065 if (cmd->argc != 2) {
2066 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2067 "Usage: /LEAVE <channel>");
2068 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2072 if (cmd->argv[1][0] == '*') {
2073 if (!conn->current_channel) {
2074 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2075 "You are not on any channel");
2076 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2079 name = conn->current_channel->channel_name;
2081 name = cmd->argv[1];
2084 /* Get the channel entry */
2085 channel = silc_client_get_channel(cmd->client, conn, name);
2087 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2088 "You are not on that channel");
2089 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2093 /* Remove us from channel */
2094 chu = silc_client_on_channel(channel, conn->local_entry);
2096 silc_hash_table_del(chu->client->channels, chu->channel);
2097 silc_hash_table_del(chu->channel->user_list, chu->client);
2101 /* Send LEAVE command to the server */
2102 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2103 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2104 1, idp->data, idp->len);
2105 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2106 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2107 silc_buffer_free(buffer);
2108 silc_buffer_free(idp);
2110 /* Notify application */
2111 COMMAND(SILC_STATUS_OK);
2113 if (conn->current_channel == channel)
2114 conn->current_channel = NULL;
2116 silc_client_del_channel(cmd->client, cmd->conn, channel);
2119 silc_client_command_free(cmd);
2122 /* Command USERS. Requests the USERS of the clients joined on requested
2125 SILC_CLIENT_CMD_FUNC(users)
2127 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2128 SilcClientConnection conn = cmd->conn;
2133 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2134 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2138 if (cmd->argc != 2) {
2139 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2140 "Usage: /USERS <channel>");
2141 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2145 if (cmd->argv[1][0] == '*') {
2146 if (!conn->current_channel) {
2147 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2148 "You are not on any channel");
2149 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2152 name = conn->current_channel->channel_name;
2154 name = cmd->argv[1];
2157 /* Send USERS command to the server */
2158 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2159 ++conn->cmd_ident, 1,
2160 2, name, strlen(name));
2161 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2162 NULL, 0, NULL, NULL, buffer->data,
2164 silc_buffer_free(buffer);
2166 /* Notify application */
2167 COMMAND(SILC_STATUS_OK);
2170 silc_client_command_free(cmd);
2173 /* Command GETKEY. Used to fetch remote client's public key. */
2175 SILC_CLIENT_CMD_FUNC(getkey)
2177 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2178 SilcClientConnection conn = cmd->conn;
2179 SilcClient client = cmd->client;
2180 SilcClientEntry client_entry = NULL;
2181 SilcServerEntry server_entry = NULL;
2182 char *nickname = NULL;
2183 SilcBuffer idp, buffer;
2185 SILC_LOG_DEBUG(("Start"));
2188 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2189 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2193 if (cmd->argc < 2) {
2194 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2195 "Usage: /GETKEY <nickname or server name>");
2196 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2200 /* Parse the typed nickname. */
2201 if (client->internal->params->nickname_parse)
2202 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2204 nickname = strdup(cmd->argv[1]);
2206 /* Find client entry */
2207 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2209 if (!client_entry) {
2210 /* Check whether user requested server actually */
2211 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2213 if (!server_entry) {
2214 /* No. what ever user wants we don't have it, so resolve it. We
2215 will first try to resolve the client, and if that fails then
2216 we'll try to resolve the server. */
2218 if (!cmd->pending) {
2219 /* This will send the IDENTIFY command for nickname */
2220 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2221 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2223 silc_client_command_getkey,
2224 silc_client_command_dup(cmd));
2228 SilcClientCommandReplyContext reply =
2229 (SilcClientCommandReplyContext)context2;
2232 /* If nickname was not found, then resolve the server. */
2233 silc_command_get_status(reply->payload, NULL, &error);
2234 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2235 /* This sends the IDENTIFY command to resolve the server. */
2236 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2238 silc_client_command_reply_identify_i, 0,
2240 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2242 2, cmd->argv[1], cmd->argv_lens[1]);
2243 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2245 silc_client_command_getkey,
2246 silc_client_command_dup(cmd));
2250 /* If server was not found, then we've resolved both nickname and
2251 server and did not find anybody. */
2252 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2253 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2254 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2255 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2256 silc_get_status_message(error));
2257 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2261 COMMAND_ERROR(error);
2266 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2268 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2271 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2272 1, idp->data, idp->len);
2273 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2274 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2275 silc_buffer_free(buffer);
2276 silc_buffer_free(idp);
2278 /* Notify application */
2279 COMMAND(SILC_STATUS_OK);
2282 silc_free(nickname);
2283 silc_client_command_free(cmd);
2286 /* Register a new command indicated by the `command' to the SILC client.
2287 The `name' is optional command name. If provided the command may be
2288 searched using the silc_client_command_find by that name. The
2289 `command_function' is the function to be called when the command is
2290 executed, and the `command_reply_function' is the function to be
2291 called after the server has sent reply back to the command.
2293 The `ident' is optional identifier for the command. If non-zero
2294 the `command_reply_function' for the command type `command' will be
2295 called only if the command reply sent by server includes the
2296 command identifier `ident'. Application usually does not need it
2297 and set it to zero value. */
2299 bool silc_client_command_register(SilcClient client,
2300 SilcCommand command,
2302 SilcCommandCb command_function,
2303 SilcCommandCb command_reply_function,
2307 SilcClientCommand cmd;
2309 cmd = silc_calloc(1, sizeof(*cmd));
2311 cmd->command = command_function;
2312 cmd->reply = command_reply_function;
2313 cmd->name = name ? strdup(name) : NULL;
2314 cmd->max_args = max_args;
2317 silc_list_add(client->internal->commands, cmd);
2322 /* Unregister a command indicated by the `command' with command function
2323 `command_function' and command reply function `command_reply_function'.
2324 Returns TRUE if the command was found and unregistered. */
2326 bool silc_client_command_unregister(SilcClient client,
2327 SilcCommand command,
2328 SilcCommandCb command_function,
2329 SilcCommandCb command_reply_function,
2332 SilcClientCommand cmd;
2334 silc_list_start(client->internal->commands);
2335 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2336 if (cmd->cmd == command && cmd->command == command_function &&
2337 cmd->reply == command_reply_function && cmd->ident == ident) {
2338 silc_list_del(client->internal->commands, cmd);
2339 silc_free(cmd->name);
2348 /* Private range commands, specific to this implementation (and compatible
2349 with SILC Server). */
2351 /* CONNECT command. Connects the server to another server. */
2353 SILC_CLIENT_CMD_FUNC(connect)
2355 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2356 SilcClientConnection conn = cmd->conn;
2358 unsigned char port[4];
2362 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2363 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2367 if (cmd->argc < 2) {
2368 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2369 "Usage: /CONNECT <server> [<port>]");
2370 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2374 if (cmd->argc == 3) {
2375 tmp = atoi(cmd->argv[2]);
2376 SILC_PUT32_MSB(tmp, port);
2380 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2382 strlen(cmd->argv[1]),
2385 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2387 strlen(cmd->argv[1]));
2388 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2389 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2390 silc_buffer_free(buffer);
2392 /* Notify application */
2393 COMMAND(SILC_STATUS_OK);
2396 silc_client_command_free(cmd);
2400 /* CLOSE command. Close server connection to the remote server */
2402 SILC_CLIENT_CMD_FUNC(close)
2404 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2405 SilcClientConnection conn = cmd->conn;
2407 unsigned char port[4];
2411 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2412 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2416 if (cmd->argc < 2) {
2417 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2418 "Usage: /CLOSE <server> [<port>]");
2419 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2423 if (cmd->argc == 3) {
2424 tmp = atoi(cmd->argv[2]);
2425 SILC_PUT32_MSB(tmp, port);
2429 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2431 strlen(cmd->argv[1]),
2434 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2436 strlen(cmd->argv[1]));
2437 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2438 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2439 silc_buffer_free(buffer);
2441 /* Notify application */
2442 COMMAND(SILC_STATUS_OK);
2445 silc_client_command_free(cmd);
2448 /* SHUTDOWN command. Shutdowns the server. */
2450 SILC_CLIENT_CMD_FUNC(shutdown)
2452 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2455 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2456 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2460 /* Send the command */
2461 silc_client_command_send(cmd->client, cmd->conn,
2462 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2464 /* Notify application */
2465 COMMAND(SILC_STATUS_OK);
2468 silc_client_command_free(cmd);
2471 /* Register all default commands provided by the client library for the
2474 void silc_client_commands_register(SilcClient client)
2476 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2479 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2480 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2481 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2482 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2483 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2484 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2485 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2486 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2487 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2488 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2489 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2490 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2491 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2492 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2493 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2494 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2495 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2496 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2497 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2498 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2499 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2500 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2501 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2502 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2503 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2505 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2506 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2507 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2510 /* Unregister all commands. */
2512 void silc_client_commands_unregister(SilcClient client)
2514 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2515 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2516 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2517 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2518 SILC_CLIENT_CMDU(list, LIST, "LIST");
2519 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2520 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2521 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2522 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2523 SILC_CLIENT_CMDU(info, INFO, "INFO");
2524 SILC_CLIENT_CMDU(ping, PING, "PING");
2525 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2526 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2527 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2528 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2529 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2530 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2531 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2532 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2533 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2534 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2535 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2536 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2537 SILC_CLIENT_CMDU(users, USERS, "USERS");
2538 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2540 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2541 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2542 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");