5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, use /SERVER to connect");
29 /* Command operation that is called at the end of all commands.
30 Usage: COMMAND(status); */
31 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
32 cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
34 /* Error to application. Usage: COMMAND_ERROR(status); */
35 #define COMMAND_ERROR(status) \
36 cmd->client->internal->ops->command(cmd->client, \
37 cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
39 #define SAY cmd->client->internal->ops->say
41 /* Generic function to send any command. The arguments must be sent already
42 encoded into correct form and in correct order. */
44 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
45 SilcCommand command, SilcUInt16 ident,
53 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
54 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
55 NULL, 0, NULL, NULL, packet->data,
57 silc_buffer_free(packet);
60 /* Finds and returns a pointer to the command list. Return NULL if the
61 command is not found. */
63 SilcClientCommand silc_client_command_find(SilcClient client,
66 SilcClientCommand cmd;
68 silc_list_start(client->internal->commands);
69 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
70 if (cmd->name && !strcmp(cmd->name, name))
77 /* Calls the command (executes it). Application can call this after
78 it has allocated the SilcClientCommandContext with the function
79 silc_client_command_alloc and found the command from the client
80 library by calling silc_client_command_find. This will execute
83 void silc_client_command_call(SilcClientCommand command,
84 SilcClientCommandContext cmd)
86 (*command->command)((void *)cmd, NULL);
89 /* Add new pending command to be executed when reply to a command has been
90 received. The `reply_cmd' is the command that will call the `callback'
91 with `context' when reply has been received. It can be SILC_COMMAND_NONE
92 to match any command with the `ident'. If `ident' is non-zero
93 the `callback' will be executed when received reply with command
94 identifier `ident'. If there already exists pending command for the
95 specified command, ident, callback and context this function has no
98 void silc_client_command_pending(SilcClientConnection conn,
99 SilcCommand reply_cmd,
101 SilcCommandCb callback,
104 SilcClientCommandPending *reply;
106 /* Check whether identical pending already exists for same command,
107 ident, callback and callback context. If it does then it would be
108 error to register it again. */
109 silc_dlist_start(conn->pending_commands);
110 while ((reply = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
111 if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
112 reply->callback == callback && reply->context == context)
116 reply = silc_calloc(1, sizeof(*reply));
117 reply->reply_cmd = reply_cmd;
118 reply->ident = ident;
119 reply->context = context;
120 reply->callback = callback;
121 silc_dlist_add(conn->pending_commands, reply);
124 /* Deletes pending command by reply command type. */
126 void silc_client_command_pending_del(SilcClientConnection conn,
127 SilcCommand reply_cmd,
130 SilcClientCommandPending *r;
132 if (!conn->pending_commands)
135 silc_dlist_start(conn->pending_commands);
136 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
137 if (r->reply_cmd == reply_cmd && r->ident == ident) {
138 silc_dlist_del(conn->pending_commands, r);
144 /* Checks for pending commands and marks callbacks to be called from
145 the command reply function. */
147 SilcClientCommandPendingCallbacks
148 silc_client_command_pending_check(SilcClientConnection conn,
149 SilcClientCommandReplyContext ctx,
152 SilcUInt32 *callbacks_count)
154 SilcClientCommandPending *r;
155 SilcClientCommandPendingCallbacks callbacks = NULL;
158 silc_dlist_start(conn->pending_commands);
159 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
160 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
161 && r->ident == ident) {
162 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
163 callbacks[i].context = r->context;
164 callbacks[i].callback = r->callback;
170 *callbacks_count = i;
174 /* Allocate Command Context */
176 SilcClientCommandContext silc_client_command_alloc(void)
178 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
183 /* Free command context and its internals */
185 void silc_client_command_free(SilcClientCommandContext ctx)
188 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
190 if (ctx->users < 1) {
193 for (i = 0; i < ctx->argc; i++)
194 silc_free(ctx->argv[i]);
195 silc_free(ctx->argv_lens);
196 silc_free(ctx->argv_types);
201 /* Duplicate Command Context by adding reference counter. The context won't
202 be free'd untill it hits zero. */
204 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
207 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
212 /* Command WHOIS. This command is used to query information about
215 SILC_CLIENT_CMD_FUNC(whois)
217 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
218 SilcClientConnection conn = cmd->conn;
220 unsigned char count[4];
223 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
224 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
228 /* Given without arguments fetches client's own information */
230 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
231 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
233 1, 4, buffer->data, buffer->len);
234 silc_buffer_free(buffer);
238 if (cmd->argc == 2) {
239 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
240 ++conn->cmd_ident, 1,
244 int c = atoi(cmd->argv[2]);
245 memset(count, 0, sizeof(count));
246 SILC_PUT32_MSB(c, count);
247 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
248 ++conn->cmd_ident, 2,
249 1, cmd->argv[1], cmd->argv_lens[1],
250 2, count, sizeof(count));
252 silc_client_packet_send(cmd->client, cmd->conn->sock,
253 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
254 buffer->data, buffer->len, TRUE);
255 silc_buffer_free(buffer);
257 /* Notify application */
258 COMMAND(SILC_STATUS_OK);
261 silc_client_command_free(cmd);
264 /* Command WHOWAS. This command is used to query history information about
265 specific user that used to exist in the network. */
267 SILC_CLIENT_CMD_FUNC(whowas)
269 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
270 SilcClientConnection conn = cmd->conn;
272 unsigned char count[4];
275 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
276 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
280 if (cmd->argc < 2 || cmd->argc > 3) {
281 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
282 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
283 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
284 SILC_STATUS_ERR_TOO_MANY_PARAMS));
288 if (cmd->argc == 2) {
289 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
290 ++conn->cmd_ident, 1,
294 int c = atoi(cmd->argv[2]);
295 memset(count, 0, sizeof(count));
296 SILC_PUT32_MSB(c, count);
297 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
298 ++conn->cmd_ident, 2,
299 1, cmd->argv[1], cmd->argv_lens[1],
300 2, count, sizeof(count));
302 silc_client_packet_send(cmd->client, cmd->conn->sock,
303 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
304 buffer->data, buffer->len, TRUE);
305 silc_buffer_free(buffer);
307 /* Notify application */
308 COMMAND(SILC_STATUS_OK);
311 silc_client_command_free(cmd);
314 /* Command IDENTIFY. This command is used to query information about
315 specific user, especially ID's.
317 NOTE: This command is used only internally by the client library
318 and application MUST NOT call this command directly. */
320 SILC_CLIENT_CMD_FUNC(identify)
322 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
323 SilcClientConnection conn = cmd->conn;
325 unsigned char count[4];
328 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
329 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
333 if (cmd->argc < 2 || cmd->argc > 3)
336 if (cmd->argc == 2) {
337 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
338 ++conn->cmd_ident, 1,
342 int c = atoi(cmd->argv[2]);
343 memset(count, 0, sizeof(count));
344 SILC_PUT32_MSB(c, count);
345 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
346 ++conn->cmd_ident, 2,
349 4, count, sizeof(count));
352 silc_client_packet_send(cmd->client, cmd->conn->sock,
353 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
354 buffer->data, buffer->len, TRUE);
355 silc_buffer_free(buffer);
358 silc_client_command_free(cmd);
361 /* Command NICK. Shows current nickname/sets new nickname on current
364 SILC_CLIENT_CMD_FUNC(nick)
366 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
367 SilcClientConnection conn = cmd->conn;
371 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
372 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
378 "Usage: /NICK <nickname>");
379 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
383 if (!strcmp(conn->nickname, cmd->argv[1]))
386 /* Show current nickname */
389 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
390 "Your nickname is %s on server %s",
391 conn->nickname, conn->remote_host);
393 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
394 "Your nickname is %s", conn->nickname);
397 COMMAND(SILC_STATUS_OK);
401 if (cmd->argv_lens[1] > 128)
402 cmd->argv_lens[1] = 128;
404 /* Send the NICK command */
405 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
409 ++cmd->conn->cmd_ident);
410 silc_client_packet_send(cmd->client, cmd->conn->sock,
411 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
412 buffer->data, buffer->len, TRUE);
413 silc_buffer_free(buffer);
416 silc_client_command_free(cmd);
419 /* Command LIST. Lists channels on the current server. */
421 SILC_CLIENT_CMD_FUNC(list)
423 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
424 SilcClientConnection conn = cmd->conn;
425 SilcIDCacheEntry id_cache = NULL;
426 SilcChannelEntry channel;
427 SilcBuffer buffer, idp = NULL;
431 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
432 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
436 if (cmd->argc == 2) {
439 /* Get the Channel ID of the channel */
440 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
441 channel = (SilcChannelEntry)id_cache->context;
442 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
447 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
448 ++conn->cmd_ident, 0);
450 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
451 ++conn->cmd_ident, 1,
452 1, idp->data, idp->len);
454 silc_client_packet_send(cmd->client, cmd->conn->sock,
455 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
456 buffer->data, buffer->len, TRUE);
457 silc_buffer_free(buffer);
459 silc_buffer_free(idp);
461 /* Notify application */
462 COMMAND(SILC_STATUS_OK);
465 silc_client_command_free(cmd);
468 /* Command TOPIC. Sets/shows topic on a channel. */
470 SILC_CLIENT_CMD_FUNC(topic)
472 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
473 SilcClientConnection conn = cmd->conn;
474 SilcIDCacheEntry id_cache = NULL;
475 SilcChannelEntry channel;
476 SilcBuffer buffer, idp;
480 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
481 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
485 if (cmd->argc < 2 || cmd->argc > 3) {
486 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
487 "Usage: /TOPIC <channel> [<topic>]");
488 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
489 SILC_STATUS_ERR_TOO_MANY_PARAMS));
493 if (cmd->argv[1][0] == '*') {
494 if (!conn->current_channel) {
495 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
496 "You are not on any channel");
497 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
500 name = conn->current_channel->channel_name;
505 if (!conn->current_channel) {
506 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
507 "You are not on that channel");
508 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
512 /* Get the Channel ID of the channel */
513 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
514 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
515 "You are not on that channel");
516 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
520 channel = (SilcChannelEntry)id_cache->context;
522 /* Send TOPIC command to the server */
523 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
525 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
526 ++conn->cmd_ident, 2,
527 1, idp->data, idp->len,
529 strlen(cmd->argv[2]));
531 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
532 ++conn->cmd_ident, 1,
533 1, idp->data, idp->len);
534 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
535 0, NULL, NULL, buffer->data, buffer->len, TRUE);
536 silc_buffer_free(buffer);
537 silc_buffer_free(idp);
539 /* Notify application */
540 COMMAND(SILC_STATUS_OK);
543 silc_client_command_free(cmd);
546 /* Command INVITE. Invites specific client to join a channel. This is
547 also used to mange the invite list of the channel. */
549 SILC_CLIENT_CMD_FUNC(invite)
551 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
552 SilcClient client = cmd->client;
553 SilcClientConnection conn = cmd->conn;
554 SilcClientEntry client_entry = NULL;
555 SilcChannelEntry channel;
556 SilcBuffer buffer, clidp, chidp;
558 char *nickname = NULL, *name;
562 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
563 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
568 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
569 "Usage: /INVITE <channel> [<nickname>[@server>]"
570 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
571 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
575 if (cmd->argv[1][0] == '*') {
576 if (!conn->current_channel) {
577 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
578 "You are not on any channel");
579 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
583 channel = conn->current_channel;
587 channel = silc_client_get_channel(cmd->client, conn, name);
589 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
590 "You are on that channel");
591 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
596 /* Parse the typed nickname. */
597 if (cmd->argc == 3) {
598 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
599 if (client->internal->params->nickname_parse)
600 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
602 nickname = strdup(cmd->argv[2]);
604 /* Find client entry */
605 client_entry = silc_idlist_get_client(client, conn, nickname,
609 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
613 /* Client entry not found, it was requested thus mark this to be
615 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
617 silc_client_command_invite,
618 silc_client_command_dup(cmd));
623 invite = cmd->argv[2];
625 if (cmd->argv[2][0] == '+')
632 /* Send the command */
633 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
635 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
636 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
637 ++conn->cmd_ident, 3,
638 1, chidp->data, chidp->len,
639 2, clidp->data, clidp->len,
640 type, invite, invite ?
642 silc_buffer_free(clidp);
644 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
645 ++conn->cmd_ident, 2,
646 1, chidp->data, chidp->len,
647 type, invite, invite ?
651 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
652 0, NULL, NULL, buffer->data, buffer->len, TRUE);
653 silc_buffer_free(buffer);
654 silc_buffer_free(chidp);
656 /* Notify application */
657 COMMAND(SILC_STATUS_OK);
661 silc_client_command_free(cmd);
666 SilcClientConnection conn;
669 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
671 QuitInternal q = (QuitInternal)context;
673 /* Close connection */
674 q->client->internal->ops->disconnect(q->client, q->conn);
675 silc_client_close_connection(q->client, q->conn->sock->user_data);
680 /* Command QUIT. Closes connection with current server. */
682 SILC_CLIENT_CMD_FUNC(quit)
684 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
689 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
690 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
695 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
696 &cmd->argv[1], &cmd->argv_lens[1],
697 &cmd->argv_types[1], 0);
699 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
700 NULL, NULL, NULL, 0);
701 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
703 buffer->data, buffer->len, TRUE);
704 silc_buffer_free(buffer);
706 q = silc_calloc(1, sizeof(*q));
707 q->client = cmd->client;
710 /* Sleep for a while */
713 /* We quit the connection with little timeout */
714 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
715 silc_client_command_quit_cb, (void *)q,
716 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
718 /* Notify application */
719 COMMAND(SILC_STATUS_OK);
722 silc_client_command_free(cmd);
725 /* Timeout callback to remove the killed client from cache */
727 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
729 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
730 SilcClient client = cmd->client;
731 SilcClientConnection conn = cmd->conn;
732 SilcClientEntry target;
733 char *nickname = NULL;
735 /* Parse the typed nickname. */
736 if (client->internal->params->nickname_parse)
737 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
739 nickname = strdup(cmd->argv[1]);
741 /* Get the target client */
742 target = silc_idlist_get_client(cmd->client, conn, nickname,
743 cmd->argv[1], FALSE);
745 /* Remove the client from all channels and free it */
746 silc_client_del_client(client, conn, target);
749 silc_client_command_free(cmd);
752 /* Kill command's pending command callback to actually remove the killed
753 client from our local cache. */
755 SILC_CLIENT_CMD_FUNC(kill_remove)
757 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
758 SilcClientCommandReplyContext reply =
759 (SilcClientCommandReplyContext)context2;
762 silc_command_get_status(reply->payload, &status, NULL);
763 if (status == SILC_STATUS_OK) {
764 /* Remove with timeout */
765 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
766 silc_client_command_kill_remove_later, context,
767 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
771 silc_client_command_free(cmd);
774 /* Command KILL. Router operator can use this command to remove an client
775 fromthe SILC Network. */
777 SILC_CLIENT_CMD_FUNC(kill)
779 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
780 SilcClient client = cmd->client;
781 SilcClientConnection conn = cmd->conn;
782 SilcBuffer buffer, idp;
783 SilcClientEntry target;
784 char *nickname = NULL;
787 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
788 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
793 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
794 "Usage: /KILL <nickname> [<comment>]");
795 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 /* Parse the typed nickname. */
800 if (client->internal->params->nickname_parse)
801 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
803 nickname = strdup(cmd->argv[1]);
805 /* Get the target client */
806 target = silc_idlist_get_client(cmd->client, conn, nickname,
810 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
814 /* Client entry not found, it was requested thus mark this to be
816 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
818 silc_client_command_kill,
819 silc_client_command_dup(cmd));
824 /* Send the KILL command to the server */
825 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
827 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
828 ++conn->cmd_ident, 1,
829 1, idp->data, idp->len);
831 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
832 ++conn->cmd_ident, 2,
833 1, idp->data, idp->len,
835 strlen(cmd->argv[2]));
836 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
837 0, NULL, NULL, buffer->data, buffer->len, TRUE);
838 silc_buffer_free(buffer);
839 silc_buffer_free(idp);
841 /* Notify application */
842 COMMAND(SILC_STATUS_OK);
844 /* Register a pending callback that will actually remove the killed
845 client from our cache. */
846 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
847 silc_client_command_kill_remove,
848 silc_client_command_dup(cmd));
852 silc_client_command_free(cmd);
855 /* Command INFO. Request information about specific server. If specific
856 server is not provided the current server is used. */
858 SILC_CLIENT_CMD_FUNC(info)
860 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
861 SilcClientConnection conn = cmd->conn;
866 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
867 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
872 name = strdup(cmd->argv[1]);
874 /* Send the command */
876 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
877 1, name, strlen(name));
879 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
880 NULL, NULL, NULL, 0);
881 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
882 0, NULL, NULL, buffer->data, buffer->len, TRUE);
883 silc_buffer_free(buffer);
887 /* Notify application */
888 COMMAND(SILC_STATUS_OK);
891 silc_client_command_free(cmd);
894 /* Command PING. Sends ping to server. This is used to test the
895 communication channel. */
897 SILC_CLIENT_CMD_FUNC(ping)
899 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
900 SilcClientConnection conn = cmd->conn;
906 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
907 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
911 /* Send the command */
912 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
913 1, conn->remote_id_data,
914 silc_id_get_len(conn->remote_id,
916 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
917 0, NULL, NULL, buffer->data, buffer->len, TRUE);
918 silc_buffer_free(buffer);
920 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
923 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
924 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
928 /* Start counting time */
929 for (i = 0; i < conn->ping_count; i++) {
930 if (conn->ping[i].dest_id == NULL) {
931 conn->ping[i].start_time = time(NULL);
932 conn->ping[i].dest_id = id;
933 conn->ping[i].dest_name = strdup(conn->remote_host);
937 if (i >= conn->ping_count) {
938 i = conn->ping_count;
939 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
940 conn->ping[i].start_time = time(NULL);
941 conn->ping[i].dest_id = id;
942 conn->ping[i].dest_name = strdup(conn->remote_host);
946 /* Notify application */
947 COMMAND(SILC_STATUS_OK);
950 silc_client_command_free(cmd);
953 /* Command JOIN. Joins to a channel. */
955 SILC_CLIENT_CMD_FUNC(join)
957 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
958 SilcClientConnection conn = cmd->conn;
959 SilcChannelEntry channel;
960 SilcBuffer buffer, idp, auth = NULL;
961 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
962 int i, passphrase_len = 0;
965 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
966 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
971 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
975 /* See if we have joined to the requested channel already */
976 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
977 if (channel && silc_client_on_channel(channel, conn->local_entry))
980 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
982 if (cmd->argv_lens[1] > 256)
983 cmd->argv_lens[1] = 256;
987 for (i = 2; i < cmd->argc; i++) {
988 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
989 cipher = cmd->argv[i + 1];
991 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
992 hmac = cmd->argv[i + 1];
994 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
995 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
996 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
997 cmd->client->private_key,
998 cmd->client->rng, conn->hash,
1002 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1004 cmd->argv_lens[i + 1]);
1008 /* Passphrases must be UTF-8 encoded, so encode if it is not */
1009 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1010 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
1011 cmd->argv_lens[i], 0);
1012 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1013 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1014 0, pu8, passphrase_len);
1017 passphrase = strdup(cmd->argv[i]);
1018 passphrase_len = cmd->argv_lens[i];
1023 /* Send JOIN command to the server */
1025 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1026 1, name, strlen(name),
1027 2, idp->data, idp->len,
1028 3, passphrase, passphrase_len,
1029 4, cipher, cipher ? strlen(cipher) : 0,
1030 5, hmac, hmac ? strlen(hmac) : 0,
1031 6, auth ? auth->data : NULL,
1032 auth ? auth->len : 0);
1033 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1034 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1035 silc_buffer_free(buffer);
1036 silc_buffer_free(idp);
1038 silc_buffer_free(auth);
1039 silc_free(passphrase);
1041 /* Notify application */
1042 COMMAND(SILC_STATUS_OK);
1045 silc_client_command_free(cmd);
1048 /* MOTD command. Requests motd from server. */
1050 SILC_CLIENT_CMD_FUNC(motd)
1052 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1053 SilcClientConnection conn = cmd->conn;
1057 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1058 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1062 if (cmd->argc < 1 || cmd->argc > 2) {
1063 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1064 "Usage: /MOTD [<server>]");
1065 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1066 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1070 /* Send TOPIC command to the server */
1072 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1073 1, conn->remote_host,
1074 strlen(conn->remote_host));
1076 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1079 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1080 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1081 silc_buffer_free(buffer);
1083 /* Notify application */
1084 COMMAND(SILC_STATUS_OK);
1087 silc_client_command_free(cmd);
1090 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1091 modes as client cannot set itself server/router operator privileges. */
1093 SILC_CLIENT_CMD_FUNC(umode)
1095 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1096 SilcClientConnection conn = cmd->conn;
1097 SilcBuffer buffer, idp;
1098 unsigned char *cp, modebuf[4];
1099 SilcUInt32 mode, add, len;
1103 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1104 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1108 if (cmd->argc < 2) {
1109 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1110 "Usage: /UMODE +|-<modes>");
1111 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1115 mode = conn->local_entry->mode;
1117 /* Are we adding or removing mode */
1118 if (cmd->argv[1][0] == '-')
1124 cp = cmd->argv[1] + 1;
1126 for (i = 0; i < len; i++) {
1131 mode |= SILC_UMODE_SERVER_OPERATOR;
1132 mode |= SILC_UMODE_ROUTER_OPERATOR;
1133 mode |= SILC_UMODE_GONE;
1134 mode |= SILC_UMODE_INDISPOSED;
1135 mode |= SILC_UMODE_BUSY;
1136 mode |= SILC_UMODE_PAGE;
1137 mode |= SILC_UMODE_HYPER;
1138 mode |= SILC_UMODE_ROBOT;
1139 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1140 mode |= SILC_UMODE_REJECT_WATCHING;
1142 mode = SILC_UMODE_NONE;
1147 mode |= SILC_UMODE_SERVER_OPERATOR;
1149 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1153 mode |= SILC_UMODE_ROUTER_OPERATOR;
1155 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1159 mode |= SILC_UMODE_GONE;
1161 mode &= ~SILC_UMODE_GONE;
1165 mode |= SILC_UMODE_INDISPOSED;
1167 mode &= ~SILC_UMODE_INDISPOSED;
1171 mode |= SILC_UMODE_BUSY;
1173 mode &= ~SILC_UMODE_BUSY;
1177 mode |= SILC_UMODE_PAGE;
1179 mode &= ~SILC_UMODE_PAGE;
1183 mode |= SILC_UMODE_HYPER;
1185 mode &= ~SILC_UMODE_HYPER;
1189 mode |= SILC_UMODE_ROBOT;
1191 mode &= ~SILC_UMODE_ROBOT;
1195 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1197 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1201 mode |= SILC_UMODE_REJECT_WATCHING;
1203 mode &= ~SILC_UMODE_REJECT_WATCHING;
1207 mode |= SILC_UMODE_BLOCK_INVITE;
1209 mode &= ~SILC_UMODE_BLOCK_INVITE;
1212 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1218 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1219 SILC_PUT32_MSB(mode, modebuf);
1221 /* Send the command packet. We support sending only one mode at once
1222 that requires an argument. */
1224 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1225 1, idp->data, idp->len,
1226 2, modebuf, sizeof(modebuf));
1227 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1228 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1229 silc_buffer_free(buffer);
1230 silc_buffer_free(idp);
1232 /* Notify application */
1233 COMMAND(SILC_STATUS_OK);
1236 silc_client_command_free(cmd);
1239 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1240 can be set several at once. Those modes that require argument must be set
1241 separately (unless set with modes that does not require arguments). */
1243 SILC_CLIENT_CMD_FUNC(cmode)
1245 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1246 SilcClientConnection conn = cmd->conn;
1247 SilcChannelEntry channel;
1248 SilcBuffer buffer, chidp, auth = NULL;
1249 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1250 SilcUInt32 mode, add, type, len, arg_len = 0;
1254 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1255 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1259 if (cmd->argc < 3) {
1260 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1261 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1262 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1266 if (cmd->argv[1][0] == '*') {
1267 if (!conn->current_channel) {
1268 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1269 "You are not on any channel");
1270 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1274 channel = conn->current_channel;
1276 name = cmd->argv[1];
1278 channel = silc_client_get_channel(cmd->client, conn, name);
1280 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1281 "You are on that channel");
1282 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1287 mode = channel->mode;
1289 /* Are we adding or removing mode */
1290 if (cmd->argv[2][0] == '-')
1295 /* Argument type to be sent to server */
1299 cp = cmd->argv[2] + 1;
1301 for (i = 0; i < len; i++) {
1305 mode |= SILC_CHANNEL_MODE_PRIVATE;
1307 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1311 mode |= SILC_CHANNEL_MODE_SECRET;
1313 mode &= ~SILC_CHANNEL_MODE_SECRET;
1317 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1319 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1323 mode |= SILC_CHANNEL_MODE_INVITE;
1325 mode &= ~SILC_CHANNEL_MODE_INVITE;
1329 mode |= SILC_CHANNEL_MODE_TOPIC;
1331 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1335 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1337 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1341 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1343 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1348 mode |= SILC_CHANNEL_MODE_ULIMIT;
1350 if (cmd->argc < 4) {
1351 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1352 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1353 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1356 ll = atoi(cmd->argv[3]);
1357 SILC_PUT32_MSB(ll, tmp);
1361 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1366 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1368 if (cmd->argc < 4) {
1369 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1370 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1371 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1375 arg_len = cmd->argv_lens[3];
1377 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1382 mode |= SILC_CHANNEL_MODE_CIPHER;
1384 if (cmd->argc < 4) {
1385 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1386 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1387 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1391 arg_len = cmd->argv_lens[3];
1393 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1398 mode |= SILC_CHANNEL_MODE_HMAC;
1400 if (cmd->argc < 4) {
1401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1402 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1403 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1407 arg_len = cmd->argv_lens[3];
1409 mode &= ~SILC_CHANNEL_MODE_HMAC;
1414 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1417 if (cmd->argc < 4) {
1418 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1419 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1420 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1424 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1425 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1426 cmd->client->private_key,
1432 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1433 cmd->argv[3], cmd->argv_lens[3]);
1437 arg_len = auth->len;
1439 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1443 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1449 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1450 SILC_PUT32_MSB(mode, modebuf);
1452 /* Send the command packet. We support sending only one mode at once
1453 that requires an argument. */
1456 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1457 1, chidp->data, chidp->len,
1458 2, modebuf, sizeof(modebuf),
1459 type, arg, arg_len);
1462 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1463 1, chidp->data, chidp->len,
1464 2, modebuf, sizeof(modebuf));
1467 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1468 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1469 silc_buffer_free(buffer);
1470 silc_buffer_free(chidp);
1472 silc_buffer_free(auth);
1474 /* Notify application */
1475 COMMAND(SILC_STATUS_OK);
1478 silc_client_command_free(cmd);
1481 /* CUMODE command. Changes client's mode on a channel. */
1483 SILC_CLIENT_CMD_FUNC(cumode)
1485 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1486 SilcClient client = cmd->client;
1487 SilcClientConnection conn = cmd->conn;
1488 SilcChannelEntry channel;
1489 SilcChannelUser chu;
1490 SilcClientEntry client_entry;
1491 SilcBuffer buffer, clidp, chidp, auth = NULL;
1492 unsigned char *name, *cp, modebuf[4];
1493 SilcUInt32 mode = 0, add, len;
1494 char *nickname = NULL;
1498 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1499 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1503 if (cmd->argc < 4) {
1504 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1505 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1510 if (cmd->argv[1][0] == '*') {
1511 if (!conn->current_channel) {
1512 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1513 "You are not on any channel");
1514 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1518 channel = conn->current_channel;
1520 name = cmd->argv[1];
1522 channel = silc_client_get_channel(cmd->client, conn, name);
1524 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1525 "You are on that channel");
1526 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1531 /* Parse the typed nickname. */
1532 if (client->internal->params->nickname_parse)
1533 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1535 nickname = strdup(cmd->argv[3]);
1537 /* Find client entry */
1538 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1539 cmd->argv[3], TRUE);
1540 if (!client_entry) {
1542 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1546 /* Client entry not found, it was requested thus mark this to be
1548 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1550 silc_client_command_cumode,
1551 silc_client_command_dup(cmd));
1556 /* Get the current mode */
1557 chu = silc_client_on_channel(channel, client_entry);
1561 /* Are we adding or removing mode */
1562 if (cmd->argv[2][0] == '-')
1568 cp = cmd->argv[2] + 1;
1570 for (i = 0; i < len; i++) {
1574 mode |= SILC_CHANNEL_UMODE_CHANFO;
1575 mode |= SILC_CHANNEL_UMODE_CHANOP;
1576 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1577 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1578 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1580 mode = SILC_CHANNEL_UMODE_NONE;
1585 if (cmd->argc == 5) {
1586 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1587 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1588 cmd->client->private_key,
1594 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1595 cmd->argv[4], cmd->argv_lens[4]);
1598 mode |= SILC_CHANNEL_UMODE_CHANFO;
1600 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1605 mode |= SILC_CHANNEL_UMODE_CHANOP;
1607 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1611 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1613 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1617 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1619 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1623 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1625 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1628 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1634 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1635 SILC_PUT32_MSB(mode, modebuf);
1636 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1638 /* Send the command packet. We support sending only one mode at once
1639 that requires an argument. */
1640 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1642 1, chidp->data, chidp->len,
1644 3, clidp->data, clidp->len,
1645 4, auth ? auth->data : NULL,
1646 auth ? auth->len : 0);
1648 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1649 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1650 silc_buffer_free(buffer);
1651 silc_buffer_free(chidp);
1652 silc_buffer_free(clidp);
1654 silc_buffer_free(auth);
1656 /* Notify application */
1657 COMMAND(SILC_STATUS_OK);
1660 silc_free(nickname);
1661 silc_client_command_free(cmd);
1664 /* KICK command. Kicks a client out of channel. */
1666 SILC_CLIENT_CMD_FUNC(kick)
1668 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1669 SilcClient client = cmd->client;
1670 SilcClientConnection conn = cmd->conn;
1671 SilcIDCacheEntry id_cache = NULL;
1672 SilcChannelEntry channel;
1673 SilcBuffer buffer, idp, idp2;
1674 SilcClientEntry target;
1676 char *nickname = NULL;
1679 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1680 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1684 if (cmd->argc < 3) {
1685 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1686 "Usage: /KICK <channel> <nickname> [<comment>]");
1687 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1691 if (cmd->argv[1][0] == '*') {
1692 if (!conn->current_channel) {
1693 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1694 "You are not on any channel");
1695 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1698 name = conn->current_channel->channel_name;
1700 name = cmd->argv[1];
1703 if (!conn->current_channel) {
1704 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1705 "You are not on that channel");
1706 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1710 /* Get the Channel ID of the channel */
1711 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1712 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1713 "You are not on that channel");
1714 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1718 channel = (SilcChannelEntry)id_cache->context;
1720 /* Parse the typed nickname. */
1721 if (client->internal->params->nickname_parse)
1722 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1724 nickname = strdup(cmd->argv[2]);
1726 /* Get the target client */
1727 target = silc_idlist_get_client(cmd->client, conn, nickname,
1728 cmd->argv[2], FALSE);
1730 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1731 "No such client: %s", cmd->argv[2]);
1732 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1736 /* Send KICK command to the server */
1737 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1738 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1740 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1741 1, idp->data, idp->len,
1742 2, idp2->data, idp2->len);
1744 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1745 1, idp->data, idp->len,
1746 2, idp2->data, idp2->len,
1748 strlen(cmd->argv[3]));
1749 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1750 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1751 silc_buffer_free(buffer);
1752 silc_buffer_free(idp);
1753 silc_buffer_free(idp2);
1755 /* Notify application */
1756 COMMAND(SILC_STATUS_OK);
1759 silc_free(nickname);
1760 silc_client_command_free(cmd);
1763 static void silc_client_command_oper_send(unsigned char *data,
1764 SilcUInt32 data_len, void *context)
1766 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1767 SilcClientConnection conn = cmd->conn;
1768 SilcBuffer buffer, auth;
1770 if (cmd->argc >= 3) {
1771 /* Encode the public key authentication payload */
1772 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1773 cmd->client->private_key,
1774 cmd->client->rng, conn->hash,
1778 /* Encode the password authentication payload */
1779 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1783 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1785 strlen(cmd->argv[1]),
1786 2, auth->data, auth->len);
1787 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1788 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1790 silc_buffer_free(buffer);
1791 silc_buffer_free(auth);
1793 /* Notify application */
1794 COMMAND(SILC_STATUS_OK);
1797 /* OPER command. Used to obtain server operator privileges. */
1799 SILC_CLIENT_CMD_FUNC(oper)
1801 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1802 SilcClientConnection conn = cmd->conn;
1805 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1806 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1810 if (cmd->argc < 2) {
1811 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1812 "Usage: /OPER <username> [-pubkey]");
1813 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1817 if (cmd->argc < 3) {
1818 /* Get passphrase */
1819 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1820 silc_client_command_oper_send,
1825 silc_client_command_oper_send(NULL, 0, context);
1828 silc_client_command_free(cmd);
1831 static void silc_client_command_silcoper_send(unsigned char *data,
1832 SilcUInt32 data_len,
1835 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1836 SilcClientConnection conn = cmd->conn;
1837 SilcBuffer buffer, auth;
1839 if (cmd->argc >= 3) {
1840 /* Encode the public key authentication payload */
1841 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1842 cmd->client->private_key,
1843 cmd->client->rng, conn->hash,
1847 /* Encode the password authentication payload */
1848 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1852 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1854 strlen(cmd->argv[1]),
1855 2, auth->data, auth->len);
1856 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1857 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1859 silc_buffer_free(buffer);
1860 silc_buffer_free(auth);
1862 /* Notify application */
1863 COMMAND(SILC_STATUS_OK);
1866 /* SILCOPER command. Used to obtain router operator privileges. */
1868 SILC_CLIENT_CMD_FUNC(silcoper)
1870 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1871 SilcClientConnection conn = cmd->conn;
1874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1875 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1879 if (cmd->argc < 2) {
1880 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1881 "Usage: /SILCOPER <username> [-pubkey]");
1882 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1886 if (cmd->argc < 3) {
1887 /* Get passphrase */
1888 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1889 silc_client_command_silcoper_send,
1894 silc_client_command_silcoper_send(NULL, 0, context);
1897 silc_client_command_free(cmd);
1900 /* Command BAN. This is used to manage the ban list of the channel. */
1902 SILC_CLIENT_CMD_FUNC(ban)
1904 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1905 SilcClientConnection conn = cmd->conn;
1906 SilcChannelEntry channel;
1907 SilcBuffer buffer, chidp;
1909 char *name, *ban = NULL;
1912 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1913 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1917 if (cmd->argc < 2) {
1918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1919 "Usage: /BAN <channel> "
1920 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1921 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1925 if (cmd->argv[1][0] == '*') {
1926 if (!conn->current_channel) {
1927 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1928 "You are not on any channel");
1929 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1933 channel = conn->current_channel;
1935 name = cmd->argv[1];
1937 channel = silc_client_get_channel(cmd->client, conn, name);
1939 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1940 "You are noton that channel");
1941 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1946 if (cmd->argc == 3) {
1947 if (cmd->argv[2][0] == '+')
1956 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1958 /* Send the command */
1959 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1960 ++conn->cmd_ident, 2,
1961 1, chidp->data, chidp->len,
1962 type, ban, ban ? strlen(ban) : 0);
1963 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1964 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1965 silc_buffer_free(buffer);
1966 silc_buffer_free(chidp);
1968 /* Notify application */
1969 COMMAND(SILC_STATUS_OK);
1972 silc_client_command_free(cmd);
1975 /* Command DETACH. This is used to detach from the server */
1977 SILC_CLIENT_CMD_FUNC(detach)
1979 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1980 SilcClientConnection conn = cmd->conn;
1984 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1985 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1989 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1990 ++conn->cmd_ident, 0);
1991 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1992 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1993 silc_buffer_free(buffer);
1995 /* Notify application */
1996 COMMAND(SILC_STATUS_OK);
1999 silc_client_command_free(cmd);
2002 /* Command WATCH. */
2004 SILC_CLIENT_CMD_FUNC(watch)
2006 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2007 SilcClientConnection conn = cmd->conn;
2008 SilcBuffer buffer, idp = NULL;
2012 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2013 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2017 if (cmd->argc < 3) {
2018 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2022 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2024 if (!strcasecmp(cmd->argv[1], "-add")) {
2026 } else if (!strcasecmp(cmd->argv[1], "-del")) {
2029 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2033 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2034 ++conn->cmd_ident, 2,
2035 1, idp->data, idp->len,
2038 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2039 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2040 silc_buffer_free(buffer);
2042 /* Notify application */
2043 COMMAND(SILC_STATUS_OK);
2047 silc_buffer_free(idp);
2048 silc_client_command_free(cmd);
2051 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2053 SILC_CLIENT_CMD_FUNC(leave)
2055 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2056 SilcClientConnection conn = cmd->conn;
2057 SilcChannelEntry channel;
2058 SilcChannelUser chu;
2059 SilcBuffer buffer, idp;
2063 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2064 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2068 if (cmd->argc != 2) {
2069 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2070 "Usage: /LEAVE <channel>");
2071 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2075 if (cmd->argv[1][0] == '*') {
2076 if (!conn->current_channel) {
2077 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2078 "You are not on any channel");
2079 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2082 name = conn->current_channel->channel_name;
2084 name = cmd->argv[1];
2087 /* Get the channel entry */
2088 channel = silc_client_get_channel(cmd->client, conn, name);
2090 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2091 "You are not on that channel");
2092 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2096 /* Remove us from channel */
2097 chu = silc_client_on_channel(channel, conn->local_entry);
2099 silc_hash_table_del(chu->client->channels, chu->channel);
2100 silc_hash_table_del(chu->channel->user_list, chu->client);
2104 /* Send LEAVE command to the server */
2105 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2106 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2107 1, idp->data, idp->len);
2108 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2109 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2110 silc_buffer_free(buffer);
2111 silc_buffer_free(idp);
2113 /* Notify application */
2114 COMMAND(SILC_STATUS_OK);
2116 if (conn->current_channel == channel)
2117 conn->current_channel = NULL;
2119 silc_client_del_channel(cmd->client, cmd->conn, channel);
2122 silc_client_command_free(cmd);
2125 /* Command USERS. Requests the USERS of the clients joined on requested
2128 SILC_CLIENT_CMD_FUNC(users)
2130 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2131 SilcClientConnection conn = cmd->conn;
2136 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2137 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2141 if (cmd->argc != 2) {
2142 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2143 "Usage: /USERS <channel>");
2144 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2148 if (cmd->argv[1][0] == '*') {
2149 if (!conn->current_channel) {
2150 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2151 "You are not on any channel");
2152 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2155 name = conn->current_channel->channel_name;
2157 name = cmd->argv[1];
2160 /* Send USERS command to the server */
2161 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2162 ++conn->cmd_ident, 1,
2163 2, name, strlen(name));
2164 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2165 NULL, 0, NULL, NULL, buffer->data,
2167 silc_buffer_free(buffer);
2169 /* Notify application */
2170 COMMAND(SILC_STATUS_OK);
2173 silc_client_command_free(cmd);
2176 /* Command GETKEY. Used to fetch remote client's public key. */
2178 SILC_CLIENT_CMD_FUNC(getkey)
2180 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2181 SilcClientConnection conn = cmd->conn;
2182 SilcClient client = cmd->client;
2183 SilcClientEntry client_entry = NULL;
2184 SilcServerEntry server_entry = NULL;
2185 char *nickname = NULL;
2186 SilcBuffer idp, buffer;
2188 SILC_LOG_DEBUG(("Start"));
2191 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2192 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2196 if (cmd->argc < 2) {
2197 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2198 "Usage: /GETKEY <nickname or server name>");
2199 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2203 /* Parse the typed nickname. */
2204 if (client->internal->params->nickname_parse)
2205 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2207 nickname = strdup(cmd->argv[1]);
2209 /* Find client entry */
2210 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2212 if (!client_entry) {
2213 /* Check whether user requested server actually */
2214 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2216 if (!server_entry) {
2217 /* No. what ever user wants we don't have it, so resolve it. We
2218 will first try to resolve the client, and if that fails then
2219 we'll try to resolve the server. */
2221 if (!cmd->pending) {
2222 /* This will send the IDENTIFY command for nickname */
2223 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2224 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2226 silc_client_command_getkey,
2227 silc_client_command_dup(cmd));
2231 SilcClientCommandReplyContext reply =
2232 (SilcClientCommandReplyContext)context2;
2235 /* If nickname was not found, then resolve the server. */
2236 silc_command_get_status(reply->payload, NULL, &error);
2237 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2238 /* This sends the IDENTIFY command to resolve the server. */
2239 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2241 silc_client_command_reply_identify_i, 0,
2243 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2245 2, cmd->argv[1], cmd->argv_lens[1]);
2246 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2248 silc_client_command_getkey,
2249 silc_client_command_dup(cmd));
2253 /* If server was not found, then we've resolved both nickname and
2254 server and did not find anybody. */
2255 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2256 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2257 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2258 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2259 silc_get_status_message(error));
2260 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2264 COMMAND_ERROR(error);
2269 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2271 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2274 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2275 1, idp->data, idp->len);
2276 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2277 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2278 silc_buffer_free(buffer);
2279 silc_buffer_free(idp);
2281 /* Notify application */
2282 COMMAND(SILC_STATUS_OK);
2285 silc_free(nickname);
2286 silc_client_command_free(cmd);
2289 /* Register a new command indicated by the `command' to the SILC client.
2290 The `name' is optional command name. If provided the command may be
2291 searched using the silc_client_command_find by that name. The
2292 `command_function' is the function to be called when the command is
2293 executed, and the `command_reply_function' is the function to be
2294 called after the server has sent reply back to the command.
2296 The `ident' is optional identifier for the command. If non-zero
2297 the `command_reply_function' for the command type `command' will be
2298 called only if the command reply sent by server includes the
2299 command identifier `ident'. Application usually does not need it
2300 and set it to zero value. */
2302 bool silc_client_command_register(SilcClient client,
2303 SilcCommand command,
2305 SilcCommandCb command_function,
2306 SilcCommandCb command_reply_function,
2310 SilcClientCommand cmd;
2312 cmd = silc_calloc(1, sizeof(*cmd));
2314 cmd->command = command_function;
2315 cmd->reply = command_reply_function;
2316 cmd->name = name ? strdup(name) : NULL;
2317 cmd->max_args = max_args;
2320 silc_list_add(client->internal->commands, cmd);
2325 /* Unregister a command indicated by the `command' with command function
2326 `command_function' and command reply function `command_reply_function'.
2327 Returns TRUE if the command was found and unregistered. */
2329 bool silc_client_command_unregister(SilcClient client,
2330 SilcCommand command,
2331 SilcCommandCb command_function,
2332 SilcCommandCb command_reply_function,
2335 SilcClientCommand cmd;
2337 silc_list_start(client->internal->commands);
2338 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2339 if (cmd->cmd == command && cmd->command == command_function &&
2340 cmd->reply == command_reply_function && cmd->ident == ident) {
2341 silc_list_del(client->internal->commands, cmd);
2342 silc_free(cmd->name);
2351 /* Private range commands, specific to this implementation (and compatible
2352 with SILC Server). */
2354 /* CONNECT command. Connects the server to another server. */
2356 SILC_CLIENT_CMD_FUNC(connect)
2358 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2359 SilcClientConnection conn = cmd->conn;
2361 unsigned char port[4];
2365 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2366 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2370 if (cmd->argc < 2) {
2371 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2372 "Usage: /CONNECT <server> [<port>]");
2373 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2377 if (cmd->argc == 3) {
2378 tmp = atoi(cmd->argv[2]);
2379 SILC_PUT32_MSB(tmp, port);
2383 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2385 strlen(cmd->argv[1]),
2388 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2390 strlen(cmd->argv[1]));
2391 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2392 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2393 silc_buffer_free(buffer);
2395 /* Notify application */
2396 COMMAND(SILC_STATUS_OK);
2399 silc_client_command_free(cmd);
2403 /* CLOSE command. Close server connection to the remote server */
2405 SILC_CLIENT_CMD_FUNC(close)
2407 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2408 SilcClientConnection conn = cmd->conn;
2410 unsigned char port[4];
2414 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2415 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2419 if (cmd->argc < 2) {
2420 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2421 "Usage: /CLOSE <server> [<port>]");
2422 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2426 if (cmd->argc == 3) {
2427 tmp = atoi(cmd->argv[2]);
2428 SILC_PUT32_MSB(tmp, port);
2432 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2434 strlen(cmd->argv[1]),
2437 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2439 strlen(cmd->argv[1]));
2440 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2441 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2442 silc_buffer_free(buffer);
2444 /* Notify application */
2445 COMMAND(SILC_STATUS_OK);
2448 silc_client_command_free(cmd);
2451 /* SHUTDOWN command. Shutdowns the server. */
2453 SILC_CLIENT_CMD_FUNC(shutdown)
2455 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2458 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2459 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2463 /* Send the command */
2464 silc_client_command_send(cmd->client, cmd->conn,
2465 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2467 /* Notify application */
2468 COMMAND(SILC_STATUS_OK);
2471 silc_client_command_free(cmd);
2474 /* Register all default commands provided by the client library for the
2477 void silc_client_commands_register(SilcClient client)
2479 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2482 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2483 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2484 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2485 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2486 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2487 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2488 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2489 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2490 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2491 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2492 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2493 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2494 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2495 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2496 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2497 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2498 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2499 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2500 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2501 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2502 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2503 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2504 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2505 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2506 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2508 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2509 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2510 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2513 /* Unregister all commands. */
2515 void silc_client_commands_unregister(SilcClient client)
2517 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2518 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2519 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2520 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2521 SILC_CLIENT_CMDU(list, LIST, "LIST");
2522 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2523 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2524 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2525 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2526 SILC_CLIENT_CMDU(info, INFO, "INFO");
2527 SILC_CLIENT_CMDU(ping, PING, "PING");
2528 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2529 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2530 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2531 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2532 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2533 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2534 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2535 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2536 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2537 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2538 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2539 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2540 SILC_CLIENT_CMDU(users, USERS, "USERS");
2541 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2543 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2544 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2545 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");