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 "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, use /SERVER to connect");
29 /* Command operation that is called at the end of all commands.
31 #define COMMAND cmd->client->internal->ops->command(cmd->client, cmd->conn, \
32 cmd, TRUE, cmd->command->cmd)
34 /* Error to application. Usage: COMMAND_ERROR; */
35 #define COMMAND_ERROR cmd->client->internal->ops->command(cmd->client, \
36 cmd->conn, cmd, FALSE, cmd->command->cmd)
38 #define SAY cmd->client->internal->ops->say
40 /* Generic function to send any command. The arguments must be sent already
41 encoded into correct form and in correct order. */
43 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
44 SilcCommand command, SilcUInt16 ident,
52 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
53 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
54 NULL, 0, NULL, NULL, packet->data,
56 silc_buffer_free(packet);
59 /* Finds and returns a pointer to the command list. Return NULL if the
60 command is not found. */
62 SilcClientCommand silc_client_command_find(SilcClient client,
65 SilcClientCommand cmd;
67 silc_list_start(client->internal->commands);
68 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
69 if (cmd->name && !strcmp(cmd->name, name))
76 /* Calls the command (executes it). Application can call this after
77 it has allocated the SilcClientCommandContext with the function
78 silc_client_command_alloc and found the command from the client
79 library by calling silc_client_command_find. This will execute
82 void silc_client_command_call(SilcClientCommand command,
83 SilcClientCommandContext cmd)
85 (*command->command)((void *)cmd, NULL);
88 /* Add new pending command to be executed when reply to a command has been
89 received. The `reply_cmd' is the command that will call the `callback'
90 with `context' when reply has been received. If `ident is non-zero
91 the `callback' will be executed when received reply with command
92 identifier `ident'. */
94 void silc_client_command_pending(SilcClientConnection conn,
95 SilcCommand reply_cmd,
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 silc_dlist_add(conn->pending_commands, reply);
110 /* Deletes pending command by reply command type. */
112 void silc_client_command_pending_del(SilcClientConnection conn,
113 SilcCommand reply_cmd,
116 SilcClientCommandPending *r;
118 silc_dlist_start(conn->pending_commands);
119 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
120 if (r->reply_cmd == reply_cmd && r->ident == ident) {
121 silc_dlist_del(conn->pending_commands, r);
127 /* Checks for pending commands and marks callbacks to be called from
128 the command reply function. Returns TRUE if there were pending command. */
130 int silc_client_command_pending_check(SilcClientConnection conn,
131 SilcClientCommandReplyContext ctx,
135 SilcClientCommandPending *r;
137 silc_dlist_start(conn->pending_commands);
138 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
139 if (r->reply_cmd == command && r->ident == ident) {
140 ctx->context = r->context;
141 ctx->callback = r->callback;
150 /* Allocate Command Context */
152 SilcClientCommandContext silc_client_command_alloc(void)
154 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
159 /* Free command context and its internals */
161 void silc_client_command_free(SilcClientCommandContext ctx)
164 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
166 if (ctx->users < 1) {
169 for (i = 0; i < ctx->argc; i++)
170 silc_free(ctx->argv[i]);
171 silc_free(ctx->argv_lens);
172 silc_free(ctx->argv_types);
177 /* Duplicate Command Context by adding reference counter. The context won't
178 be free'd untill it hits zero. */
180 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
183 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
188 /* Command WHOIS. This command is used to query information about
191 SILC_CLIENT_CMD_FUNC(whois)
193 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
194 SilcClientConnection conn = cmd->conn;
198 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
203 /* Given without arguments fetches client's own information */
205 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
206 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
208 1, 3, buffer->data, buffer->len);
209 silc_buffer_free(buffer);
213 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
214 cmd->argc - 1, ++cmd->argv,
215 ++cmd->argv_lens, ++cmd->argv_types,
217 silc_client_packet_send(cmd->client, cmd->conn->sock,
218 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
219 buffer->data, buffer->len, TRUE);
220 silc_buffer_free(buffer);
225 /* Notify application */
229 silc_client_command_free(cmd);
232 /* Command WHOWAS. This command is used to query history information about
233 specific user that used to exist in the network. */
235 SILC_CLIENT_CMD_FUNC(whowas)
237 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
238 SilcClientConnection conn = cmd->conn;
242 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
247 if (cmd->argc < 2 || cmd->argc > 3) {
248 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
249 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
254 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
255 cmd->argc - 1, ++cmd->argv,
256 ++cmd->argv_lens, ++cmd->argv_types,
258 silc_client_packet_send(cmd->client, cmd->conn->sock,
259 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
260 buffer->data, buffer->len, TRUE);
261 silc_buffer_free(buffer);
266 /* Notify application */
270 silc_client_command_free(cmd);
273 /* Command IDENTIFY. This command is used to query information about
274 specific user, especially ID's.
276 NOTE: This command is used only internally by the client library
277 and application MUST NOT call this command directly. */
279 SILC_CLIENT_CMD_FUNC(identify)
281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
282 SilcClientConnection conn = cmd->conn;
286 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
290 if (cmd->argc < 2 || cmd->argc > 3)
294 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
295 ++conn->cmd_ident, 1,
299 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
300 ++conn->cmd_ident, 2,
306 silc_client_packet_send(cmd->client, cmd->conn->sock,
307 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
308 buffer->data, buffer->len, TRUE);
309 silc_buffer_free(buffer);
312 silc_client_command_free(cmd);
315 /* Pending callbcak that will be called after the NICK command was
316 replied by the server. This sets the nickname if there were no
319 SILC_CLIENT_CMD_FUNC(nick_change)
321 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
322 SilcClientConnection conn = cmd->conn;
323 SilcClientCommandReplyContext reply =
324 (SilcClientCommandReplyContext)context2;
325 SilcCommandStatus status = silc_command_get_status(reply->payload);
327 if (status == SILC_STATUS_OK) {
328 /* Set the nickname */
329 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
331 silc_free(conn->nickname);
332 conn->nickname = strdup(cmd->argv[1]);
333 conn->local_entry->nickname = conn->nickname;
334 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
335 silc_idcache_add(conn->client_cache, strdup(cmd->argv[1]),
336 conn->local_entry->id, conn->local_entry, 0, NULL);
342 silc_client_command_free(cmd);
345 /* Command NICK. Shows current nickname/sets new nickname on current
348 SILC_CLIENT_CMD_FUNC(nick)
350 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
351 SilcClientConnection conn = cmd->conn;
355 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
361 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
362 "Usage: /NICK <nickname>");
367 if (!strcmp(conn->nickname, cmd->argv[1]))
370 /* Show current nickname */
373 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
374 "Your nickname is %s on server %s",
375 conn->nickname, conn->remote_host);
377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
378 "Your nickname is %s", conn->nickname);
385 if (cmd->argv_lens[1] > 128)
386 cmd->argv_lens[1] = 128;
388 /* Send the NICK command */
389 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
393 ++cmd->conn->cmd_ident);
394 silc_client_packet_send(cmd->client, cmd->conn->sock,
395 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
396 buffer->data, buffer->len, TRUE);
397 silc_buffer_free(buffer);
399 /* Register pending callback that will actually set the new nickname
400 if there were no errors returned by the server. */
401 silc_client_command_pending(conn, SILC_COMMAND_NICK,
402 cmd->conn->cmd_ident,
403 silc_client_command_nick_change,
404 silc_client_command_dup(cmd));
408 silc_client_command_free(cmd);
411 /* Command LIST. Lists channels on the current server. */
413 SILC_CLIENT_CMD_FUNC(list)
415 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
416 SilcClientConnection conn = cmd->conn;
417 SilcIDCacheEntry id_cache = NULL;
418 SilcChannelEntry channel;
419 SilcBuffer buffer, idp = NULL;
423 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
428 if (cmd->argc == 2) {
431 /* Get the Channel ID of the channel */
432 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
433 channel = (SilcChannelEntry)id_cache->context;
434 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
439 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
440 ++conn->cmd_ident, 0);
442 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
443 ++conn->cmd_ident, 1,
444 1, idp->data, idp->len);
446 silc_client_packet_send(cmd->client, cmd->conn->sock,
447 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
448 buffer->data, buffer->len, TRUE);
449 silc_buffer_free(buffer);
451 silc_buffer_free(idp);
453 /* Notify application */
457 silc_client_command_free(cmd);
460 /* Command TOPIC. Sets/shows topic on a channel. */
462 SILC_CLIENT_CMD_FUNC(topic)
464 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
465 SilcClientConnection conn = cmd->conn;
466 SilcIDCacheEntry id_cache = NULL;
467 SilcChannelEntry channel;
468 SilcBuffer buffer, idp;
472 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
477 if (cmd->argc < 2 || cmd->argc > 3) {
478 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
479 "Usage: /TOPIC <channel> [<topic>]");
484 if (cmd->argv[1][0] == '*') {
485 if (!conn->current_channel) {
486 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
487 "You are not on any channel");
491 name = conn->current_channel->channel_name;
496 if (!conn->current_channel) {
497 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
498 "You are not on that channel");
503 /* Get the Channel ID of the channel */
504 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
505 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
506 "You are not on that channel");
511 channel = (SilcChannelEntry)id_cache->context;
513 /* Send TOPIC command to the server */
514 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
516 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
517 ++conn->cmd_ident, 2,
518 1, idp->data, idp->len,
520 strlen(cmd->argv[2]));
522 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
523 ++conn->cmd_ident, 1,
524 1, idp->data, idp->len);
525 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
526 0, NULL, NULL, buffer->data, buffer->len, TRUE);
527 silc_buffer_free(buffer);
528 silc_buffer_free(idp);
530 /* Notify application */
534 silc_client_command_free(cmd);
537 /* Command INVITE. Invites specific client to join a channel. This is
538 also used to mange the invite list of the channel. */
540 SILC_CLIENT_CMD_FUNC(invite)
542 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
543 SilcClient client = cmd->client;
544 SilcClientConnection conn = cmd->conn;
545 SilcClientEntry client_entry = NULL;
546 SilcChannelEntry channel;
547 SilcBuffer buffer, clidp, chidp;
549 char *nickname = NULL, *name;
553 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
559 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
560 "Usage: /INVITE <channel> [<nickname>[@server>]"
561 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
566 if (cmd->argv[1][0] == '*') {
567 if (!conn->current_channel) {
568 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
569 "You are not on any channel");
574 channel = conn->current_channel;
578 channel = silc_client_get_channel(cmd->client, conn, name);
580 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
581 "You are on that channel");
587 /* Parse the typed nickname. */
588 if (cmd->argc == 3) {
589 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
590 if (client->internal->params->nickname_parse)
591 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
593 nickname = strdup(cmd->argv[2]);
595 /* Find client entry */
596 client_entry = silc_idlist_get_client(client, conn, nickname,
604 /* Client entry not found, it was requested thus mark this to be
606 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
608 silc_client_command_invite,
609 silc_client_command_dup(cmd));
614 invite = cmd->argv[2];
616 if (cmd->argv[2][0] == '+')
623 /* Send the command */
624 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
626 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
627 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
628 ++conn->cmd_ident, 3,
629 1, chidp->data, chidp->len,
630 2, clidp->data, clidp->len,
631 type, invite, invite ?
633 silc_buffer_free(clidp);
635 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
636 ++conn->cmd_ident, 2,
637 1, chidp->data, chidp->len,
638 type, invite, invite ?
642 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
643 0, NULL, NULL, buffer->data, buffer->len, TRUE);
644 silc_buffer_free(buffer);
645 silc_buffer_free(chidp);
647 /* Notify application */
652 silc_client_command_free(cmd);
657 SilcClientConnection conn;
660 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
662 QuitInternal q = (QuitInternal)context;
664 /* Close connection */
665 q->client->internal->ops->disconnect(q->client, q->conn);
666 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
671 /* Command QUIT. Closes connection with current server. */
673 SILC_CLIENT_CMD_FUNC(quit)
675 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
680 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
686 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
687 &cmd->argv[1], &cmd->argv_lens[1],
688 &cmd->argv_types[1], 0);
690 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
691 NULL, NULL, NULL, 0);
692 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
694 buffer->data, buffer->len, TRUE);
695 silc_buffer_free(buffer);
697 q = silc_calloc(1, sizeof(*q));
698 q->client = cmd->client;
701 /* Sleep for a while */
704 /* We quit the connection with little timeout */
705 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
706 silc_client_command_quit_cb, (void *)q,
707 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
709 /* Notify application */
713 silc_client_command_free(cmd);
716 /* Timeout callback to remove the killed client from cache */
718 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
720 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
721 SilcClient client = cmd->client;
722 SilcClientConnection conn = cmd->conn;
723 SilcClientEntry target;
724 char *nickname = NULL;
726 /* Parse the typed nickname. */
727 if (client->internal->params->nickname_parse)
728 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
730 nickname = strdup(cmd->argv[1]);
732 /* Get the target client */
733 target = silc_idlist_get_client(cmd->client, conn, nickname,
734 cmd->argv[1], FALSE);
736 /* Remove the client from all channels and free it */
737 silc_client_del_client(client, conn, target);
740 silc_client_command_free(cmd);
743 /* Kill command's pending command callback to actually remove the killed
744 client from our local cache. */
746 SILC_CLIENT_CMD_FUNC(kill_remove)
748 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
749 SilcClientCommandReplyContext reply =
750 (SilcClientCommandReplyContext)context2;
751 SilcCommandStatus status = silc_command_get_status(reply->payload);
753 if (status == SILC_STATUS_OK) {
754 /* Remove with timeout */
755 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
756 silc_client_command_kill_remove_later, context,
757 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
761 silc_client_command_free(cmd);
764 /* Command KILL. Router operator can use this command to remove an client
765 fromthe SILC Network. */
767 SILC_CLIENT_CMD_FUNC(kill)
769 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
770 SilcClient client = cmd->client;
771 SilcClientConnection conn = cmd->conn;
772 SilcBuffer buffer, idp;
773 SilcClientEntry target;
774 char *nickname = NULL;
777 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
783 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
784 "Usage: /KILL <nickname> [<comment>]");
789 /* Parse the typed nickname. */
790 if (client->internal->params->nickname_parse)
791 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
793 nickname = strdup(cmd->argv[1]);
795 /* Get the target client */
796 target = silc_idlist_get_client(cmd->client, conn, nickname,
804 /* Client entry not found, it was requested thus mark this to be
806 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
808 silc_client_command_kill,
809 silc_client_command_dup(cmd));
814 /* Send the KILL command to the server */
815 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
817 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
818 ++conn->cmd_ident, 1,
819 1, idp->data, idp->len);
821 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
822 ++conn->cmd_ident, 2,
823 1, idp->data, idp->len,
825 strlen(cmd->argv[2]));
826 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
827 0, NULL, NULL, buffer->data, buffer->len, TRUE);
828 silc_buffer_free(buffer);
829 silc_buffer_free(idp);
831 /* Notify application */
834 /* Register a pending callback that will actually remove the killed
835 client from our cache. */
836 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
837 silc_client_command_kill_remove,
838 silc_client_command_dup(cmd));
842 silc_client_command_free(cmd);
845 /* Command INFO. Request information about specific server. If specific
846 server is not provided the current server is used. */
848 SILC_CLIENT_CMD_FUNC(info)
850 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
851 SilcClientConnection conn = cmd->conn;
856 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
862 name = strdup(cmd->argv[1]);
864 /* Send the command */
866 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
867 1, name, strlen(name));
869 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
870 NULL, NULL, NULL, 0);
871 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
872 0, NULL, NULL, buffer->data, buffer->len, TRUE);
873 silc_buffer_free(buffer);
877 /* Notify application */
881 silc_client_command_free(cmd);
884 /* Command PING. Sends ping to server. This is used to test the
885 communication channel. */
887 SILC_CLIENT_CMD_FUNC(ping)
889 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
890 SilcClientConnection conn = cmd->conn;
896 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
901 /* Send the command */
902 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
903 1, conn->remote_id_data,
904 silc_id_get_len(conn->remote_id,
906 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
907 0, NULL, NULL, buffer->data, buffer->len, TRUE);
908 silc_buffer_free(buffer);
910 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
913 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
918 /* Start counting time */
919 for (i = 0; i < conn->ping_count; i++) {
920 if (conn->ping[i].dest_id == NULL) {
921 conn->ping[i].start_time = time(NULL);
922 conn->ping[i].dest_id = id;
923 conn->ping[i].dest_name = strdup(conn->remote_host);
927 if (i >= conn->ping_count) {
928 i = conn->ping_count;
929 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
930 conn->ping[i].start_time = time(NULL);
931 conn->ping[i].dest_id = id;
932 conn->ping[i].dest_name = strdup(conn->remote_host);
936 /* Notify application */
940 silc_client_command_free(cmd);
943 /* Command JOIN. Joins to a channel. */
945 SILC_CLIENT_CMD_FUNC(join)
947 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
948 SilcClientConnection conn = cmd->conn;
949 SilcChannelEntry channel;
950 SilcBuffer buffer, idp, auth = NULL;
951 char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
955 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
965 /* See if we have joined to the requested channel already */
966 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
967 if (channel && silc_client_on_channel(channel, conn->local_entry))
970 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
972 if (cmd->argv_lens[1] > 256)
973 cmd->argv_lens[1] = 256;
977 for (i = 2; i < cmd->argc; i++) {
978 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
979 cipher = cmd->argv[i + 1];
981 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
982 hmac = cmd->argv[i + 1];
984 } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
985 if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
986 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
987 cmd->client->private_key,
988 cmd->client->rng, conn->hash,
992 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
994 cmd->argv_lens[i + 1]);
998 passphrase = cmd->argv[i];
1002 /* Send JOIN command to the server */
1004 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1005 1, name, strlen(name),
1006 2, idp->data, idp->len,
1008 passphrase ? strlen(passphrase) : 0,
1009 4, cipher, cipher ? strlen(cipher) : 0,
1010 5, hmac, hmac ? strlen(hmac) : 0,
1011 6, auth ? auth->data : NULL,
1012 auth ? auth->len : 0);
1013 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1014 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1015 silc_buffer_free(buffer);
1016 silc_buffer_free(idp);
1018 silc_buffer_free(auth);
1020 /* Notify application */
1024 silc_client_command_free(cmd);
1027 /* MOTD command. Requests motd from server. */
1029 SILC_CLIENT_CMD_FUNC(motd)
1031 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1032 SilcClientConnection conn = cmd->conn;
1036 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1041 if (cmd->argc < 1 || cmd->argc > 2) {
1042 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1043 "Usage: /MOTD [<server>]");
1048 /* Send TOPIC command to the server */
1050 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1051 1, conn->remote_host,
1052 strlen(conn->remote_host));
1054 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1057 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1058 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1059 silc_buffer_free(buffer);
1061 /* Notify application */
1065 silc_client_command_free(cmd);
1068 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1069 modes as client cannot set itself server/router operator privileges. */
1071 SILC_CLIENT_CMD_FUNC(umode)
1073 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1074 SilcClientConnection conn = cmd->conn;
1075 SilcBuffer buffer, idp;
1076 unsigned char *cp, modebuf[4];
1077 SilcUInt32 mode, add, len;
1081 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1086 if (cmd->argc < 2) {
1087 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1088 "Usage: /UMODE +|-<modes>");
1093 mode = conn->local_entry->mode;
1095 /* Are we adding or removing mode */
1096 if (cmd->argv[1][0] == '-')
1102 cp = cmd->argv[1] + 1;
1104 for (i = 0; i < len; i++) {
1109 mode |= SILC_UMODE_SERVER_OPERATOR;
1110 mode |= SILC_UMODE_ROUTER_OPERATOR;
1112 mode = SILC_UMODE_NONE;
1117 mode |= SILC_UMODE_SERVER_OPERATOR;
1119 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1123 mode |= SILC_UMODE_ROUTER_OPERATOR;
1125 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1129 mode |= SILC_UMODE_GONE;
1131 mode &= ~SILC_UMODE_GONE;
1140 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1141 SILC_PUT32_MSB(mode, modebuf);
1143 /* Send the command packet. We support sending only one mode at once
1144 that requires an argument. */
1146 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1147 1, idp->data, idp->len,
1148 2, modebuf, sizeof(modebuf));
1149 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1150 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1151 silc_buffer_free(buffer);
1152 silc_buffer_free(idp);
1154 /* Notify application */
1158 silc_client_command_free(cmd);
1161 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1162 can be set several at once. Those modes that require argument must be set
1163 separately (unless set with modes that does not require arguments). */
1165 SILC_CLIENT_CMD_FUNC(cmode)
1167 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1168 SilcClientConnection conn = cmd->conn;
1169 SilcChannelEntry channel;
1170 SilcBuffer buffer, chidp, auth = NULL;
1171 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1172 SilcUInt32 mode, add, type, len, arg_len = 0;
1176 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1181 if (cmd->argc < 3) {
1182 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1183 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1188 if (cmd->argv[1][0] == '*') {
1189 if (!conn->current_channel) {
1190 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1191 "You are not on any channel");
1196 channel = conn->current_channel;
1198 name = cmd->argv[1];
1200 channel = silc_client_get_channel(cmd->client, conn, name);
1202 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1203 "You are on that channel");
1209 mode = channel->mode;
1211 /* Are we adding or removing mode */
1212 if (cmd->argv[2][0] == '-')
1217 /* Argument type to be sent to server */
1221 cp = cmd->argv[2] + 1;
1223 for (i = 0; i < len; i++) {
1227 mode |= SILC_CHANNEL_MODE_PRIVATE;
1229 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1233 mode |= SILC_CHANNEL_MODE_SECRET;
1235 mode &= ~SILC_CHANNEL_MODE_SECRET;
1239 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1241 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1245 mode |= SILC_CHANNEL_MODE_INVITE;
1247 mode &= ~SILC_CHANNEL_MODE_INVITE;
1251 mode |= SILC_CHANNEL_MODE_TOPIC;
1253 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1257 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1259 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1263 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1265 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1270 mode |= SILC_CHANNEL_MODE_ULIMIT;
1272 if (cmd->argc < 4) {
1273 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1274 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1278 ll = atoi(cmd->argv[3]);
1279 SILC_PUT32_MSB(ll, tmp);
1283 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1288 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1290 if (cmd->argc < 4) {
1291 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1292 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1297 arg_len = cmd->argv_lens[3];
1299 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1304 mode |= SILC_CHANNEL_MODE_CIPHER;
1306 if (cmd->argc < 4) {
1307 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1308 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1313 arg_len = cmd->argv_lens[3];
1315 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1320 mode |= SILC_CHANNEL_MODE_HMAC;
1322 if (cmd->argc < 4) {
1323 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1324 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1329 arg_len = cmd->argv_lens[3];
1331 mode &= ~SILC_CHANNEL_MODE_HMAC;
1336 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1339 if (cmd->argc < 4) {
1340 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1341 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1346 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1347 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1348 cmd->client->private_key,
1354 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1355 cmd->argv[3], cmd->argv_lens[3]);
1359 arg_len = auth->len;
1361 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1371 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1372 SILC_PUT32_MSB(mode, modebuf);
1374 /* Send the command packet. We support sending only one mode at once
1375 that requires an argument. */
1378 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1379 1, chidp->data, chidp->len,
1380 2, modebuf, sizeof(modebuf),
1381 type, arg, arg_len);
1384 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1385 1, chidp->data, chidp->len,
1386 2, modebuf, sizeof(modebuf));
1389 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1390 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1391 silc_buffer_free(buffer);
1392 silc_buffer_free(chidp);
1394 silc_buffer_free(auth);
1396 /* Notify application */
1400 silc_client_command_free(cmd);
1403 /* CUMODE command. Changes client's mode on a channel. */
1405 SILC_CLIENT_CMD_FUNC(cumode)
1407 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1408 SilcClient client = cmd->client;
1409 SilcClientConnection conn = cmd->conn;
1410 SilcChannelEntry channel;
1411 SilcChannelUser chu;
1412 SilcClientEntry client_entry;
1413 SilcBuffer buffer, clidp, chidp, auth = NULL;
1414 unsigned char *name, *cp, modebuf[4];
1415 SilcUInt32 mode = 0, add, len;
1416 char *nickname = NULL;
1420 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1425 if (cmd->argc < 4) {
1426 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1427 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1432 if (cmd->argv[1][0] == '*') {
1433 if (!conn->current_channel) {
1434 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1435 "You are not on any channel");
1440 channel = conn->current_channel;
1442 name = cmd->argv[1];
1444 channel = silc_client_get_channel(cmd->client, conn, name);
1446 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1447 "You are on that channel");
1453 /* Parse the typed nickname. */
1454 if (client->internal->params->nickname_parse)
1455 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1457 nickname = strdup(cmd->argv[3]);
1459 /* Find client entry */
1460 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1461 cmd->argv[3], TRUE);
1462 if (!client_entry) {
1468 /* Client entry not found, it was requested thus mark this to be
1470 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1472 silc_client_command_cumode,
1473 silc_client_command_dup(cmd));
1478 /* Get the current mode */
1479 chu = silc_client_on_channel(channel, client_entry);
1483 /* Are we adding or removing mode */
1484 if (cmd->argv[2][0] == '-')
1490 cp = cmd->argv[2] + 1;
1492 for (i = 0; i < len; i++) {
1496 mode |= SILC_CHANNEL_UMODE_CHANFO;
1497 mode |= SILC_CHANNEL_UMODE_CHANOP;
1499 mode = SILC_CHANNEL_UMODE_NONE;
1504 if (cmd->argc == 5) {
1505 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1506 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1507 cmd->client->private_key,
1513 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1514 cmd->argv[4], cmd->argv_lens[4]);
1517 mode |= SILC_CHANNEL_UMODE_CHANFO;
1519 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1524 mode |= SILC_CHANNEL_UMODE_CHANOP;
1526 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1535 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1536 SILC_PUT32_MSB(mode, modebuf);
1537 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1539 /* Send the command packet. We support sending only one mode at once
1540 that requires an argument. */
1541 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1543 1, chidp->data, chidp->len,
1545 3, clidp->data, clidp->len,
1546 4, auth ? auth->data : NULL,
1547 auth ? auth->len : 0);
1549 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1550 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1551 silc_buffer_free(buffer);
1552 silc_buffer_free(chidp);
1553 silc_buffer_free(clidp);
1555 silc_buffer_free(auth);
1557 /* Notify application */
1561 silc_free(nickname);
1562 silc_client_command_free(cmd);
1565 /* KICK command. Kicks a client out of channel. */
1567 SILC_CLIENT_CMD_FUNC(kick)
1569 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1570 SilcClient client = cmd->client;
1571 SilcClientConnection conn = cmd->conn;
1572 SilcIDCacheEntry id_cache = NULL;
1573 SilcChannelEntry channel;
1574 SilcBuffer buffer, idp, idp2;
1575 SilcClientEntry target;
1577 char *nickname = NULL;
1580 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1585 if (cmd->argc < 3) {
1586 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1587 "Usage: /KICK <channel> <nickname> [<comment>]");
1592 if (cmd->argv[1][0] == '*') {
1593 if (!conn->current_channel) {
1594 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1595 "You are not on any channel");
1599 name = conn->current_channel->channel_name;
1601 name = cmd->argv[1];
1604 if (!conn->current_channel) {
1605 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1606 "You are not on that channel");
1611 /* Get the Channel ID of the channel */
1612 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1613 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1614 "You are not on that channel");
1619 channel = (SilcChannelEntry)id_cache->context;
1621 /* Parse the typed nickname. */
1622 if (client->internal->params->nickname_parse)
1623 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1625 nickname = strdup(cmd->argv[2]);
1627 /* Get the target client */
1628 target = silc_idlist_get_client(cmd->client, conn, nickname,
1629 cmd->argv[2], FALSE);
1631 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1632 "No such client: %s", cmd->argv[2]);
1637 /* Send KICK command to the server */
1638 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1639 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1641 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1642 1, idp->data, idp->len,
1643 2, idp2->data, idp2->len);
1645 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1646 1, idp->data, idp->len,
1647 2, idp2->data, idp2->len,
1649 strlen(cmd->argv[3]));
1650 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1651 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1652 silc_buffer_free(buffer);
1653 silc_buffer_free(idp);
1654 silc_buffer_free(idp2);
1656 /* Notify application */
1660 silc_free(nickname);
1661 silc_client_command_free(cmd);
1664 static void silc_client_command_oper_send(unsigned char *data,
1665 SilcUInt32 data_len, void *context)
1667 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1668 SilcClientConnection conn = cmd->conn;
1669 SilcBuffer buffer, auth;
1671 if (cmd->argc >= 3) {
1672 /* Encode the public key authentication payload */
1673 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1674 cmd->client->private_key,
1675 cmd->client->rng, conn->hash,
1679 /* Encode the password authentication payload */
1680 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1684 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1686 strlen(cmd->argv[1]),
1687 2, auth->data, auth->len);
1688 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1689 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1691 silc_buffer_free(buffer);
1692 silc_buffer_free(auth);
1694 /* Notify application */
1698 /* OPER command. Used to obtain server operator privileges. */
1700 SILC_CLIENT_CMD_FUNC(oper)
1702 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1703 SilcClientConnection conn = cmd->conn;
1706 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1711 if (cmd->argc < 2) {
1712 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1713 "Usage: /OPER <username> [-pubkey]");
1718 if (cmd->argc < 3) {
1719 /* Get passphrase */
1720 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1721 silc_client_command_oper_send,
1726 silc_client_command_oper_send(NULL, 0, context);
1729 silc_client_command_free(cmd);
1732 static void silc_client_command_silcoper_send(unsigned char *data,
1733 SilcUInt32 data_len, void *context)
1735 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1736 SilcClientConnection conn = cmd->conn;
1737 SilcBuffer buffer, auth;
1739 if (cmd->argc >= 3) {
1740 /* Encode the public key authentication payload */
1741 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1742 cmd->client->private_key,
1743 cmd->client->rng, conn->hash,
1747 /* Encode the password authentication payload */
1748 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1752 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1754 strlen(cmd->argv[1]),
1755 2, auth->data, auth->len);
1756 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1757 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1759 silc_buffer_free(buffer);
1760 silc_buffer_free(auth);
1762 /* Notify application */
1766 /* SILCOPER command. Used to obtain router operator privileges. */
1768 SILC_CLIENT_CMD_FUNC(silcoper)
1770 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1771 SilcClientConnection conn = cmd->conn;
1774 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1779 if (cmd->argc < 2) {
1780 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1781 "Usage: /SILCOPER <username> [-pubkey]");
1786 if (cmd->argc < 3) {
1787 /* Get passphrase */
1788 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1789 silc_client_command_silcoper_send,
1794 silc_client_command_silcoper_send(NULL, 0, context);
1797 silc_client_command_free(cmd);
1800 /* Command BAN. This is used to manage the ban list of the channel. */
1802 SILC_CLIENT_CMD_FUNC(ban)
1804 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1805 SilcClientConnection conn = cmd->conn;
1806 SilcChannelEntry channel;
1807 SilcBuffer buffer, chidp;
1809 char *name, *ban = NULL;
1812 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1817 if (cmd->argc < 2) {
1818 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1819 "Usage: /BAN <channel> "
1820 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1825 if (cmd->argv[1][0] == '*') {
1826 if (!conn->current_channel) {
1827 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1828 "You are not on any channel");
1833 channel = conn->current_channel;
1835 name = cmd->argv[1];
1837 channel = silc_client_get_channel(cmd->client, conn, name);
1839 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1840 "You are on that channel");
1846 if (cmd->argc == 3) {
1847 if (cmd->argv[2][0] == '+')
1856 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1858 /* Send the command */
1860 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1861 1, chidp->data, chidp->len,
1862 type, ban, strlen(ban));
1864 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1865 1, chidp->data, chidp->len);
1867 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1868 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1869 silc_buffer_free(buffer);
1870 silc_buffer_free(chidp);
1872 /* Notify application */
1876 silc_client_command_free(cmd);
1879 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1881 SILC_CLIENT_CMD_FUNC(leave)
1883 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1884 SilcClientConnection conn = cmd->conn;
1885 SilcChannelEntry channel;
1886 SilcChannelUser chu;
1887 SilcBuffer buffer, idp;
1891 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1896 if (cmd->argc != 2) {
1897 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1898 "Usage: /LEAVE <channel>");
1903 if (cmd->argv[1][0] == '*') {
1904 if (!conn->current_channel) {
1905 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1906 "You are not on any channel");
1910 name = conn->current_channel->channel_name;
1912 name = cmd->argv[1];
1915 /* Get the channel entry */
1916 channel = silc_client_get_channel(cmd->client, conn, name);
1918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1919 "You are not on that channel");
1924 /* Remove us from channel */
1925 chu = silc_client_on_channel(channel, conn->local_entry);
1927 silc_hash_table_del(chu->client->channels, chu->channel);
1928 silc_hash_table_del(chu->channel->user_list, chu->client);
1932 /* Send LEAVE command to the server */
1933 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1934 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1935 1, idp->data, idp->len);
1936 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1937 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1938 silc_buffer_free(buffer);
1939 silc_buffer_free(idp);
1941 /* Notify application */
1944 if (conn->current_channel == channel)
1945 conn->current_channel = NULL;
1947 silc_client_del_channel(cmd->client, cmd->conn, channel);
1950 silc_client_command_free(cmd);
1953 /* Command USERS. Requests the USERS of the clients joined on requested
1956 SILC_CLIENT_CMD_FUNC(users)
1958 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1959 SilcClientConnection conn = cmd->conn;
1964 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1969 if (cmd->argc != 2) {
1970 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1971 "Usage: /USERS <channel>");
1976 if (cmd->argv[1][0] == '*') {
1977 if (!conn->current_channel) {
1978 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1979 "You are not on any channel");
1983 name = conn->current_channel->channel_name;
1985 name = cmd->argv[1];
1988 /* Send USERS command to the server */
1989 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1990 ++conn->cmd_ident, 1,
1991 2, name, strlen(name));
1992 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1993 NULL, 0, NULL, NULL, buffer->data,
1995 silc_buffer_free(buffer);
1997 /* Notify application */
2001 silc_client_command_free(cmd);
2004 /* Command GETKEY. Used to fetch remote client's public key. */
2006 SILC_CLIENT_CMD_FUNC(getkey)
2008 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2009 SilcClientConnection conn = cmd->conn;
2010 SilcClient client = cmd->client;
2011 SilcClientEntry client_entry = NULL;
2012 SilcServerEntry server_entry = NULL;
2013 char *nickname = NULL;
2014 SilcBuffer idp, buffer;
2016 SILC_LOG_DEBUG(("Start"));
2019 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2024 if (cmd->argc < 2) {
2025 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2026 "Usage: /GETKEY <nickname or server name>");
2031 /* Parse the typed nickname. */
2032 if (client->internal->params->nickname_parse)
2033 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2035 nickname = strdup(cmd->argv[1]);
2037 /* Find client entry */
2038 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2040 if (!client_entry) {
2041 /* Check whether user requested server actually */
2042 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2044 if (!server_entry) {
2045 /* No. what ever user wants we don't have it, so resolve it. We
2046 will first try to resolve the client, and if that fails then
2047 we'll try to resolve the server. */
2049 if (!cmd->pending) {
2050 /* This will send the IDENTIFY command for nickname */
2051 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2052 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2054 silc_client_command_getkey,
2055 silc_client_command_dup(cmd));
2059 SilcClientCommandReplyContext reply =
2060 (SilcClientCommandReplyContext)context2;
2061 SilcCommandStatus status = silc_command_get_status(reply->payload);
2063 /* If nickname was not found, then resolve the server. */
2064 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
2065 /* This sends the IDENTIFY command to resolve the server. */
2066 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2068 silc_client_command_reply_identify_i, 0,
2070 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2072 2, cmd->argv[1], cmd->argv_lens[1]);
2073 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2075 silc_client_command_getkey,
2076 silc_client_command_dup(cmd));
2080 /* If server was not found, then we've resolved both nickname and
2081 server and did not find anybody. */
2082 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2083 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2084 silc_client_command_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2085 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2086 silc_client_command_status_message(status));
2096 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2098 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2101 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2102 1, idp->data, idp->len);
2103 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2104 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2105 silc_buffer_free(buffer);
2106 silc_buffer_free(idp);
2108 /* Notify application */
2112 silc_free(nickname);
2113 silc_client_command_free(cmd);
2116 /* Register a new command indicated by the `command' to the SILC client.
2117 The `name' is optional command name. If provided the command may be
2118 searched using the silc_client_command_find by that name. The
2119 `command_function' is the function to be called when the command is
2120 executed, and the `command_reply_function' is the function to be
2121 called after the server has sent reply back to the command.
2123 The `ident' is optional identifier for the command. If non-zero
2124 the `command_reply_function' for the command type `command' will be
2125 called only if the command reply sent by server includes the
2126 command identifier `ident'. Application usually does not need it
2127 and set it to zero value. */
2129 bool silc_client_command_register(SilcClient client,
2130 SilcCommand command,
2132 SilcCommandCb command_function,
2133 SilcCommandCb command_reply_function,
2137 SilcClientCommand cmd;
2139 cmd = silc_calloc(1, sizeof(*cmd));
2141 cmd->command = command_function;
2142 cmd->reply = command_reply_function;
2143 cmd->name = name ? strdup(name) : NULL;
2144 cmd->max_args = max_args;
2147 silc_list_add(client->internal->commands, cmd);
2152 /* Unregister a command indicated by the `command' with command function
2153 `command_function' and command reply function `command_reply_function'.
2154 Returns TRUE if the command was found and unregistered. */
2156 bool silc_client_command_unregister(SilcClient client,
2157 SilcCommand command,
2158 SilcCommandCb command_function,
2159 SilcCommandCb command_reply_function,
2162 SilcClientCommand cmd;
2164 silc_list_start(client->internal->commands);
2165 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2166 if (cmd->cmd == command && cmd->command == command_function &&
2167 cmd->reply == command_reply_function && cmd->ident == ident) {
2168 silc_list_del(client->internal->commands, cmd);
2169 silc_free(cmd->name);
2178 /* Private range commands, specific to this implementation (and compatible
2179 with SILC Server). */
2181 /* CONNECT command. Connects the server to another server. */
2183 SILC_CLIENT_CMD_FUNC(connect)
2185 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2186 SilcClientConnection conn = cmd->conn;
2188 unsigned char port[4];
2192 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2197 if (cmd->argc < 2) {
2198 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2199 "Usage: /CONNECT <server> [<port>]");
2204 if (cmd->argc == 3) {
2205 tmp = atoi(cmd->argv[2]);
2206 SILC_PUT32_MSB(tmp, port);
2210 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2212 strlen(cmd->argv[1]),
2215 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2217 strlen(cmd->argv[1]));
2218 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2219 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2220 silc_buffer_free(buffer);
2222 /* Notify application */
2226 silc_client_command_free(cmd);
2230 /* CLOSE command. Close server connection to the remote server */
2232 SILC_CLIENT_CMD_FUNC(close)
2234 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2235 SilcClientConnection conn = cmd->conn;
2237 unsigned char port[4];
2241 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2246 if (cmd->argc < 2) {
2247 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2248 "Usage: /CLOSE <server> [<port>]");
2253 if (cmd->argc == 3) {
2254 tmp = atoi(cmd->argv[2]);
2255 SILC_PUT32_MSB(tmp, port);
2259 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2261 strlen(cmd->argv[1]),
2264 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2266 strlen(cmd->argv[1]));
2267 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2268 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2269 silc_buffer_free(buffer);
2271 /* Notify application */
2275 silc_client_command_free(cmd);
2278 /* SHUTDOWN command. Shutdowns the server. */
2280 SILC_CLIENT_CMD_FUNC(shutdown)
2282 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2285 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2290 /* Send the command */
2291 silc_client_command_send(cmd->client, cmd->conn,
2292 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2294 /* Notify application */
2298 silc_client_command_free(cmd);
2301 /* Register all default commands provided by the client library for the
2304 void silc_client_commands_register(SilcClient client)
2306 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2309 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2310 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2311 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2312 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2313 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2314 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2315 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2316 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2317 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2318 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2319 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2320 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2321 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2322 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2323 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2324 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2325 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2326 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2327 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2328 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2329 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2330 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2331 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2333 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2334 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2335 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
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(ping, PING, "PING");
2353 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2354 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2355 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2356 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2357 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2358 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2359 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2360 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2361 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2362 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2363 SILC_CLIENT_CMDU(users, USERS, "USERS");
2364 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2366 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2367 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2368 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");