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 SilcChannelEntry channel;
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 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
968 if (channel && silc_client_on_channel(channel, conn->local_entry))
971 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
973 if (cmd->argv_lens[1] > 256)
974 cmd->argv_lens[1] = 256;
978 for (i = 2; i < cmd->argc; i++) {
979 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
980 cipher = cmd->argv[i + 1];
982 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
983 hmac = cmd->argv[i + 1];
985 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
986 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
987 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
988 cmd->client->private_key,
993 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
995 cmd->argv_lens[i + 1]);
999 passphrase = cmd->argv[i];
1003 /* Send JOIN command to the server */
1005 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1006 1, name, strlen(name),
1007 2, idp->data, idp->len,
1009 passphrase ? strlen(passphrase) : 0,
1010 4, cipher, cipher ? strlen(cipher) : 0,
1011 5, hmac, hmac ? strlen(hmac) : 0,
1012 6, auth ? auth->data : NULL,
1013 auth ? auth->len : 0);
1014 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1015 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1016 silc_buffer_free(buffer);
1017 silc_buffer_free(idp);
1019 silc_buffer_free(auth);
1021 /* Notify application */
1025 silc_client_command_free(cmd);
1028 /* MOTD command. Requests motd from server. */
1030 SILC_CLIENT_CMD_FUNC(motd)
1032 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1033 SilcClientConnection conn = cmd->conn;
1037 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1042 if (cmd->argc < 1 || cmd->argc > 2) {
1043 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1044 "Usage: /MOTD [<server>]");
1049 /* Send TOPIC command to the server */
1051 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1052 1, conn->remote_host,
1053 strlen(conn->remote_host));
1055 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1058 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1059 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1060 silc_buffer_free(buffer);
1062 /* Notify application */
1066 silc_client_command_free(cmd);
1069 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1070 modes as client cannot set itself server/router operator privileges. */
1072 SILC_CLIENT_CMD_FUNC(umode)
1074 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1075 SilcClientConnection conn = cmd->conn;
1076 SilcBuffer buffer, idp;
1077 unsigned char *cp, modebuf[4];
1078 uint32 mode, add, len;
1082 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1087 if (cmd->argc < 2) {
1088 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1089 "Usage: /UMODE +|-<modes>");
1094 mode = conn->local_entry->mode;
1096 /* Are we adding or removing mode */
1097 if (cmd->argv[1][0] == '-')
1103 cp = cmd->argv[1] + 1;
1105 for (i = 0; i < len; i++) {
1110 mode |= SILC_UMODE_SERVER_OPERATOR;
1111 mode |= SILC_UMODE_ROUTER_OPERATOR;
1113 mode = SILC_UMODE_NONE;
1118 mode |= SILC_UMODE_SERVER_OPERATOR;
1120 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1124 mode |= SILC_UMODE_ROUTER_OPERATOR;
1126 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1130 mode |= SILC_UMODE_GONE;
1132 mode &= ~SILC_UMODE_GONE;
1141 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1142 SILC_PUT32_MSB(mode, modebuf);
1144 /* Send the command packet. We support sending only one mode at once
1145 that requires an argument. */
1147 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1148 1, idp->data, idp->len,
1149 2, modebuf, sizeof(modebuf));
1150 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1151 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1152 silc_buffer_free(buffer);
1153 silc_buffer_free(idp);
1155 /* Notify application */
1159 silc_client_command_free(cmd);
1162 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1163 can be set several at once. Those modes that require argument must be set
1164 separately (unless set with modes that does not require arguments). */
1166 SILC_CLIENT_CMD_FUNC(cmode)
1168 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1169 SilcClientConnection conn = cmd->conn;
1170 SilcChannelEntry channel;
1171 SilcBuffer buffer, chidp, auth = NULL;
1172 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1173 uint32 mode, add, type, len, arg_len = 0;
1177 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1182 if (cmd->argc < 3) {
1183 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1184 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1189 if (cmd->argv[1][0] == '*') {
1190 if (!conn->current_channel) {
1191 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1192 "You are not on any channel");
1197 channel = conn->current_channel;
1199 name = cmd->argv[1];
1201 channel = silc_client_get_channel(cmd->client, conn, name);
1203 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1204 "You are on that channel");
1210 mode = channel->mode;
1212 /* Are we adding or removing mode */
1213 if (cmd->argv[2][0] == '-')
1218 /* Argument type to be sent to server */
1222 cp = cmd->argv[2] + 1;
1224 for (i = 0; i < len; i++) {
1228 mode |= SILC_CHANNEL_MODE_PRIVATE;
1230 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1234 mode |= SILC_CHANNEL_MODE_SECRET;
1236 mode &= ~SILC_CHANNEL_MODE_SECRET;
1240 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1242 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1246 mode |= SILC_CHANNEL_MODE_INVITE;
1248 mode &= ~SILC_CHANNEL_MODE_INVITE;
1252 mode |= SILC_CHANNEL_MODE_TOPIC;
1254 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1259 mode |= SILC_CHANNEL_MODE_ULIMIT;
1261 if (cmd->argc < 4) {
1262 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1263 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1267 ll = atoi(cmd->argv[3]);
1268 SILC_PUT32_MSB(ll, tmp);
1272 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1277 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1279 if (cmd->argc < 4) {
1280 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1281 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1286 arg_len = cmd->argv_lens[3];
1288 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1293 mode |= SILC_CHANNEL_MODE_CIPHER;
1295 if (cmd->argc < 4) {
1296 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1297 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1302 arg_len = cmd->argv_lens[3];
1304 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1309 mode |= SILC_CHANNEL_MODE_HMAC;
1311 if (cmd->argc < 4) {
1312 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1313 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1318 arg_len = cmd->argv_lens[3];
1320 mode &= ~SILC_CHANNEL_MODE_HMAC;
1325 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1328 if (cmd->argc < 4) {
1329 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1330 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1335 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1336 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1337 cmd->client->private_key,
1342 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1343 cmd->argv[3], cmd->argv_lens[3]);
1347 arg_len = auth->len;
1349 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1359 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1360 SILC_PUT32_MSB(mode, modebuf);
1362 /* Send the command packet. We support sending only one mode at once
1363 that requires an argument. */
1366 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1367 1, chidp->data, chidp->len,
1368 2, modebuf, sizeof(modebuf),
1369 type, arg, arg_len);
1372 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1373 1, chidp->data, chidp->len,
1374 2, modebuf, sizeof(modebuf));
1377 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1378 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1379 silc_buffer_free(buffer);
1380 silc_buffer_free(chidp);
1382 silc_buffer_free(auth);
1384 /* Notify application */
1388 silc_client_command_free(cmd);
1391 /* CUMODE command. Changes client's mode on a channel. */
1393 SILC_CLIENT_CMD_FUNC(cumode)
1395 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1396 SilcClient client = cmd->client;
1397 SilcClientConnection conn = cmd->conn;
1398 SilcChannelEntry channel;
1399 SilcChannelUser chu;
1400 SilcClientEntry client_entry;
1401 SilcBuffer buffer, clidp, chidp, auth = NULL;
1402 unsigned char *name, *cp, modebuf[4];
1403 uint32 mode = 0, add, len;
1404 char *nickname = NULL;
1408 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1413 if (cmd->argc < 4) {
1414 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1415 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1420 if (cmd->argv[1][0] == '*') {
1421 if (!conn->current_channel) {
1422 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1423 "You are not on any channel");
1428 channel = conn->current_channel;
1430 name = cmd->argv[1];
1432 channel = silc_client_get_channel(cmd->client, conn, name);
1434 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1435 "You are on that channel");
1441 /* Parse the typed nickname. */
1442 if (client->internal->params->nickname_parse)
1443 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1445 nickname = strdup(cmd->argv[3]);
1447 /* Find client entry */
1448 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1449 cmd->argv[3], TRUE);
1450 if (!client_entry) {
1456 /* Client entry not found, it was requested thus mark this to be
1458 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1460 silc_client_command_cumode,
1461 silc_client_command_dup(cmd));
1466 /* Get the current mode */
1467 chu = silc_client_on_channel(channel, client_entry);
1471 /* Are we adding or removing mode */
1472 if (cmd->argv[2][0] == '-')
1478 cp = cmd->argv[2] + 1;
1480 for (i = 0; i < len; i++) {
1484 mode |= SILC_CHANNEL_UMODE_CHANFO;
1485 mode |= SILC_CHANNEL_UMODE_CHANOP;
1487 mode = SILC_CHANNEL_UMODE_NONE;
1492 if (cmd->argc == 5) {
1493 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1494 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1495 cmd->client->private_key,
1500 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1501 cmd->argv[4], cmd->argv_lens[4]);
1504 mode |= SILC_CHANNEL_UMODE_CHANFO;
1506 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1511 mode |= SILC_CHANNEL_UMODE_CHANOP;
1513 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1522 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1523 SILC_PUT32_MSB(mode, modebuf);
1524 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1526 /* Send the command packet. We support sending only one mode at once
1527 that requires an argument. */
1528 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1530 1, chidp->data, chidp->len,
1532 3, clidp->data, clidp->len,
1533 4, auth ? auth->data : NULL,
1534 auth ? auth->len : 0);
1536 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1537 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1538 silc_buffer_free(buffer);
1539 silc_buffer_free(chidp);
1540 silc_buffer_free(clidp);
1542 silc_buffer_free(auth);
1544 /* Notify application */
1548 silc_free(nickname);
1549 silc_client_command_free(cmd);
1552 /* KICK command. Kicks a client out of channel. */
1554 SILC_CLIENT_CMD_FUNC(kick)
1556 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1557 SilcClient client = cmd->client;
1558 SilcClientConnection conn = cmd->conn;
1559 SilcIDCacheEntry id_cache = NULL;
1560 SilcChannelEntry channel;
1561 SilcBuffer buffer, idp, idp2;
1562 SilcClientEntry target;
1564 char *nickname = NULL;
1567 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1572 if (cmd->argc < 3) {
1573 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1574 "Usage: /KICK <channel> <nickname> [<comment>]");
1579 if (cmd->argv[1][0] == '*') {
1580 if (!conn->current_channel) {
1581 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1582 "You are not on any channel");
1586 name = conn->current_channel->channel_name;
1588 name = cmd->argv[1];
1591 if (!conn->current_channel) {
1592 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1593 "You are not on that channel");
1598 /* Get the Channel ID of the channel */
1599 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1600 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1601 "You are not on that channel");
1606 channel = (SilcChannelEntry)id_cache->context;
1608 /* Parse the typed nickname. */
1609 if (client->internal->params->nickname_parse)
1610 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1612 nickname = strdup(cmd->argv[2]);
1614 /* Get the target client */
1615 target = silc_idlist_get_client(cmd->client, conn, nickname,
1616 cmd->argv[2], FALSE);
1618 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1619 "No such client: %s", cmd->argv[2]);
1624 /* Send KICK command to the server */
1625 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1626 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1628 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1629 1, idp->data, idp->len,
1630 2, idp2->data, idp2->len);
1632 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1633 1, idp->data, idp->len,
1634 2, idp2->data, idp2->len,
1636 strlen(cmd->argv[3]));
1637 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1638 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1639 silc_buffer_free(buffer);
1640 silc_buffer_free(idp);
1641 silc_buffer_free(idp2);
1643 /* Notify application */
1647 silc_free(nickname);
1648 silc_client_command_free(cmd);
1651 static void silc_client_command_oper_send(unsigned char *data,
1652 uint32 data_len, void *context)
1654 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1655 SilcClientConnection conn = cmd->conn;
1656 SilcBuffer buffer, auth;
1658 if (cmd->argc >= 3) {
1659 /* Encode the public key authentication payload */
1660 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1661 cmd->client->private_key,
1666 /* Encode the password authentication payload */
1667 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1671 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1673 strlen(cmd->argv[1]),
1674 2, auth->data, auth->len);
1675 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1676 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1678 silc_buffer_free(buffer);
1679 silc_buffer_free(auth);
1681 /* Notify application */
1685 /* OPER command. Used to obtain server operator privileges. */
1687 SILC_CLIENT_CMD_FUNC(oper)
1689 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1690 SilcClientConnection conn = cmd->conn;
1693 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1698 if (cmd->argc < 2) {
1699 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1700 "Usage: /OPER <username> [-pubkey]");
1705 if (cmd->argc < 3) {
1706 /* Get passphrase */
1707 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1708 silc_client_command_oper_send,
1713 silc_client_command_oper_send(NULL, 0, context);
1716 silc_client_command_free(cmd);
1719 static void silc_client_command_silcoper_send(unsigned char *data,
1720 uint32 data_len, void *context)
1722 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1723 SilcClientConnection conn = cmd->conn;
1724 SilcBuffer buffer, auth;
1726 if (cmd->argc >= 3) {
1727 /* Encode the public key authentication payload */
1728 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1729 cmd->client->private_key,
1734 /* Encode the password authentication payload */
1735 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1739 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1741 strlen(cmd->argv[1]),
1742 2, auth->data, auth->len);
1743 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1744 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1746 silc_buffer_free(buffer);
1747 silc_buffer_free(auth);
1749 /* Notify application */
1753 /* SILCOPER command. Used to obtain router operator privileges. */
1755 SILC_CLIENT_CMD_FUNC(silcoper)
1757 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1758 SilcClientConnection conn = cmd->conn;
1761 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1766 if (cmd->argc < 2) {
1767 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1768 "Usage: /SILCOPER <username> [-pubkey]");
1773 if (cmd->argc < 3) {
1774 /* Get passphrase */
1775 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1776 silc_client_command_silcoper_send,
1781 silc_client_command_silcoper_send(NULL, 0, context);
1784 silc_client_command_free(cmd);
1787 /* CONNECT command. Connects the server to another server. */
1789 SILC_CLIENT_CMD_FUNC(connect)
1791 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1792 SilcClientConnection conn = cmd->conn;
1794 unsigned char port[4];
1798 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1803 if (cmd->argc < 2) {
1804 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1805 "Usage: /CONNECT <server> [<port>]");
1810 if (cmd->argc == 3) {
1811 tmp = atoi(cmd->argv[2]);
1812 SILC_PUT32_MSB(tmp, port);
1816 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1818 strlen(cmd->argv[1]),
1821 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1823 strlen(cmd->argv[1]));
1824 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1825 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1826 silc_buffer_free(buffer);
1828 /* Notify application */
1832 silc_client_command_free(cmd);
1835 /* Command BAN. This is used to manage the ban list of the channel. */
1837 SILC_CLIENT_CMD_FUNC(ban)
1839 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1840 SilcClientConnection conn = cmd->conn;
1841 SilcChannelEntry channel;
1842 SilcBuffer buffer, chidp;
1844 char *name, *ban = NULL;
1847 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1852 if (cmd->argc < 2) {
1853 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1854 "Usage: /BAN <channel> "
1855 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1860 if (cmd->argv[1][0] == '*') {
1861 if (!conn->current_channel) {
1862 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1863 "You are not on any channel");
1868 channel = conn->current_channel;
1870 name = cmd->argv[1];
1872 channel = silc_client_get_channel(cmd->client, conn, name);
1874 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1875 "You are on that channel");
1881 if (cmd->argc == 3) {
1882 if (cmd->argv[2][0] == '+')
1891 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1893 /* Send the command */
1895 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1896 1, chidp->data, chidp->len,
1897 type, ban, strlen(ban));
1899 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1900 1, chidp->data, chidp->len);
1902 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1903 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1904 silc_buffer_free(buffer);
1905 silc_buffer_free(chidp);
1907 /* Notify application */
1911 silc_client_command_free(cmd);
1914 /* CLOSE command. Close server connection to the remote server */
1916 SILC_CLIENT_CMD_FUNC(close)
1918 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1919 SilcClientConnection conn = cmd->conn;
1921 unsigned char port[4];
1925 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1930 if (cmd->argc < 2) {
1931 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1932 "Usage: /CLOSE <server> [<port>]");
1937 if (cmd->argc == 3) {
1938 tmp = atoi(cmd->argv[2]);
1939 SILC_PUT32_MSB(tmp, port);
1943 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1945 strlen(cmd->argv[1]),
1948 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1950 strlen(cmd->argv[1]));
1951 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1952 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1953 silc_buffer_free(buffer);
1955 /* Notify application */
1959 silc_client_command_free(cmd);
1962 /* SHUTDOWN command. Shutdowns the server. */
1964 SILC_CLIENT_CMD_FUNC(shutdown)
1966 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1969 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1974 /* Send the command */
1975 silc_client_command_send(cmd->client, cmd->conn,
1976 SILC_COMMAND_SHUTDOWN, 0, 0);
1978 /* Notify application */
1982 silc_client_command_free(cmd);
1985 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1987 SILC_CLIENT_CMD_FUNC(leave)
1989 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1990 SilcClientConnection conn = cmd->conn;
1991 SilcChannelEntry channel;
1992 SilcChannelUser chu;
1993 SilcBuffer buffer, idp;
1997 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2002 if (cmd->argc != 2) {
2003 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2004 "Usage: /LEAVE <channel>");
2009 if (cmd->argv[1][0] == '*') {
2010 if (!conn->current_channel) {
2011 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2012 "You are not on any channel");
2016 name = conn->current_channel->channel_name;
2018 name = cmd->argv[1];
2021 /* Get the channel entry */
2022 channel = silc_client_get_channel(cmd->client, conn, name);
2024 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2025 "You are not on that channel");
2030 /* Remove us from channel */
2031 chu = silc_client_on_channel(channel, conn->local_entry);
2033 silc_hash_table_del(chu->client->channels, chu->channel);
2034 silc_hash_table_del(chu->channel->user_list, chu->client);
2038 /* Send LEAVE command to the server */
2039 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2040 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2041 1, idp->data, idp->len);
2042 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2043 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2044 silc_buffer_free(buffer);
2045 silc_buffer_free(idp);
2047 /* Notify application */
2050 if (conn->current_channel == channel)
2051 conn->current_channel = NULL;
2053 silc_client_del_channel(cmd->client, cmd->conn, channel);
2056 silc_client_command_free(cmd);
2059 /* Command USERS. Requests the USERS of the clients joined on requested
2062 SILC_CLIENT_CMD_FUNC(users)
2064 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2065 SilcClientConnection conn = cmd->conn;
2070 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2075 if (cmd->argc != 2) {
2076 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2077 "Usage: /USERS <channel>");
2082 if (cmd->argv[1][0] == '*') {
2083 if (!conn->current_channel) {
2084 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2085 "You are not on any channel");
2089 name = conn->current_channel->channel_name;
2091 name = cmd->argv[1];
2094 /* Send USERS command to the server */
2095 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2096 ++conn->cmd_ident, 1,
2097 2, name, strlen(name));
2098 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2099 NULL, 0, NULL, NULL, buffer->data,
2101 silc_buffer_free(buffer);
2103 /* Notify application */
2107 silc_client_command_free(cmd);
2110 /* Command GETKEY. Used to fetch remote client's public key. */
2112 SILC_CLIENT_CMD_FUNC(getkey)
2114 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2115 SilcClientConnection conn = cmd->conn;
2116 SilcClient client = cmd->client;
2117 SilcClientEntry client_entry = NULL;
2118 SilcServerEntry server_entry = NULL;
2119 char *nickname = NULL;
2120 SilcBuffer idp, buffer;
2122 SILC_LOG_DEBUG(("Start"));
2125 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2130 if (cmd->argc < 2) {
2131 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2132 "Usage: /GETKEY <nickname or server name>");
2137 /* Parse the typed nickname. */
2138 if (client->internal->params->nickname_parse)
2139 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2141 nickname = strdup(cmd->argv[1]);
2143 /* Find client entry */
2144 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2146 if (!client_entry) {
2147 /* Check whether user requested server actually */
2148 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2150 if (!server_entry) {
2151 /* No. what ever user wants we don't have it, so resolve it. We
2152 will first try to resolve the client, and if that fails then
2153 we'll try to resolve the server. */
2155 if (!cmd->pending) {
2156 /* This will send the IDENTIFY command for nickname */
2157 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2158 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2160 silc_client_command_getkey,
2161 silc_client_command_dup(cmd));
2165 SilcClientCommandReplyContext reply =
2166 (SilcClientCommandReplyContext)context2;
2167 SilcCommandStatus status;
2168 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2169 SILC_GET16_MSB(status, tmp);
2171 /* If nickname was not found, then resolve the server. */
2172 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
2173 /* This sends the IDENTIFY command to resolve the server. */
2174 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2176 silc_client_command_reply_identify_i, 0,
2178 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2180 2, cmd->argv[1], cmd->argv_lens[1]);
2181 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2183 silc_client_command_getkey,
2184 silc_client_command_dup(cmd));
2188 /* If server was not found, then we've resolved both nickname and
2189 server and did not find anybody. */
2190 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2191 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2192 silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2193 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2194 silc_client_command_status_message(status));
2204 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2206 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2209 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2210 1, idp->data, idp->len);
2211 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2212 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2213 silc_buffer_free(buffer);
2214 silc_buffer_free(idp);
2216 /* Notify application */
2220 silc_free(nickname);
2221 silc_client_command_free(cmd);
2224 /* Register a new command indicated by the `command' to the SILC client.
2225 The `name' is optional command name. If provided the command may be
2226 searched using the silc_client_command_find by that name. The
2227 `command_function' is the function to be called when the command is
2228 executed, and the `command_reply_function' is the function to be
2229 called after the server has sent reply back to the command.
2231 The `ident' is optional identifier for the command. If non-zero
2232 the `command_reply_function' for the command type `command' will be
2233 called only if the command reply sent by server includes the
2234 command identifier `ident'. Application usually does not need it
2235 and set it to zero value. */
2237 bool silc_client_command_register(SilcClient client,
2238 SilcCommand command,
2240 SilcCommandCb command_function,
2241 SilcCommandCb command_reply_function,
2245 SilcClientCommand cmd;
2247 cmd = silc_calloc(1, sizeof(*cmd));
2249 cmd->command = command_function;
2250 cmd->reply = command_reply_function;
2251 cmd->name = name ? strdup(name) : NULL;
2252 cmd->max_args = max_args;
2255 silc_list_add(client->internal->commands, cmd);
2260 /* Unregister a command indicated by the `command' with command function
2261 `command_function' and command reply function `command_reply_function'.
2262 Returns TRUE if the command was found and unregistered. */
2264 bool silc_client_command_unregister(SilcClient client,
2265 SilcCommand command,
2266 SilcCommandCb command_function,
2267 SilcCommandCb command_reply_function,
2270 SilcClientCommand cmd;
2272 silc_list_start(client->internal->commands);
2273 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2274 if (cmd->cmd == command && cmd->command == command_function &&
2275 cmd->reply == command_reply_function && cmd->ident == ident) {
2276 silc_list_del(client->internal->commands, cmd);
2277 silc_free(cmd->name);
2286 /* Register all default commands provided by the client library for the
2289 void silc_client_commands_register(SilcClient client)
2291 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2294 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2295 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2296 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2297 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2298 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2299 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2300 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2301 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2302 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2303 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2304 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2305 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2306 SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
2307 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2308 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2309 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2310 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2311 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2312 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2313 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2314 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2315 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2316 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2317 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2318 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2319 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2322 /* Unregister all commands. */
2324 void silc_client_commands_unregister(SilcClient client)
2326 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2327 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2328 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2329 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2330 SILC_CLIENT_CMDU(list, LIST, "LIST");
2331 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2332 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2333 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2334 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2335 SILC_CLIENT_CMDU(info, INFO, "INFO");
2336 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2337 SILC_CLIENT_CMDU(ping, PING, "PING");
2338 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2339 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2340 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2341 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2342 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2343 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2344 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2345 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2346 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2347 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2348 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2349 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2350 SILC_CLIENT_CMDU(users, USERS, "USERS");
2351 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");