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 "clientlibincludes.h"
22 #include "client_internal.h"
24 #define SILC_NOT_CONNECTED(x, c) \
25 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
26 "You are not connected to a server, use /SERVER to connect");
28 /* Command operation that is called at the end of all commands.
30 #define COMMAND cmd->client->internal->ops->command(cmd->client, cmd->conn, \
31 cmd, TRUE, cmd->command->cmd)
33 /* Error to application. Usage: COMMAND_ERROR; */
34 #define COMMAND_ERROR cmd->client->internal->ops->command(cmd->client, \
35 cmd->conn, cmd, FALSE, cmd->command->cmd)
37 #define SAY cmd->client->internal->ops->say
39 /* Generic function to send any command. The arguments must be sent already
40 encoded into correct form and in correct order. */
42 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
43 SilcCommand command, uint16 ident,
51 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
52 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
53 NULL, 0, NULL, NULL, packet->data,
55 silc_buffer_free(packet);
58 /* Finds and returns a pointer to the command list. Return NULL if the
59 command is not found. */
61 SilcClientCommand silc_client_command_find(SilcClient client,
64 SilcClientCommand cmd;
66 silc_list_start(client->internal->commands);
67 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
68 if (cmd->name && !strcmp(cmd->name, name))
75 /* Calls the command (executes it). Application can call this after
76 it has allocated the SilcClientCommandContext with the function
77 silc_client_command_alloc and found the command from the client
78 library by calling silc_client_command_find. This will execute
81 void silc_client_command_call(SilcClientCommand command,
82 SilcClientCommandContext cmd)
84 (*command->command)((void *)cmd, NULL);
87 /* Add new pending command to be executed when reply to a command has been
88 received. The `reply_cmd' is the command that will call the `callback'
89 with `context' when reply has been received. If `ident is non-zero
90 the `callback' will be executed when received reply with command
91 identifier `ident'. */
93 void silc_client_command_pending(SilcClientConnection conn,
94 SilcCommand reply_cmd,
96 SilcCommandCb callback,
99 SilcClientCommandPending *reply;
101 reply = silc_calloc(1, sizeof(*reply));
102 reply->reply_cmd = reply_cmd;
103 reply->ident = ident;
104 reply->context = context;
105 reply->callback = callback;
106 silc_dlist_add(conn->pending_commands, reply);
109 /* Deletes pending command by reply command type. */
111 void silc_client_command_pending_del(SilcClientConnection conn,
112 SilcCommand reply_cmd,
115 SilcClientCommandPending *r;
117 silc_dlist_start(conn->pending_commands);
118 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
119 if (r->reply_cmd == reply_cmd && r->ident == ident) {
120 silc_dlist_del(conn->pending_commands, r);
126 /* Checks for pending commands and marks callbacks to be called from
127 the command reply function. Returns TRUE if there were pending command. */
129 int silc_client_command_pending_check(SilcClientConnection conn,
130 SilcClientCommandReplyContext ctx,
134 SilcClientCommandPending *r;
136 silc_dlist_start(conn->pending_commands);
137 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
138 if (r->reply_cmd == command && r->ident == ident) {
139 ctx->context = r->context;
140 ctx->callback = r->callback;
149 /* Allocate Command Context */
151 SilcClientCommandContext silc_client_command_alloc(void)
153 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
158 /* Free command context and its internals */
160 void silc_client_command_free(SilcClientCommandContext ctx)
163 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
165 if (ctx->users < 1) {
168 for (i = 0; i < ctx->argc; i++)
169 silc_free(ctx->argv[i]);
170 silc_free(ctx->argv_lens);
171 silc_free(ctx->argv_types);
176 /* Duplicate Command Context by adding reference counter. The context won't
177 be free'd untill it hits zero. */
179 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
182 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
187 /* Command WHOIS. This command is used to query information about
190 SILC_CLIENT_CMD_FUNC(whois)
192 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
193 SilcClientConnection conn = cmd->conn;
197 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
202 /* Given without arguments fetches client's own information */
204 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
205 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
207 1, 3, buffer->data, buffer->len);
208 silc_buffer_free(buffer);
212 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
213 cmd->argc - 1, ++cmd->argv,
214 ++cmd->argv_lens, ++cmd->argv_types,
216 silc_client_packet_send(cmd->client, cmd->conn->sock,
217 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
218 buffer->data, buffer->len, TRUE);
219 silc_buffer_free(buffer);
224 /* Notify application */
228 silc_client_command_free(cmd);
231 /* Command WHOWAS. This command is used to query history information about
232 specific user that used to exist in the network. */
234 SILC_CLIENT_CMD_FUNC(whowas)
236 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
237 SilcClientConnection conn = cmd->conn;
241 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
246 if (cmd->argc < 2 || cmd->argc > 3) {
247 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
248 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
253 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
254 cmd->argc - 1, ++cmd->argv,
255 ++cmd->argv_lens, ++cmd->argv_types,
257 silc_client_packet_send(cmd->client, cmd->conn->sock,
258 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
259 buffer->data, buffer->len, TRUE);
260 silc_buffer_free(buffer);
265 /* Notify application */
269 silc_client_command_free(cmd);
272 /* Command IDENTIFY. This command is used to query information about
273 specific user, especially ID's.
275 NOTE: This command is used only internally by the client library
276 and application MUST NOT call this command directly. */
278 SILC_CLIENT_CMD_FUNC(identify)
280 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
281 SilcClientConnection conn = cmd->conn;
285 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
289 if (cmd->argc < 2 || cmd->argc > 3)
293 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
294 ++conn->cmd_ident, 1,
298 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
299 ++conn->cmd_ident, 2,
305 silc_client_packet_send(cmd->client, cmd->conn->sock,
306 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
307 buffer->data, buffer->len, TRUE);
308 silc_buffer_free(buffer);
311 silc_client_command_free(cmd);
314 /* Pending callbcak that will be called after the NICK command was
315 replied by the server. This sets the nickname if there were no
318 SILC_CLIENT_CMD_FUNC(nick_change)
320 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
321 SilcClientConnection conn = cmd->conn;
322 SilcClientCommandReplyContext reply =
323 (SilcClientCommandReplyContext)context2;
324 SilcCommandStatus status;
326 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
327 if (status == SILC_STATUS_OK) {
328 /* Set the nickname */
329 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
331 silc_free(conn->nickname);
332 conn->nickname = strdup(cmd->argv[1]);
333 conn->local_entry->nickname = conn->nickname;
334 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
335 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
336 conn->local_entry->id, conn->local_entry, 0, NULL);
342 silc_client_command_free(cmd);
345 /* Command NICK. Shows current nickname/sets new nickname on current
348 SILC_CLIENT_CMD_FUNC(nick)
350 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
351 SilcClientConnection conn = cmd->conn;
355 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
361 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
362 "Usage: /NICK <nickname>");
367 if (!strcmp(conn->nickname, cmd->argv[1]))
370 /* Show current nickname */
373 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
374 "Your nickname is %s on server %s",
375 conn->nickname, conn->remote_host);
377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
378 "Your nickname is %s", conn->nickname);
385 if (cmd->argv_lens[1] > 128)
386 cmd->argv_lens[1] = 128;
388 /* Send the NICK command */
389 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
393 ++cmd->conn->cmd_ident);
394 silc_client_packet_send(cmd->client, cmd->conn->sock,
395 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
396 buffer->data, buffer->len, TRUE);
397 silc_buffer_free(buffer);
399 /* Register pending callback that will actually set the new nickname
400 if there were no errors returned by the server. */
401 silc_client_command_pending(conn, SILC_COMMAND_NICK,
402 cmd->conn->cmd_ident,
403 silc_client_command_nick_change,
404 silc_client_command_dup(cmd));
408 silc_client_command_free(cmd);
411 /* Command LIST. Lists channels on the current server. */
413 SILC_CLIENT_CMD_FUNC(list)
415 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
416 SilcClientConnection conn = cmd->conn;
417 SilcIDCacheEntry id_cache = NULL;
418 SilcChannelEntry channel;
419 SilcBuffer buffer, idp = NULL;
423 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
428 if (cmd->argc == 2) {
431 /* Get the Channel ID of the channel */
432 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
433 channel = (SilcChannelEntry)id_cache->context;
434 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
439 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
440 ++conn->cmd_ident, 0);
442 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
443 ++conn->cmd_ident, 1,
444 1, idp->data, idp->len);
446 silc_client_packet_send(cmd->client, cmd->conn->sock,
447 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
448 buffer->data, buffer->len, TRUE);
449 silc_buffer_free(buffer);
451 silc_buffer_free(idp);
453 /* Notify application */
457 silc_client_command_free(cmd);
460 /* Command TOPIC. Sets/shows topic on a channel. */
462 SILC_CLIENT_CMD_FUNC(topic)
464 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
465 SilcClientConnection conn = cmd->conn;
466 SilcIDCacheEntry id_cache = NULL;
467 SilcChannelEntry channel;
468 SilcBuffer buffer, idp;
472 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
477 if (cmd->argc < 2 || cmd->argc > 3) {
478 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
479 "Usage: /TOPIC <channel> [<topic>]");
484 if (cmd->argv[1][0] == '*') {
485 if (!conn->current_channel) {
486 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
487 "You are not on any channel");
491 name = conn->current_channel->channel_name;
496 if (!conn->current_channel) {
497 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
498 "You are not on that channel");
503 /* Get the Channel ID of the channel */
504 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
505 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
506 "You are not on that channel");
511 channel = (SilcChannelEntry)id_cache->context;
513 /* Send TOPIC command to the server */
514 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
516 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
517 ++conn->cmd_ident, 2,
518 1, idp->data, idp->len,
520 strlen(cmd->argv[2]));
522 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
523 ++conn->cmd_ident, 1,
524 1, idp->data, idp->len);
525 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
526 0, NULL, NULL, buffer->data, buffer->len, TRUE);
527 silc_buffer_free(buffer);
528 silc_buffer_free(idp);
530 /* Notify application */
534 silc_client_command_free(cmd);
537 /* Command INVITE. Invites specific client to join a channel. This is
538 also used to mange the invite list of the channel. */
540 SILC_CLIENT_CMD_FUNC(invite)
542 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
543 SilcClient client = cmd->client;
544 SilcClientConnection conn = cmd->conn;
545 SilcClientEntry client_entry = NULL;
546 SilcChannelEntry channel;
547 SilcBuffer buffer, clidp, chidp;
549 char *nickname = NULL, *name;
553 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
559 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
560 "Usage: /INVITE <channel> [<nickname>[@server>]"
561 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
566 if (cmd->argv[1][0] == '*') {
567 if (!conn->current_channel) {
568 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
569 "You are not on any channel");
574 channel = conn->current_channel;
578 channel = silc_client_get_channel(cmd->client, conn, name);
580 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
581 "You are on that channel");
587 /* Parse the typed nickname. */
588 if (cmd->argc == 3) {
589 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
590 if (client->internal->params->nickname_parse)
591 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
593 nickname = strdup(cmd->argv[2]);
595 /* Find client entry */
596 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,
808 /* Client entry not found, it was requested thus mark this to be
810 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
812 silc_client_command_kill,
813 silc_client_command_dup(cmd));
818 /* Send the KILL command to the server */
819 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
821 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
822 ++conn->cmd_ident, 1,
823 1, idp->data, idp->len);
825 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
826 ++conn->cmd_ident, 2,
827 1, idp->data, idp->len,
829 strlen(cmd->argv[2]));
830 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
831 0, NULL, NULL, buffer->data, buffer->len, TRUE);
832 silc_buffer_free(buffer);
833 silc_buffer_free(idp);
835 /* Notify application */
838 /* Register a pending callback that will actually remove the killed
839 client from our cache. */
840 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
841 silc_client_command_kill_remove,
842 silc_client_command_dup(cmd));
846 silc_client_command_free(cmd);
849 /* Command INFO. Request information about specific server. If specific
850 server is not provided the current server is used. */
852 SILC_CLIENT_CMD_FUNC(info)
854 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
855 SilcClientConnection conn = cmd->conn;
860 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
866 name = strdup(cmd->argv[1]);
868 /* Send the command */
870 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
871 1, name, strlen(name));
873 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
874 NULL, NULL, NULL, 0);
875 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
876 0, NULL, NULL, buffer->data, buffer->len, TRUE);
877 silc_buffer_free(buffer);
881 /* Notify application */
885 silc_client_command_free(cmd);
888 /* Command PING. Sends ping to server. This is used to test the
889 communication channel. */
891 SILC_CLIENT_CMD_FUNC(ping)
893 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
894 SilcClientConnection conn = cmd->conn;
900 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
905 /* Send the command */
906 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
907 1, conn->remote_id_data,
908 silc_id_get_len(conn->remote_id,
910 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
911 0, NULL, NULL, buffer->data, buffer->len, TRUE);
912 silc_buffer_free(buffer);
914 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
917 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
922 /* Start counting time */
923 for (i = 0; i < conn->ping_count; i++) {
924 if (conn->ping[i].dest_id == NULL) {
925 conn->ping[i].start_time = time(NULL);
926 conn->ping[i].dest_id = id;
927 conn->ping[i].dest_name = strdup(conn->remote_host);
931 if (i >= conn->ping_count) {
932 i = conn->ping_count;
933 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
934 conn->ping[i].start_time = time(NULL);
935 conn->ping[i].dest_id = id;
936 conn->ping[i].dest_name = strdup(conn->remote_host);
940 /* Notify application */
944 silc_client_command_free(cmd);
947 /* Command JOIN. Joins to a channel. */
949 SILC_CLIENT_CMD_FUNC(join)
951 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
952 SilcClientConnection conn = cmd->conn;
953 SilcIDCacheEntry id_cache = NULL;
954 SilcBuffer buffer, idp, auth = NULL;
955 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
969 /* See if we have joined to the requested channel already */
970 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
972 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
973 if (channel->on_channel)
977 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
979 if (cmd->argv_lens[1] > 256)
980 cmd->argv_lens[1] = 256;
984 for (i = 2; i < cmd->argc; i++) {
985 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
986 cipher = cmd->argv[i + 1];
988 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
989 hmac = cmd->argv[i + 1];
991 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
992 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
993 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
994 cmd->client->private_key,
999 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1001 cmd->argv_lens[i + 1]);
1005 passphrase = cmd->argv[i];
1009 /* Send JOIN command to the server */
1011 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1012 1, name, strlen(name),
1013 2, idp->data, idp->len,
1015 passphrase ? strlen(passphrase) : 0,
1016 4, cipher, cipher ? strlen(cipher) : 0,
1017 5, hmac, hmac ? strlen(hmac) : 0,
1018 6, auth ? auth->data : NULL,
1019 auth ? auth->len : 0);
1020 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1021 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1022 silc_buffer_free(buffer);
1023 silc_buffer_free(idp);
1025 silc_buffer_free(auth);
1027 /* Notify application */
1031 silc_client_command_free(cmd);
1034 /* MOTD command. Requests motd from server. */
1036 SILC_CLIENT_CMD_FUNC(motd)
1038 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1039 SilcClientConnection conn = cmd->conn;
1043 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1048 if (cmd->argc < 1 || cmd->argc > 2) {
1049 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1050 "Usage: /MOTD [<server>]");
1055 /* Send TOPIC command to the server */
1057 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1058 1, conn->remote_host,
1059 strlen(conn->remote_host));
1061 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1064 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1065 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1066 silc_buffer_free(buffer);
1068 /* Notify application */
1072 silc_client_command_free(cmd);
1075 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1076 modes as client cannot set itself server/router operator privileges. */
1078 SILC_CLIENT_CMD_FUNC(umode)
1080 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1081 SilcClientConnection conn = cmd->conn;
1082 SilcBuffer buffer, idp;
1083 unsigned char *cp, modebuf[4];
1084 uint32 mode, add, len;
1088 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1093 if (cmd->argc < 2) {
1094 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1095 "Usage: /UMODE +|-<modes>");
1100 mode = conn->local_entry->mode;
1102 /* Are we adding or removing mode */
1103 if (cmd->argv[1][0] == '-')
1109 cp = cmd->argv[1] + 1;
1111 for (i = 0; i < len; i++) {
1116 mode |= SILC_UMODE_SERVER_OPERATOR;
1117 mode |= SILC_UMODE_ROUTER_OPERATOR;
1119 mode = SILC_UMODE_NONE;
1124 mode |= SILC_UMODE_SERVER_OPERATOR;
1126 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1130 mode |= SILC_UMODE_ROUTER_OPERATOR;
1132 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1136 mode |= SILC_UMODE_GONE;
1138 mode &= ~SILC_UMODE_GONE;
1147 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1148 SILC_PUT32_MSB(mode, modebuf);
1150 /* Send the command packet. We support sending only one mode at once
1151 that requires an argument. */
1153 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1154 1, idp->data, idp->len,
1155 2, modebuf, sizeof(modebuf));
1156 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1157 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1158 silc_buffer_free(buffer);
1159 silc_buffer_free(idp);
1161 /* Notify application */
1165 silc_client_command_free(cmd);
1168 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1169 can be set several at once. Those modes that require argument must be set
1170 separately (unless set with modes that does not require arguments). */
1172 SILC_CLIENT_CMD_FUNC(cmode)
1174 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1175 SilcClientConnection conn = cmd->conn;
1176 SilcChannelEntry channel;
1177 SilcBuffer buffer, chidp, auth = NULL;
1178 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1179 uint32 mode, add, type, len, arg_len = 0;
1183 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1188 if (cmd->argc < 3) {
1189 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1190 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1195 if (cmd->argv[1][0] == '*') {
1196 if (!conn->current_channel) {
1197 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1198 "You are not on any channel");
1203 channel = conn->current_channel;
1205 name = cmd->argv[1];
1207 channel = silc_client_get_channel(cmd->client, conn, name);
1209 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1210 "You are on that channel");
1216 mode = channel->mode;
1218 /* Are we adding or removing mode */
1219 if (cmd->argv[2][0] == '-')
1224 /* Argument type to be sent to server */
1228 cp = cmd->argv[2] + 1;
1230 for (i = 0; i < len; i++) {
1234 mode |= SILC_CHANNEL_MODE_PRIVATE;
1236 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1240 mode |= SILC_CHANNEL_MODE_SECRET;
1242 mode &= ~SILC_CHANNEL_MODE_SECRET;
1246 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1248 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1252 mode |= SILC_CHANNEL_MODE_INVITE;
1254 mode &= ~SILC_CHANNEL_MODE_INVITE;
1258 mode |= SILC_CHANNEL_MODE_TOPIC;
1260 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1265 mode |= SILC_CHANNEL_MODE_ULIMIT;
1267 if (cmd->argc < 4) {
1268 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1269 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1273 ll = atoi(cmd->argv[3]);
1274 SILC_PUT32_MSB(ll, tmp);
1278 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1283 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1285 if (cmd->argc < 4) {
1286 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1287 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1292 arg_len = cmd->argv_lens[3];
1294 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1299 mode |= SILC_CHANNEL_MODE_CIPHER;
1301 if (cmd->argc < 4) {
1302 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1303 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1308 arg_len = cmd->argv_lens[3];
1310 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1315 mode |= SILC_CHANNEL_MODE_HMAC;
1317 if (cmd->argc < 4) {
1318 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1319 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1324 arg_len = cmd->argv_lens[3];
1326 mode &= ~SILC_CHANNEL_MODE_HMAC;
1331 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1334 if (cmd->argc < 4) {
1335 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1336 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1341 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1342 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1343 cmd->client->private_key,
1348 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1349 cmd->argv[3], cmd->argv_lens[3]);
1353 arg_len = auth->len;
1355 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1365 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1366 SILC_PUT32_MSB(mode, modebuf);
1368 /* Send the command packet. We support sending only one mode at once
1369 that requires an argument. */
1372 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1373 1, chidp->data, chidp->len,
1374 2, modebuf, sizeof(modebuf),
1375 type, arg, arg_len);
1378 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1379 1, chidp->data, chidp->len,
1380 2, modebuf, sizeof(modebuf));
1383 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1384 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1385 silc_buffer_free(buffer);
1386 silc_buffer_free(chidp);
1388 silc_buffer_free(auth);
1390 /* Notify application */
1394 silc_client_command_free(cmd);
1397 /* CUMODE command. Changes client's mode on a channel. */
1399 SILC_CLIENT_CMD_FUNC(cumode)
1401 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1402 SilcClient client = cmd->client;
1403 SilcClientConnection conn = cmd->conn;
1404 SilcChannelEntry channel;
1405 SilcChannelUser chu;
1406 SilcClientEntry client_entry;
1407 SilcBuffer buffer, clidp, chidp, auth = NULL;
1408 unsigned char *name, *cp, modebuf[4];
1409 uint32 mode = 0, add, len;
1410 char *nickname = NULL;
1414 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1419 if (cmd->argc < 4) {
1420 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1421 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1426 if (cmd->argv[1][0] == '*') {
1427 if (!conn->current_channel) {
1428 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1429 "You are not on any channel");
1434 channel = conn->current_channel;
1436 name = cmd->argv[1];
1438 channel = silc_client_get_channel(cmd->client, conn, name);
1440 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1441 "You are on that channel");
1447 /* Parse the typed nickname. */
1448 if (client->internal->params->nickname_parse)
1449 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1451 nickname = strdup(cmd->argv[3]);
1453 /* Find client entry */
1454 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1455 cmd->argv[3], TRUE);
1456 if (!client_entry) {
1462 silc_free(nickname);
1464 /* Client entry not found, it was requested thus mark this to be
1466 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1468 silc_client_command_cumode,
1469 silc_client_command_dup(cmd));
1474 /* Get the current mode */
1475 silc_list_start(channel->clients);
1476 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1477 if (chu->client == client_entry) {
1483 /* Are we adding or removing mode */
1484 if (cmd->argv[2][0] == '-')
1490 cp = cmd->argv[2] + 1;
1492 for (i = 0; i < len; i++) {
1496 mode |= SILC_CHANNEL_UMODE_CHANFO;
1497 mode |= SILC_CHANNEL_UMODE_CHANOP;
1499 mode = SILC_CHANNEL_UMODE_NONE;
1504 if (cmd->argc == 5) {
1505 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1506 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1507 cmd->client->private_key,
1512 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1513 cmd->argv[4], cmd->argv_lens[4]);
1516 mode |= SILC_CHANNEL_UMODE_CHANFO;
1518 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1523 mode |= SILC_CHANNEL_UMODE_CHANOP;
1525 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1534 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1535 SILC_PUT32_MSB(mode, modebuf);
1536 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1538 /* Send the command packet. We support sending only one mode at once
1539 that requires an argument. */
1540 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1542 1, chidp->data, chidp->len,
1544 3, clidp->data, clidp->len,
1545 4, auth ? auth->data : NULL,
1546 auth ? auth->len : 0);
1548 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1549 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1550 silc_buffer_free(buffer);
1551 silc_buffer_free(chidp);
1552 silc_buffer_free(clidp);
1554 silc_buffer_free(auth);
1556 /* Notify application */
1560 silc_free(nickname);
1561 silc_client_command_free(cmd);
1564 /* KICK command. Kicks a client out of channel. */
1566 SILC_CLIENT_CMD_FUNC(kick)
1568 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1569 SilcClient client = cmd->client;
1570 SilcClientConnection conn = cmd->conn;
1571 SilcIDCacheEntry id_cache = NULL;
1572 SilcChannelEntry channel;
1573 SilcBuffer buffer, idp, idp2;
1574 SilcClientEntry target;
1576 char *nickname = NULL;
1579 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1584 if (cmd->argc < 3) {
1585 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1586 "Usage: /KICK <channel> <nickname> [<comment>]");
1591 if (cmd->argv[1][0] == '*') {
1592 if (!conn->current_channel) {
1593 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1594 "You are not on any channel");
1598 name = conn->current_channel->channel_name;
1600 name = cmd->argv[1];
1603 if (!conn->current_channel) {
1604 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1605 "You are not on that channel");
1610 /* Get the Channel ID of the channel */
1611 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1612 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1613 "You are not on that channel");
1618 channel = (SilcChannelEntry)id_cache->context;
1620 /* Parse the typed nickname. */
1621 if (client->internal->params->nickname_parse)
1622 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1624 nickname = strdup(cmd->argv[2]);
1626 /* Get the target client */
1627 target = silc_idlist_get_client(cmd->client, conn, nickname,
1628 cmd->argv[2], FALSE);
1630 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1631 "No such client: %s", cmd->argv[2]);
1636 /* Send KICK command to the server */
1637 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1638 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1640 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1641 1, idp->data, idp->len,
1642 2, idp2->data, idp2->len);
1644 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1645 1, idp->data, idp->len,
1646 2, idp2->data, idp2->len,
1648 strlen(cmd->argv[3]));
1649 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1650 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1651 silc_buffer_free(buffer);
1652 silc_buffer_free(idp);
1653 silc_buffer_free(idp2);
1655 /* Notify application */
1659 silc_free(nickname);
1660 silc_client_command_free(cmd);
1663 static void silc_client_command_oper_send(unsigned char *data,
1664 uint32 data_len, void *context)
1666 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1667 SilcClientConnection conn = cmd->conn;
1668 SilcBuffer buffer, auth;
1670 if (cmd->argc >= 3) {
1671 /* Encode the public key authentication payload */
1672 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1673 cmd->client->private_key,
1678 /* Encode the password authentication payload */
1679 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1683 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1685 strlen(cmd->argv[1]),
1686 2, auth->data, auth->len);
1687 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1688 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1690 silc_buffer_free(buffer);
1691 silc_buffer_free(auth);
1693 /* Notify application */
1697 /* OPER command. Used to obtain server operator privileges. */
1699 SILC_CLIENT_CMD_FUNC(oper)
1701 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1702 SilcClientConnection conn = cmd->conn;
1705 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1710 if (cmd->argc < 2) {
1711 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1712 "Usage: /OPER <username> [-pubkey]");
1717 if (cmd->argc < 3) {
1718 /* Get passphrase */
1719 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1720 silc_client_command_oper_send,
1725 silc_client_command_oper_send(NULL, 0, context);
1728 silc_client_command_free(cmd);
1731 static void silc_client_command_silcoper_send(unsigned char *data,
1732 uint32 data_len, void *context)
1734 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1735 SilcClientConnection conn = cmd->conn;
1736 SilcBuffer buffer, auth;
1738 if (cmd->argc >= 3) {
1739 /* Encode the public key authentication payload */
1740 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1741 cmd->client->private_key,
1746 /* Encode the password authentication payload */
1747 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1751 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1753 strlen(cmd->argv[1]),
1754 2, auth->data, auth->len);
1755 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1756 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1758 silc_buffer_free(buffer);
1759 silc_buffer_free(auth);
1761 /* Notify application */
1765 /* SILCOPER command. Used to obtain router operator privileges. */
1767 SILC_CLIENT_CMD_FUNC(silcoper)
1769 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1770 SilcClientConnection conn = cmd->conn;
1773 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1778 if (cmd->argc < 2) {
1779 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1780 "Usage: /SILCOPER <username> [-pubkey]");
1785 if (cmd->argc < 3) {
1786 /* Get passphrase */
1787 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1788 silc_client_command_silcoper_send,
1793 silc_client_command_silcoper_send(NULL, 0, context);
1796 silc_client_command_free(cmd);
1799 /* CONNECT command. Connects the server to another server. */
1801 SILC_CLIENT_CMD_FUNC(connect)
1803 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1804 SilcClientConnection conn = cmd->conn;
1806 unsigned char port[4];
1810 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1815 if (cmd->argc < 2) {
1816 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1817 "Usage: /CONNECT <server> [<port>]");
1822 if (cmd->argc == 3) {
1823 tmp = atoi(cmd->argv[2]);
1824 SILC_PUT32_MSB(tmp, port);
1828 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1830 strlen(cmd->argv[1]),
1833 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1835 strlen(cmd->argv[1]));
1836 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1837 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1838 silc_buffer_free(buffer);
1840 /* Notify application */
1844 silc_client_command_free(cmd);
1847 /* Command BAN. This is used to manage the ban list of the channel. */
1849 SILC_CLIENT_CMD_FUNC(ban)
1851 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1852 SilcClientConnection conn = cmd->conn;
1853 SilcChannelEntry channel;
1854 SilcBuffer buffer, chidp;
1856 char *name, *ban = NULL;
1859 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1864 if (cmd->argc < 2) {
1865 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1866 "Usage: /BAN <channel> "
1867 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1872 if (cmd->argv[1][0] == '*') {
1873 if (!conn->current_channel) {
1874 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1875 "You are not on any channel");
1880 channel = conn->current_channel;
1882 name = cmd->argv[1];
1884 channel = silc_client_get_channel(cmd->client, conn, name);
1886 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1887 "You are on that channel");
1893 if (cmd->argc == 3) {
1894 if (cmd->argv[2][0] == '+')
1903 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1905 /* Send the command */
1907 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1908 1, chidp->data, chidp->len,
1909 type, ban, strlen(ban));
1911 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1912 1, chidp->data, chidp->len);
1914 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1915 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1916 silc_buffer_free(buffer);
1917 silc_buffer_free(chidp);
1919 /* Notify application */
1923 silc_client_command_free(cmd);
1926 /* CLOSE command. Close server connection to the remote server */
1928 SILC_CLIENT_CMD_FUNC(close)
1930 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1931 SilcClientConnection conn = cmd->conn;
1933 unsigned char port[4];
1937 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1942 if (cmd->argc < 2) {
1943 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1944 "Usage: /CLOSE <server> [<port>]");
1949 if (cmd->argc == 3) {
1950 tmp = atoi(cmd->argv[2]);
1951 SILC_PUT32_MSB(tmp, port);
1955 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1957 strlen(cmd->argv[1]),
1960 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1962 strlen(cmd->argv[1]));
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);
1967 /* Notify application */
1971 silc_client_command_free(cmd);
1974 /* SHUTDOWN command. Shutdowns the server. */
1976 SILC_CLIENT_CMD_FUNC(shutdown)
1978 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1981 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1986 /* Send the command */
1987 silc_client_command_send(cmd->client, cmd->conn,
1988 SILC_COMMAND_SHUTDOWN, 0, 0);
1990 /* Notify application */
1994 silc_client_command_free(cmd);
1997 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1999 SILC_CLIENT_CMD_FUNC(leave)
2001 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2002 SilcClientConnection conn = cmd->conn;
2003 SilcIDCacheEntry id_cache = NULL;
2004 SilcChannelEntry channel;
2005 SilcBuffer buffer, idp;
2009 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2014 if (cmd->argc != 2) {
2015 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2016 "Usage: /LEAVE <channel>");
2021 if (cmd->argv[1][0] == '*') {
2022 if (!conn->current_channel) {
2023 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2024 "You are not on any channel");
2028 name = conn->current_channel->channel_name;
2030 name = cmd->argv[1];
2033 /* Get the Channel ID of the channel */
2034 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2035 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2036 "You are not on that channel");
2041 channel = (SilcChannelEntry)id_cache->context;
2042 channel->on_channel = FALSE;
2044 /* Send LEAVE command to the server */
2045 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2046 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2047 1, idp->data, idp->len);
2048 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2049 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2050 silc_buffer_free(buffer);
2051 silc_buffer_free(idp);
2053 /* Notify application */
2056 if (conn->current_channel == channel)
2057 conn->current_channel = NULL;
2059 silc_client_del_channel(cmd->client, cmd->conn, channel);
2062 silc_client_command_free(cmd);
2065 /* Command USERS. Requests the USERS of the clients joined on requested
2068 SILC_CLIENT_CMD_FUNC(users)
2070 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2071 SilcClientConnection conn = cmd->conn;
2076 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2081 if (cmd->argc != 2) {
2082 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2083 "Usage: /USERS <channel>");
2088 if (cmd->argv[1][0] == '*') {
2089 if (!conn->current_channel) {
2090 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2091 "You are not on any channel");
2095 name = conn->current_channel->channel_name;
2097 name = cmd->argv[1];
2100 /* Send USERS command to the server */
2101 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2102 ++conn->cmd_ident, 1,
2103 2, name, strlen(name));
2104 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2105 NULL, 0, NULL, NULL, buffer->data,
2107 silc_buffer_free(buffer);
2109 /* Notify application */
2113 silc_client_command_free(cmd);
2116 /* Command GETKEY. Used to fetch remote client's public key. */
2118 SILC_CLIENT_CMD_FUNC(getkey)
2120 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2121 SilcClientConnection conn = cmd->conn;
2122 SilcClient client = cmd->client;
2123 SilcClientEntry client_entry = NULL;
2124 SilcServerEntry server_entry = NULL;
2125 char *nickname = NULL;
2126 SilcBuffer idp, buffer;
2128 SILC_LOG_DEBUG(("Start"));
2131 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2136 if (cmd->argc < 2) {
2137 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2138 "Usage: /GETKEY <nickname or server name>");
2143 /* Parse the typed nickname. */
2144 if (client->internal->params->nickname_parse)
2145 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2147 nickname = strdup(cmd->argv[1]);
2149 /* Find client entry */
2150 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2152 if (!client_entry) {
2153 /* Check whether user requested server actually */
2154 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2156 if (!server_entry) {
2157 /* No. what ever user wants we don't have it, so resolve it. We
2158 will first try to resolve the client, and if that fails then
2159 we'll try to resolve the server. */
2161 if (!cmd->pending) {
2162 /* This will send the IDENTIFY command for nickname */
2163 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2164 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2166 silc_client_command_getkey,
2167 silc_client_command_dup(cmd));
2171 SilcClientCommandReplyContext reply =
2172 (SilcClientCommandReplyContext)context2;
2173 SilcCommandStatus status;
2174 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2175 SILC_GET16_MSB(status, tmp);
2177 /* If nickname was not found, then resolve the server. */
2178 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
2179 /* This sends the IDENTIFY command to resolve the server. */
2180 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2182 silc_client_command_reply_identify_i, 0,
2184 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2186 2, cmd->argv[1], cmd->argv_lens[1]);
2187 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2189 silc_client_command_getkey,
2190 silc_client_command_dup(cmd));
2194 /* If server was not found, then we've resolved both nickname and
2195 server and did not find anybody. */
2196 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2197 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2198 silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2199 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2200 silc_client_command_status_message(status));
2210 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2212 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2215 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2216 1, idp->data, idp->len);
2217 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2218 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2219 silc_buffer_free(buffer);
2220 silc_buffer_free(idp);
2222 /* Notify application */
2226 silc_free(nickname);
2227 silc_client_command_free(cmd);
2230 /* Register a new command indicated by the `command' to the SILC client.
2231 The `name' is optional command name. If provided the command may be
2232 searched using the silc_client_command_find by that name. The
2233 `command_function' is the function to be called when the command is
2234 executed, and the `command_reply_function' is the function to be
2235 called after the server has sent reply back to the command.
2237 The `ident' is optional identifier for the command. If non-zero
2238 the `command_reply_function' for the command type `command' will be
2239 called only if the command reply sent by server includes the
2240 command identifier `ident'. Application usually does not need it
2241 and set it to zero value. */
2243 bool silc_client_command_register(SilcClient client,
2244 SilcCommand command,
2246 SilcCommandCb command_function,
2247 SilcCommandCb command_reply_function,
2251 SilcClientCommand cmd;
2253 cmd = silc_calloc(1, sizeof(*cmd));
2255 cmd->command = command_function;
2256 cmd->reply = command_reply_function;
2257 cmd->name = name ? strdup(name) : NULL;
2258 cmd->max_args = max_args;
2261 silc_list_add(client->internal->commands, cmd);
2266 /* Unregister a command indicated by the `command' with command function
2267 `command_function' and command reply function `command_reply_function'.
2268 Returns TRUE if the command was found and unregistered. */
2270 bool silc_client_command_unregister(SilcClient client,
2271 SilcCommand command,
2272 SilcCommandCb command_function,
2273 SilcCommandCb command_reply_function,
2276 SilcClientCommand cmd;
2278 silc_list_start(client->internal->commands);
2279 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2280 if (cmd->cmd == command && cmd->command == command_function &&
2281 cmd->reply == command_reply_function && cmd->ident == ident) {
2282 silc_list_del(client->internal->commands, cmd);
2283 silc_free(cmd->name);
2292 /* Register all default commands provided by the client library for the
2295 void silc_client_commands_register(SilcClient client)
2297 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2300 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2301 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2302 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2303 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2304 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2305 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2306 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2307 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2308 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2309 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2310 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2311 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2312 SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
2313 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2314 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2315 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2316 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2317 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2318 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2319 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2320 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2321 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2322 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2323 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2324 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2325 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2328 /* Unregister all commands. */
2330 void silc_client_commands_unregister(SilcClient client)
2332 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2333 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2334 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2335 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2336 SILC_CLIENT_CMDU(list, LIST, "LIST");
2337 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2338 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2339 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2340 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2341 SILC_CLIENT_CMDU(info, INFO, "INFO");
2342 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2343 SILC_CLIENT_CMDU(ping, PING, "PING");
2344 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2345 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2346 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2347 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2348 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2349 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2350 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2351 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2352 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2353 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2354 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2355 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2356 SILC_CLIENT_CMDU(users, USERS, "USERS");
2357 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2359 silc_list_uninit(client->internal->commands);