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.
31 #define COMMAND cmd->client->internal->ops->command(cmd->client, cmd->conn, \
32 cmd, TRUE, cmd->command->cmd)
34 /* Error to application. Usage: COMMAND_ERROR; */
35 #define COMMAND_ERROR cmd->client->internal->ops->command(cmd->client, \
36 cmd->conn, cmd, FALSE, cmd->command->cmd)
38 #define SAY cmd->client->internal->ops->say
40 /* Generic function to send any command. The arguments must be sent already
41 encoded into correct form and in correct order. */
43 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
44 SilcCommand command, SilcUInt16 ident,
52 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
53 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
54 NULL, 0, NULL, NULL, packet->data,
56 silc_buffer_free(packet);
59 /* Finds and returns a pointer to the command list. Return NULL if the
60 command is not found. */
62 SilcClientCommand silc_client_command_find(SilcClient client,
65 SilcClientCommand cmd;
67 silc_list_start(client->internal->commands);
68 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
69 if (cmd->name && !strcmp(cmd->name, name))
76 /* Calls the command (executes it). Application can call this after
77 it has allocated the SilcClientCommandContext with the function
78 silc_client_command_alloc and found the command from the client
79 library by calling silc_client_command_find. This will execute
82 void silc_client_command_call(SilcClientCommand command,
83 SilcClientCommandContext cmd)
85 (*command->command)((void *)cmd, NULL);
88 /* Add new pending command to be executed when reply to a command has been
89 received. The `reply_cmd' is the command that will call the `callback'
90 with `context' when reply has been received. If `ident is non-zero
91 the `callback' will be executed when received reply with command
92 identifier `ident'. */
94 void silc_client_command_pending(SilcClientConnection conn,
95 SilcCommand reply_cmd,
97 SilcCommandCb callback,
100 SilcClientCommandPending *reply;
102 reply = silc_calloc(1, sizeof(*reply));
103 reply->reply_cmd = reply_cmd;
104 reply->ident = ident;
105 reply->context = context;
106 reply->callback = callback;
107 silc_dlist_add(conn->pending_commands, reply);
110 /* Deletes pending command by reply command type. */
112 void silc_client_command_pending_del(SilcClientConnection conn,
113 SilcCommand reply_cmd,
116 SilcClientCommandPending *r;
118 silc_dlist_start(conn->pending_commands);
119 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
120 if (r->reply_cmd == reply_cmd && r->ident == ident) {
121 silc_dlist_del(conn->pending_commands, r);
127 /* Checks for pending commands and marks callbacks to be called from
128 the command reply function. Returns TRUE if there were pending command. */
130 int silc_client_command_pending_check(SilcClientConnection conn,
131 SilcClientCommandReplyContext ctx,
135 SilcClientCommandPending *r;
137 silc_dlist_start(conn->pending_commands);
138 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
139 if (r->reply_cmd == command && r->ident == ident) {
140 ctx->context = r->context;
141 ctx->callback = r->callback;
150 /* Allocate Command Context */
152 SilcClientCommandContext silc_client_command_alloc(void)
154 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
159 /* Free command context and its internals */
161 void silc_client_command_free(SilcClientCommandContext ctx)
164 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
166 if (ctx->users < 1) {
169 for (i = 0; i < ctx->argc; i++)
170 silc_free(ctx->argv[i]);
171 silc_free(ctx->argv_lens);
172 silc_free(ctx->argv_types);
177 /* Duplicate Command Context by adding reference counter. The context won't
178 be free'd untill it hits zero. */
180 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
183 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
188 /* Command WHOIS. This command is used to query information about
191 SILC_CLIENT_CMD_FUNC(whois)
193 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
194 SilcClientConnection conn = cmd->conn;
198 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
203 /* Given without arguments fetches client's own information */
205 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
206 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
208 1, 3, buffer->data, buffer->len);
209 silc_buffer_free(buffer);
213 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
214 cmd->argc - 1, ++cmd->argv,
215 ++cmd->argv_lens, ++cmd->argv_types,
217 silc_client_packet_send(cmd->client, cmd->conn->sock,
218 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
219 buffer->data, buffer->len, TRUE);
220 silc_buffer_free(buffer);
225 /* Notify application */
229 silc_client_command_free(cmd);
232 /* Command WHOWAS. This command is used to query history information about
233 specific user that used to exist in the network. */
235 SILC_CLIENT_CMD_FUNC(whowas)
237 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
238 SilcClientConnection conn = cmd->conn;
242 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
247 if (cmd->argc < 2 || cmd->argc > 3) {
248 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
249 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
254 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
255 cmd->argc - 1, ++cmd->argv,
256 ++cmd->argv_lens, ++cmd->argv_types,
258 silc_client_packet_send(cmd->client, cmd->conn->sock,
259 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
260 buffer->data, buffer->len, TRUE);
261 silc_buffer_free(buffer);
266 /* Notify application */
270 silc_client_command_free(cmd);
273 /* Command IDENTIFY. This command is used to query information about
274 specific user, especially ID's.
276 NOTE: This command is used only internally by the client library
277 and application MUST NOT call this command directly. */
279 SILC_CLIENT_CMD_FUNC(identify)
281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
282 SilcClientConnection conn = cmd->conn;
286 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
290 if (cmd->argc < 2 || cmd->argc > 3)
294 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
295 ++conn->cmd_ident, 1,
299 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
300 ++conn->cmd_ident, 2,
306 silc_client_packet_send(cmd->client, cmd->conn->sock,
307 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
308 buffer->data, buffer->len, TRUE);
309 silc_buffer_free(buffer);
312 silc_client_command_free(cmd);
315 /* Pending callbcak that will be called after the NICK command was
316 replied by the server. This sets the nickname if there were no
319 SILC_CLIENT_CMD_FUNC(nick_change)
321 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
322 SilcClientConnection conn = cmd->conn;
323 SilcClientCommandReplyContext reply =
324 (SilcClientCommandReplyContext)context2;
325 SilcCommandStatus status;
327 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
328 if (status == SILC_STATUS_OK) {
329 /* Set the nickname */
330 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
332 silc_free(conn->nickname);
333 conn->nickname = strdup(cmd->argv[1]);
334 conn->local_entry->nickname = conn->nickname;
335 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
336 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
337 conn->local_entry->id, conn->local_entry, 0, NULL);
343 silc_client_command_free(cmd);
346 /* Command NICK. Shows current nickname/sets new nickname on current
349 SILC_CLIENT_CMD_FUNC(nick)
351 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
352 SilcClientConnection conn = cmd->conn;
356 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
362 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
363 "Usage: /NICK <nickname>");
368 if (!strcmp(conn->nickname, cmd->argv[1]))
371 /* Show current nickname */
374 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
375 "Your nickname is %s on server %s",
376 conn->nickname, conn->remote_host);
378 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
379 "Your nickname is %s", conn->nickname);
386 if (cmd->argv_lens[1] > 128)
387 cmd->argv_lens[1] = 128;
389 /* Send the NICK command */
390 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
394 ++cmd->conn->cmd_ident);
395 silc_client_packet_send(cmd->client, cmd->conn->sock,
396 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
397 buffer->data, buffer->len, TRUE);
398 silc_buffer_free(buffer);
400 /* Register pending callback that will actually set the new nickname
401 if there were no errors returned by the server. */
402 silc_client_command_pending(conn, SILC_COMMAND_NICK,
403 cmd->conn->cmd_ident,
404 silc_client_command_nick_change,
405 silc_client_command_dup(cmd));
409 silc_client_command_free(cmd);
412 /* Command LIST. Lists channels on the current server. */
414 SILC_CLIENT_CMD_FUNC(list)
416 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
417 SilcClientConnection conn = cmd->conn;
418 SilcIDCacheEntry id_cache = NULL;
419 SilcChannelEntry channel;
420 SilcBuffer buffer, idp = NULL;
424 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
429 if (cmd->argc == 2) {
432 /* Get the Channel ID of the channel */
433 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
434 channel = (SilcChannelEntry)id_cache->context;
435 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
440 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
441 ++conn->cmd_ident, 0);
443 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
444 ++conn->cmd_ident, 1,
445 1, idp->data, idp->len);
447 silc_client_packet_send(cmd->client, cmd->conn->sock,
448 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
449 buffer->data, buffer->len, TRUE);
450 silc_buffer_free(buffer);
452 silc_buffer_free(idp);
454 /* Notify application */
458 silc_client_command_free(cmd);
461 /* Command TOPIC. Sets/shows topic on a channel. */
463 SILC_CLIENT_CMD_FUNC(topic)
465 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
466 SilcClientConnection conn = cmd->conn;
467 SilcIDCacheEntry id_cache = NULL;
468 SilcChannelEntry channel;
469 SilcBuffer buffer, idp;
473 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
478 if (cmd->argc < 2 || cmd->argc > 3) {
479 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
480 "Usage: /TOPIC <channel> [<topic>]");
485 if (cmd->argv[1][0] == '*') {
486 if (!conn->current_channel) {
487 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
488 "You are not on any channel");
492 name = conn->current_channel->channel_name;
497 if (!conn->current_channel) {
498 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
499 "You are not on that channel");
504 /* Get the Channel ID of the channel */
505 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
506 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
507 "You are not on that channel");
512 channel = (SilcChannelEntry)id_cache->context;
514 /* Send TOPIC command to the server */
515 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
517 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
518 ++conn->cmd_ident, 2,
519 1, idp->data, idp->len,
521 strlen(cmd->argv[2]));
523 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
524 ++conn->cmd_ident, 1,
525 1, idp->data, idp->len);
526 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
527 0, NULL, NULL, buffer->data, buffer->len, TRUE);
528 silc_buffer_free(buffer);
529 silc_buffer_free(idp);
531 /* Notify application */
535 silc_client_command_free(cmd);
538 /* Command INVITE. Invites specific client to join a channel. This is
539 also used to mange the invite list of the channel. */
541 SILC_CLIENT_CMD_FUNC(invite)
543 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
544 SilcClient client = cmd->client;
545 SilcClientConnection conn = cmd->conn;
546 SilcClientEntry client_entry = NULL;
547 SilcChannelEntry channel;
548 SilcBuffer buffer, clidp, chidp;
550 char *nickname = NULL, *name;
554 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
560 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
561 "Usage: /INVITE <channel> [<nickname>[@server>]"
562 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
567 if (cmd->argv[1][0] == '*') {
568 if (!conn->current_channel) {
569 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
570 "You are not on any channel");
575 channel = conn->current_channel;
579 channel = silc_client_get_channel(cmd->client, conn, name);
581 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
582 "You are on that channel");
588 /* Parse the typed nickname. */
589 if (cmd->argc == 3) {
590 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
591 if (client->internal->params->nickname_parse)
592 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
594 nickname = strdup(cmd->argv[2]);
596 /* Find client entry */
597 client_entry = silc_idlist_get_client(client, conn, nickname,
605 /* Client entry not found, it was requested thus mark this to be
607 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
609 silc_client_command_invite,
610 silc_client_command_dup(cmd));
615 invite = cmd->argv[2];
617 if (cmd->argv[2][0] == '+')
624 /* Send the command */
625 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
627 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
628 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
629 ++conn->cmd_ident, 3,
630 1, chidp->data, chidp->len,
631 2, clidp->data, clidp->len,
632 type, invite, invite ?
634 silc_buffer_free(clidp);
636 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
637 ++conn->cmd_ident, 2,
638 1, chidp->data, chidp->len,
639 type, invite, invite ?
643 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
644 0, NULL, NULL, buffer->data, buffer->len, TRUE);
645 silc_buffer_free(buffer);
646 silc_buffer_free(chidp);
648 /* Notify application */
653 silc_client_command_free(cmd);
658 SilcClientConnection conn;
661 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
663 QuitInternal q = (QuitInternal)context;
665 /* Close connection */
666 q->client->internal->ops->disconnect(q->client, q->conn);
667 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
672 /* Command QUIT. Closes connection with current server. */
674 SILC_CLIENT_CMD_FUNC(quit)
676 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
681 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
687 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
688 &cmd->argv[1], &cmd->argv_lens[1],
689 &cmd->argv_types[1], 0);
691 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
692 NULL, NULL, NULL, 0);
693 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
695 buffer->data, buffer->len, TRUE);
696 silc_buffer_free(buffer);
698 q = silc_calloc(1, sizeof(*q));
699 q->client = cmd->client;
702 /* Sleep for a while */
705 /* We quit the connection with little timeout */
706 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
707 silc_client_command_quit_cb, (void *)q,
708 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
710 /* Notify application */
714 silc_client_command_free(cmd);
717 /* Timeout callback to remove the killed client from cache */
719 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
721 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
722 SilcClient client = cmd->client;
723 SilcClientConnection conn = cmd->conn;
724 SilcClientEntry target;
725 char *nickname = NULL;
727 /* Parse the typed nickname. */
728 if (client->internal->params->nickname_parse)
729 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
731 nickname = strdup(cmd->argv[1]);
733 /* Get the target client */
734 target = silc_idlist_get_client(cmd->client, conn, nickname,
735 cmd->argv[1], FALSE);
737 /* Remove the client from all channels and free it */
738 silc_client_del_client(client, conn, target);
741 silc_client_command_free(cmd);
744 /* Kill command's pending command callback to actually remove the killed
745 client from our local cache. */
747 SILC_CLIENT_CMD_FUNC(kill_remove)
749 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
750 SilcClientCommandReplyContext reply =
751 (SilcClientCommandReplyContext)context2;
752 SilcCommandStatus status;
754 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
755 if (status == SILC_STATUS_OK) {
756 /* Remove with timeout */
757 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
758 silc_client_command_kill_remove_later, context,
759 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
763 silc_client_command_free(cmd);
766 /* Command KILL. Router operator can use this command to remove an client
767 fromthe SILC Network. */
769 SILC_CLIENT_CMD_FUNC(kill)
771 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
772 SilcClient client = cmd->client;
773 SilcClientConnection conn = cmd->conn;
774 SilcBuffer buffer, idp;
775 SilcClientEntry target;
776 char *nickname = NULL;
779 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
785 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
786 "Usage: /KILL <nickname> [<comment>]");
791 /* Parse the typed nickname. */
792 if (client->internal->params->nickname_parse)
793 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
795 nickname = strdup(cmd->argv[1]);
797 /* Get the target client */
798 target = silc_idlist_get_client(cmd->client, conn, nickname,
806 /* Client entry not found, it was requested thus mark this to be
808 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
810 silc_client_command_kill,
811 silc_client_command_dup(cmd));
816 /* Send the KILL command to the server */
817 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
819 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
820 ++conn->cmd_ident, 1,
821 1, idp->data, idp->len);
823 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
824 ++conn->cmd_ident, 2,
825 1, idp->data, idp->len,
827 strlen(cmd->argv[2]));
828 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
829 0, NULL, NULL, buffer->data, buffer->len, TRUE);
830 silc_buffer_free(buffer);
831 silc_buffer_free(idp);
833 /* Notify application */
836 /* Register a pending callback that will actually remove the killed
837 client from our cache. */
838 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
839 silc_client_command_kill_remove,
840 silc_client_command_dup(cmd));
844 silc_client_command_free(cmd);
847 /* Command INFO. Request information about specific server. If specific
848 server is not provided the current server is used. */
850 SILC_CLIENT_CMD_FUNC(info)
852 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
853 SilcClientConnection conn = cmd->conn;
858 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
864 name = strdup(cmd->argv[1]);
866 /* Send the command */
868 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
869 1, name, strlen(name));
871 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
872 NULL, NULL, NULL, 0);
873 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
874 0, NULL, NULL, buffer->data, buffer->len, TRUE);
875 silc_buffer_free(buffer);
879 /* Notify application */
883 silc_client_command_free(cmd);
886 /* Command PING. Sends ping to server. This is used to test the
887 communication channel. */
889 SILC_CLIENT_CMD_FUNC(ping)
891 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
892 SilcClientConnection conn = cmd->conn;
898 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
903 /* Send the command */
904 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
905 1, conn->remote_id_data,
906 silc_id_get_len(conn->remote_id,
908 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
909 0, NULL, NULL, buffer->data, buffer->len, TRUE);
910 silc_buffer_free(buffer);
912 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
915 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
920 /* Start counting time */
921 for (i = 0; i < conn->ping_count; i++) {
922 if (conn->ping[i].dest_id == NULL) {
923 conn->ping[i].start_time = time(NULL);
924 conn->ping[i].dest_id = id;
925 conn->ping[i].dest_name = strdup(conn->remote_host);
929 if (i >= conn->ping_count) {
930 i = conn->ping_count;
931 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
932 conn->ping[i].start_time = time(NULL);
933 conn->ping[i].dest_id = id;
934 conn->ping[i].dest_name = strdup(conn->remote_host);
938 /* Notify application */
942 silc_client_command_free(cmd);
945 /* Command JOIN. Joins to a channel. */
947 SILC_CLIENT_CMD_FUNC(join)
949 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
950 SilcClientConnection conn = cmd->conn;
951 SilcChannelEntry channel;
952 SilcBuffer buffer, idp, auth = NULL;
953 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
957 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
967 /* See if we have joined to the requested channel already */
968 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
969 if (channel && silc_client_on_channel(channel, conn->local_entry))
972 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
974 if (cmd->argv_lens[1] > 256)
975 cmd->argv_lens[1] = 256;
979 for (i = 2; i < cmd->argc; i++) {
980 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
981 cipher = cmd->argv[i + 1];
983 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
984 hmac = cmd->argv[i + 1];
986 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
987 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
988 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
989 cmd->client->private_key,
990 cmd->client->rng, conn->hash,
994 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
996 cmd->argv_lens[i + 1]);
1000 passphrase = cmd->argv[i];
1004 /* Send JOIN command to the server */
1006 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1007 1, name, strlen(name),
1008 2, idp->data, idp->len,
1010 passphrase ? strlen(passphrase) : 0,
1011 4, cipher, cipher ? strlen(cipher) : 0,
1012 5, hmac, hmac ? strlen(hmac) : 0,
1013 6, auth ? auth->data : NULL,
1014 auth ? auth->len : 0);
1015 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1016 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1017 silc_buffer_free(buffer);
1018 silc_buffer_free(idp);
1020 silc_buffer_free(auth);
1022 /* Notify application */
1026 silc_client_command_free(cmd);
1029 /* MOTD command. Requests motd from server. */
1031 SILC_CLIENT_CMD_FUNC(motd)
1033 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1034 SilcClientConnection conn = cmd->conn;
1038 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1043 if (cmd->argc < 1 || cmd->argc > 2) {
1044 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1045 "Usage: /MOTD [<server>]");
1050 /* Send TOPIC command to the server */
1052 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1053 1, conn->remote_host,
1054 strlen(conn->remote_host));
1056 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1059 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1060 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1061 silc_buffer_free(buffer);
1063 /* Notify application */
1067 silc_client_command_free(cmd);
1070 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1071 modes as client cannot set itself server/router operator privileges. */
1073 SILC_CLIENT_CMD_FUNC(umode)
1075 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1076 SilcClientConnection conn = cmd->conn;
1077 SilcBuffer buffer, idp;
1078 unsigned char *cp, modebuf[4];
1079 SilcUInt32 mode, add, len;
1083 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1088 if (cmd->argc < 2) {
1089 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1090 "Usage: /UMODE +|-<modes>");
1095 mode = conn->local_entry->mode;
1097 /* Are we adding or removing mode */
1098 if (cmd->argv[1][0] == '-')
1104 cp = cmd->argv[1] + 1;
1106 for (i = 0; i < len; i++) {
1111 mode |= SILC_UMODE_SERVER_OPERATOR;
1112 mode |= SILC_UMODE_ROUTER_OPERATOR;
1114 mode = SILC_UMODE_NONE;
1119 mode |= SILC_UMODE_SERVER_OPERATOR;
1121 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1125 mode |= SILC_UMODE_ROUTER_OPERATOR;
1127 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1131 mode |= SILC_UMODE_GONE;
1133 mode &= ~SILC_UMODE_GONE;
1142 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1143 SILC_PUT32_MSB(mode, modebuf);
1145 /* Send the command packet. We support sending only one mode at once
1146 that requires an argument. */
1148 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1149 1, idp->data, idp->len,
1150 2, modebuf, sizeof(modebuf));
1151 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1152 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1153 silc_buffer_free(buffer);
1154 silc_buffer_free(idp);
1156 /* Notify application */
1160 silc_client_command_free(cmd);
1163 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1164 can be set several at once. Those modes that require argument must be set
1165 separately (unless set with modes that does not require arguments). */
1167 SILC_CLIENT_CMD_FUNC(cmode)
1169 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1170 SilcClientConnection conn = cmd->conn;
1171 SilcChannelEntry channel;
1172 SilcBuffer buffer, chidp, auth = NULL;
1173 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1174 SilcUInt32 mode, add, type, len, arg_len = 0;
1178 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1183 if (cmd->argc < 3) {
1184 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1185 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1190 if (cmd->argv[1][0] == '*') {
1191 if (!conn->current_channel) {
1192 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1193 "You are not on any channel");
1198 channel = conn->current_channel;
1200 name = cmd->argv[1];
1202 channel = silc_client_get_channel(cmd->client, conn, name);
1204 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1205 "You are on that channel");
1211 mode = channel->mode;
1213 /* Are we adding or removing mode */
1214 if (cmd->argv[2][0] == '-')
1219 /* Argument type to be sent to server */
1223 cp = cmd->argv[2] + 1;
1225 for (i = 0; i < len; i++) {
1229 mode |= SILC_CHANNEL_MODE_PRIVATE;
1231 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1235 mode |= SILC_CHANNEL_MODE_SECRET;
1237 mode &= ~SILC_CHANNEL_MODE_SECRET;
1241 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1243 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1247 mode |= SILC_CHANNEL_MODE_INVITE;
1249 mode &= ~SILC_CHANNEL_MODE_INVITE;
1253 mode |= SILC_CHANNEL_MODE_TOPIC;
1255 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1260 mode |= SILC_CHANNEL_MODE_ULIMIT;
1262 if (cmd->argc < 4) {
1263 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1264 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1268 ll = atoi(cmd->argv[3]);
1269 SILC_PUT32_MSB(ll, tmp);
1273 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1278 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1280 if (cmd->argc < 4) {
1281 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1282 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1287 arg_len = cmd->argv_lens[3];
1289 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1294 mode |= SILC_CHANNEL_MODE_CIPHER;
1296 if (cmd->argc < 4) {
1297 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1298 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1303 arg_len = cmd->argv_lens[3];
1305 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1310 mode |= SILC_CHANNEL_MODE_HMAC;
1312 if (cmd->argc < 4) {
1313 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1314 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1319 arg_len = cmd->argv_lens[3];
1321 mode &= ~SILC_CHANNEL_MODE_HMAC;
1326 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1329 if (cmd->argc < 4) {
1330 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1331 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1336 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1337 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1338 cmd->client->private_key,
1344 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1345 cmd->argv[3], cmd->argv_lens[3]);
1349 arg_len = auth->len;
1351 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1361 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1362 SILC_PUT32_MSB(mode, modebuf);
1364 /* Send the command packet. We support sending only one mode at once
1365 that requires an argument. */
1368 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1369 1, chidp->data, chidp->len,
1370 2, modebuf, sizeof(modebuf),
1371 type, arg, arg_len);
1374 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1375 1, chidp->data, chidp->len,
1376 2, modebuf, sizeof(modebuf));
1379 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1380 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1381 silc_buffer_free(buffer);
1382 silc_buffer_free(chidp);
1384 silc_buffer_free(auth);
1386 /* Notify application */
1390 silc_client_command_free(cmd);
1393 /* CUMODE command. Changes client's mode on a channel. */
1395 SILC_CLIENT_CMD_FUNC(cumode)
1397 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1398 SilcClient client = cmd->client;
1399 SilcClientConnection conn = cmd->conn;
1400 SilcChannelEntry channel;
1401 SilcChannelUser chu;
1402 SilcClientEntry client_entry;
1403 SilcBuffer buffer, clidp, chidp, auth = NULL;
1404 unsigned char *name, *cp, modebuf[4];
1405 SilcUInt32 mode = 0, add, len;
1406 char *nickname = NULL;
1410 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1415 if (cmd->argc < 4) {
1416 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1417 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1422 if (cmd->argv[1][0] == '*') {
1423 if (!conn->current_channel) {
1424 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1425 "You are not on any channel");
1430 channel = conn->current_channel;
1432 name = cmd->argv[1];
1434 channel = silc_client_get_channel(cmd->client, conn, name);
1436 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1437 "You are on that channel");
1443 /* Parse the typed nickname. */
1444 if (client->internal->params->nickname_parse)
1445 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1447 nickname = strdup(cmd->argv[3]);
1449 /* Find client entry */
1450 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1451 cmd->argv[3], TRUE);
1452 if (!client_entry) {
1458 /* Client entry not found, it was requested thus mark this to be
1460 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1462 silc_client_command_cumode,
1463 silc_client_command_dup(cmd));
1468 /* Get the current mode */
1469 chu = silc_client_on_channel(channel, client_entry);
1473 /* Are we adding or removing mode */
1474 if (cmd->argv[2][0] == '-')
1480 cp = cmd->argv[2] + 1;
1482 for (i = 0; i < len; i++) {
1486 mode |= SILC_CHANNEL_UMODE_CHANFO;
1487 mode |= SILC_CHANNEL_UMODE_CHANOP;
1489 mode = SILC_CHANNEL_UMODE_NONE;
1494 if (cmd->argc == 5) {
1495 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1496 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1497 cmd->client->private_key,
1503 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1504 cmd->argv[4], cmd->argv_lens[4]);
1507 mode |= SILC_CHANNEL_UMODE_CHANFO;
1509 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1514 mode |= SILC_CHANNEL_UMODE_CHANOP;
1516 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1525 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1526 SILC_PUT32_MSB(mode, modebuf);
1527 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1529 /* Send the command packet. We support sending only one mode at once
1530 that requires an argument. */
1531 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1533 1, chidp->data, chidp->len,
1535 3, clidp->data, clidp->len,
1536 4, auth ? auth->data : NULL,
1537 auth ? auth->len : 0);
1539 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1540 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1541 silc_buffer_free(buffer);
1542 silc_buffer_free(chidp);
1543 silc_buffer_free(clidp);
1545 silc_buffer_free(auth);
1547 /* Notify application */
1551 silc_free(nickname);
1552 silc_client_command_free(cmd);
1555 /* KICK command. Kicks a client out of channel. */
1557 SILC_CLIENT_CMD_FUNC(kick)
1559 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1560 SilcClient client = cmd->client;
1561 SilcClientConnection conn = cmd->conn;
1562 SilcIDCacheEntry id_cache = NULL;
1563 SilcChannelEntry channel;
1564 SilcBuffer buffer, idp, idp2;
1565 SilcClientEntry target;
1567 char *nickname = NULL;
1570 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1575 if (cmd->argc < 3) {
1576 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1577 "Usage: /KICK <channel> <nickname> [<comment>]");
1582 if (cmd->argv[1][0] == '*') {
1583 if (!conn->current_channel) {
1584 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1585 "You are not on any channel");
1589 name = conn->current_channel->channel_name;
1591 name = cmd->argv[1];
1594 if (!conn->current_channel) {
1595 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1596 "You are not on that channel");
1601 /* Get the Channel ID of the channel */
1602 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1603 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1604 "You are not on that channel");
1609 channel = (SilcChannelEntry)id_cache->context;
1611 /* Parse the typed nickname. */
1612 if (client->internal->params->nickname_parse)
1613 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1615 nickname = strdup(cmd->argv[2]);
1617 /* Get the target client */
1618 target = silc_idlist_get_client(cmd->client, conn, nickname,
1619 cmd->argv[2], FALSE);
1621 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1622 "No such client: %s", cmd->argv[2]);
1627 /* Send KICK command to the server */
1628 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1629 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1631 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1632 1, idp->data, idp->len,
1633 2, idp2->data, idp2->len);
1635 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1636 1, idp->data, idp->len,
1637 2, idp2->data, idp2->len,
1639 strlen(cmd->argv[3]));
1640 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1641 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1642 silc_buffer_free(buffer);
1643 silc_buffer_free(idp);
1644 silc_buffer_free(idp2);
1646 /* Notify application */
1650 silc_free(nickname);
1651 silc_client_command_free(cmd);
1654 static void silc_client_command_oper_send(unsigned char *data,
1655 SilcUInt32 data_len, void *context)
1657 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1658 SilcClientConnection conn = cmd->conn;
1659 SilcBuffer buffer, auth;
1661 if (cmd->argc >= 3) {
1662 /* Encode the public key authentication payload */
1663 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1664 cmd->client->private_key,
1665 cmd->client->rng, conn->hash,
1669 /* Encode the password authentication payload */
1670 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1674 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1676 strlen(cmd->argv[1]),
1677 2, auth->data, auth->len);
1678 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1679 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1681 silc_buffer_free(buffer);
1682 silc_buffer_free(auth);
1684 /* Notify application */
1688 /* OPER command. Used to obtain server operator privileges. */
1690 SILC_CLIENT_CMD_FUNC(oper)
1692 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1693 SilcClientConnection conn = cmd->conn;
1696 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1701 if (cmd->argc < 2) {
1702 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1703 "Usage: /OPER <username> [-pubkey]");
1708 if (cmd->argc < 3) {
1709 /* Get passphrase */
1710 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1711 silc_client_command_oper_send,
1716 silc_client_command_oper_send(NULL, 0, context);
1719 silc_client_command_free(cmd);
1722 static void silc_client_command_silcoper_send(unsigned char *data,
1723 SilcUInt32 data_len, void *context)
1725 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1726 SilcClientConnection conn = cmd->conn;
1727 SilcBuffer buffer, auth;
1729 if (cmd->argc >= 3) {
1730 /* Encode the public key authentication payload */
1731 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1732 cmd->client->private_key,
1733 cmd->client->rng, conn->hash,
1737 /* Encode the password authentication payload */
1738 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1742 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1744 strlen(cmd->argv[1]),
1745 2, auth->data, auth->len);
1746 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1747 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1749 silc_buffer_free(buffer);
1750 silc_buffer_free(auth);
1752 /* Notify application */
1756 /* SILCOPER command. Used to obtain router operator privileges. */
1758 SILC_CLIENT_CMD_FUNC(silcoper)
1760 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1761 SilcClientConnection conn = cmd->conn;
1764 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1769 if (cmd->argc < 2) {
1770 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1771 "Usage: /SILCOPER <username> [-pubkey]");
1776 if (cmd->argc < 3) {
1777 /* Get passphrase */
1778 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1779 silc_client_command_silcoper_send,
1784 silc_client_command_silcoper_send(NULL, 0, context);
1787 silc_client_command_free(cmd);
1790 /* CONNECT command. Connects the server to another server. */
1792 SILC_CLIENT_CMD_FUNC(connect)
1794 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1795 SilcClientConnection conn = cmd->conn;
1797 unsigned char port[4];
1801 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1806 if (cmd->argc < 2) {
1807 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1808 "Usage: /CONNECT <server> [<port>]");
1813 if (cmd->argc == 3) {
1814 tmp = atoi(cmd->argv[2]);
1815 SILC_PUT32_MSB(tmp, port);
1819 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1821 strlen(cmd->argv[1]),
1824 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1826 strlen(cmd->argv[1]));
1827 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1828 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1829 silc_buffer_free(buffer);
1831 /* Notify application */
1835 silc_client_command_free(cmd);
1838 /* Command BAN. This is used to manage the ban list of the channel. */
1840 SILC_CLIENT_CMD_FUNC(ban)
1842 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1843 SilcClientConnection conn = cmd->conn;
1844 SilcChannelEntry channel;
1845 SilcBuffer buffer, chidp;
1847 char *name, *ban = NULL;
1850 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1855 if (cmd->argc < 2) {
1856 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1857 "Usage: /BAN <channel> "
1858 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1863 if (cmd->argv[1][0] == '*') {
1864 if (!conn->current_channel) {
1865 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1866 "You are not on any channel");
1871 channel = conn->current_channel;
1873 name = cmd->argv[1];
1875 channel = silc_client_get_channel(cmd->client, conn, name);
1877 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1878 "You are on that channel");
1884 if (cmd->argc == 3) {
1885 if (cmd->argv[2][0] == '+')
1894 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1896 /* Send the command */
1898 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1899 1, chidp->data, chidp->len,
1900 type, ban, strlen(ban));
1902 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1903 1, chidp->data, chidp->len);
1905 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1906 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1907 silc_buffer_free(buffer);
1908 silc_buffer_free(chidp);
1910 /* Notify application */
1914 silc_client_command_free(cmd);
1917 /* CLOSE command. Close server connection to the remote server */
1919 SILC_CLIENT_CMD_FUNC(close)
1921 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1922 SilcClientConnection conn = cmd->conn;
1924 unsigned char port[4];
1928 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1933 if (cmd->argc < 2) {
1934 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1935 "Usage: /CLOSE <server> [<port>]");
1940 if (cmd->argc == 3) {
1941 tmp = atoi(cmd->argv[2]);
1942 SILC_PUT32_MSB(tmp, port);
1946 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1948 strlen(cmd->argv[1]),
1951 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1953 strlen(cmd->argv[1]));
1954 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1955 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1956 silc_buffer_free(buffer);
1958 /* Notify application */
1962 silc_client_command_free(cmd);
1965 /* SHUTDOWN command. Shutdowns the server. */
1967 SILC_CLIENT_CMD_FUNC(shutdown)
1969 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1972 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1977 /* Send the command */
1978 silc_client_command_send(cmd->client, cmd->conn,
1979 SILC_COMMAND_SHUTDOWN, 0, 0);
1981 /* Notify application */
1985 silc_client_command_free(cmd);
1988 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1990 SILC_CLIENT_CMD_FUNC(leave)
1992 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1993 SilcClientConnection conn = cmd->conn;
1994 SilcChannelEntry channel;
1995 SilcChannelUser chu;
1996 SilcBuffer buffer, idp;
2000 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2005 if (cmd->argc != 2) {
2006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2007 "Usage: /LEAVE <channel>");
2012 if (cmd->argv[1][0] == '*') {
2013 if (!conn->current_channel) {
2014 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2015 "You are not on any channel");
2019 name = conn->current_channel->channel_name;
2021 name = cmd->argv[1];
2024 /* Get the channel entry */
2025 channel = silc_client_get_channel(cmd->client, conn, name);
2027 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2028 "You are not on that channel");
2033 /* Remove us from channel */
2034 chu = silc_client_on_channel(channel, conn->local_entry);
2036 silc_hash_table_del(chu->client->channels, chu->channel);
2037 silc_hash_table_del(chu->channel->user_list, chu->client);
2041 /* Send LEAVE command to the server */
2042 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2043 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2044 1, idp->data, idp->len);
2045 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2046 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2047 silc_buffer_free(buffer);
2048 silc_buffer_free(idp);
2050 /* Notify application */
2053 if (conn->current_channel == channel)
2054 conn->current_channel = NULL;
2056 silc_client_del_channel(cmd->client, cmd->conn, channel);
2059 silc_client_command_free(cmd);
2062 /* Command USERS. Requests the USERS of the clients joined on requested
2065 SILC_CLIENT_CMD_FUNC(users)
2067 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2068 SilcClientConnection conn = cmd->conn;
2073 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2078 if (cmd->argc != 2) {
2079 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2080 "Usage: /USERS <channel>");
2085 if (cmd->argv[1][0] == '*') {
2086 if (!conn->current_channel) {
2087 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2088 "You are not on any channel");
2092 name = conn->current_channel->channel_name;
2094 name = cmd->argv[1];
2097 /* Send USERS command to the server */
2098 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2099 ++conn->cmd_ident, 1,
2100 2, name, strlen(name));
2101 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2102 NULL, 0, NULL, NULL, buffer->data,
2104 silc_buffer_free(buffer);
2106 /* Notify application */
2110 silc_client_command_free(cmd);
2113 /* Command GETKEY. Used to fetch remote client's public key. */
2115 SILC_CLIENT_CMD_FUNC(getkey)
2117 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2118 SilcClientConnection conn = cmd->conn;
2119 SilcClient client = cmd->client;
2120 SilcClientEntry client_entry = NULL;
2121 SilcServerEntry server_entry = NULL;
2122 char *nickname = NULL;
2123 SilcBuffer idp, buffer;
2125 SILC_LOG_DEBUG(("Start"));
2128 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2133 if (cmd->argc < 2) {
2134 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2135 "Usage: /GETKEY <nickname or server name>");
2140 /* Parse the typed nickname. */
2141 if (client->internal->params->nickname_parse)
2142 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2144 nickname = strdup(cmd->argv[1]);
2146 /* Find client entry */
2147 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2149 if (!client_entry) {
2150 /* Check whether user requested server actually */
2151 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2153 if (!server_entry) {
2154 /* No. what ever user wants we don't have it, so resolve it. We
2155 will first try to resolve the client, and if that fails then
2156 we'll try to resolve the server. */
2158 if (!cmd->pending) {
2159 /* This will send the IDENTIFY command for nickname */
2160 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2161 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2163 silc_client_command_getkey,
2164 silc_client_command_dup(cmd));
2168 SilcClientCommandReplyContext reply =
2169 (SilcClientCommandReplyContext)context2;
2170 SilcCommandStatus status;
2171 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2172 SILC_GET16_MSB(status, tmp);
2174 /* If nickname was not found, then resolve the server. */
2175 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
2176 /* This sends the IDENTIFY command to resolve the server. */
2177 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2179 silc_client_command_reply_identify_i, 0,
2181 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2183 2, cmd->argv[1], cmd->argv_lens[1]);
2184 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2186 silc_client_command_getkey,
2187 silc_client_command_dup(cmd));
2191 /* If server was not found, then we've resolved both nickname and
2192 server and did not find anybody. */
2193 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2194 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2195 silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2196 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2197 silc_client_command_status_message(status));
2207 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2209 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2212 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2213 1, idp->data, idp->len);
2214 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2215 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2216 silc_buffer_free(buffer);
2217 silc_buffer_free(idp);
2219 /* Notify application */
2223 silc_free(nickname);
2224 silc_client_command_free(cmd);
2227 /* Register a new command indicated by the `command' to the SILC client.
2228 The `name' is optional command name. If provided the command may be
2229 searched using the silc_client_command_find by that name. The
2230 `command_function' is the function to be called when the command is
2231 executed, and the `command_reply_function' is the function to be
2232 called after the server has sent reply back to the command.
2234 The `ident' is optional identifier for the command. If non-zero
2235 the `command_reply_function' for the command type `command' will be
2236 called only if the command reply sent by server includes the
2237 command identifier `ident'. Application usually does not need it
2238 and set it to zero value. */
2240 bool silc_client_command_register(SilcClient client,
2241 SilcCommand command,
2243 SilcCommandCb command_function,
2244 SilcCommandCb command_reply_function,
2248 SilcClientCommand cmd;
2250 cmd = silc_calloc(1, sizeof(*cmd));
2252 cmd->command = command_function;
2253 cmd->reply = command_reply_function;
2254 cmd->name = name ? strdup(name) : NULL;
2255 cmd->max_args = max_args;
2258 silc_list_add(client->internal->commands, cmd);
2263 /* Unregister a command indicated by the `command' with command function
2264 `command_function' and command reply function `command_reply_function'.
2265 Returns TRUE if the command was found and unregistered. */
2267 bool silc_client_command_unregister(SilcClient client,
2268 SilcCommand command,
2269 SilcCommandCb command_function,
2270 SilcCommandCb command_reply_function,
2273 SilcClientCommand cmd;
2275 silc_list_start(client->internal->commands);
2276 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2277 if (cmd->cmd == command && cmd->command == command_function &&
2278 cmd->reply == command_reply_function && cmd->ident == ident) {
2279 silc_list_del(client->internal->commands, cmd);
2280 silc_free(cmd->name);
2289 /* Register all default commands provided by the client library for the
2292 void silc_client_commands_register(SilcClient client)
2294 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2297 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2298 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2299 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2300 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2301 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2302 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2303 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2304 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2305 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2306 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2307 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2308 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2309 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2310 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2311 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2312 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2313 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2314 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2315 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2316 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2317 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2318 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2319 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2320 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2321 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2322 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2325 /* Unregister all commands. */
2327 void silc_client_commands_unregister(SilcClient client)
2329 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2330 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2331 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2332 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2333 SILC_CLIENT_CMDU(list, LIST, "LIST");
2334 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2335 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2336 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2337 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2338 SILC_CLIENT_CMDU(info, INFO, "INFO");
2339 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2340 SILC_CLIENT_CMDU(ping, PING, "PING");
2341 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2342 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2343 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2344 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2345 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2346 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2347 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2348 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2349 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2350 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2351 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2352 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2353 SILC_CLIENT_CMDU(users, USERS, "USERS");
2354 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");