5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
25 /* Client command list. */
26 SilcClientCommand silc_command_list[] =
28 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
30 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
31 SILC_CF_LAG | SILC_CF_REG, 3),
32 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
34 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
36 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
37 SILC_CLIENT_CMD(kill, KILL, "KILL",
38 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
39 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
40 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
41 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
42 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
43 SILC_CLIENT_CMD(oper, OPER, "OPER",
44 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
46 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
48 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
49 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
50 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
51 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
52 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
53 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
54 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
55 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
56 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
57 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
58 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
59 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
60 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
61 SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
63 { NULL, 0, NULL, 0, 0 },
66 #define SILC_NOT_CONNECTED(x, c) \
67 x->ops->say((x), (c), \
68 "You are not connected to a server, use /SERVER to connect");
70 /* Command operation that is called at the end of all commands.
72 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
73 cmd, TRUE, cmd->command->cmd)
75 /* Error to application. Usage: COMMAND_ERROR; */
76 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
77 cmd, FALSE, cmd->command->cmd)
79 /* Generic function to send any command. The arguments must be sent already
80 encoded into correct form and in correct order. */
82 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
83 SilcCommand command, unsigned short ident,
84 unsigned int argc, ...)
91 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
92 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
93 NULL, 0, NULL, NULL, packet->data,
95 silc_buffer_free(packet);
98 /* Finds and returns a pointer to the command list. Return NULL if the
99 command is not found. */
101 SilcClientCommand *silc_client_command_find(const char *name)
103 SilcClientCommand *cmd;
105 for (cmd = silc_command_list; cmd->name; cmd++) {
106 if (!strcmp(cmd->name, name))
113 /* Add new pending command to be executed when reply to a command has been
114 received. The `reply_cmd' is the command that will call the `callback'
115 with `context' when reply has been received. If `ident is non-zero
116 the `callback' will be executed when received reply with command
117 identifier `ident'. */
119 void silc_client_command_pending(SilcClientConnection conn,
120 SilcCommand reply_cmd,
121 unsigned short ident,
122 SilcClientPendingDestructor destructor,
123 SilcCommandCb callback,
126 SilcClientCommandPending *reply;
128 reply = silc_calloc(1, sizeof(*reply));
129 reply->reply_cmd = reply_cmd;
130 reply->ident = ident;
131 reply->context = context;
132 reply->callback = callback;
133 reply->destructor = destructor;
134 silc_dlist_add(conn->pending_commands, reply);
137 /* Deletes pending command by reply command type. */
139 void silc_client_command_pending_del(SilcClientConnection conn,
140 SilcCommand reply_cmd,
141 unsigned short ident)
143 SilcClientCommandPending *r;
145 silc_dlist_start(conn->pending_commands);
146 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
147 if (r->reply_cmd == reply_cmd && r->ident == ident) {
148 silc_dlist_del(conn->pending_commands, r);
154 /* Checks for pending commands and marks callbacks to be called from
155 the command reply function. Returns TRUE if there were pending command. */
157 int silc_client_command_pending_check(SilcClientConnection conn,
158 SilcClientCommandReplyContext ctx,
160 unsigned short ident)
162 SilcClientCommandPending *r;
164 silc_dlist_start(conn->pending_commands);
165 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
166 if (r->reply_cmd == command && r->ident == ident) {
167 ctx->context = r->context;
168 ctx->callback = r->callback;
169 ctx->destructor = r->destructor;
178 /* Allocate Command Context */
180 SilcClientCommandContext silc_client_command_alloc()
182 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
187 /* Free command context and its internals */
189 void silc_client_command_free(SilcClientCommandContext ctx)
192 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
194 if (ctx->users < 1) {
197 for (i = 0; i < ctx->argc; i++)
198 silc_free(ctx->argv[i]);
203 /* Duplicate Command Context by adding reference counter. The context won't
204 be free'd untill it hits zero. */
206 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
209 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
214 /* Pending command destructor. */
216 static void silc_client_command_destructor(void *context)
218 silc_client_command_free((SilcClientCommandContext)context);
221 /* silc_client_get_client completion callback */
222 void silc_client_command_completion(SilcClient client,
223 SilcClientConnection conn,
224 SilcClientEntry clients,
225 unsigned int clients_count,
231 /* Command WHOIS. This command is used to query information about
234 SILC_CLIENT_CMD_FUNC(whois)
236 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
237 SilcClientConnection conn = cmd->conn;
241 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
246 if (cmd->argc < 2 || cmd->argc > 3) {
247 cmd->client->ops->say(cmd->client, conn,
248 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
253 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
254 cmd->argc - 1, ++cmd->argv,
255 ++cmd->argv_lens, ++cmd->argv_types,
257 silc_client_packet_send(cmd->client, cmd->conn->sock,
258 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
259 buffer->data, buffer->len, TRUE);
260 silc_buffer_free(buffer);
265 /* Notify application */
269 silc_client_command_free(cmd);
272 /* Command WHOWAS. This command is used to query history information about
273 specific user that used to exist in the network. */
275 SILC_CLIENT_CMD_FUNC(whowas)
277 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
278 SilcClientConnection conn = cmd->conn;
282 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
287 if (cmd->argc < 2 || cmd->argc > 3) {
288 cmd->client->ops->say(cmd->client, conn,
289 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
294 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
295 cmd->argc - 1, ++cmd->argv,
296 ++cmd->argv_lens, ++cmd->argv_types,
298 silc_client_packet_send(cmd->client, cmd->conn->sock,
299 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
300 buffer->data, buffer->len, TRUE);
301 silc_buffer_free(buffer);
306 /* Notify application */
310 silc_client_command_free(cmd);
313 /* Command IDENTIFY. This command is used to query information about
314 specific user, especially ID's. */
316 SILC_CLIENT_CMD_FUNC(identify)
318 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
319 SilcClientConnection conn = cmd->conn;
323 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
328 if (cmd->argc < 2 || cmd->argc > 3) {
329 cmd->client->ops->say(cmd->client, conn,
330 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
335 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
336 cmd->argc - 1, ++cmd->argv,
337 ++cmd->argv_lens, ++cmd->argv_types,
339 silc_client_packet_send(cmd->client, cmd->conn->sock,
340 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
341 buffer->data, buffer->len, TRUE);
342 silc_buffer_free(buffer);
347 /* Notify application */
351 silc_client_command_free(cmd);
354 /* Command NICK. Shows current nickname/sets new nickname on current
357 SILC_CLIENT_CMD_FUNC(nick)
359 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
360 SilcClientConnection conn = cmd->conn;
364 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
369 if (!strcmp(conn->nickname, cmd->argv[1]))
372 /* Show current nickname */
375 cmd->client->ops->say(cmd->client, conn,
376 "Your nickname is %s on server %s",
377 conn->nickname, conn->remote_host);
379 cmd->client->ops->say(cmd->client, conn,
380 "Your nickname is %s", conn->nickname);
383 /* XXX Notify application */
388 /* Set new nickname */
389 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
390 cmd->argc - 1, ++cmd->argv,
391 ++cmd->argv_lens, ++cmd->argv_types,
392 ++cmd->conn->cmd_ident);
393 silc_client_packet_send(cmd->client, cmd->conn->sock,
394 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
395 buffer->data, buffer->len, TRUE);
396 silc_buffer_free(buffer);
401 silc_free(conn->nickname);
402 conn->nickname = strdup(cmd->argv[1]);
404 /* Notify application */
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_data_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 cmd->client->ops->say(cmd->client, conn,
479 "Usage: /TOPIC <channel> [<topic>]");
484 if (cmd->argv[1][0] == '*') {
485 if (!conn->current_channel) {
486 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
490 name = conn->current_channel->channel_name;
495 if (!conn->current_channel) {
496 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
501 /* Get the Channel ID of the channel */
502 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
503 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
508 channel = (SilcChannelEntry)id_cache->context;
510 /* Send TOPIC command to the server */
511 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
513 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
514 1, idp->data, idp->len,
516 strlen(cmd->argv[2]));
518 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
519 1, idp->data, idp->len,
521 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
522 0, NULL, NULL, buffer->data, buffer->len, TRUE);
523 silc_buffer_free(buffer);
524 silc_buffer_free(idp);
526 /* Notify application */
530 silc_client_command_free(cmd);
533 /* Command INVITE. Invites specific client to join a channel. This is
534 also used to mange the invite list of the channel. */
536 SILC_CLIENT_CMD_FUNC(invite)
538 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
539 SilcClient client = cmd->client;
540 SilcClientConnection conn = cmd->conn;
541 SilcClientEntry client_entry = NULL;
542 SilcChannelEntry channel;
543 SilcBuffer buffer, clidp, chidp;
544 unsigned int num = 0, type = 0;
545 char *nickname = NULL, *server = NULL, *name;
549 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
555 cmd->client->ops->say(cmd->client, conn,
556 "Usage: /INVITE <channel> [<nickname>[@server>]"
557 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
562 if (cmd->argv[1][0] == '*') {
563 if (!conn->current_channel) {
564 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
569 channel = conn->current_channel;
573 channel = silc_client_get_channel(cmd->client, conn, name);
575 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
581 /* Parse the typed nickname. */
582 if (cmd->argc == 3) {
583 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
584 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
585 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
590 /* Find client entry */
591 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_destructor,
609 silc_client_command_invite,
610 silc_client_command_dup(cmd));
615 cmd->client->ops->say(cmd->client, conn,
616 "Inviting %s to channel %s", cmd->argv[2],
617 channel->channel_name);
619 invite = cmd->argv[2];
621 if (cmd->argv[2][0] == '+')
628 /* Send the command */
629 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
631 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
632 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
633 ++conn->cmd_ident, 3,
634 1, chidp->data, chidp->len,
635 2, clidp->data, clidp->len,
636 type, invite, invite ?
638 silc_buffer_free(clidp);
640 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
641 ++conn->cmd_ident, 2,
642 1, chidp->data, chidp->len,
643 type, invite, invite ?
647 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
648 0, NULL, NULL, buffer->data, buffer->len, TRUE);
649 silc_buffer_free(buffer);
650 silc_buffer_free(chidp);
652 /* Notify application */
660 silc_client_command_free(cmd);
665 SilcClientConnection conn;
668 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
670 QuitInternal q = (QuitInternal)context;
672 /* Close connection */
673 q->client->ops->disconnect(q->client, q->conn);
674 silc_client_close_connection(q->client, q->conn->sock->user_data);
679 /* Command QUIT. Closes connection with current server. */
681 SILC_CLIENT_CMD_FUNC(quit)
683 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
688 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
694 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
695 &cmd->argv[1], &cmd->argv_lens[1],
696 &cmd->argv_types[1], 0);
698 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
699 NULL, NULL, NULL, 0);
700 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
702 buffer->data, buffer->len, TRUE);
703 silc_buffer_free(buffer);
705 q = silc_calloc(1, sizeof(*q));
706 q->client = cmd->client;
709 /* We quit the connection with little timeout */
710 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
711 silc_client_command_quit_cb, (void *)q,
712 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
714 /* Notify application */
718 silc_client_command_free(cmd);
721 /* Command KILL. Router operator can use this command to remove an client
722 fromthe SILC Network. */
724 SILC_CLIENT_CMD_FUNC(kill)
726 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
727 SilcClientConnection conn = cmd->conn;
728 SilcBuffer buffer, idp;
729 SilcClientEntry target;
730 unsigned int num = 0;
731 char *nickname = NULL, *server = NULL;
734 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
740 cmd->client->ops->say(cmd->client, conn,
741 "Usage: /KILL <nickname> [<comment>]");
746 /* Parse the typed nickname. */
747 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
748 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
753 /* Get the target client */
754 target = silc_idlist_get_client(cmd->client, conn, nickname,
766 /* Client entry not found, it was requested thus mark this to be
768 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
770 silc_client_command_destructor,
771 silc_client_command_kill,
772 silc_client_command_dup(cmd));
777 /* Send the KILL command to the server */
778 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
780 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
781 1, idp->data, idp->len);
783 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
784 1, idp->data, idp->len,
786 strlen(cmd->argv[2]));
787 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
788 0, NULL, NULL, buffer->data, buffer->len, TRUE);
789 silc_buffer_free(buffer);
790 silc_buffer_free(idp);
792 /* Notify application */
795 /* Remove the client entry to be killed */
796 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
798 if (target->nickname)
799 silc_free(target->nickname);
801 silc_free(target->server);
803 silc_free(target->id);
804 if (target->send_key)
805 silc_cipher_free(target->send_key);
806 if (target->receive_key)
807 silc_cipher_free(target->receive_key);
815 silc_client_command_free(cmd);
818 /* Command INFO. Request information about specific server. If specific
819 server is not provided the current server is used. */
821 SILC_CLIENT_CMD_FUNC(info)
823 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
824 SilcClientConnection conn = cmd->conn;
829 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
835 name = strdup(conn->remote_host);
837 name = strdup(cmd->argv[1]);
839 /* Send the command */
840 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
841 1, name, strlen(name));
842 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
843 0, NULL, NULL, buffer->data, buffer->len, TRUE);
844 silc_buffer_free(buffer);
846 /* Notify application */
850 silc_client_command_free(cmd);
853 /* Command PING. Sends ping to server. This is used to test the
854 communication channel. */
856 SILC_CLIENT_CMD_FUNC(ping)
858 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
859 SilcClientConnection conn = cmd->conn;
866 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
871 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
872 name = strdup(conn->remote_host);
874 /* Send the command */
875 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
876 1, conn->remote_id_data,
878 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
879 0, NULL, NULL, buffer->data, buffer->len, TRUE);
880 silc_buffer_free(buffer);
882 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
885 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
890 /* Start counting time */
891 for (i = 0; i < conn->ping_count; i++) {
892 if (conn->ping[i].dest_id == NULL) {
893 conn->ping[i].start_time = time(NULL);
894 conn->ping[i].dest_id = id;
895 conn->ping[i].dest_name = name;
900 if (i >= conn->ping_count) {
901 i = conn->ping_count;
902 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
903 conn->ping[i].start_time = time(NULL);
904 conn->ping[i].dest_id = id;
905 conn->ping[i].dest_name = name;
909 /* Notify application */
913 silc_client_command_free(cmd);
916 SILC_CLIENT_CMD_FUNC(notice)
920 /* Command JOIN. Joins to a channel. */
922 SILC_CLIENT_CMD_FUNC(join)
924 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
925 SilcClientConnection conn = cmd->conn;
926 SilcIDCacheEntry id_cache = NULL;
927 SilcBuffer buffer, idp;
930 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
936 /* Show channels currently joined to */
941 /* See if we have joined to the requested channel already */
942 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
944 cmd->client->ops->say(cmd->client, conn,
945 "You are talking to channel %s", cmd->argv[1]);
946 conn->current_channel = (SilcChannelEntry)id_cache->context;
948 cmd->client->screen->bottom_line->channel = cmd->argv[1];
949 silc_screen_print_bottom_line(cmd->client->screen, 0);
954 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
956 /* Send JOIN command to the server */
959 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
960 1, cmd->argv[1], cmd->argv_lens[1],
961 2, idp->data, idp->len);
962 else if (cmd->argc == 3)
965 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
966 1, cmd->argv[1], cmd->argv_lens[1],
967 2, idp->data, idp->len,
968 3, cmd->argv[2], cmd->argv_lens[2]);
971 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
972 1, cmd->argv[1], cmd->argv_lens[1],
973 2, idp->data, idp->len,
974 3, cmd->argv[2], cmd->argv_lens[2],
975 4, cmd->argv[3], cmd->argv_lens[3]);
977 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
978 0, NULL, NULL, buffer->data, buffer->len, TRUE);
979 silc_buffer_free(buffer);
980 silc_buffer_free(idp);
982 /* Notify application */
986 silc_client_command_free(cmd);
989 /* MOTD command. Requests motd from server. */
991 SILC_CLIENT_CMD_FUNC(motd)
993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
994 SilcClientConnection conn = cmd->conn;
998 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1003 if (cmd->argc < 1 || cmd->argc > 2) {
1004 cmd->client->ops->say(cmd->client, conn,
1005 "Usage: /MOTD [<server>]");
1010 /* Send TOPIC command to the server */
1012 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1013 1, conn->remote_host,
1014 strlen(conn->remote_host));
1016 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1019 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1020 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1021 silc_buffer_free(buffer);
1023 /* Notify application */
1027 silc_client_command_free(cmd);
1030 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1031 modes as client cannot set itself server/router operator privileges. */
1033 SILC_CLIENT_CMD_FUNC(umode)
1035 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1036 SilcClientConnection conn = cmd->conn;
1037 SilcBuffer buffer, idp;
1038 unsigned char *cp, modebuf[4];
1039 unsigned int mode, add, len;
1043 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1048 if (cmd->argc < 2) {
1049 cmd->client->ops->say(cmd->client, conn,
1050 "Usage: /UMODE +|-<modes>");
1055 mode = conn->local_entry->mode;
1057 /* Are we adding or removing mode */
1058 if (cmd->argv[1][0] == '-')
1064 cp = cmd->argv[1] + 1;
1066 for (i = 0; i < len; i++) {
1071 mode |= SILC_UMODE_SERVER_OPERATOR;
1072 mode |= SILC_UMODE_ROUTER_OPERATOR;
1074 mode = SILC_UMODE_NONE;
1079 mode |= SILC_UMODE_SERVER_OPERATOR;
1081 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1085 mode |= SILC_UMODE_ROUTER_OPERATOR;
1087 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1096 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1097 SILC_PUT32_MSB(mode, modebuf);
1099 /* Send the command packet. We support sending only one mode at once
1100 that requires an argument. */
1102 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1103 1, idp->data, idp->len,
1104 2, modebuf, sizeof(modebuf));
1105 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1106 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1107 silc_buffer_free(buffer);
1108 silc_buffer_free(idp);
1110 /* Notify application */
1114 silc_client_command_free(cmd);
1117 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1118 can be set several at once. Those modes that require argument must be set
1119 separately (unless set with modes that does not require arguments). */
1121 SILC_CLIENT_CMD_FUNC(cmode)
1123 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1124 SilcClientConnection conn = cmd->conn;
1125 SilcChannelEntry channel;
1126 SilcBuffer buffer, chidp;
1127 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1128 unsigned int mode, add, type, len, arg_len = 0;
1132 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1137 if (cmd->argc < 3) {
1138 cmd->client->ops->say(cmd->client, conn,
1139 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1144 if (cmd->argv[1][0] == '*') {
1145 if (!conn->current_channel) {
1146 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1151 channel = conn->current_channel;
1153 name = cmd->argv[1];
1155 channel = silc_client_get_channel(cmd->client, conn, name);
1157 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1163 mode = channel->mode;
1165 /* Are we adding or removing mode */
1166 if (cmd->argv[2][0] == '-')
1171 /* Argument type to be sent to server */
1175 cp = cmd->argv[2] + 1;
1177 for (i = 0; i < len; i++) {
1181 mode |= SILC_CHANNEL_MODE_PRIVATE;
1183 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1187 mode |= SILC_CHANNEL_MODE_SECRET;
1189 mode &= ~SILC_CHANNEL_MODE_SECRET;
1193 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1195 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1199 mode |= SILC_CHANNEL_MODE_INVITE;
1201 mode &= ~SILC_CHANNEL_MODE_INVITE;
1205 mode |= SILC_CHANNEL_MODE_TOPIC;
1207 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1212 mode |= SILC_CHANNEL_MODE_ULIMIT;
1214 ll = atoi(cmd->argv[3]);
1215 SILC_PUT32_MSB(ll, tmp);
1219 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1224 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1227 arg_len = cmd->argv_lens[3];
1229 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1234 mode |= SILC_CHANNEL_MODE_CIPHER;
1237 arg_len = cmd->argv_lens[3];
1239 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1249 if (type && cmd->argc < 3) {
1254 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1255 SILC_PUT32_MSB(mode, modebuf);
1257 /* Send the command packet. We support sending only one mode at once
1258 that requires an argument. */
1261 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1262 1, chidp->data, chidp->len,
1263 2, modebuf, sizeof(modebuf),
1264 type, arg, arg_len);
1267 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1268 1, chidp->data, chidp->len,
1269 2, modebuf, sizeof(modebuf));
1272 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1273 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1274 silc_buffer_free(buffer);
1275 silc_buffer_free(chidp);
1277 /* Notify application */
1281 silc_client_command_free(cmd);
1284 /* CUMODE command. Changes client's mode on a channel. */
1286 SILC_CLIENT_CMD_FUNC(cumode)
1288 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1289 SilcClientConnection conn = cmd->conn;
1290 SilcChannelEntry channel;
1291 SilcChannelUser chu;
1292 SilcClientEntry client_entry;
1293 SilcBuffer buffer, clidp, chidp;
1294 unsigned char *name, *cp, modebuf[4];
1295 unsigned int mode = 0, add, len;
1296 char *nickname = NULL, *server = NULL;
1297 unsigned int num = 0;
1301 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1306 if (cmd->argc < 4) {
1307 cmd->client->ops->say(cmd->client, conn,
1308 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1313 if (cmd->argv[1][0] == '*') {
1314 if (!conn->current_channel) {
1315 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1320 channel = conn->current_channel;
1322 name = cmd->argv[1];
1324 channel = silc_client_get_channel(cmd->client, conn, name);
1326 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1332 /* Parse the typed nickname. */
1333 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1334 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1339 /* Find client entry */
1340 client_entry = silc_idlist_get_client(cmd->client, conn,
1341 nickname, server, num, TRUE);
1342 if (!client_entry) {
1348 /* Client entry not found, it was requested thus mark this to be
1350 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1352 silc_client_command_destructor,
1353 silc_client_command_cumode,
1354 silc_client_command_dup(cmd));
1359 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1360 if (chu->client == client_entry) {
1366 /* Are we adding or removing mode */
1367 if (cmd->argv[2][0] == '-')
1373 cp = cmd->argv[2] + 1;
1375 for (i = 0; i < len; i++) {
1379 mode |= SILC_CHANNEL_UMODE_CHANFO;
1380 mode |= SILC_CHANNEL_UMODE_CHANOP;
1382 mode = SILC_CHANNEL_UMODE_NONE;
1387 mode |= SILC_CHANNEL_UMODE_CHANFO;
1389 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1393 mode |= SILC_CHANNEL_UMODE_CHANOP;
1395 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1404 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1405 SILC_PUT32_MSB(mode, modebuf);
1406 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1408 /* Send the command packet. We support sending only one mode at once
1409 that requires an argument. */
1410 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
1411 1, chidp->data, chidp->len,
1413 3, clidp->data, clidp->len);
1415 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1416 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1417 silc_buffer_free(buffer);
1418 silc_buffer_free(chidp);
1419 silc_buffer_free(clidp);
1421 /* Notify application */
1426 silc_free(nickname);
1429 silc_client_command_free(cmd);
1432 /* KICK command. Kicks a client out of channel. */
1434 SILC_CLIENT_CMD_FUNC(kick)
1436 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1437 SilcClientConnection conn = cmd->conn;
1438 SilcIDCacheEntry id_cache = NULL;
1439 SilcChannelEntry channel;
1440 SilcBuffer buffer, idp, idp2;
1441 SilcClientEntry target;
1443 unsigned int num = 0;
1444 char *nickname = NULL, *server = NULL;
1447 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1452 if (cmd->argc < 3) {
1453 cmd->client->ops->say(cmd->client, conn,
1454 "Usage: /KICK <channel> <nickname> [<comment>]");
1459 if (cmd->argv[1][0] == '*') {
1460 if (!conn->current_channel) {
1461 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1465 name = conn->current_channel->channel_name;
1467 name = cmd->argv[1];
1470 if (!conn->current_channel) {
1471 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1476 /* Get the Channel ID of the channel */
1477 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1478 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1483 channel = (SilcChannelEntry)id_cache->context;
1485 /* Parse the typed nickname. */
1486 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1487 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1492 /* Get the target client */
1493 target = silc_idlist_get_client(cmd->client, conn, nickname,
1494 server, num, FALSE);
1496 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1502 /* Send KICK command to the server */
1503 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1504 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1506 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1507 1, idp->data, idp->len,
1508 2, idp2->data, idp2->len);
1510 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1511 1, idp->data, idp->len,
1512 2, idp2->data, idp2->len,
1514 strlen(cmd->argv[3]));
1515 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1516 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1517 silc_buffer_free(buffer);
1518 silc_buffer_free(idp);
1519 silc_buffer_free(idp2);
1521 /* Notify application */
1526 silc_free(nickname);
1529 silc_client_command_free(cmd);
1532 /* OPER command. Used to obtain server operator privileges. */
1534 SILC_CLIENT_CMD_FUNC(oper)
1536 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1537 SilcClientConnection conn = cmd->conn;
1539 unsigned char *auth_data;
1543 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1548 if (cmd->argc < 2) {
1549 cmd->client->ops->say(cmd->client, conn,
1550 "Usage: /OPER <username> [<public key>]");
1555 if (cmd->argc == 3) {
1556 /* XXX Get public key */
1561 /* Get passphrase */
1563 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1569 /* Encode the authentication payload */
1570 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1571 auth_data, strlen(auth_data));
1574 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1576 strlen(cmd->argv[1]),
1577 2, auth->data, auth->len);
1578 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1579 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1581 silc_buffer_free(buffer);
1582 silc_buffer_free(auth);
1583 memset(auth_data, 0, strlen(auth_data));
1584 silc_free(auth_data);
1586 /* Notify application */
1590 silc_client_command_free(cmd);
1593 /* SILCOPER command. Used to obtain router operator privileges. */
1595 SILC_CLIENT_CMD_FUNC(silcoper)
1597 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1598 SilcClientConnection conn = cmd->conn;
1600 unsigned char *auth_data;
1604 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1609 if (cmd->argc < 2) {
1610 cmd->client->ops->say(cmd->client, conn,
1611 "Usage: /SILCOPER <username> [<public key>]");
1616 if (cmd->argc == 3) {
1617 /* XXX Get public key */
1622 /* Get passphrase */
1624 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1630 /* Encode the authentication payload */
1631 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1632 auth_data, strlen(auth_data));
1635 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1637 strlen(cmd->argv[1]),
1638 2, auth->data, auth->len);
1639 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1640 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1642 silc_buffer_free(buffer);
1643 silc_buffer_free(auth);
1644 memset(auth_data, 0, strlen(auth_data));
1645 silc_free(auth_data);
1647 /* Notify application */
1651 silc_client_command_free(cmd);
1654 /* CONNECT command. Connects the server to another server. */
1656 SILC_CLIENT_CMD_FUNC(connect)
1658 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1659 SilcClientConnection conn = cmd->conn;
1661 unsigned char port[4];
1665 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1670 if (cmd->argc < 2) {
1671 cmd->client->ops->say(cmd->client, conn,
1672 "Usage: /CONNECT <server> [<port>]");
1677 if (cmd->argc == 3) {
1678 tmp = atoi(cmd->argv[2]);
1679 SILC_PUT32_MSB(tmp, port);
1683 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1685 strlen(cmd->argv[1]),
1688 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1690 strlen(cmd->argv[1]));
1691 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1692 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1693 silc_buffer_free(buffer);
1695 /* Notify application */
1699 silc_client_command_free(cmd);
1702 SILC_CLIENT_CMD_FUNC(restart)
1706 /* CLOSE command. Close server connection to the remote server */
1708 SILC_CLIENT_CMD_FUNC(close)
1710 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1711 SilcClientConnection conn = cmd->conn;
1713 unsigned char port[4];
1717 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1722 if (cmd->argc < 2) {
1723 cmd->client->ops->say(cmd->client, conn,
1724 "Usage: /CLOSE <server> [<port>]");
1729 if (cmd->argc == 3) {
1730 tmp = atoi(cmd->argv[2]);
1731 SILC_PUT32_MSB(tmp, port);
1735 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1737 strlen(cmd->argv[1]),
1740 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1742 strlen(cmd->argv[1]));
1743 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1744 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1745 silc_buffer_free(buffer);
1747 /* Notify application */
1751 silc_client_command_free(cmd);
1754 /* SHUTDOWN command. Shutdowns the server. */
1756 SILC_CLIENT_CMD_FUNC(shutdown)
1758 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1761 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1766 /* Send the command */
1767 silc_client_send_command(cmd->client, cmd->conn,
1768 SILC_COMMAND_SHUTDOWN, 0, 0);
1770 /* Notify application */
1774 silc_client_command_free(cmd);
1777 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1779 SILC_CLIENT_CMD_FUNC(leave)
1781 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1782 SilcClientConnection conn = cmd->conn;
1783 SilcIDCacheEntry id_cache = NULL;
1784 SilcChannelEntry channel;
1785 SilcBuffer buffer, idp;
1789 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1794 if (cmd->argc != 2) {
1795 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1800 if (cmd->argv[1][0] == '*') {
1801 if (!conn->current_channel) {
1802 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1806 name = conn->current_channel->channel_name;
1808 name = cmd->argv[1];
1811 if (!conn->current_channel) {
1812 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1817 /* Get the Channel ID of the channel */
1818 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1819 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1824 channel = (SilcChannelEntry)id_cache->context;
1826 /* Send LEAVE command to the server */
1827 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1828 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1829 1, idp->data, idp->len);
1830 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1831 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1832 silc_buffer_free(buffer);
1833 silc_buffer_free(idp);
1835 /* We won't talk anymore on this channel */
1836 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1838 conn->current_channel = NULL;
1840 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1841 silc_free(channel->channel_name);
1842 silc_free(channel->id);
1843 silc_free(channel->key);
1844 silc_cipher_free(channel->channel_key);
1847 /* Notify application */
1851 silc_client_command_free(cmd);
1854 /* Command USERS. Requests the USERS of the clients joined on requested
1857 SILC_CLIENT_CMD_FUNC(users)
1859 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1860 SilcClientConnection conn = cmd->conn;
1861 SilcIDCacheEntry id_cache = NULL;
1862 SilcChannelEntry channel;
1863 SilcBuffer buffer, idp;
1864 char *name, *line = NULL;
1865 unsigned int line_len = 0;
1868 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1873 if (cmd->argc != 2) {
1874 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1879 if (cmd->argv[1][0] == '*') {
1880 if (!conn->current_channel) {
1881 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1885 name = conn->current_channel->channel_name;
1887 name = cmd->argv[1];
1890 if (!conn->current_channel) {
1891 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1896 /* Get the Channel ID of the channel */
1897 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1898 /* XXX should resolve the channel ID; LIST command */
1899 cmd->client->ops->say(cmd->client, conn,
1900 "You are not on that channel", name);
1905 channel = (SilcChannelEntry)id_cache->context;
1907 if (!cmd->pending) {
1908 /* Send USERS command to the server */
1909 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1910 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1911 ++conn->cmd_ident, 1,
1912 1, idp->data, idp->len);
1913 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1914 NULL, 0, NULL, NULL, buffer->data,
1916 silc_buffer_free(buffer);
1917 silc_buffer_free(idp);
1919 /* Register pending callback which will recall this command callback with
1920 same context and reprocesses the command. When reprocessing we actually
1921 display the information on the screen. */
1922 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1923 silc_client_command_destructor,
1924 silc_client_command_users,
1925 silc_client_command_dup(cmd));
1926 cmd->pending = TRUE;
1931 /* Pending command. Now we've resolved the information from server and
1932 we are ready to display the information on screen. */
1934 SilcChannelUser chu;
1936 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1937 channel->channel_name);
1939 line = silc_calloc(4096, sizeof(*line));
1941 silc_list_start(channel->clients);
1942 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1943 SilcClientEntry e = chu->client;
1944 char *m, tmp[80], len1;
1946 memset(line, 0, sizeof(line_len));
1948 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1950 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1951 line = silc_calloc(line_len, sizeof(*line));
1954 memset(tmp, 0, sizeof(tmp));
1955 m = silc_client_chumode_char(chu->mode);
1957 strncat(line, " ", 1);
1958 strncat(line, e->nickname, strlen(e->nickname));
1959 strncat(line, e->server ? "@" : "", 1);
1963 len1 = strlen(e->server);
1964 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1966 len1 = strlen(line);
1968 memset(&line[29], 0, len1 - 29);
1970 for (i = 0; i < 30 - len1 - 1; i++)
1974 strncat(line, " H", 3);
1975 strcat(tmp, m ? m : "");
1976 strncat(line, tmp, strlen(tmp));
1978 if (strlen(tmp) < 5)
1979 for (i = 0; i < 5 - strlen(tmp); i++)
1982 strcat(line, e->username ? e->username : "");
1984 cmd->client->ops->say(cmd->client, conn, "%s", line);
1994 /* Notify application */
1998 silc_client_command_free(cmd);
2001 /* Command BAN. This is used to manage the ban list of the channel. */
2003 SILC_CLIENT_CMD_FUNC(ban)
2005 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2006 SilcClientConnection conn = cmd->conn;
2007 SilcChannelEntry channel;
2008 SilcBuffer buffer, chidp;
2010 char *name, *ban = NULL;
2013 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2018 if (cmd->argc < 2) {
2019 cmd->client->ops->say(cmd->client, conn,
2020 "Usage: /BAN <channel> "
2021 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2026 if (cmd->argv[1][0] == '*') {
2027 if (!conn->current_channel) {
2028 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2033 channel = conn->current_channel;
2035 name = cmd->argv[1];
2037 channel = silc_client_get_channel(cmd->client, conn, name);
2039 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2045 if (cmd->argc == 3) {
2046 if (cmd->argv[2][0] == '+')
2055 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2057 /* Send the command */
2059 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
2060 1, chidp->data, chidp->len,
2061 type, ban, strlen(ban));
2063 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
2064 1, chidp->data, chidp->len);
2066 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2067 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2068 silc_buffer_free(buffer);
2069 silc_buffer_free(chidp);
2071 /* Notify application */
2075 silc_client_command_free(cmd);