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,
604 /* Client entry not found, it was requested thus mark this to be
606 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
608 silc_client_command_invite,
609 silc_client_command_dup(cmd));
614 invite = cmd->argv[2];
616 if (cmd->argv[2][0] == '+')
623 /* Send the command */
624 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
626 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
627 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
628 ++conn->cmd_ident, 3,
629 1, chidp->data, chidp->len,
630 2, clidp->data, clidp->len,
631 type, invite, invite ?
633 silc_buffer_free(clidp);
635 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
636 ++conn->cmd_ident, 2,
637 1, chidp->data, chidp->len,
638 type, invite, invite ?
642 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
643 0, NULL, NULL, buffer->data, buffer->len, TRUE);
644 silc_buffer_free(buffer);
645 silc_buffer_free(chidp);
647 /* Notify application */
652 silc_client_command_free(cmd);
657 SilcClientConnection conn;
660 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
662 QuitInternal q = (QuitInternal)context;
664 /* Close connection */
665 q->client->internal->ops->disconnect(q->client, q->conn);
666 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
671 /* Command QUIT. Closes connection with current server. */
673 SILC_CLIENT_CMD_FUNC(quit)
675 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
680 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
686 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
687 &cmd->argv[1], &cmd->argv_lens[1],
688 &cmd->argv_types[1], 0);
690 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
691 NULL, NULL, NULL, 0);
692 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
694 buffer->data, buffer->len, TRUE);
695 silc_buffer_free(buffer);
697 q = silc_calloc(1, sizeof(*q));
698 q->client = cmd->client;
701 /* Sleep for a while */
704 /* We quit the connection with little timeout */
705 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
706 silc_client_command_quit_cb, (void *)q,
707 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
709 /* Notify application */
713 silc_client_command_free(cmd);
716 /* Timeout callback to remove the killed client from cache */
718 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
720 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
721 SilcClient client = cmd->client;
722 SilcClientConnection conn = cmd->conn;
723 SilcClientEntry target;
724 char *nickname = NULL;
726 /* Parse the typed nickname. */
727 if (client->internal->params->nickname_parse)
728 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
730 nickname = strdup(cmd->argv[1]);
732 /* Get the target client */
733 target = silc_idlist_get_client(cmd->client, conn, nickname,
734 cmd->argv[1], FALSE);
736 /* Remove the client from all channels and free it */
737 silc_client_del_client(client, conn, target);
740 silc_client_command_free(cmd);
743 /* Kill command's pending command callback to actually remove the killed
744 client from our local cache. */
746 SILC_CLIENT_CMD_FUNC(kill_remove)
748 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
749 SilcClientCommandReplyContext reply =
750 (SilcClientCommandReplyContext)context2;
751 SilcCommandStatus status;
753 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
754 if (status == SILC_STATUS_OK) {
755 /* Remove with timeout */
756 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
757 silc_client_command_kill_remove_later, context,
758 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
762 silc_client_command_free(cmd);
765 /* Command KILL. Router operator can use this command to remove an client
766 fromthe SILC Network. */
768 SILC_CLIENT_CMD_FUNC(kill)
770 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
771 SilcClient client = cmd->client;
772 SilcClientConnection conn = cmd->conn;
773 SilcBuffer buffer, idp;
774 SilcClientEntry target;
775 char *nickname = NULL;
778 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
784 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
785 "Usage: /KILL <nickname> [<comment>]");
790 /* Parse the typed nickname. */
791 if (client->internal->params->nickname_parse)
792 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
794 nickname = strdup(cmd->argv[1]);
796 /* Get the target client */
797 target = silc_idlist_get_client(cmd->client, conn, nickname,
805 /* Client entry not found, it was requested thus mark this to be
807 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
809 silc_client_command_kill,
810 silc_client_command_dup(cmd));
815 /* Send the KILL command to the server */
816 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
818 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
819 ++conn->cmd_ident, 1,
820 1, idp->data, idp->len);
822 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
823 ++conn->cmd_ident, 2,
824 1, idp->data, idp->len,
826 strlen(cmd->argv[2]));
827 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
828 0, NULL, NULL, buffer->data, buffer->len, TRUE);
829 silc_buffer_free(buffer);
830 silc_buffer_free(idp);
832 /* Notify application */
835 /* Register a pending callback that will actually remove the killed
836 client from our cache. */
837 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
838 silc_client_command_kill_remove,
839 silc_client_command_dup(cmd));
843 silc_client_command_free(cmd);
846 /* Command INFO. Request information about specific server. If specific
847 server is not provided the current server is used. */
849 SILC_CLIENT_CMD_FUNC(info)
851 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
852 SilcClientConnection conn = cmd->conn;
857 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
863 name = strdup(cmd->argv[1]);
865 /* Send the command */
867 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
868 1, name, strlen(name));
870 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
871 NULL, NULL, NULL, 0);
872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
874 silc_buffer_free(buffer);
878 /* Notify application */
882 silc_client_command_free(cmd);
885 /* Command PING. Sends ping to server. This is used to test the
886 communication channel. */
888 SILC_CLIENT_CMD_FUNC(ping)
890 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
891 SilcClientConnection conn = cmd->conn;
897 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
902 /* Send the command */
903 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
904 1, conn->remote_id_data,
905 silc_id_get_len(conn->remote_id,
907 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
908 0, NULL, NULL, buffer->data, buffer->len, TRUE);
909 silc_buffer_free(buffer);
911 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
914 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
919 /* Start counting time */
920 for (i = 0; i < conn->ping_count; i++) {
921 if (conn->ping[i].dest_id == NULL) {
922 conn->ping[i].start_time = time(NULL);
923 conn->ping[i].dest_id = id;
924 conn->ping[i].dest_name = strdup(conn->remote_host);
928 if (i >= conn->ping_count) {
929 i = conn->ping_count;
930 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
931 conn->ping[i].start_time = time(NULL);
932 conn->ping[i].dest_id = id;
933 conn->ping[i].dest_name = strdup(conn->remote_host);
937 /* Notify application */
941 silc_client_command_free(cmd);
944 /* Command JOIN. Joins to a channel. */
946 SILC_CLIENT_CMD_FUNC(join)
948 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
949 SilcClientConnection conn = cmd->conn;
950 SilcIDCacheEntry id_cache = NULL;
951 SilcBuffer buffer, idp, auth = NULL;
952 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
956 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
966 /* See if we have joined to the requested channel already */
967 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
969 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
970 if (channel->on_channel)
974 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
976 if (cmd->argv_lens[1] > 256)
977 cmd->argv_lens[1] = 256;
981 for (i = 2; i < cmd->argc; i++) {
982 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
983 cipher = cmd->argv[i + 1];
985 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
986 hmac = cmd->argv[i + 1];
988 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
989 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
990 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
991 cmd->client->private_key,
996 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
998 cmd->argv_lens[i + 1]);
1002 passphrase = cmd->argv[i];
1006 /* Send JOIN command to the server */
1008 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1009 1, name, strlen(name),
1010 2, idp->data, idp->len,
1012 passphrase ? strlen(passphrase) : 0,
1013 4, cipher, cipher ? strlen(cipher) : 0,
1014 5, hmac, hmac ? strlen(hmac) : 0,
1015 6, auth ? auth->data : NULL,
1016 auth ? auth->len : 0);
1017 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1018 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1019 silc_buffer_free(buffer);
1020 silc_buffer_free(idp);
1022 silc_buffer_free(auth);
1024 /* Notify application */
1028 silc_client_command_free(cmd);
1031 /* MOTD command. Requests motd from server. */
1033 SILC_CLIENT_CMD_FUNC(motd)
1035 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1036 SilcClientConnection conn = cmd->conn;
1040 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1045 if (cmd->argc < 1 || cmd->argc > 2) {
1046 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1047 "Usage: /MOTD [<server>]");
1052 /* Send TOPIC command to the server */
1054 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1055 1, conn->remote_host,
1056 strlen(conn->remote_host));
1058 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1061 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1062 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1063 silc_buffer_free(buffer);
1065 /* Notify application */
1069 silc_client_command_free(cmd);
1072 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1073 modes as client cannot set itself server/router operator privileges. */
1075 SILC_CLIENT_CMD_FUNC(umode)
1077 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1078 SilcClientConnection conn = cmd->conn;
1079 SilcBuffer buffer, idp;
1080 unsigned char *cp, modebuf[4];
1081 uint32 mode, add, len;
1085 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1090 if (cmd->argc < 2) {
1091 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1092 "Usage: /UMODE +|-<modes>");
1097 mode = conn->local_entry->mode;
1099 /* Are we adding or removing mode */
1100 if (cmd->argv[1][0] == '-')
1106 cp = cmd->argv[1] + 1;
1108 for (i = 0; i < len; i++) {
1113 mode |= SILC_UMODE_SERVER_OPERATOR;
1114 mode |= SILC_UMODE_ROUTER_OPERATOR;
1116 mode = SILC_UMODE_NONE;
1121 mode |= SILC_UMODE_SERVER_OPERATOR;
1123 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1127 mode |= SILC_UMODE_ROUTER_OPERATOR;
1129 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1133 mode |= SILC_UMODE_GONE;
1135 mode &= ~SILC_UMODE_GONE;
1144 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1145 SILC_PUT32_MSB(mode, modebuf);
1147 /* Send the command packet. We support sending only one mode at once
1148 that requires an argument. */
1150 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1151 1, idp->data, idp->len,
1152 2, modebuf, sizeof(modebuf));
1153 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1154 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1155 silc_buffer_free(buffer);
1156 silc_buffer_free(idp);
1158 /* Notify application */
1162 silc_client_command_free(cmd);
1165 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1166 can be set several at once. Those modes that require argument must be set
1167 separately (unless set with modes that does not require arguments). */
1169 SILC_CLIENT_CMD_FUNC(cmode)
1171 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1172 SilcClientConnection conn = cmd->conn;
1173 SilcChannelEntry channel;
1174 SilcBuffer buffer, chidp, auth = NULL;
1175 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1176 uint32 mode, add, type, len, arg_len = 0;
1180 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1185 if (cmd->argc < 3) {
1186 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1187 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1192 if (cmd->argv[1][0] == '*') {
1193 if (!conn->current_channel) {
1194 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1195 "You are not on any channel");
1200 channel = conn->current_channel;
1202 name = cmd->argv[1];
1204 channel = silc_client_get_channel(cmd->client, conn, name);
1206 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1207 "You are on that channel");
1213 mode = channel->mode;
1215 /* Are we adding or removing mode */
1216 if (cmd->argv[2][0] == '-')
1221 /* Argument type to be sent to server */
1225 cp = cmd->argv[2] + 1;
1227 for (i = 0; i < len; i++) {
1231 mode |= SILC_CHANNEL_MODE_PRIVATE;
1233 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1237 mode |= SILC_CHANNEL_MODE_SECRET;
1239 mode &= ~SILC_CHANNEL_MODE_SECRET;
1243 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1245 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1249 mode |= SILC_CHANNEL_MODE_INVITE;
1251 mode &= ~SILC_CHANNEL_MODE_INVITE;
1255 mode |= SILC_CHANNEL_MODE_TOPIC;
1257 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1262 mode |= SILC_CHANNEL_MODE_ULIMIT;
1264 if (cmd->argc < 4) {
1265 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1266 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1270 ll = atoi(cmd->argv[3]);
1271 SILC_PUT32_MSB(ll, tmp);
1275 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1280 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1282 if (cmd->argc < 4) {
1283 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1284 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1289 arg_len = cmd->argv_lens[3];
1291 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1296 mode |= SILC_CHANNEL_MODE_CIPHER;
1298 if (cmd->argc < 4) {
1299 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1300 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1305 arg_len = cmd->argv_lens[3];
1307 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1312 mode |= SILC_CHANNEL_MODE_HMAC;
1314 if (cmd->argc < 4) {
1315 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1316 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1321 arg_len = cmd->argv_lens[3];
1323 mode &= ~SILC_CHANNEL_MODE_HMAC;
1328 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1331 if (cmd->argc < 4) {
1332 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1333 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1338 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1339 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1340 cmd->client->private_key,
1345 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1346 cmd->argv[3], cmd->argv_lens[3]);
1350 arg_len = auth->len;
1352 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1362 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1363 SILC_PUT32_MSB(mode, modebuf);
1365 /* Send the command packet. We support sending only one mode at once
1366 that requires an argument. */
1369 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1370 1, chidp->data, chidp->len,
1371 2, modebuf, sizeof(modebuf),
1372 type, arg, arg_len);
1375 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1376 1, chidp->data, chidp->len,
1377 2, modebuf, sizeof(modebuf));
1380 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1381 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1382 silc_buffer_free(buffer);
1383 silc_buffer_free(chidp);
1385 silc_buffer_free(auth);
1387 /* Notify application */
1391 silc_client_command_free(cmd);
1394 /* CUMODE command. Changes client's mode on a channel. */
1396 SILC_CLIENT_CMD_FUNC(cumode)
1398 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1399 SilcClient client = cmd->client;
1400 SilcClientConnection conn = cmd->conn;
1401 SilcChannelEntry channel;
1402 SilcChannelUser chu;
1403 SilcClientEntry client_entry;
1404 SilcBuffer buffer, clidp, chidp, auth = NULL;
1405 unsigned char *name, *cp, modebuf[4];
1406 uint32 mode = 0, add, len;
1407 char *nickname = NULL;
1411 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1416 if (cmd->argc < 4) {
1417 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1418 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1423 if (cmd->argv[1][0] == '*') {
1424 if (!conn->current_channel) {
1425 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1426 "You are not on any channel");
1431 channel = conn->current_channel;
1433 name = cmd->argv[1];
1435 channel = silc_client_get_channel(cmd->client, conn, name);
1437 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1438 "You are on that channel");
1444 /* Parse the typed nickname. */
1445 if (client->internal->params->nickname_parse)
1446 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1448 nickname = strdup(cmd->argv[3]);
1450 /* Find client entry */
1451 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1452 cmd->argv[3], TRUE);
1453 if (!client_entry) {
1459 /* Client entry not found, it was requested thus mark this to be
1461 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1463 silc_client_command_cumode,
1464 silc_client_command_dup(cmd));
1469 /* Get the current mode */
1470 silc_list_start(channel->clients);
1471 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1472 if (chu->client == client_entry) {
1478 /* Are we adding or removing mode */
1479 if (cmd->argv[2][0] == '-')
1485 cp = cmd->argv[2] + 1;
1487 for (i = 0; i < len; i++) {
1491 mode |= SILC_CHANNEL_UMODE_CHANFO;
1492 mode |= SILC_CHANNEL_UMODE_CHANOP;
1494 mode = SILC_CHANNEL_UMODE_NONE;
1499 if (cmd->argc == 5) {
1500 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1501 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1502 cmd->client->private_key,
1507 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1508 cmd->argv[4], cmd->argv_lens[4]);
1511 mode |= SILC_CHANNEL_UMODE_CHANFO;
1513 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1518 mode |= SILC_CHANNEL_UMODE_CHANOP;
1520 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1529 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1530 SILC_PUT32_MSB(mode, modebuf);
1531 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1533 /* Send the command packet. We support sending only one mode at once
1534 that requires an argument. */
1535 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1537 1, chidp->data, chidp->len,
1539 3, clidp->data, clidp->len,
1540 4, auth ? auth->data : NULL,
1541 auth ? auth->len : 0);
1543 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1544 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1545 silc_buffer_free(buffer);
1546 silc_buffer_free(chidp);
1547 silc_buffer_free(clidp);
1549 silc_buffer_free(auth);
1551 /* Notify application */
1555 silc_free(nickname);
1556 silc_client_command_free(cmd);
1559 /* KICK command. Kicks a client out of channel. */
1561 SILC_CLIENT_CMD_FUNC(kick)
1563 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1564 SilcClient client = cmd->client;
1565 SilcClientConnection conn = cmd->conn;
1566 SilcIDCacheEntry id_cache = NULL;
1567 SilcChannelEntry channel;
1568 SilcBuffer buffer, idp, idp2;
1569 SilcClientEntry target;
1571 char *nickname = NULL;
1574 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1579 if (cmd->argc < 3) {
1580 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1581 "Usage: /KICK <channel> <nickname> [<comment>]");
1586 if (cmd->argv[1][0] == '*') {
1587 if (!conn->current_channel) {
1588 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1589 "You are not on any channel");
1593 name = conn->current_channel->channel_name;
1595 name = cmd->argv[1];
1598 if (!conn->current_channel) {
1599 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1600 "You are not on that channel");
1605 /* Get the Channel ID of the channel */
1606 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1607 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1608 "You are not on that channel");
1613 channel = (SilcChannelEntry)id_cache->context;
1615 /* Parse the typed nickname. */
1616 if (client->internal->params->nickname_parse)
1617 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1619 nickname = strdup(cmd->argv[2]);
1621 /* Get the target client */
1622 target = silc_idlist_get_client(cmd->client, conn, nickname,
1623 cmd->argv[2], FALSE);
1625 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1626 "No such client: %s", cmd->argv[2]);
1631 /* Send KICK command to the server */
1632 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1633 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1635 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1636 1, idp->data, idp->len,
1637 2, idp2->data, idp2->len);
1639 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1640 1, idp->data, idp->len,
1641 2, idp2->data, idp2->len,
1643 strlen(cmd->argv[3]));
1644 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1645 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1646 silc_buffer_free(buffer);
1647 silc_buffer_free(idp);
1648 silc_buffer_free(idp2);
1650 /* Notify application */
1654 silc_free(nickname);
1655 silc_client_command_free(cmd);
1658 static void silc_client_command_oper_send(unsigned char *data,
1659 uint32 data_len, void *context)
1661 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1662 SilcClientConnection conn = cmd->conn;
1663 SilcBuffer buffer, auth;
1665 if (cmd->argc >= 3) {
1666 /* Encode the public key authentication payload */
1667 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1668 cmd->client->private_key,
1673 /* Encode the password authentication payload */
1674 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1678 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1680 strlen(cmd->argv[1]),
1681 2, auth->data, auth->len);
1682 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1683 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1685 silc_buffer_free(buffer);
1686 silc_buffer_free(auth);
1688 /* Notify application */
1692 /* OPER command. Used to obtain server operator privileges. */
1694 SILC_CLIENT_CMD_FUNC(oper)
1696 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1697 SilcClientConnection conn = cmd->conn;
1700 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1705 if (cmd->argc < 2) {
1706 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1707 "Usage: /OPER <username> [-pubkey]");
1712 if (cmd->argc < 3) {
1713 /* Get passphrase */
1714 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1715 silc_client_command_oper_send,
1720 silc_client_command_oper_send(NULL, 0, context);
1723 silc_client_command_free(cmd);
1726 static void silc_client_command_silcoper_send(unsigned char *data,
1727 uint32 data_len, void *context)
1729 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1730 SilcClientConnection conn = cmd->conn;
1731 SilcBuffer buffer, auth;
1733 if (cmd->argc >= 3) {
1734 /* Encode the public key authentication payload */
1735 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1736 cmd->client->private_key,
1741 /* Encode the password authentication payload */
1742 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1746 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1748 strlen(cmd->argv[1]),
1749 2, auth->data, auth->len);
1750 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1751 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1753 silc_buffer_free(buffer);
1754 silc_buffer_free(auth);
1756 /* Notify application */
1760 /* SILCOPER command. Used to obtain router operator privileges. */
1762 SILC_CLIENT_CMD_FUNC(silcoper)
1764 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1765 SilcClientConnection conn = cmd->conn;
1768 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1773 if (cmd->argc < 2) {
1774 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1775 "Usage: /SILCOPER <username> [-pubkey]");
1780 if (cmd->argc < 3) {
1781 /* Get passphrase */
1782 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1783 silc_client_command_silcoper_send,
1788 silc_client_command_silcoper_send(NULL, 0, context);
1791 silc_client_command_free(cmd);
1794 /* CONNECT command. Connects the server to another server. */
1796 SILC_CLIENT_CMD_FUNC(connect)
1798 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1799 SilcClientConnection conn = cmd->conn;
1801 unsigned char port[4];
1805 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1810 if (cmd->argc < 2) {
1811 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1812 "Usage: /CONNECT <server> [<port>]");
1817 if (cmd->argc == 3) {
1818 tmp = atoi(cmd->argv[2]);
1819 SILC_PUT32_MSB(tmp, port);
1823 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1825 strlen(cmd->argv[1]),
1828 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1830 strlen(cmd->argv[1]));
1831 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1832 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1833 silc_buffer_free(buffer);
1835 /* Notify application */
1839 silc_client_command_free(cmd);
1842 /* Command BAN. This is used to manage the ban list of the channel. */
1844 SILC_CLIENT_CMD_FUNC(ban)
1846 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1847 SilcClientConnection conn = cmd->conn;
1848 SilcChannelEntry channel;
1849 SilcBuffer buffer, chidp;
1851 char *name, *ban = NULL;
1854 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1859 if (cmd->argc < 2) {
1860 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1861 "Usage: /BAN <channel> "
1862 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1867 if (cmd->argv[1][0] == '*') {
1868 if (!conn->current_channel) {
1869 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1870 "You are not on any channel");
1875 channel = conn->current_channel;
1877 name = cmd->argv[1];
1879 channel = silc_client_get_channel(cmd->client, conn, name);
1881 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1882 "You are on that channel");
1888 if (cmd->argc == 3) {
1889 if (cmd->argv[2][0] == '+')
1898 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1900 /* Send the command */
1902 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1903 1, chidp->data, chidp->len,
1904 type, ban, strlen(ban));
1906 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1907 1, chidp->data, chidp->len);
1909 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1910 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1911 silc_buffer_free(buffer);
1912 silc_buffer_free(chidp);
1914 /* Notify application */
1918 silc_client_command_free(cmd);
1921 /* CLOSE command. Close server connection to the remote server */
1923 SILC_CLIENT_CMD_FUNC(close)
1925 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1926 SilcClientConnection conn = cmd->conn;
1928 unsigned char port[4];
1932 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1937 if (cmd->argc < 2) {
1938 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1939 "Usage: /CLOSE <server> [<port>]");
1944 if (cmd->argc == 3) {
1945 tmp = atoi(cmd->argv[2]);
1946 SILC_PUT32_MSB(tmp, port);
1950 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1952 strlen(cmd->argv[1]),
1955 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1957 strlen(cmd->argv[1]));
1958 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1959 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1960 silc_buffer_free(buffer);
1962 /* Notify application */
1966 silc_client_command_free(cmd);
1969 /* SHUTDOWN command. Shutdowns the server. */
1971 SILC_CLIENT_CMD_FUNC(shutdown)
1973 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1976 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1981 /* Send the command */
1982 silc_client_command_send(cmd->client, cmd->conn,
1983 SILC_COMMAND_SHUTDOWN, 0, 0);
1985 /* Notify application */
1989 silc_client_command_free(cmd);
1992 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1994 SILC_CLIENT_CMD_FUNC(leave)
1996 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1997 SilcClientConnection conn = cmd->conn;
1998 SilcIDCacheEntry id_cache = NULL;
1999 SilcChannelEntry channel;
2000 SilcBuffer buffer, idp;
2004 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2009 if (cmd->argc != 2) {
2010 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2011 "Usage: /LEAVE <channel>");
2016 if (cmd->argv[1][0] == '*') {
2017 if (!conn->current_channel) {
2018 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2019 "You are not on any channel");
2023 name = conn->current_channel->channel_name;
2025 name = cmd->argv[1];
2028 /* Get the Channel ID of the channel */
2029 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "You are not on that channel");
2036 channel = (SilcChannelEntry)id_cache->context;
2037 channel->on_channel = FALSE;
2039 /* Send LEAVE command to the server */
2040 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2041 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2042 1, idp->data, idp->len);
2043 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2044 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2045 silc_buffer_free(buffer);
2046 silc_buffer_free(idp);
2048 /* Notify application */
2051 if (conn->current_channel == channel)
2052 conn->current_channel = NULL;
2054 silc_client_del_channel(cmd->client, cmd->conn, channel);
2057 silc_client_command_free(cmd);
2060 /* Command USERS. Requests the USERS of the clients joined on requested
2063 SILC_CLIENT_CMD_FUNC(users)
2065 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2066 SilcClientConnection conn = cmd->conn;
2071 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2076 if (cmd->argc != 2) {
2077 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2078 "Usage: /USERS <channel>");
2083 if (cmd->argv[1][0] == '*') {
2084 if (!conn->current_channel) {
2085 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2086 "You are not on any channel");
2090 name = conn->current_channel->channel_name;
2092 name = cmd->argv[1];
2095 /* Send USERS command to the server */
2096 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2097 ++conn->cmd_ident, 1,
2098 2, name, strlen(name));
2099 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2100 NULL, 0, NULL, NULL, buffer->data,
2102 silc_buffer_free(buffer);
2104 /* Notify application */
2108 silc_client_command_free(cmd);
2111 /* Command GETKEY. Used to fetch remote client's public key. */
2113 SILC_CLIENT_CMD_FUNC(getkey)
2115 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2116 SilcClientConnection conn = cmd->conn;
2117 SilcClient client = cmd->client;
2118 SilcClientEntry client_entry = NULL;
2119 SilcServerEntry server_entry = NULL;
2120 char *nickname = NULL;
2121 SilcBuffer idp, buffer;
2123 SILC_LOG_DEBUG(("Start"));
2126 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2131 if (cmd->argc < 2) {
2132 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2133 "Usage: /GETKEY <nickname or server name>");
2138 /* Parse the typed nickname. */
2139 if (client->internal->params->nickname_parse)
2140 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2142 nickname = strdup(cmd->argv[1]);
2144 /* Find client entry */
2145 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2147 if (!client_entry) {
2148 /* Check whether user requested server actually */
2149 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2151 if (!server_entry) {
2152 /* No. what ever user wants we don't have it, so resolve it. We
2153 will first try to resolve the client, and if that fails then
2154 we'll try to resolve the server. */
2156 if (!cmd->pending) {
2157 /* This will send the IDENTIFY command for nickname */
2158 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2159 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2161 silc_client_command_getkey,
2162 silc_client_command_dup(cmd));
2166 SilcClientCommandReplyContext reply =
2167 (SilcClientCommandReplyContext)context2;
2168 SilcCommandStatus status;
2169 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2170 SILC_GET16_MSB(status, tmp);
2172 /* If nickname was not found, then resolve the server. */
2173 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
2174 /* This sends the IDENTIFY command to resolve the server. */
2175 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2177 silc_client_command_reply_identify_i, 0,
2179 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2181 2, cmd->argv[1], cmd->argv_lens[1]);
2182 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2184 silc_client_command_getkey,
2185 silc_client_command_dup(cmd));
2189 /* If server was not found, then we've resolved both nickname and
2190 server and did not find anybody. */
2191 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2192 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2193 silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2194 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2195 silc_client_command_status_message(status));
2205 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2207 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2210 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2211 1, idp->data, idp->len);
2212 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2213 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2214 silc_buffer_free(buffer);
2215 silc_buffer_free(idp);
2217 /* Notify application */
2221 silc_free(nickname);
2222 silc_client_command_free(cmd);
2225 /* Register a new command indicated by the `command' to the SILC client.
2226 The `name' is optional command name. If provided the command may be
2227 searched using the silc_client_command_find by that name. The
2228 `command_function' is the function to be called when the command is
2229 executed, and the `command_reply_function' is the function to be
2230 called after the server has sent reply back to the command.
2232 The `ident' is optional identifier for the command. If non-zero
2233 the `command_reply_function' for the command type `command' will be
2234 called only if the command reply sent by server includes the
2235 command identifier `ident'. Application usually does not need it
2236 and set it to zero value. */
2238 bool silc_client_command_register(SilcClient client,
2239 SilcCommand command,
2241 SilcCommandCb command_function,
2242 SilcCommandCb command_reply_function,
2246 SilcClientCommand cmd;
2248 cmd = silc_calloc(1, sizeof(*cmd));
2250 cmd->command = command_function;
2251 cmd->reply = command_reply_function;
2252 cmd->name = name ? strdup(name) : NULL;
2253 cmd->max_args = max_args;
2256 silc_list_add(client->internal->commands, cmd);
2261 /* Unregister a command indicated by the `command' with command function
2262 `command_function' and command reply function `command_reply_function'.
2263 Returns TRUE if the command was found and unregistered. */
2265 bool silc_client_command_unregister(SilcClient client,
2266 SilcCommand command,
2267 SilcCommandCb command_function,
2268 SilcCommandCb command_reply_function,
2271 SilcClientCommand cmd;
2273 silc_list_start(client->internal->commands);
2274 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2275 if (cmd->cmd == command && cmd->command == command_function &&
2276 cmd->reply == command_reply_function && cmd->ident == ident) {
2277 silc_list_del(client->internal->commands, cmd);
2278 silc_free(cmd->name);
2287 /* Register all default commands provided by the client library for the
2290 void silc_client_commands_register(SilcClient client)
2292 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2295 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2296 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2297 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2298 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2299 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2300 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2301 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2302 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2303 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2304 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2305 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2306 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2307 SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
2308 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2309 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2310 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2311 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2312 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2313 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2314 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2315 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2316 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2317 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2318 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2319 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2320 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2323 /* Unregister all commands. */
2325 void silc_client_commands_unregister(SilcClient client)
2327 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2328 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2329 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2330 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2331 SILC_CLIENT_CMDU(list, LIST, "LIST");
2332 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2333 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2334 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2335 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2336 SILC_CLIENT_CMDU(info, INFO, "INFO");
2337 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2338 SILC_CLIENT_CMDU(ping, PING, "PING");
2339 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2340 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2341 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2342 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2343 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2344 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2345 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2346 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2347 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2348 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2349 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2350 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2351 SILC_CLIENT_CMDU(users, USERS, "USERS");
2352 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2354 silc_list_uninit(client->internal->commands);