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;
1703 SilcClientConnection conn = cmd->conn;
1707 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1712 buffer = silc_command_payload_encode(SILC_COMMAND_RESTART, 0,
1713 NULL, NULL, NULL, 0);
1714 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
1715 NULL, 0, NULL, NULL,
1716 buffer->data, buffer->len, TRUE);
1717 silc_buffer_free(buffer);
1719 /* Notify application */
1723 silc_client_command_free(cmd);
1726 /* CLOSE command. Close server connection to the remote server */
1728 SILC_CLIENT_CMD_FUNC(close)
1730 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1731 SilcClientConnection conn = cmd->conn;
1733 unsigned char port[4];
1737 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1742 if (cmd->argc < 2) {
1743 cmd->client->ops->say(cmd->client, conn,
1744 "Usage: /CLOSE <server> [<port>]");
1749 if (cmd->argc == 3) {
1750 tmp = atoi(cmd->argv[2]);
1751 SILC_PUT32_MSB(tmp, port);
1755 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1757 strlen(cmd->argv[1]),
1760 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1762 strlen(cmd->argv[1]));
1763 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1764 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1765 silc_buffer_free(buffer);
1767 /* Notify application */
1771 silc_client_command_free(cmd);
1774 /* SHUTDOWN command. Shutdowns the server. */
1776 SILC_CLIENT_CMD_FUNC(shutdown)
1778 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1781 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1786 /* Send the command */
1787 silc_client_send_command(cmd->client, cmd->conn,
1788 SILC_COMMAND_SHUTDOWN, 0, 0);
1790 /* Notify application */
1794 silc_client_command_free(cmd);
1797 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1799 SILC_CLIENT_CMD_FUNC(leave)
1801 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1802 SilcClientConnection conn = cmd->conn;
1803 SilcIDCacheEntry id_cache = NULL;
1804 SilcChannelEntry channel;
1805 SilcBuffer buffer, idp;
1809 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1814 if (cmd->argc != 2) {
1815 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1820 if (cmd->argv[1][0] == '*') {
1821 if (!conn->current_channel) {
1822 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1826 name = conn->current_channel->channel_name;
1828 name = cmd->argv[1];
1831 if (!conn->current_channel) {
1832 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1837 /* Get the Channel ID of the channel */
1838 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1839 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1844 channel = (SilcChannelEntry)id_cache->context;
1846 /* Send LEAVE command to the server */
1847 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1848 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1849 1, idp->data, idp->len);
1850 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1851 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1852 silc_buffer_free(buffer);
1853 silc_buffer_free(idp);
1855 /* We won't talk anymore on this channel */
1856 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1858 conn->current_channel = NULL;
1860 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1861 silc_free(channel->channel_name);
1862 silc_free(channel->id);
1863 silc_free(channel->key);
1864 silc_cipher_free(channel->channel_key);
1867 /* Notify application */
1871 silc_client_command_free(cmd);
1874 /* Command USERS. Requests the USERS of the clients joined on requested
1877 SILC_CLIENT_CMD_FUNC(users)
1879 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1880 SilcClientConnection conn = cmd->conn;
1881 SilcIDCacheEntry id_cache = NULL;
1882 SilcChannelEntry channel;
1883 SilcBuffer buffer, idp;
1884 char *name, *line = NULL;
1885 unsigned int line_len = 0;
1888 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1893 if (cmd->argc != 2) {
1894 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1899 if (cmd->argv[1][0] == '*') {
1900 if (!conn->current_channel) {
1901 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1905 name = conn->current_channel->channel_name;
1907 name = cmd->argv[1];
1910 if (!conn->current_channel) {
1911 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1916 /* Get the Channel ID of the channel */
1917 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1918 /* XXX should resolve the channel ID; LIST command */
1919 cmd->client->ops->say(cmd->client, conn,
1920 "You are not on that channel", name);
1925 channel = (SilcChannelEntry)id_cache->context;
1927 if (!cmd->pending) {
1928 /* Send USERS command to the server */
1929 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1930 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1931 ++conn->cmd_ident, 1,
1932 1, idp->data, idp->len);
1933 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1934 NULL, 0, NULL, NULL, buffer->data,
1936 silc_buffer_free(buffer);
1937 silc_buffer_free(idp);
1939 /* Register pending callback which will recall this command callback with
1940 same context and reprocesses the command. When reprocessing we actually
1941 display the information on the screen. */
1942 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1943 silc_client_command_destructor,
1944 silc_client_command_users,
1945 silc_client_command_dup(cmd));
1946 cmd->pending = TRUE;
1951 /* Pending command. Now we've resolved the information from server and
1952 we are ready to display the information on screen. */
1954 SilcChannelUser chu;
1956 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1957 channel->channel_name);
1959 line = silc_calloc(4096, sizeof(*line));
1961 silc_list_start(channel->clients);
1962 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1963 SilcClientEntry e = chu->client;
1964 char *m, tmp[80], len1;
1966 memset(line, 0, sizeof(line_len));
1968 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1970 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1971 line = silc_calloc(line_len, sizeof(*line));
1974 memset(tmp, 0, sizeof(tmp));
1975 m = silc_client_chumode_char(chu->mode);
1977 strncat(line, " ", 1);
1978 strncat(line, e->nickname, strlen(e->nickname));
1979 strncat(line, e->server ? "@" : "", 1);
1983 len1 = strlen(e->server);
1984 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1986 len1 = strlen(line);
1988 memset(&line[29], 0, len1 - 29);
1990 for (i = 0; i < 30 - len1 - 1; i++)
1994 strncat(line, " H", 3);
1995 strcat(tmp, m ? m : "");
1996 strncat(line, tmp, strlen(tmp));
1998 if (strlen(tmp) < 5)
1999 for (i = 0; i < 5 - strlen(tmp); i++)
2002 strcat(line, e->username ? e->username : "");
2004 cmd->client->ops->say(cmd->client, conn, "%s", line);
2014 /* Notify application */
2018 silc_client_command_free(cmd);
2021 /* Command BAN. This is used to manage the ban list of the channel. */
2023 SILC_CLIENT_CMD_FUNC(ban)
2025 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2026 SilcClientConnection conn = cmd->conn;
2027 SilcChannelEntry channel;
2028 SilcBuffer buffer, chidp;
2030 char *name, *ban = NULL;
2033 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2038 if (cmd->argc < 2) {
2039 cmd->client->ops->say(cmd->client, conn,
2040 "Usage: /BAN <channel> "
2041 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2046 if (cmd->argv[1][0] == '*') {
2047 if (!conn->current_channel) {
2048 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2053 channel = conn->current_channel;
2055 name = cmd->argv[1];
2057 channel = silc_client_get_channel(cmd->client, conn, name);
2059 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2065 if (cmd->argc == 3) {
2066 if (cmd->argv[2][0] == '+')
2075 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2077 /* Send the command */
2079 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
2080 1, chidp->data, chidp->len,
2081 type, ban, strlen(ban));
2083 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
2084 1, chidp->data, chidp->len);
2086 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2087 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2088 silc_buffer_free(buffer);
2089 silc_buffer_free(chidp);
2091 /* Notify application */
2095 silc_client_command_free(cmd);