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 */
800 silc_client_command_free(cmd);
803 /* Command INFO. Request information about specific server. If specific
804 server is not provided the current server is used. */
806 SILC_CLIENT_CMD_FUNC(info)
808 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
809 SilcClientConnection conn = cmd->conn;
814 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
820 name = strdup(conn->remote_host);
822 name = strdup(cmd->argv[1]);
824 /* Send the command */
825 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
826 1, name, strlen(name));
827 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
828 0, NULL, NULL, buffer->data, buffer->len, TRUE);
829 silc_buffer_free(buffer);
831 /* Notify application */
835 silc_client_command_free(cmd);
838 /* Command PING. Sends ping to server. This is used to test the
839 communication channel. */
841 SILC_CLIENT_CMD_FUNC(ping)
843 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
844 SilcClientConnection conn = cmd->conn;
851 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
856 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
857 name = strdup(conn->remote_host);
859 /* Send the command */
860 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
861 1, conn->remote_id_data,
863 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
864 0, NULL, NULL, buffer->data, buffer->len, TRUE);
865 silc_buffer_free(buffer);
867 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
870 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
875 /* Start counting time */
876 for (i = 0; i < conn->ping_count; i++) {
877 if (conn->ping[i].dest_id == NULL) {
878 conn->ping[i].start_time = time(NULL);
879 conn->ping[i].dest_id = id;
880 conn->ping[i].dest_name = name;
885 if (i >= conn->ping_count) {
886 i = conn->ping_count;
887 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
888 conn->ping[i].start_time = time(NULL);
889 conn->ping[i].dest_id = id;
890 conn->ping[i].dest_name = name;
894 /* Notify application */
898 silc_client_command_free(cmd);
901 SILC_CLIENT_CMD_FUNC(notice)
905 /* Command JOIN. Joins to a channel. */
907 SILC_CLIENT_CMD_FUNC(join)
909 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
910 SilcClientConnection conn = cmd->conn;
911 SilcIDCacheEntry id_cache = NULL;
912 SilcBuffer buffer, idp;
915 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
921 /* Show channels currently joined to */
926 /* See if we have joined to the requested channel already */
927 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
929 cmd->client->ops->say(cmd->client, conn,
930 "You are talking to channel %s", cmd->argv[1]);
931 conn->current_channel = (SilcChannelEntry)id_cache->context;
933 cmd->client->screen->bottom_line->channel = cmd->argv[1];
934 silc_screen_print_bottom_line(cmd->client->screen, 0);
939 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
941 /* Send JOIN command to the server */
944 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
945 1, cmd->argv[1], cmd->argv_lens[1],
946 2, idp->data, idp->len);
947 else if (cmd->argc == 3)
950 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
951 1, cmd->argv[1], cmd->argv_lens[1],
952 2, idp->data, idp->len,
953 3, cmd->argv[2], cmd->argv_lens[2]);
956 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
957 1, cmd->argv[1], cmd->argv_lens[1],
958 2, idp->data, idp->len,
959 3, cmd->argv[2], cmd->argv_lens[2],
960 4, cmd->argv[3], cmd->argv_lens[3]);
962 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
963 0, NULL, NULL, buffer->data, buffer->len, TRUE);
964 silc_buffer_free(buffer);
965 silc_buffer_free(idp);
967 /* Notify application */
971 silc_client_command_free(cmd);
974 /* MOTD command. Requests motd from server. */
976 SILC_CLIENT_CMD_FUNC(motd)
978 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
979 SilcClientConnection conn = cmd->conn;
983 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
988 if (cmd->argc < 1 || cmd->argc > 2) {
989 cmd->client->ops->say(cmd->client, conn,
990 "Usage: /MOTD [<server>]");
995 /* Send TOPIC command to the server */
997 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
998 1, conn->remote_host,
999 strlen(conn->remote_host));
1001 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1004 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1005 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1006 silc_buffer_free(buffer);
1008 /* Notify application */
1012 silc_client_command_free(cmd);
1015 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1016 modes as client cannot set itself server/router operator privileges. */
1018 SILC_CLIENT_CMD_FUNC(umode)
1020 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1021 SilcClientConnection conn = cmd->conn;
1022 SilcBuffer buffer, idp;
1023 unsigned char *cp, modebuf[4];
1024 unsigned int mode, add, len;
1028 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1033 if (cmd->argc < 2) {
1034 cmd->client->ops->say(cmd->client, conn,
1035 "Usage: /UMODE +|-<modes>");
1040 mode = conn->local_entry->mode;
1042 /* Are we adding or removing mode */
1043 if (cmd->argv[1][0] == '-')
1049 cp = cmd->argv[1] + 1;
1051 for (i = 0; i < len; i++) {
1056 mode |= SILC_UMODE_SERVER_OPERATOR;
1057 mode |= SILC_UMODE_ROUTER_OPERATOR;
1059 mode = SILC_UMODE_NONE;
1064 mode |= SILC_UMODE_SERVER_OPERATOR;
1066 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1070 mode |= SILC_UMODE_ROUTER_OPERATOR;
1072 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1081 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1082 SILC_PUT32_MSB(mode, modebuf);
1084 /* Send the command packet. We support sending only one mode at once
1085 that requires an argument. */
1087 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1088 1, idp->data, idp->len,
1089 2, modebuf, sizeof(modebuf));
1090 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1091 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1092 silc_buffer_free(buffer);
1093 silc_buffer_free(idp);
1095 /* Notify application */
1099 silc_client_command_free(cmd);
1102 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1103 can be set several at once. Those modes that require argument must be set
1104 separately (unless set with modes that does not require arguments). */
1106 SILC_CLIENT_CMD_FUNC(cmode)
1108 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1109 SilcClientConnection conn = cmd->conn;
1110 SilcChannelEntry channel;
1111 SilcBuffer buffer, chidp;
1112 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1113 unsigned int mode, add, type, len, arg_len = 0;
1117 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1122 if (cmd->argc < 3) {
1123 cmd->client->ops->say(cmd->client, conn,
1124 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1129 if (cmd->argv[1][0] == '*') {
1130 if (!conn->current_channel) {
1131 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1136 channel = conn->current_channel;
1138 name = cmd->argv[1];
1140 channel = silc_client_get_channel(cmd->client, conn, name);
1142 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1148 mode = channel->mode;
1150 /* Are we adding or removing mode */
1151 if (cmd->argv[2][0] == '-')
1156 /* Argument type to be sent to server */
1160 cp = cmd->argv[2] + 1;
1162 for (i = 0; i < len; i++) {
1166 mode |= SILC_CHANNEL_MODE_PRIVATE;
1168 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1172 mode |= SILC_CHANNEL_MODE_SECRET;
1174 mode &= ~SILC_CHANNEL_MODE_SECRET;
1178 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1180 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1184 mode |= SILC_CHANNEL_MODE_INVITE;
1186 mode &= ~SILC_CHANNEL_MODE_INVITE;
1190 mode |= SILC_CHANNEL_MODE_TOPIC;
1192 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1197 mode |= SILC_CHANNEL_MODE_ULIMIT;
1199 ll = atoi(cmd->argv[3]);
1200 SILC_PUT32_MSB(ll, tmp);
1204 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1209 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1212 arg_len = cmd->argv_lens[3];
1214 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1219 mode |= SILC_CHANNEL_MODE_CIPHER;
1222 arg_len = cmd->argv_lens[3];
1224 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1229 mode |= SILC_CHANNEL_MODE_HMAC;
1232 arg_len = cmd->argv_lens[3];
1234 mode &= ~SILC_CHANNEL_MODE_HMAC;
1244 if (type && cmd->argc < 3) {
1249 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1250 SILC_PUT32_MSB(mode, modebuf);
1252 /* Send the command packet. We support sending only one mode at once
1253 that requires an argument. */
1256 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1257 1, chidp->data, chidp->len,
1258 2, modebuf, sizeof(modebuf),
1259 type, arg, arg_len);
1262 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1263 1, chidp->data, chidp->len,
1264 2, modebuf, sizeof(modebuf));
1267 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1268 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1269 silc_buffer_free(buffer);
1270 silc_buffer_free(chidp);
1272 /* Notify application */
1276 silc_client_command_free(cmd);
1279 /* CUMODE command. Changes client's mode on a channel. */
1281 SILC_CLIENT_CMD_FUNC(cumode)
1283 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1284 SilcClientConnection conn = cmd->conn;
1285 SilcChannelEntry channel;
1286 SilcChannelUser chu;
1287 SilcClientEntry client_entry;
1288 SilcBuffer buffer, clidp, chidp;
1289 unsigned char *name, *cp, modebuf[4];
1290 unsigned int mode = 0, add, len;
1291 char *nickname = NULL, *server = NULL;
1292 unsigned int num = 0;
1296 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1301 if (cmd->argc < 4) {
1302 cmd->client->ops->say(cmd->client, conn,
1303 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1308 if (cmd->argv[1][0] == '*') {
1309 if (!conn->current_channel) {
1310 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1315 channel = conn->current_channel;
1317 name = cmd->argv[1];
1319 channel = silc_client_get_channel(cmd->client, conn, name);
1321 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1327 /* Parse the typed nickname. */
1328 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1329 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1334 /* Find client entry */
1335 client_entry = silc_idlist_get_client(cmd->client, conn,
1336 nickname, server, num, TRUE);
1337 if (!client_entry) {
1343 /* Client entry not found, it was requested thus mark this to be
1345 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1347 silc_client_command_destructor,
1348 silc_client_command_cumode,
1349 silc_client_command_dup(cmd));
1354 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1355 if (chu->client == client_entry) {
1361 /* Are we adding or removing mode */
1362 if (cmd->argv[2][0] == '-')
1368 cp = cmd->argv[2] + 1;
1370 for (i = 0; i < len; i++) {
1374 mode |= SILC_CHANNEL_UMODE_CHANFO;
1375 mode |= SILC_CHANNEL_UMODE_CHANOP;
1377 mode = SILC_CHANNEL_UMODE_NONE;
1382 mode |= SILC_CHANNEL_UMODE_CHANFO;
1384 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1388 mode |= SILC_CHANNEL_UMODE_CHANOP;
1390 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1399 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1400 SILC_PUT32_MSB(mode, modebuf);
1401 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1403 /* Send the command packet. We support sending only one mode at once
1404 that requires an argument. */
1405 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
1406 1, chidp->data, chidp->len,
1408 3, clidp->data, clidp->len);
1410 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1411 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1412 silc_buffer_free(buffer);
1413 silc_buffer_free(chidp);
1414 silc_buffer_free(clidp);
1416 /* Notify application */
1421 silc_free(nickname);
1424 silc_client_command_free(cmd);
1427 /* KICK command. Kicks a client out of channel. */
1429 SILC_CLIENT_CMD_FUNC(kick)
1431 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1432 SilcClientConnection conn = cmd->conn;
1433 SilcIDCacheEntry id_cache = NULL;
1434 SilcChannelEntry channel;
1435 SilcBuffer buffer, idp, idp2;
1436 SilcClientEntry target;
1438 unsigned int num = 0;
1439 char *nickname = NULL, *server = NULL;
1442 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1447 if (cmd->argc < 3) {
1448 cmd->client->ops->say(cmd->client, conn,
1449 "Usage: /KICK <channel> <nickname> [<comment>]");
1454 if (cmd->argv[1][0] == '*') {
1455 if (!conn->current_channel) {
1456 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1460 name = conn->current_channel->channel_name;
1462 name = cmd->argv[1];
1465 if (!conn->current_channel) {
1466 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1471 /* Get the Channel ID of the channel */
1472 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1473 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1478 channel = (SilcChannelEntry)id_cache->context;
1480 /* Parse the typed nickname. */
1481 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1482 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1487 /* Get the target client */
1488 target = silc_idlist_get_client(cmd->client, conn, nickname,
1489 server, num, FALSE);
1491 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1497 /* Send KICK command to the server */
1498 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1499 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1501 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1502 1, idp->data, idp->len,
1503 2, idp2->data, idp2->len);
1505 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1506 1, idp->data, idp->len,
1507 2, idp2->data, idp2->len,
1509 strlen(cmd->argv[3]));
1510 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1511 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1512 silc_buffer_free(buffer);
1513 silc_buffer_free(idp);
1514 silc_buffer_free(idp2);
1516 /* Notify application */
1521 silc_free(nickname);
1524 silc_client_command_free(cmd);
1527 /* OPER command. Used to obtain server operator privileges. */
1529 SILC_CLIENT_CMD_FUNC(oper)
1531 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1532 SilcClientConnection conn = cmd->conn;
1534 unsigned char *auth_data;
1538 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1543 if (cmd->argc < 2) {
1544 cmd->client->ops->say(cmd->client, conn,
1545 "Usage: /OPER <username> [<public key>]");
1550 if (cmd->argc == 3) {
1551 /* XXX Get public key */
1556 /* Get passphrase */
1558 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1564 /* Encode the authentication payload */
1565 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1566 auth_data, strlen(auth_data));
1569 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1571 strlen(cmd->argv[1]),
1572 2, auth->data, auth->len);
1573 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1574 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1576 silc_buffer_free(buffer);
1577 silc_buffer_free(auth);
1578 memset(auth_data, 0, strlen(auth_data));
1579 silc_free(auth_data);
1581 /* Notify application */
1585 silc_client_command_free(cmd);
1588 /* SILCOPER command. Used to obtain router operator privileges. */
1590 SILC_CLIENT_CMD_FUNC(silcoper)
1592 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1593 SilcClientConnection conn = cmd->conn;
1595 unsigned char *auth_data;
1599 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1604 if (cmd->argc < 2) {
1605 cmd->client->ops->say(cmd->client, conn,
1606 "Usage: /SILCOPER <username> [<public key>]");
1611 if (cmd->argc == 3) {
1612 /* XXX Get public key */
1617 /* Get passphrase */
1619 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1625 /* Encode the authentication payload */
1626 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1627 auth_data, strlen(auth_data));
1630 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1632 strlen(cmd->argv[1]),
1633 2, auth->data, auth->len);
1634 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1635 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1637 silc_buffer_free(buffer);
1638 silc_buffer_free(auth);
1639 memset(auth_data, 0, strlen(auth_data));
1640 silc_free(auth_data);
1642 /* Notify application */
1646 silc_client_command_free(cmd);
1649 /* CONNECT command. Connects the server to another server. */
1651 SILC_CLIENT_CMD_FUNC(connect)
1653 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1654 SilcClientConnection conn = cmd->conn;
1656 unsigned char port[4];
1660 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1665 if (cmd->argc < 2) {
1666 cmd->client->ops->say(cmd->client, conn,
1667 "Usage: /CONNECT <server> [<port>]");
1672 if (cmd->argc == 3) {
1673 tmp = atoi(cmd->argv[2]);
1674 SILC_PUT32_MSB(tmp, port);
1678 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1680 strlen(cmd->argv[1]),
1683 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1685 strlen(cmd->argv[1]));
1686 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1687 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1688 silc_buffer_free(buffer);
1690 /* Notify application */
1694 silc_client_command_free(cmd);
1697 /* RESTART command. Restarts the server. You must be server operator
1698 to be able to use this command. */
1700 SILC_CLIENT_CMD_FUNC(restart)
1702 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1706 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1711 buffer = silc_command_payload_encode(SILC_COMMAND_RESTART, 0,
1712 NULL, NULL, NULL, 0);
1713 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
1714 NULL, 0, NULL, NULL,
1715 buffer->data, buffer->len, TRUE);
1716 silc_buffer_free(buffer);
1718 /* Notify application */
1722 silc_client_command_free(cmd);
1725 /* CLOSE command. Close server connection to the remote server */
1727 SILC_CLIENT_CMD_FUNC(close)
1729 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1730 SilcClientConnection conn = cmd->conn;
1732 unsigned char port[4];
1736 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1741 if (cmd->argc < 2) {
1742 cmd->client->ops->say(cmd->client, conn,
1743 "Usage: /CLOSE <server> [<port>]");
1748 if (cmd->argc == 3) {
1749 tmp = atoi(cmd->argv[2]);
1750 SILC_PUT32_MSB(tmp, port);
1754 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1756 strlen(cmd->argv[1]),
1759 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1761 strlen(cmd->argv[1]));
1762 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1763 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1764 silc_buffer_free(buffer);
1766 /* Notify application */
1770 silc_client_command_free(cmd);
1773 /* SHUTDOWN command. Shutdowns the server. */
1775 SILC_CLIENT_CMD_FUNC(shutdown)
1777 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1780 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1785 /* Send the command */
1786 silc_client_send_command(cmd->client, cmd->conn,
1787 SILC_COMMAND_SHUTDOWN, 0, 0);
1789 /* Notify application */
1793 silc_client_command_free(cmd);
1796 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1798 SILC_CLIENT_CMD_FUNC(leave)
1800 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1801 SilcClientConnection conn = cmd->conn;
1802 SilcIDCacheEntry id_cache = NULL;
1803 SilcChannelEntry channel;
1804 SilcBuffer buffer, idp;
1808 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1813 if (cmd->argc != 2) {
1814 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1819 if (cmd->argv[1][0] == '*') {
1820 if (!conn->current_channel) {
1821 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1825 name = conn->current_channel->channel_name;
1827 name = cmd->argv[1];
1830 if (!conn->current_channel) {
1831 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1836 /* Get the Channel ID of the channel */
1837 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1838 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1843 channel = (SilcChannelEntry)id_cache->context;
1845 /* Send LEAVE command to the server */
1846 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1847 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1848 1, idp->data, idp->len);
1849 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1850 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1851 silc_buffer_free(buffer);
1852 silc_buffer_free(idp);
1854 /* We won't talk anymore on this channel */
1855 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1857 conn->current_channel = NULL;
1859 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1860 silc_free(channel->channel_name);
1861 silc_free(channel->id);
1862 silc_free(channel->key);
1863 silc_cipher_free(channel->channel_key);
1866 /* Notify application */
1870 silc_client_command_free(cmd);
1873 /* Command USERS. Requests the USERS of the clients joined on requested
1876 SILC_CLIENT_CMD_FUNC(users)
1878 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1879 SilcClientConnection conn = cmd->conn;
1880 SilcIDCacheEntry id_cache = NULL;
1881 SilcChannelEntry channel;
1882 SilcBuffer buffer, idp;
1883 char *name, *line = NULL;
1884 unsigned int line_len = 0;
1887 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1892 if (cmd->argc != 2) {
1893 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1898 if (cmd->argv[1][0] == '*') {
1899 if (!conn->current_channel) {
1900 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1904 name = conn->current_channel->channel_name;
1906 name = cmd->argv[1];
1909 if (!conn->current_channel) {
1910 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1915 /* Get the Channel ID of the channel */
1916 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1917 /* XXX should resolve the channel ID; LIST command */
1918 cmd->client->ops->say(cmd->client, conn,
1919 "You are not on that channel", name);
1924 channel = (SilcChannelEntry)id_cache->context;
1926 if (!cmd->pending) {
1927 /* Send USERS command to the server */
1928 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1929 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1930 ++conn->cmd_ident, 1,
1931 1, idp->data, idp->len);
1932 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1933 NULL, 0, NULL, NULL, buffer->data,
1935 silc_buffer_free(buffer);
1936 silc_buffer_free(idp);
1938 /* Register pending callback which will recall this command callback with
1939 same context and reprocesses the command. When reprocessing we actually
1940 display the information on the screen. */
1941 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1942 silc_client_command_destructor,
1943 silc_client_command_users,
1944 silc_client_command_dup(cmd));
1945 cmd->pending = TRUE;
1950 /* Pending command. Now we've resolved the information from server and
1951 we are ready to display the information on screen. */
1953 SilcChannelUser chu;
1955 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1956 channel->channel_name);
1958 line = silc_calloc(4096, sizeof(*line));
1960 silc_list_start(channel->clients);
1961 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1962 SilcClientEntry e = chu->client;
1963 char *m, tmp[80], len1;
1965 memset(line, 0, sizeof(line_len));
1967 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1969 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1970 line = silc_calloc(line_len, sizeof(*line));
1973 memset(tmp, 0, sizeof(tmp));
1974 m = silc_client_chumode_char(chu->mode);
1976 strncat(line, " ", 1);
1977 strncat(line, e->nickname, strlen(e->nickname));
1978 strncat(line, e->server ? "@" : "", 1);
1982 len1 = strlen(e->server);
1983 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1985 len1 = strlen(line);
1987 memset(&line[29], 0, len1 - 29);
1989 for (i = 0; i < 30 - len1 - 1; i++)
1993 strncat(line, " H", 3);
1994 strcat(tmp, m ? m : "");
1995 strncat(line, tmp, strlen(tmp));
1997 if (strlen(tmp) < 5)
1998 for (i = 0; i < 5 - strlen(tmp); i++)
2001 strcat(line, e->username ? e->username : "");
2003 cmd->client->ops->say(cmd->client, conn, "%s", line);
2013 /* Notify application */
2017 silc_client_command_free(cmd);
2020 /* Command BAN. This is used to manage the ban list of the channel. */
2022 SILC_CLIENT_CMD_FUNC(ban)
2024 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2025 SilcClientConnection conn = cmd->conn;
2026 SilcChannelEntry channel;
2027 SilcBuffer buffer, chidp;
2029 char *name, *ban = NULL;
2032 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2037 if (cmd->argc < 2) {
2038 cmd->client->ops->say(cmd->client, conn,
2039 "Usage: /BAN <channel> "
2040 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2045 if (cmd->argv[1][0] == '*') {
2046 if (!conn->current_channel) {
2047 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2052 channel = conn->current_channel;
2054 name = cmd->argv[1];
2056 channel = silc_client_get_channel(cmd->client, conn, name);
2058 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2064 if (cmd->argc == 3) {
2065 if (cmd->argv[2][0] == '+')
2074 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2076 /* Send the command */
2078 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
2079 1, chidp->data, chidp->len,
2080 type, ban, strlen(ban));
2082 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
2083 1, chidp->data, chidp->len);
2085 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2086 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2087 silc_buffer_free(buffer);
2088 silc_buffer_free(chidp);
2090 /* Notify application */
2094 silc_client_command_free(cmd);