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 SilcClientPendingDestructor destructor,
97 SilcCommandCb callback,
100 SilcClientCommandPending *reply;
102 reply = silc_calloc(1, sizeof(*reply));
103 reply->reply_cmd = reply_cmd;
104 reply->ident = ident;
105 reply->context = context;
106 reply->callback = callback;
107 reply->destructor = destructor;
108 silc_dlist_add(conn->pending_commands, reply);
111 /* Deletes pending command by reply command type. */
113 void silc_client_command_pending_del(SilcClientConnection conn,
114 SilcCommand reply_cmd,
117 SilcClientCommandPending *r;
119 silc_dlist_start(conn->pending_commands);
120 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
121 if (r->reply_cmd == reply_cmd && r->ident == ident) {
122 silc_dlist_del(conn->pending_commands, r);
128 /* Checks for pending commands and marks callbacks to be called from
129 the command reply function. Returns TRUE if there were pending command. */
131 int silc_client_command_pending_check(SilcClientConnection conn,
132 SilcClientCommandReplyContext ctx,
136 SilcClientCommandPending *r;
138 silc_dlist_start(conn->pending_commands);
139 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
140 if (r->reply_cmd == command && r->ident == ident) {
141 ctx->context = r->context;
142 ctx->callback = r->callback;
143 ctx->destructor = r->destructor;
152 /* Allocate Command Context */
154 SilcClientCommandContext silc_client_command_alloc(void)
156 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
161 /* Free command context and its internals */
163 void silc_client_command_free(SilcClientCommandContext ctx)
166 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
168 if (ctx->users < 1) {
171 for (i = 0; i < ctx->argc; i++)
172 silc_free(ctx->argv[i]);
173 silc_free(ctx->argv_lens);
174 silc_free(ctx->argv_types);
179 /* Duplicate Command Context by adding reference counter. The context won't
180 be free'd untill it hits zero. */
182 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
185 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
190 /* Pending command destructor. */
192 static void silc_client_command_destructor(void *context)
194 silc_client_command_free((SilcClientCommandContext)context);
197 /* Command WHOIS. This command is used to query information about
200 SILC_CLIENT_CMD_FUNC(whois)
202 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
203 SilcClientConnection conn = cmd->conn;
207 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
212 /* Given without arguments fetches client's own information */
214 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
215 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
217 1, 3, buffer->data, buffer->len);
218 silc_buffer_free(buffer);
222 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
223 cmd->argc - 1, ++cmd->argv,
224 ++cmd->argv_lens, ++cmd->argv_types,
226 silc_client_packet_send(cmd->client, cmd->conn->sock,
227 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
228 buffer->data, buffer->len, TRUE);
229 silc_buffer_free(buffer);
234 /* Notify application */
238 silc_client_command_free(cmd);
241 /* Command WHOWAS. This command is used to query history information about
242 specific user that used to exist in the network. */
244 SILC_CLIENT_CMD_FUNC(whowas)
246 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
247 SilcClientConnection conn = cmd->conn;
251 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
256 if (cmd->argc < 2 || cmd->argc > 3) {
257 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
258 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
263 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
264 cmd->argc - 1, ++cmd->argv,
265 ++cmd->argv_lens, ++cmd->argv_types,
267 silc_client_packet_send(cmd->client, cmd->conn->sock,
268 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
269 buffer->data, buffer->len, TRUE);
270 silc_buffer_free(buffer);
275 /* Notify application */
279 silc_client_command_free(cmd);
282 /* Command IDENTIFY. This command is used to query information about
283 specific user, especially ID's.
285 NOTE: This command is used only internally by the client library
286 and application MUST NOT call this command directly. */
288 SILC_CLIENT_CMD_FUNC(identify)
290 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
291 SilcClientConnection conn = cmd->conn;
295 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
299 if (cmd->argc < 2 || cmd->argc > 3)
303 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
304 ++conn->cmd_ident, 1,
308 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
309 ++conn->cmd_ident, 2,
315 silc_client_packet_send(cmd->client, cmd->conn->sock,
316 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
317 buffer->data, buffer->len, TRUE);
318 silc_buffer_free(buffer);
321 silc_client_command_free(cmd);
324 /* Pending callbcak that will be called after the NICK command was
325 replied by the server. This sets the nickname if there were no
328 SILC_CLIENT_CMD_FUNC(nick_change)
330 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
331 SilcClientConnection conn = cmd->conn;
332 SilcClientCommandReplyContext reply =
333 (SilcClientCommandReplyContext)context2;
334 SilcCommandStatus status;
336 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
337 if (status == SILC_STATUS_OK) {
338 /* Set the nickname */
339 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
341 silc_free(conn->nickname);
342 conn->nickname = strdup(cmd->argv[1]);
343 conn->local_entry->nickname = conn->nickname;
344 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
345 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
346 conn->local_entry->id, conn->local_entry, 0, NULL);
352 silc_client_command_free(cmd);
355 /* Command NICK. Shows current nickname/sets new nickname on current
358 SILC_CLIENT_CMD_FUNC(nick)
360 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
361 SilcClientConnection conn = cmd->conn;
365 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
371 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
372 "Usage: /NICK <nickname>");
377 if (!strcmp(conn->nickname, cmd->argv[1]))
380 /* Show current nickname */
383 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
384 "Your nickname is %s on server %s",
385 conn->nickname, conn->remote_host);
387 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
388 "Your nickname is %s", conn->nickname);
395 if (cmd->argv_lens[1] > 128)
396 cmd->argv_lens[1] = 128;
398 /* Send the NICK command */
399 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
403 ++cmd->conn->cmd_ident);
404 silc_client_packet_send(cmd->client, cmd->conn->sock,
405 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
406 buffer->data, buffer->len, TRUE);
407 silc_buffer_free(buffer);
409 /* Register pending callback that will actually set the new nickname
410 if there were no errors returned by the server. */
411 silc_client_command_pending(conn, SILC_COMMAND_NICK,
412 cmd->conn->cmd_ident,
413 silc_client_command_destructor,
414 silc_client_command_nick_change,
415 silc_client_command_dup(cmd));
420 silc_client_command_free(cmd);
423 /* Command LIST. Lists channels on the current server. */
425 SILC_CLIENT_CMD_FUNC(list)
427 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
428 SilcClientConnection conn = cmd->conn;
429 SilcIDCacheEntry id_cache = NULL;
430 SilcChannelEntry channel;
431 SilcBuffer buffer, idp = NULL;
435 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
440 if (cmd->argc == 2) {
443 /* Get the Channel ID of the channel */
444 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
445 channel = (SilcChannelEntry)id_cache->context;
446 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
451 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
452 ++conn->cmd_ident, 0);
454 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
455 ++conn->cmd_ident, 1,
456 1, idp->data, idp->len);
458 silc_client_packet_send(cmd->client, cmd->conn->sock,
459 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
460 buffer->data, buffer->len, TRUE);
461 silc_buffer_free(buffer);
463 silc_buffer_free(idp);
465 /* Notify application */
469 silc_client_command_free(cmd);
472 /* Command TOPIC. Sets/shows topic on a channel. */
474 SILC_CLIENT_CMD_FUNC(topic)
476 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
477 SilcClientConnection conn = cmd->conn;
478 SilcIDCacheEntry id_cache = NULL;
479 SilcChannelEntry channel;
480 SilcBuffer buffer, idp;
484 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
489 if (cmd->argc < 2 || cmd->argc > 3) {
490 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
491 "Usage: /TOPIC <channel> [<topic>]");
496 if (cmd->argv[1][0] == '*') {
497 if (!conn->current_channel) {
498 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
499 "You are not on any channel");
503 name = conn->current_channel->channel_name;
508 if (!conn->current_channel) {
509 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
510 "You are not on that channel");
515 /* Get the Channel ID of the channel */
516 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
517 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
518 "You are not on that channel");
523 channel = (SilcChannelEntry)id_cache->context;
525 /* Send TOPIC command to the server */
526 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
528 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
529 ++conn->cmd_ident, 2,
530 1, idp->data, idp->len,
532 strlen(cmd->argv[2]));
534 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
535 ++conn->cmd_ident, 1,
536 1, idp->data, idp->len);
537 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
538 0, NULL, NULL, buffer->data, buffer->len, TRUE);
539 silc_buffer_free(buffer);
540 silc_buffer_free(idp);
542 /* Notify application */
546 silc_client_command_free(cmd);
549 /* Command INVITE. Invites specific client to join a channel. This is
550 also used to mange the invite list of the channel. */
552 SILC_CLIENT_CMD_FUNC(invite)
554 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
555 SilcClient client = cmd->client;
556 SilcClientConnection conn = cmd->conn;
557 SilcClientEntry client_entry = NULL;
558 SilcChannelEntry channel;
559 SilcBuffer buffer, clidp, chidp;
561 char *nickname = NULL, *name;
565 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
571 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
572 "Usage: /INVITE <channel> [<nickname>[@server>]"
573 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
578 if (cmd->argv[1][0] == '*') {
579 if (!conn->current_channel) {
580 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
581 "You are not on any channel");
586 channel = conn->current_channel;
590 channel = silc_client_get_channel(cmd->client, conn, name);
592 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
593 "You are on that channel");
599 /* Parse the typed nickname. */
600 if (cmd->argc == 3) {
601 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
602 if (client->internal->params->nickname_parse)
603 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
605 nickname = strdup(cmd->argv[2]);
607 /* Find client entry */
608 client_entry = silc_idlist_get_client(client, conn, nickname,
617 /* Client entry not found, it was requested thus mark this to be
619 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
621 silc_client_command_destructor,
622 silc_client_command_invite,
623 silc_client_command_dup(cmd));
628 invite = cmd->argv[2];
630 if (cmd->argv[2][0] == '+')
637 /* Send the command */
638 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
640 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
641 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
642 ++conn->cmd_ident, 3,
643 1, chidp->data, chidp->len,
644 2, clidp->data, clidp->len,
645 type, invite, invite ?
647 silc_buffer_free(clidp);
649 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
650 ++conn->cmd_ident, 2,
651 1, chidp->data, chidp->len,
652 type, invite, invite ?
656 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
657 0, NULL, NULL, buffer->data, buffer->len, TRUE);
658 silc_buffer_free(buffer);
659 silc_buffer_free(chidp);
661 /* Notify application */
666 silc_client_command_free(cmd);
671 SilcClientConnection conn;
674 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
676 QuitInternal q = (QuitInternal)context;
678 /* Close connection */
679 q->client->internal->ops->disconnect(q->client, q->conn);
680 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
685 /* Command QUIT. Closes connection with current server. */
687 SILC_CLIENT_CMD_FUNC(quit)
689 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
694 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
700 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
701 &cmd->argv[1], &cmd->argv_lens[1],
702 &cmd->argv_types[1], 0);
704 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
705 NULL, NULL, NULL, 0);
706 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
708 buffer->data, buffer->len, TRUE);
709 silc_buffer_free(buffer);
711 q = silc_calloc(1, sizeof(*q));
712 q->client = cmd->client;
715 /* Sleep for a while */
718 /* We quit the connection with little timeout */
719 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
720 silc_client_command_quit_cb, (void *)q,
721 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
723 /* Notify application */
727 silc_client_command_free(cmd);
730 /* Timeout callback to remove the killed client from cache */
732 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
734 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
735 SilcClient client = cmd->client;
736 SilcClientConnection conn = cmd->conn;
737 SilcClientEntry target;
738 char *nickname = NULL;
740 /* Parse the typed nickname. */
741 if (client->internal->params->nickname_parse)
742 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
744 nickname = strdup(cmd->argv[1]);
746 /* Get the target client */
747 target = silc_idlist_get_client(cmd->client, conn, nickname,
748 cmd->argv[1], FALSE);
750 /* Remove the client from all channels and free it */
751 silc_client_del_client(client, conn, target);
754 silc_client_command_free(cmd);
757 /* Kill command's pending command callback to actually remove the killed
758 client from our local cache. */
760 SILC_CLIENT_CMD_FUNC(kill_remove)
762 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
763 SilcClientCommandReplyContext reply =
764 (SilcClientCommandReplyContext)context2;
765 SilcCommandStatus status;
767 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
768 if (status == SILC_STATUS_OK) {
769 /* Remove with timeout */
770 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
771 silc_client_command_kill_remove_later, context,
772 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
776 silc_client_command_free(cmd);
779 /* Command KILL. Router operator can use this command to remove an client
780 fromthe SILC Network. */
782 SILC_CLIENT_CMD_FUNC(kill)
784 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
785 SilcClient client = cmd->client;
786 SilcClientConnection conn = cmd->conn;
787 SilcBuffer buffer, idp;
788 SilcClientEntry target;
789 char *nickname = NULL;
792 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
798 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
799 "Usage: /KILL <nickname> [<comment>]");
804 /* Parse the typed nickname. */
805 if (client->internal->params->nickname_parse)
806 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
808 nickname = strdup(cmd->argv[1]);
810 /* Get the target client */
811 target = silc_idlist_get_client(cmd->client, conn, nickname,
821 /* Client entry not found, it was requested thus mark this to be
823 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
825 silc_client_command_destructor,
826 silc_client_command_kill,
827 silc_client_command_dup(cmd));
832 /* Send the KILL command to the server */
833 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
835 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
836 ++conn->cmd_ident, 1,
837 1, idp->data, idp->len);
839 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
840 ++conn->cmd_ident, 2,
841 1, idp->data, idp->len,
843 strlen(cmd->argv[2]));
844 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
845 0, NULL, NULL, buffer->data, buffer->len, TRUE);
846 silc_buffer_free(buffer);
847 silc_buffer_free(idp);
849 /* Notify application */
852 /* Register a pending callback that will actually remove the killed
853 client from our cache. */
854 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
855 NULL, silc_client_command_kill_remove,
856 silc_client_command_dup(cmd));
860 silc_client_command_free(cmd);
863 /* Command INFO. Request information about specific server. If specific
864 server is not provided the current server is used. */
866 SILC_CLIENT_CMD_FUNC(info)
868 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
869 SilcClientConnection conn = cmd->conn;
874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
880 name = strdup(cmd->argv[1]);
882 /* Send the command */
884 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
885 1, name, strlen(name));
887 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
888 NULL, NULL, NULL, 0);
889 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
890 0, NULL, NULL, buffer->data, buffer->len, TRUE);
891 silc_buffer_free(buffer);
895 /* Notify application */
899 silc_client_command_free(cmd);
902 /* Command PING. Sends ping to server. This is used to test the
903 communication channel. */
905 SILC_CLIENT_CMD_FUNC(ping)
907 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
908 SilcClientConnection conn = cmd->conn;
914 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
919 /* Send the command */
920 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
921 1, conn->remote_id_data,
922 silc_id_get_len(conn->remote_id,
924 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
925 0, NULL, NULL, buffer->data, buffer->len, TRUE);
926 silc_buffer_free(buffer);
928 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
931 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
936 /* Start counting time */
937 for (i = 0; i < conn->ping_count; i++) {
938 if (conn->ping[i].dest_id == NULL) {
939 conn->ping[i].start_time = time(NULL);
940 conn->ping[i].dest_id = id;
941 conn->ping[i].dest_name = strdup(conn->remote_host);
945 if (i >= conn->ping_count) {
946 i = conn->ping_count;
947 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
948 conn->ping[i].start_time = time(NULL);
949 conn->ping[i].dest_id = id;
950 conn->ping[i].dest_name = strdup(conn->remote_host);
954 /* Notify application */
958 silc_client_command_free(cmd);
961 /* Command JOIN. Joins to a channel. */
963 SILC_CLIENT_CMD_FUNC(join)
965 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
966 SilcClientConnection conn = cmd->conn;
967 SilcIDCacheEntry id_cache = NULL;
968 SilcBuffer buffer, idp, auth = NULL;
969 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
973 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
983 /* See if we have joined to the requested channel already */
984 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
986 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
987 if (channel->on_channel)
991 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
993 if (cmd->argv_lens[1] > 256)
994 cmd->argv_lens[1] = 256;
998 for (i = 2; i < cmd->argc; i++) {
999 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1000 cipher = cmd->argv[i + 1];
1002 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1003 hmac = cmd->argv[i + 1];
1005 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
1006 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
1007 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1008 cmd->client->private_key,
1013 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1015 cmd->argv_lens[i + 1]);
1019 passphrase = cmd->argv[i];
1023 /* Send JOIN command to the server */
1025 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1026 1, name, strlen(name),
1027 2, idp->data, idp->len,
1029 passphrase ? strlen(passphrase) : 0,
1030 4, cipher, cipher ? strlen(cipher) : 0,
1031 5, hmac, hmac ? strlen(hmac) : 0,
1032 6, auth ? auth->data : NULL,
1033 auth ? auth->len : 0);
1034 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1035 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1036 silc_buffer_free(buffer);
1037 silc_buffer_free(idp);
1039 silc_buffer_free(auth);
1041 /* Notify application */
1045 silc_client_command_free(cmd);
1048 /* MOTD command. Requests motd from server. */
1050 SILC_CLIENT_CMD_FUNC(motd)
1052 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1053 SilcClientConnection conn = cmd->conn;
1057 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1062 if (cmd->argc < 1 || cmd->argc > 2) {
1063 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1064 "Usage: /MOTD [<server>]");
1069 /* Send TOPIC command to the server */
1071 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1072 1, conn->remote_host,
1073 strlen(conn->remote_host));
1075 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1078 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1079 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1080 silc_buffer_free(buffer);
1082 /* Notify application */
1086 silc_client_command_free(cmd);
1089 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1090 modes as client cannot set itself server/router operator privileges. */
1092 SILC_CLIENT_CMD_FUNC(umode)
1094 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1095 SilcClientConnection conn = cmd->conn;
1096 SilcBuffer buffer, idp;
1097 unsigned char *cp, modebuf[4];
1098 uint32 mode, add, len;
1102 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1107 if (cmd->argc < 2) {
1108 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1109 "Usage: /UMODE +|-<modes>");
1114 mode = conn->local_entry->mode;
1116 /* Are we adding or removing mode */
1117 if (cmd->argv[1][0] == '-')
1123 cp = cmd->argv[1] + 1;
1125 for (i = 0; i < len; i++) {
1130 mode |= SILC_UMODE_SERVER_OPERATOR;
1131 mode |= SILC_UMODE_ROUTER_OPERATOR;
1133 mode = SILC_UMODE_NONE;
1138 mode |= SILC_UMODE_SERVER_OPERATOR;
1140 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1144 mode |= SILC_UMODE_ROUTER_OPERATOR;
1146 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1150 mode |= SILC_UMODE_GONE;
1152 mode &= ~SILC_UMODE_GONE;
1161 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1162 SILC_PUT32_MSB(mode, modebuf);
1164 /* Send the command packet. We support sending only one mode at once
1165 that requires an argument. */
1167 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1168 1, idp->data, idp->len,
1169 2, modebuf, sizeof(modebuf));
1170 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1171 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1172 silc_buffer_free(buffer);
1173 silc_buffer_free(idp);
1175 /* Notify application */
1179 silc_client_command_free(cmd);
1182 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1183 can be set several at once. Those modes that require argument must be set
1184 separately (unless set with modes that does not require arguments). */
1186 SILC_CLIENT_CMD_FUNC(cmode)
1188 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1189 SilcClientConnection conn = cmd->conn;
1190 SilcChannelEntry channel;
1191 SilcBuffer buffer, chidp, auth = NULL;
1192 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1193 uint32 mode, add, type, len, arg_len = 0;
1197 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1202 if (cmd->argc < 3) {
1203 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1204 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1209 if (cmd->argv[1][0] == '*') {
1210 if (!conn->current_channel) {
1211 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1212 "You are not on any channel");
1217 channel = conn->current_channel;
1219 name = cmd->argv[1];
1221 channel = silc_client_get_channel(cmd->client, conn, name);
1223 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1224 "You are on that channel");
1230 mode = channel->mode;
1232 /* Are we adding or removing mode */
1233 if (cmd->argv[2][0] == '-')
1238 /* Argument type to be sent to server */
1242 cp = cmd->argv[2] + 1;
1244 for (i = 0; i < len; i++) {
1248 mode |= SILC_CHANNEL_MODE_PRIVATE;
1250 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1254 mode |= SILC_CHANNEL_MODE_SECRET;
1256 mode &= ~SILC_CHANNEL_MODE_SECRET;
1260 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1262 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1266 mode |= SILC_CHANNEL_MODE_INVITE;
1268 mode &= ~SILC_CHANNEL_MODE_INVITE;
1272 mode |= SILC_CHANNEL_MODE_TOPIC;
1274 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1279 mode |= SILC_CHANNEL_MODE_ULIMIT;
1281 if (cmd->argc < 4) {
1282 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1283 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1287 ll = atoi(cmd->argv[3]);
1288 SILC_PUT32_MSB(ll, tmp);
1292 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1297 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1299 if (cmd->argc < 4) {
1300 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1301 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1306 arg_len = cmd->argv_lens[3];
1308 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1313 mode |= SILC_CHANNEL_MODE_CIPHER;
1315 if (cmd->argc < 4) {
1316 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1317 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1322 arg_len = cmd->argv_lens[3];
1324 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1329 mode |= SILC_CHANNEL_MODE_HMAC;
1331 if (cmd->argc < 4) {
1332 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1333 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1338 arg_len = cmd->argv_lens[3];
1340 mode &= ~SILC_CHANNEL_MODE_HMAC;
1345 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1348 if (cmd->argc < 4) {
1349 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1350 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1355 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1356 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1357 cmd->client->private_key,
1362 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1363 cmd->argv[3], cmd->argv_lens[3]);
1367 arg_len = auth->len;
1369 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1379 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1380 SILC_PUT32_MSB(mode, modebuf);
1382 /* Send the command packet. We support sending only one mode at once
1383 that requires an argument. */
1386 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1387 1, chidp->data, chidp->len,
1388 2, modebuf, sizeof(modebuf),
1389 type, arg, arg_len);
1392 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1393 1, chidp->data, chidp->len,
1394 2, modebuf, sizeof(modebuf));
1397 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1398 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1399 silc_buffer_free(buffer);
1400 silc_buffer_free(chidp);
1402 silc_buffer_free(auth);
1404 /* Notify application */
1408 silc_client_command_free(cmd);
1411 /* CUMODE command. Changes client's mode on a channel. */
1413 SILC_CLIENT_CMD_FUNC(cumode)
1415 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1416 SilcClient client = cmd->client;
1417 SilcClientConnection conn = cmd->conn;
1418 SilcChannelEntry channel;
1419 SilcChannelUser chu;
1420 SilcClientEntry client_entry;
1421 SilcBuffer buffer, clidp, chidp, auth = NULL;
1422 unsigned char *name, *cp, modebuf[4];
1423 uint32 mode = 0, add, len;
1424 char *nickname = NULL;
1428 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1433 if (cmd->argc < 4) {
1434 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1435 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1440 if (cmd->argv[1][0] == '*') {
1441 if (!conn->current_channel) {
1442 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1443 "You are not on any channel");
1448 channel = conn->current_channel;
1450 name = cmd->argv[1];
1452 channel = silc_client_get_channel(cmd->client, conn, name);
1454 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1455 "You are on that channel");
1461 /* Parse the typed nickname. */
1462 if (client->internal->params->nickname_parse)
1463 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1465 nickname = strdup(cmd->argv[3]);
1467 /* Find client entry */
1468 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1469 cmd->argv[3], TRUE);
1470 if (!client_entry) {
1476 silc_free(nickname);
1478 /* Client entry not found, it was requested thus mark this to be
1480 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1482 silc_client_command_destructor,
1483 silc_client_command_cumode,
1484 silc_client_command_dup(cmd));
1489 /* Get the current mode */
1490 silc_list_start(channel->clients);
1491 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1492 if (chu->client == client_entry) {
1498 /* Are we adding or removing mode */
1499 if (cmd->argv[2][0] == '-')
1505 cp = cmd->argv[2] + 1;
1507 for (i = 0; i < len; i++) {
1511 mode |= SILC_CHANNEL_UMODE_CHANFO;
1512 mode |= SILC_CHANNEL_UMODE_CHANOP;
1514 mode = SILC_CHANNEL_UMODE_NONE;
1519 if (cmd->argc == 5) {
1520 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1521 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1522 cmd->client->private_key,
1527 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1528 cmd->argv[4], cmd->argv_lens[4]);
1531 mode |= SILC_CHANNEL_UMODE_CHANFO;
1533 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1538 mode |= SILC_CHANNEL_UMODE_CHANOP;
1540 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1549 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1550 SILC_PUT32_MSB(mode, modebuf);
1551 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1553 /* Send the command packet. We support sending only one mode at once
1554 that requires an argument. */
1555 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1557 1, chidp->data, chidp->len,
1559 3, clidp->data, clidp->len,
1560 4, auth ? auth->data : NULL,
1561 auth ? auth->len : 0);
1563 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1564 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1565 silc_buffer_free(buffer);
1566 silc_buffer_free(chidp);
1567 silc_buffer_free(clidp);
1569 silc_buffer_free(auth);
1571 /* Notify application */
1575 silc_free(nickname);
1576 silc_client_command_free(cmd);
1579 /* KICK command. Kicks a client out of channel. */
1581 SILC_CLIENT_CMD_FUNC(kick)
1583 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1584 SilcClient client = cmd->client;
1585 SilcClientConnection conn = cmd->conn;
1586 SilcIDCacheEntry id_cache = NULL;
1587 SilcChannelEntry channel;
1588 SilcBuffer buffer, idp, idp2;
1589 SilcClientEntry target;
1591 char *nickname = NULL;
1594 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1599 if (cmd->argc < 3) {
1600 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1601 "Usage: /KICK <channel> <nickname> [<comment>]");
1606 if (cmd->argv[1][0] == '*') {
1607 if (!conn->current_channel) {
1608 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1609 "You are not on any channel");
1613 name = conn->current_channel->channel_name;
1615 name = cmd->argv[1];
1618 if (!conn->current_channel) {
1619 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1620 "You are not on that channel");
1625 /* Get the Channel ID of the channel */
1626 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1627 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1628 "You are not on that channel");
1633 channel = (SilcChannelEntry)id_cache->context;
1635 /* Parse the typed nickname. */
1636 if (client->internal->params->nickname_parse)
1637 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1639 nickname = strdup(cmd->argv[2]);
1641 /* Get the target client */
1642 target = silc_idlist_get_client(cmd->client, conn, nickname,
1643 cmd->argv[2], FALSE);
1645 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1646 "No such client: %s", cmd->argv[2]);
1651 /* Send KICK command to the server */
1652 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1653 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1655 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1656 1, idp->data, idp->len,
1657 2, idp2->data, idp2->len);
1659 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1660 1, idp->data, idp->len,
1661 2, idp2->data, idp2->len,
1663 strlen(cmd->argv[3]));
1664 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1665 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1666 silc_buffer_free(buffer);
1667 silc_buffer_free(idp);
1668 silc_buffer_free(idp2);
1670 /* Notify application */
1674 silc_free(nickname);
1675 silc_client_command_free(cmd);
1678 static void silc_client_command_oper_send(unsigned char *data,
1679 uint32 data_len, void *context)
1681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1682 SilcClientConnection conn = cmd->conn;
1683 SilcBuffer buffer, auth;
1685 if (cmd->argc >= 3) {
1686 /* Encode the public key authentication payload */
1687 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1688 cmd->client->private_key,
1693 /* Encode the password authentication payload */
1694 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1698 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1700 strlen(cmd->argv[1]),
1701 2, auth->data, auth->len);
1702 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1703 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1705 silc_buffer_free(buffer);
1706 silc_buffer_free(auth);
1708 /* Notify application */
1712 /* OPER command. Used to obtain server operator privileges. */
1714 SILC_CLIENT_CMD_FUNC(oper)
1716 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1717 SilcClientConnection conn = cmd->conn;
1720 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1725 if (cmd->argc < 2) {
1726 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1727 "Usage: /OPER <username> [-pubkey]");
1732 if (cmd->argc < 3) {
1733 /* Get passphrase */
1734 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1735 silc_client_command_oper_send,
1740 silc_client_command_oper_send(NULL, 0, context);
1743 silc_client_command_free(cmd);
1746 static void silc_client_command_silcoper_send(unsigned char *data,
1747 uint32 data_len, void *context)
1749 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1750 SilcClientConnection conn = cmd->conn;
1751 SilcBuffer buffer, auth;
1753 if (cmd->argc >= 3) {
1754 /* Encode the public key authentication payload */
1755 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1756 cmd->client->private_key,
1761 /* Encode the password authentication payload */
1762 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1766 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1768 strlen(cmd->argv[1]),
1769 2, auth->data, auth->len);
1770 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1771 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1773 silc_buffer_free(buffer);
1774 silc_buffer_free(auth);
1776 /* Notify application */
1780 /* SILCOPER command. Used to obtain router operator privileges. */
1782 SILC_CLIENT_CMD_FUNC(silcoper)
1784 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1785 SilcClientConnection conn = cmd->conn;
1788 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1793 if (cmd->argc < 2) {
1794 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1795 "Usage: /SILCOPER <username> [-pubkey]");
1800 if (cmd->argc < 3) {
1801 /* Get passphrase */
1802 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1803 silc_client_command_silcoper_send,
1808 silc_client_command_silcoper_send(NULL, 0, context);
1811 silc_client_command_free(cmd);
1814 /* CONNECT command. Connects the server to another server. */
1816 SILC_CLIENT_CMD_FUNC(connect)
1818 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1819 SilcClientConnection conn = cmd->conn;
1821 unsigned char port[4];
1825 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1830 if (cmd->argc < 2) {
1831 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1832 "Usage: /CONNECT <server> [<port>]");
1837 if (cmd->argc == 3) {
1838 tmp = atoi(cmd->argv[2]);
1839 SILC_PUT32_MSB(tmp, port);
1843 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1845 strlen(cmd->argv[1]),
1848 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1850 strlen(cmd->argv[1]));
1851 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1852 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1853 silc_buffer_free(buffer);
1855 /* Notify application */
1859 silc_client_command_free(cmd);
1862 /* Command BAN. This is used to manage the ban list of the channel. */
1864 SILC_CLIENT_CMD_FUNC(ban)
1866 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1867 SilcClientConnection conn = cmd->conn;
1868 SilcChannelEntry channel;
1869 SilcBuffer buffer, chidp;
1871 char *name, *ban = NULL;
1874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1879 if (cmd->argc < 2) {
1880 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1881 "Usage: /BAN <channel> "
1882 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1887 if (cmd->argv[1][0] == '*') {
1888 if (!conn->current_channel) {
1889 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1890 "You are not on any channel");
1895 channel = conn->current_channel;
1897 name = cmd->argv[1];
1899 channel = silc_client_get_channel(cmd->client, conn, name);
1901 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1902 "You are on that channel");
1908 if (cmd->argc == 3) {
1909 if (cmd->argv[2][0] == '+')
1918 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1920 /* Send the command */
1922 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1923 1, chidp->data, chidp->len,
1924 type, ban, strlen(ban));
1926 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1927 1, chidp->data, chidp->len);
1929 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1930 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1931 silc_buffer_free(buffer);
1932 silc_buffer_free(chidp);
1934 /* Notify application */
1938 silc_client_command_free(cmd);
1941 /* CLOSE command. Close server connection to the remote server */
1943 SILC_CLIENT_CMD_FUNC(close)
1945 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1946 SilcClientConnection conn = cmd->conn;
1948 unsigned char port[4];
1952 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1957 if (cmd->argc < 2) {
1958 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1959 "Usage: /CLOSE <server> [<port>]");
1964 if (cmd->argc == 3) {
1965 tmp = atoi(cmd->argv[2]);
1966 SILC_PUT32_MSB(tmp, port);
1970 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1972 strlen(cmd->argv[1]),
1975 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1977 strlen(cmd->argv[1]));
1978 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1979 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1980 silc_buffer_free(buffer);
1982 /* Notify application */
1986 silc_client_command_free(cmd);
1989 /* SHUTDOWN command. Shutdowns the server. */
1991 SILC_CLIENT_CMD_FUNC(shutdown)
1993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1996 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2001 /* Send the command */
2002 silc_client_command_send(cmd->client, cmd->conn,
2003 SILC_COMMAND_SHUTDOWN, 0, 0);
2005 /* Notify application */
2009 silc_client_command_free(cmd);
2012 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2014 SILC_CLIENT_CMD_FUNC(leave)
2016 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2017 SilcClientConnection conn = cmd->conn;
2018 SilcIDCacheEntry id_cache = NULL;
2019 SilcChannelEntry channel;
2020 SilcBuffer buffer, idp;
2024 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2029 if (cmd->argc != 2) {
2030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "Usage: /LEAVE <channel>");
2036 if (cmd->argv[1][0] == '*') {
2037 if (!conn->current_channel) {
2038 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2039 "You are not on any channel");
2043 name = conn->current_channel->channel_name;
2045 name = cmd->argv[1];
2048 /* Get the Channel ID of the channel */
2049 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2050 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2051 "You are not on that channel");
2056 channel = (SilcChannelEntry)id_cache->context;
2057 channel->on_channel = FALSE;
2059 /* Send LEAVE command to the server */
2060 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2061 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2062 1, idp->data, idp->len);
2063 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2064 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2065 silc_buffer_free(buffer);
2066 silc_buffer_free(idp);
2068 /* Notify application */
2071 if (conn->current_channel == channel)
2072 conn->current_channel = NULL;
2074 silc_client_del_channel(cmd->client, cmd->conn, channel);
2077 silc_client_command_free(cmd);
2080 /* Command USERS. Requests the USERS of the clients joined on requested
2083 SILC_CLIENT_CMD_FUNC(users)
2085 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2086 SilcClientConnection conn = cmd->conn;
2091 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2096 if (cmd->argc != 2) {
2097 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2098 "Usage: /USERS <channel>");
2103 if (cmd->argv[1][0] == '*') {
2104 if (!conn->current_channel) {
2105 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2106 "You are not on any channel");
2110 name = conn->current_channel->channel_name;
2112 name = cmd->argv[1];
2115 /* Send USERS command to the server */
2116 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2117 ++conn->cmd_ident, 1,
2118 2, name, strlen(name));
2119 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2120 NULL, 0, NULL, NULL, buffer->data,
2122 silc_buffer_free(buffer);
2124 /* Notify application */
2128 silc_client_command_free(cmd);
2131 /* Command GETKEY. Used to fetch remote client's public key. */
2133 SILC_CLIENT_CMD_FUNC(getkey)
2135 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2136 SilcClientConnection conn = cmd->conn;
2137 SilcClient client = cmd->client;
2138 SilcClientEntry client_entry = NULL;
2139 SilcServerEntry server_entry = NULL;
2140 char *nickname = NULL;
2141 SilcBuffer idp, buffer;
2144 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2149 if (cmd->argc < 2) {
2150 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2151 "Usage: /GETKEY <nickname or server name>");
2157 SilcClientCommandReplyContext reply =
2158 (SilcClientCommandReplyContext)context2;
2159 SilcCommandStatus status;
2160 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2161 SILC_GET16_MSB(status, tmp);
2163 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2164 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2165 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2166 silc_client_command_status_message(status));
2172 /* Parse the typed nickname. */
2173 if (client->internal->params->nickname_parse)
2174 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2176 nickname = strdup(cmd->argv[1]);
2178 /* Find client entry */
2179 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2181 if (!client_entry) {
2182 /* Check whether user requested server actually */
2183 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2185 if (!server_entry) {
2191 /* No. what ever user wants we don't have it, so resolve it. We
2192 will try to resolve both client and server, one of them is
2193 bound to be wrong. */
2195 /* This will send the IDENTIFY command */
2196 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2197 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2199 silc_client_command_destructor,
2200 silc_client_command_getkey,
2201 silc_client_command_dup(cmd));
2203 /* This sends the IDENTIFY command to resolve the server. */
2204 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
2205 silc_client_command_reply_identify_i, 0,
2207 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2209 2, cmd->argv[1], cmd->argv_lens[1]);
2210 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2211 conn->cmd_ident, NULL,
2212 silc_client_command_getkey,
2213 silc_client_command_dup(cmd));
2216 silc_free(nickname);
2220 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2222 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2225 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2226 1, idp->data, idp->len);
2227 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2228 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2229 silc_buffer_free(buffer);
2230 silc_buffer_free(idp);
2232 /* Notify application */
2236 silc_free(nickname);
2237 silc_client_command_free(cmd);
2240 /* Register a new command indicated by the `command' to the SILC client.
2241 The `name' is optional command name. If provided the command may be
2242 searched using the silc_client_command_find by that name. The
2243 `command_function' is the function to be called when the command is
2244 executed, and the `command_reply_function' is the function to be
2245 called after the server has sent reply back to the command.
2247 The `ident' is optional identifier for the command. If non-zero
2248 the `command_reply_function' for the command type `command' will be
2249 called only if the command reply sent by server includes the
2250 command identifier `ident'. Application usually does not need it
2251 and set it to zero value. */
2253 bool silc_client_command_register(SilcClient client,
2254 SilcCommand command,
2256 SilcCommandCb command_function,
2257 SilcCommandCb command_reply_function,
2261 SilcClientCommand cmd;
2263 cmd = silc_calloc(1, sizeof(*cmd));
2265 cmd->command = command_function;
2266 cmd->reply = command_reply_function;
2267 cmd->name = name ? strdup(name) : NULL;
2268 cmd->max_args = max_args;
2271 silc_list_add(client->internal->commands, cmd);
2276 /* Unregister a command indicated by the `command' with command function
2277 `command_function' and command reply function `command_reply_function'.
2278 Returns TRUE if the command was found and unregistered. */
2280 bool silc_client_command_unregister(SilcClient client,
2281 SilcCommand command,
2282 SilcCommandCb command_function,
2283 SilcCommandCb command_reply_function,
2286 SilcClientCommand cmd;
2288 silc_list_start(client->internal->commands);
2289 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2290 if (cmd->cmd == command && cmd->command == command_function &&
2291 cmd->reply == command_reply_function && cmd->ident == ident) {
2292 silc_list_del(client->internal->commands, cmd);
2293 silc_free(cmd->name);
2302 /* Register all default commands provided by the client library for the
2305 void silc_client_commands_register(SilcClient client)
2307 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2310 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2311 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2312 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2313 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2314 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2315 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2316 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2317 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2318 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2319 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2320 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2321 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2322 SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
2323 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2324 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2325 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2326 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2327 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2328 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2329 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2330 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2331 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2332 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2333 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2334 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2335 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2338 /* Unregister all commands. */
2340 void silc_client_commands_unregister(SilcClient client)
2342 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2343 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2344 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2345 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2346 SILC_CLIENT_CMDU(list, LIST, "LIST");
2347 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2348 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2349 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2350 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2351 SILC_CLIENT_CMDU(info, INFO, "INFO");
2352 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2353 SILC_CLIENT_CMDU(ping, PING, "PING");
2354 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2355 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2356 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2357 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2358 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2359 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2360 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2361 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2362 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2363 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2364 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2365 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2366 SILC_CLIENT_CMDU(users, USERS, "USERS");
2367 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2369 silc_list_uninit(client->internal->commands);