5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 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 silc_client_remove_from_channels(client, conn, target);
751 silc_client_del_client(client, conn, target);
755 silc_client_command_free(cmd);
758 /* Kill command's pending command callback to actually remove the killed
759 client from our local cache. */
761 SILC_CLIENT_CMD_FUNC(kill_remove)
763 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
764 SilcClientCommandReplyContext reply =
765 (SilcClientCommandReplyContext)context2;
766 SilcCommandStatus status;
768 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
769 if (status == SILC_STATUS_OK) {
770 /* Remove with timeout */
771 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
772 silc_client_command_kill_remove_later, context,
773 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
777 silc_client_command_free(cmd);
780 /* Command KILL. Router operator can use this command to remove an client
781 fromthe SILC Network. */
783 SILC_CLIENT_CMD_FUNC(kill)
785 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
786 SilcClient client = cmd->client;
787 SilcClientConnection conn = cmd->conn;
788 SilcBuffer buffer, idp;
789 SilcClientEntry target;
790 char *nickname = NULL;
793 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
799 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
800 "Usage: /KILL <nickname> [<comment>]");
805 /* Parse the typed nickname. */
806 if (client->internal->params->nickname_parse)
807 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
809 nickname = strdup(cmd->argv[1]);
811 /* Get the target client */
812 target = silc_idlist_get_client(cmd->client, conn, nickname,
822 /* Client entry not found, it was requested thus mark this to be
824 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
826 silc_client_command_destructor,
827 silc_client_command_kill,
828 silc_client_command_dup(cmd));
833 /* Send the KILL command to the server */
834 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
836 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
837 ++conn->cmd_ident, 1,
838 1, idp->data, idp->len);
840 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
841 ++conn->cmd_ident, 2,
842 1, idp->data, idp->len,
844 strlen(cmd->argv[2]));
845 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
846 0, NULL, NULL, buffer->data, buffer->len, TRUE);
847 silc_buffer_free(buffer);
848 silc_buffer_free(idp);
850 /* Notify application */
853 /* Register a pending callback that will actually remove the killed
854 client from our cache. */
855 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
856 NULL, silc_client_command_kill_remove,
857 silc_client_command_dup(cmd));
861 silc_client_command_free(cmd);
864 /* Command INFO. Request information about specific server. If specific
865 server is not provided the current server is used. */
867 SILC_CLIENT_CMD_FUNC(info)
869 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
870 SilcClientConnection conn = cmd->conn;
875 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
881 name = strdup(cmd->argv[1]);
883 /* Send the command */
885 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
886 1, name, strlen(name));
888 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
889 NULL, NULL, NULL, 0);
890 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
891 0, NULL, NULL, buffer->data, buffer->len, TRUE);
892 silc_buffer_free(buffer);
896 /* Notify application */
900 silc_client_command_free(cmd);
903 /* Command PING. Sends ping to server. This is used to test the
904 communication channel. */
906 SILC_CLIENT_CMD_FUNC(ping)
908 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
909 SilcClientConnection conn = cmd->conn;
915 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
920 /* Send the command */
921 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
922 1, conn->remote_id_data,
923 silc_id_get_len(conn->remote_id,
925 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
926 0, NULL, NULL, buffer->data, buffer->len, TRUE);
927 silc_buffer_free(buffer);
929 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
932 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
937 /* Start counting time */
938 for (i = 0; i < conn->ping_count; i++) {
939 if (conn->ping[i].dest_id == NULL) {
940 conn->ping[i].start_time = time(NULL);
941 conn->ping[i].dest_id = id;
942 conn->ping[i].dest_name = strdup(conn->remote_host);
946 if (i >= conn->ping_count) {
947 i = conn->ping_count;
948 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
949 conn->ping[i].start_time = time(NULL);
950 conn->ping[i].dest_id = id;
951 conn->ping[i].dest_name = strdup(conn->remote_host);
955 /* Notify application */
959 silc_client_command_free(cmd);
962 /* Command JOIN. Joins to a channel. */
964 SILC_CLIENT_CMD_FUNC(join)
966 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
967 SilcClientConnection conn = cmd->conn;
968 SilcIDCacheEntry id_cache = NULL;
969 SilcBuffer buffer, idp, auth = NULL;
970 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
974 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
984 /* See if we have joined to the requested channel already */
985 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
987 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
988 if (channel->on_channel)
992 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
994 if (cmd->argv_lens[1] > 256)
995 cmd->argv_lens[1] = 256;
999 for (i = 2; i < cmd->argc; i++) {
1000 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
1001 cipher = cmd->argv[i + 1];
1003 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
1004 hmac = cmd->argv[i + 1];
1006 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
1007 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
1008 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1009 cmd->client->private_key,
1014 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1016 cmd->argv_lens[i + 1]);
1020 passphrase = cmd->argv[i];
1024 /* Send JOIN command to the server */
1026 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1027 1, name, strlen(name),
1028 2, idp->data, idp->len,
1030 passphrase ? strlen(passphrase) : 0,
1031 4, cipher, cipher ? strlen(cipher) : 0,
1032 5, hmac, hmac ? strlen(hmac) : 0,
1033 6, auth ? auth->data : NULL,
1034 auth ? auth->len : 0);
1035 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1036 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1037 silc_buffer_free(buffer);
1038 silc_buffer_free(idp);
1040 silc_buffer_free(auth);
1042 /* Notify application */
1046 silc_client_command_free(cmd);
1049 /* MOTD command. Requests motd from server. */
1051 SILC_CLIENT_CMD_FUNC(motd)
1053 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1054 SilcClientConnection conn = cmd->conn;
1058 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1063 if (cmd->argc < 1 || cmd->argc > 2) {
1064 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1065 "Usage: /MOTD [<server>]");
1070 /* Send TOPIC command to the server */
1072 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1073 1, conn->remote_host,
1074 strlen(conn->remote_host));
1076 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1079 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1080 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1081 silc_buffer_free(buffer);
1083 /* Notify application */
1087 silc_client_command_free(cmd);
1090 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1091 modes as client cannot set itself server/router operator privileges. */
1093 SILC_CLIENT_CMD_FUNC(umode)
1095 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1096 SilcClientConnection conn = cmd->conn;
1097 SilcBuffer buffer, idp;
1098 unsigned char *cp, modebuf[4];
1099 uint32 mode, add, len;
1103 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1108 if (cmd->argc < 2) {
1109 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1110 "Usage: /UMODE +|-<modes>");
1115 mode = conn->local_entry->mode;
1117 /* Are we adding or removing mode */
1118 if (cmd->argv[1][0] == '-')
1124 cp = cmd->argv[1] + 1;
1126 for (i = 0; i < len; i++) {
1131 mode |= SILC_UMODE_SERVER_OPERATOR;
1132 mode |= SILC_UMODE_ROUTER_OPERATOR;
1134 mode = SILC_UMODE_NONE;
1139 mode |= SILC_UMODE_SERVER_OPERATOR;
1141 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1145 mode |= SILC_UMODE_ROUTER_OPERATOR;
1147 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1151 mode |= SILC_UMODE_GONE;
1153 mode &= ~SILC_UMODE_GONE;
1162 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1163 SILC_PUT32_MSB(mode, modebuf);
1165 /* Send the command packet. We support sending only one mode at once
1166 that requires an argument. */
1168 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1169 1, idp->data, idp->len,
1170 2, modebuf, sizeof(modebuf));
1171 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1172 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1173 silc_buffer_free(buffer);
1174 silc_buffer_free(idp);
1176 /* Notify application */
1180 silc_client_command_free(cmd);
1183 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1184 can be set several at once. Those modes that require argument must be set
1185 separately (unless set with modes that does not require arguments). */
1187 SILC_CLIENT_CMD_FUNC(cmode)
1189 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1190 SilcClientConnection conn = cmd->conn;
1191 SilcChannelEntry channel;
1192 SilcBuffer buffer, chidp, auth = NULL;
1193 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1194 uint32 mode, add, type, len, arg_len = 0;
1198 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1203 if (cmd->argc < 3) {
1204 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1205 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1210 if (cmd->argv[1][0] == '*') {
1211 if (!conn->current_channel) {
1212 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1213 "You are not on any channel");
1218 channel = conn->current_channel;
1220 name = cmd->argv[1];
1222 channel = silc_client_get_channel(cmd->client, conn, name);
1224 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1225 "You are on that channel");
1231 mode = channel->mode;
1233 /* Are we adding or removing mode */
1234 if (cmd->argv[2][0] == '-')
1239 /* Argument type to be sent to server */
1243 cp = cmd->argv[2] + 1;
1245 for (i = 0; i < len; i++) {
1249 mode |= SILC_CHANNEL_MODE_PRIVATE;
1251 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1255 mode |= SILC_CHANNEL_MODE_SECRET;
1257 mode &= ~SILC_CHANNEL_MODE_SECRET;
1261 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1263 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1267 mode |= SILC_CHANNEL_MODE_INVITE;
1269 mode &= ~SILC_CHANNEL_MODE_INVITE;
1273 mode |= SILC_CHANNEL_MODE_TOPIC;
1275 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1280 mode |= SILC_CHANNEL_MODE_ULIMIT;
1282 if (cmd->argc < 4) {
1283 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1284 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1288 ll = atoi(cmd->argv[3]);
1289 SILC_PUT32_MSB(ll, tmp);
1293 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1298 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1300 if (cmd->argc < 4) {
1301 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1302 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1307 arg_len = cmd->argv_lens[3];
1309 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1314 mode |= SILC_CHANNEL_MODE_CIPHER;
1316 if (cmd->argc < 4) {
1317 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1318 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1323 arg_len = cmd->argv_lens[3];
1325 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1330 mode |= SILC_CHANNEL_MODE_HMAC;
1332 if (cmd->argc < 4) {
1333 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1334 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1339 arg_len = cmd->argv_lens[3];
1341 mode &= ~SILC_CHANNEL_MODE_HMAC;
1346 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1349 if (cmd->argc < 4) {
1350 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1351 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1356 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1357 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1358 cmd->client->private_key,
1363 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1364 cmd->argv[3], cmd->argv_lens[3]);
1368 arg_len = auth->len;
1370 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1380 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1381 SILC_PUT32_MSB(mode, modebuf);
1383 /* Send the command packet. We support sending only one mode at once
1384 that requires an argument. */
1387 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1388 1, chidp->data, chidp->len,
1389 2, modebuf, sizeof(modebuf),
1390 type, arg, arg_len);
1393 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1394 1, chidp->data, chidp->len,
1395 2, modebuf, sizeof(modebuf));
1398 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1399 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1400 silc_buffer_free(buffer);
1401 silc_buffer_free(chidp);
1403 silc_buffer_free(auth);
1405 /* Notify application */
1409 silc_client_command_free(cmd);
1412 /* CUMODE command. Changes client's mode on a channel. */
1414 SILC_CLIENT_CMD_FUNC(cumode)
1416 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1417 SilcClient client = cmd->client;
1418 SilcClientConnection conn = cmd->conn;
1419 SilcChannelEntry channel;
1420 SilcChannelUser chu;
1421 SilcClientEntry client_entry;
1422 SilcBuffer buffer, clidp, chidp, auth = NULL;
1423 unsigned char *name, *cp, modebuf[4];
1424 uint32 mode = 0, add, len;
1425 char *nickname = NULL;
1429 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1434 if (cmd->argc < 4) {
1435 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1436 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1441 if (cmd->argv[1][0] == '*') {
1442 if (!conn->current_channel) {
1443 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1444 "You are not on any channel");
1449 channel = conn->current_channel;
1451 name = cmd->argv[1];
1453 channel = silc_client_get_channel(cmd->client, conn, name);
1455 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1456 "You are on that channel");
1462 /* Parse the typed nickname. */
1463 if (client->internal->params->nickname_parse)
1464 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1466 nickname = strdup(cmd->argv[3]);
1468 /* Find client entry */
1469 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1470 cmd->argv[3], TRUE);
1471 if (!client_entry) {
1477 silc_free(nickname);
1479 /* Client entry not found, it was requested thus mark this to be
1481 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1483 silc_client_command_destructor,
1484 silc_client_command_cumode,
1485 silc_client_command_dup(cmd));
1490 /* Get the current mode */
1491 silc_list_start(channel->clients);
1492 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1493 if (chu->client == client_entry) {
1499 /* Are we adding or removing mode */
1500 if (cmd->argv[2][0] == '-')
1506 cp = cmd->argv[2] + 1;
1508 for (i = 0; i < len; i++) {
1512 mode |= SILC_CHANNEL_UMODE_CHANFO;
1513 mode |= SILC_CHANNEL_UMODE_CHANOP;
1515 mode = SILC_CHANNEL_UMODE_NONE;
1520 if (cmd->argc == 5) {
1521 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1522 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1523 cmd->client->private_key,
1528 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1529 cmd->argv[4], cmd->argv_lens[4]);
1532 mode |= SILC_CHANNEL_UMODE_CHANFO;
1534 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1539 mode |= SILC_CHANNEL_UMODE_CHANOP;
1541 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1550 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1551 SILC_PUT32_MSB(mode, modebuf);
1552 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1554 /* Send the command packet. We support sending only one mode at once
1555 that requires an argument. */
1556 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1558 1, chidp->data, chidp->len,
1560 3, clidp->data, clidp->len,
1561 4, auth ? auth->data : NULL,
1562 auth ? auth->len : 0);
1564 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1565 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1566 silc_buffer_free(buffer);
1567 silc_buffer_free(chidp);
1568 silc_buffer_free(clidp);
1570 silc_buffer_free(auth);
1572 /* Notify application */
1576 silc_free(nickname);
1577 silc_client_command_free(cmd);
1580 /* KICK command. Kicks a client out of channel. */
1582 SILC_CLIENT_CMD_FUNC(kick)
1584 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1585 SilcClient client = cmd->client;
1586 SilcClientConnection conn = cmd->conn;
1587 SilcIDCacheEntry id_cache = NULL;
1588 SilcChannelEntry channel;
1589 SilcBuffer buffer, idp, idp2;
1590 SilcClientEntry target;
1592 char *nickname = NULL;
1595 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1600 if (cmd->argc < 3) {
1601 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1602 "Usage: /KICK <channel> <nickname> [<comment>]");
1607 if (cmd->argv[1][0] == '*') {
1608 if (!conn->current_channel) {
1609 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1610 "You are not on any channel");
1614 name = conn->current_channel->channel_name;
1616 name = cmd->argv[1];
1619 if (!conn->current_channel) {
1620 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1621 "You are not on that channel");
1626 /* Get the Channel ID of the channel */
1627 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1628 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1629 "You are not on that channel");
1634 channel = (SilcChannelEntry)id_cache->context;
1636 /* Parse the typed nickname. */
1637 if (client->internal->params->nickname_parse)
1638 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1640 nickname = strdup(cmd->argv[2]);
1642 /* Get the target client */
1643 target = silc_idlist_get_client(cmd->client, conn, nickname,
1644 cmd->argv[2], FALSE);
1646 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1647 "No such client: %s", cmd->argv[2]);
1652 /* Send KICK command to the server */
1653 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1654 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1656 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1657 1, idp->data, idp->len,
1658 2, idp2->data, idp2->len);
1660 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1661 1, idp->data, idp->len,
1662 2, idp2->data, idp2->len,
1664 strlen(cmd->argv[3]));
1665 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1666 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1667 silc_buffer_free(buffer);
1668 silc_buffer_free(idp);
1669 silc_buffer_free(idp2);
1671 /* Notify application */
1675 silc_free(nickname);
1676 silc_client_command_free(cmd);
1679 static void silc_client_command_oper_send(unsigned char *data,
1680 uint32 data_len, void *context)
1682 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1683 SilcClientConnection conn = cmd->conn;
1684 SilcBuffer buffer, auth;
1686 if (cmd->argc >= 3) {
1687 /* Encode the public key authentication payload */
1688 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1689 cmd->client->private_key,
1694 /* Encode the password authentication payload */
1695 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1699 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1701 strlen(cmd->argv[1]),
1702 2, auth->data, auth->len);
1703 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1704 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1706 silc_buffer_free(buffer);
1707 silc_buffer_free(auth);
1709 /* Notify application */
1713 /* OPER command. Used to obtain server operator privileges. */
1715 SILC_CLIENT_CMD_FUNC(oper)
1717 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1718 SilcClientConnection conn = cmd->conn;
1721 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1726 if (cmd->argc < 2) {
1727 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1728 "Usage: /OPER <username> [-pubkey]");
1733 if (cmd->argc < 3) {
1734 /* Get passphrase */
1735 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1736 silc_client_command_oper_send,
1741 silc_client_command_oper_send(NULL, 0, context);
1744 silc_client_command_free(cmd);
1747 static void silc_client_command_silcoper_send(unsigned char *data,
1748 uint32 data_len, void *context)
1750 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1751 SilcClientConnection conn = cmd->conn;
1752 SilcBuffer buffer, auth;
1754 if (cmd->argc >= 3) {
1755 /* Encode the public key authentication payload */
1756 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1757 cmd->client->private_key,
1762 /* Encode the password authentication payload */
1763 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1767 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1769 strlen(cmd->argv[1]),
1770 2, auth->data, auth->len);
1771 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1772 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1774 silc_buffer_free(buffer);
1775 silc_buffer_free(auth);
1777 /* Notify application */
1781 /* SILCOPER command. Used to obtain router operator privileges. */
1783 SILC_CLIENT_CMD_FUNC(silcoper)
1785 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1786 SilcClientConnection conn = cmd->conn;
1789 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1794 if (cmd->argc < 2) {
1795 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1796 "Usage: /SILCOPER <username> [-pubkey]");
1801 if (cmd->argc < 3) {
1802 /* Get passphrase */
1803 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1804 silc_client_command_silcoper_send,
1809 silc_client_command_silcoper_send(NULL, 0, context);
1812 silc_client_command_free(cmd);
1815 /* CONNECT command. Connects the server to another server. */
1817 SILC_CLIENT_CMD_FUNC(connect)
1819 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1820 SilcClientConnection conn = cmd->conn;
1822 unsigned char port[4];
1826 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1831 if (cmd->argc < 2) {
1832 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1833 "Usage: /CONNECT <server> [<port>]");
1838 if (cmd->argc == 3) {
1839 tmp = atoi(cmd->argv[2]);
1840 SILC_PUT32_MSB(tmp, port);
1844 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1846 strlen(cmd->argv[1]),
1849 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1851 strlen(cmd->argv[1]));
1852 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1853 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1854 silc_buffer_free(buffer);
1856 /* Notify application */
1860 silc_client_command_free(cmd);
1863 /* Command BAN. This is used to manage the ban list of the channel. */
1865 SILC_CLIENT_CMD_FUNC(ban)
1867 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1868 SilcClientConnection conn = cmd->conn;
1869 SilcChannelEntry channel;
1870 SilcBuffer buffer, chidp;
1872 char *name, *ban = NULL;
1875 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1880 if (cmd->argc < 2) {
1881 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1882 "Usage: /BAN <channel> "
1883 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1888 if (cmd->argv[1][0] == '*') {
1889 if (!conn->current_channel) {
1890 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1891 "You are not on any channel");
1896 channel = conn->current_channel;
1898 name = cmd->argv[1];
1900 channel = silc_client_get_channel(cmd->client, conn, name);
1902 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1903 "You are on that channel");
1909 if (cmd->argc == 3) {
1910 if (cmd->argv[2][0] == '+')
1919 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1921 /* Send the command */
1923 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1924 1, chidp->data, chidp->len,
1925 type, ban, strlen(ban));
1927 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1928 1, chidp->data, chidp->len);
1930 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1931 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1932 silc_buffer_free(buffer);
1933 silc_buffer_free(chidp);
1935 /* Notify application */
1939 silc_client_command_free(cmd);
1942 /* CLOSE command. Close server connection to the remote server */
1944 SILC_CLIENT_CMD_FUNC(close)
1946 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1947 SilcClientConnection conn = cmd->conn;
1949 unsigned char port[4];
1953 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1958 if (cmd->argc < 2) {
1959 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1960 "Usage: /CLOSE <server> [<port>]");
1965 if (cmd->argc == 3) {
1966 tmp = atoi(cmd->argv[2]);
1967 SILC_PUT32_MSB(tmp, port);
1971 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1973 strlen(cmd->argv[1]),
1976 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1978 strlen(cmd->argv[1]));
1979 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1980 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1981 silc_buffer_free(buffer);
1983 /* Notify application */
1987 silc_client_command_free(cmd);
1990 /* SHUTDOWN command. Shutdowns the server. */
1992 SILC_CLIENT_CMD_FUNC(shutdown)
1994 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1997 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2002 /* Send the command */
2003 silc_client_command_send(cmd->client, cmd->conn,
2004 SILC_COMMAND_SHUTDOWN, 0, 0);
2006 /* Notify application */
2010 silc_client_command_free(cmd);
2013 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2015 SILC_CLIENT_CMD_FUNC(leave)
2017 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2018 SilcClientConnection conn = cmd->conn;
2019 SilcIDCacheEntry id_cache = NULL;
2020 SilcChannelEntry channel;
2021 SilcBuffer buffer, idp;
2025 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2030 if (cmd->argc != 2) {
2031 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2032 "Usage: /LEAVE <channel>");
2037 if (cmd->argv[1][0] == '*') {
2038 if (!conn->current_channel) {
2039 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2040 "You are not on any channel");
2044 name = conn->current_channel->channel_name;
2046 name = cmd->argv[1];
2049 /* Get the Channel ID of the channel */
2050 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2051 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2052 "You are not on that channel");
2057 channel = (SilcChannelEntry)id_cache->context;
2058 channel->on_channel = FALSE;
2060 /* Send LEAVE command to the server */
2061 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2062 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2063 1, idp->data, idp->len);
2064 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2065 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2066 silc_buffer_free(buffer);
2067 silc_buffer_free(idp);
2069 /* Notify application */
2072 if (conn->current_channel == channel)
2073 conn->current_channel = NULL;
2075 silc_client_del_channel(cmd->client, cmd->conn, channel);
2078 silc_client_command_free(cmd);
2081 /* Command USERS. Requests the USERS of the clients joined on requested
2084 SILC_CLIENT_CMD_FUNC(users)
2086 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2087 SilcClientConnection conn = cmd->conn;
2092 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2097 if (cmd->argc != 2) {
2098 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2099 "Usage: /USERS <channel>");
2104 if (cmd->argv[1][0] == '*') {
2105 if (!conn->current_channel) {
2106 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2107 "You are not on any channel");
2111 name = conn->current_channel->channel_name;
2113 name = cmd->argv[1];
2116 /* Send USERS command to the server */
2117 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2118 ++conn->cmd_ident, 1,
2119 2, name, strlen(name));
2120 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2121 NULL, 0, NULL, NULL, buffer->data,
2123 silc_buffer_free(buffer);
2125 /* Notify application */
2129 silc_client_command_free(cmd);
2132 /* Command GETKEY. Used to fetch remote client's public key. */
2134 SILC_CLIENT_CMD_FUNC(getkey)
2136 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2137 SilcClientConnection conn = cmd->conn;
2138 SilcClient client = cmd->client;
2139 SilcClientEntry client_entry = NULL;
2140 SilcServerEntry server_entry = NULL;
2141 char *nickname = NULL;
2142 SilcBuffer idp, buffer;
2145 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2150 if (cmd->argc < 2) {
2151 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2152 "Usage: /GETKEY <nickname or server name>");
2158 SilcClientCommandReplyContext reply =
2159 (SilcClientCommandReplyContext)context2;
2160 SilcCommandStatus status;
2161 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2162 SILC_GET16_MSB(status, tmp);
2164 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2165 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2166 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2167 silc_client_command_status_message(status));
2173 /* Parse the typed nickname. */
2174 if (client->internal->params->nickname_parse)
2175 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2177 nickname = strdup(cmd->argv[1]);
2179 /* Find client entry */
2180 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2182 if (!client_entry) {
2183 /* Check whether user requested server actually */
2184 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2186 if (!server_entry) {
2192 /* No. what ever user wants we don't have it, so resolve it. We
2193 will try to resolve both client and server, one of them is
2194 bound to be wrong. */
2196 /* This will send the IDENTIFY command */
2197 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2198 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2200 silc_client_command_destructor,
2201 silc_client_command_getkey,
2202 silc_client_command_dup(cmd));
2204 /* This sends the IDENTIFY command to resolve the server. */
2205 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
2206 silc_client_command_reply_identify_i, 0,
2208 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2210 2, cmd->argv[1], cmd->argv_lens[1]);
2211 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2212 conn->cmd_ident, NULL,
2213 silc_client_command_getkey,
2214 silc_client_command_dup(cmd));
2217 silc_free(nickname);
2221 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2223 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2226 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2227 1, idp->data, idp->len);
2228 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2229 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2230 silc_buffer_free(buffer);
2231 silc_buffer_free(idp);
2233 /* Notify application */
2237 silc_free(nickname);
2238 silc_client_command_free(cmd);
2241 /* Register a new command indicated by the `command' to the SILC client.
2242 The `name' is optional command name. If provided the command may be
2243 searched using the silc_client_command_find by that name. The
2244 `command_function' is the function to be called when the command is
2245 executed, and the `command_reply_function' is the function to be
2246 called after the server has sent reply back to the command.
2248 The `ident' is optional identifier for the command. If non-zero
2249 the `command_reply_function' for the command type `command' will be
2250 called only if the command reply sent by server includes the
2251 command identifier `ident'. Application usually does not need it
2252 and set it to zero value. */
2254 bool silc_client_command_register(SilcClient client,
2255 SilcCommand command,
2257 SilcCommandCb command_function,
2258 SilcCommandCb command_reply_function,
2262 SilcClientCommand cmd;
2264 cmd = silc_calloc(1, sizeof(*cmd));
2266 cmd->command = command_function;
2267 cmd->reply = command_reply_function;
2268 cmd->name = name ? strdup(name) : NULL;
2269 cmd->max_args = max_args;
2272 silc_list_add(client->internal->commands, cmd);
2277 /* Unregister a command indicated by the `command' with command function
2278 `command_function' and command reply function `command_reply_function'.
2279 Returns TRUE if the command was found and unregistered. */
2281 bool silc_client_command_unregister(SilcClient client,
2282 SilcCommand command,
2283 SilcCommandCb command_function,
2284 SilcCommandCb command_reply_function,
2287 SilcClientCommand cmd;
2289 silc_list_start(client->internal->commands);
2290 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2291 if (cmd->cmd == command && cmd->command == command_function &&
2292 cmd->reply == command_reply_function && cmd->ident == ident) {
2293 silc_list_del(client->internal->commands, cmd);
2294 silc_free(cmd->name);
2303 /* Register all default commands provided by the client library for the
2306 void silc_client_commands_register(SilcClient client)
2308 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2311 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2312 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2313 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2314 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2315 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2316 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2317 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2318 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2319 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2320 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2321 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
2322 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2323 SILC_CLIENT_CMD(oper, OPER, "OPER", 2);
2324 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2325 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2326 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2327 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2328 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2329 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2330 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2331 SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
2332 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
2333 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2334 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2335 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2336 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2339 /* Unregister all commands. */
2341 void silc_client_commands_unregister(SilcClient client)
2343 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2344 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2345 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2346 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2347 SILC_CLIENT_CMDU(list, LIST, "LIST");
2348 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2349 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2350 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2351 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2352 SILC_CLIENT_CMDU(info, INFO, "INFO");
2353 SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
2354 SILC_CLIENT_CMDU(ping, PING, "PING");
2355 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2356 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2357 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2358 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2359 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2360 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2361 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2362 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2363 SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
2364 SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
2365 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2366 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2367 SILC_CLIENT_CMDU(users, USERS, "USERS");
2368 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2370 silc_list_uninit(client->internal->commands);