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 SILC_CLIENT_CMD_FUNC(restart)
1701 /* CLOSE command. Close server connection to the remote server */
1703 SILC_CLIENT_CMD_FUNC(close)
1705 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1706 SilcClientConnection conn = cmd->conn;
1708 unsigned char port[4];
1712 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1717 if (cmd->argc < 2) {
1718 cmd->client->ops->say(cmd->client, conn,
1719 "Usage: /CLOSE <server> [<port>]");
1724 if (cmd->argc == 3) {
1725 tmp = atoi(cmd->argv[2]);
1726 SILC_PUT32_MSB(tmp, port);
1730 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1732 strlen(cmd->argv[1]),
1735 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1737 strlen(cmd->argv[1]));
1738 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1739 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1740 silc_buffer_free(buffer);
1742 /* Notify application */
1746 silc_client_command_free(cmd);
1749 /* SHUTDOWN command. Shutdowns the server. */
1751 SILC_CLIENT_CMD_FUNC(shutdown)
1753 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1756 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1761 /* Send the command */
1762 silc_client_send_command(cmd->client, cmd->conn,
1763 SILC_COMMAND_SHUTDOWN, 0, 0);
1765 /* Notify application */
1769 silc_client_command_free(cmd);
1772 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1774 SILC_CLIENT_CMD_FUNC(leave)
1776 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1777 SilcClientConnection conn = cmd->conn;
1778 SilcIDCacheEntry id_cache = NULL;
1779 SilcChannelEntry channel;
1780 SilcBuffer buffer, idp;
1784 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1789 if (cmd->argc != 2) {
1790 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1795 if (cmd->argv[1][0] == '*') {
1796 if (!conn->current_channel) {
1797 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1801 name = conn->current_channel->channel_name;
1803 name = cmd->argv[1];
1806 if (!conn->current_channel) {
1807 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1812 /* Get the Channel ID of the channel */
1813 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1814 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1819 channel = (SilcChannelEntry)id_cache->context;
1821 /* Send LEAVE command to the server */
1822 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1823 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1824 1, idp->data, idp->len);
1825 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1826 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1827 silc_buffer_free(buffer);
1828 silc_buffer_free(idp);
1830 /* We won't talk anymore on this channel */
1831 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1833 conn->current_channel = NULL;
1835 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1836 silc_free(channel->channel_name);
1837 silc_free(channel->id);
1838 silc_free(channel->key);
1839 silc_cipher_free(channel->channel_key);
1842 /* Notify application */
1846 silc_client_command_free(cmd);
1849 /* Command USERS. Requests the USERS of the clients joined on requested
1852 SILC_CLIENT_CMD_FUNC(users)
1854 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1855 SilcClientConnection conn = cmd->conn;
1856 SilcIDCacheEntry id_cache = NULL;
1857 SilcChannelEntry channel;
1858 SilcBuffer buffer, idp;
1859 char *name, *line = NULL;
1860 unsigned int line_len = 0;
1863 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1868 if (cmd->argc != 2) {
1869 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1874 if (cmd->argv[1][0] == '*') {
1875 if (!conn->current_channel) {
1876 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1880 name = conn->current_channel->channel_name;
1882 name = cmd->argv[1];
1885 if (!conn->current_channel) {
1886 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1891 /* Get the Channel ID of the channel */
1892 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1893 /* XXX should resolve the channel ID; LIST command */
1894 cmd->client->ops->say(cmd->client, conn,
1895 "You are not on that channel", name);
1900 channel = (SilcChannelEntry)id_cache->context;
1902 if (!cmd->pending) {
1903 /* Send USERS command to the server */
1904 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1905 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1906 ++conn->cmd_ident, 1,
1907 1, idp->data, idp->len);
1908 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1909 NULL, 0, NULL, NULL, buffer->data,
1911 silc_buffer_free(buffer);
1912 silc_buffer_free(idp);
1914 /* Register pending callback which will recall this command callback with
1915 same context and reprocesses the command. When reprocessing we actually
1916 display the information on the screen. */
1917 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1918 silc_client_command_destructor,
1919 silc_client_command_users,
1920 silc_client_command_dup(cmd));
1921 cmd->pending = TRUE;
1926 /* Pending command. Now we've resolved the information from server and
1927 we are ready to display the information on screen. */
1929 SilcChannelUser chu;
1931 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1932 channel->channel_name);
1934 line = silc_calloc(4096, sizeof(*line));
1936 silc_list_start(channel->clients);
1937 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1938 SilcClientEntry e = chu->client;
1939 char *m, tmp[80], len1;
1941 memset(line, 0, sizeof(line_len));
1943 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1945 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1946 line = silc_calloc(line_len, sizeof(*line));
1949 memset(tmp, 0, sizeof(tmp));
1950 m = silc_client_chumode_char(chu->mode);
1952 strncat(line, " ", 1);
1953 strncat(line, e->nickname, strlen(e->nickname));
1954 strncat(line, e->server ? "@" : "", 1);
1958 len1 = strlen(e->server);
1959 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1961 len1 = strlen(line);
1963 memset(&line[29], 0, len1 - 29);
1965 for (i = 0; i < 30 - len1 - 1; i++)
1969 strncat(line, " H", 3);
1970 strcat(tmp, m ? m : "");
1971 strncat(line, tmp, strlen(tmp));
1973 if (strlen(tmp) < 5)
1974 for (i = 0; i < 5 - strlen(tmp); i++)
1977 strcat(line, e->username ? e->username : "");
1979 cmd->client->ops->say(cmd->client, conn, "%s", line);
1989 /* Notify application */
1993 silc_client_command_free(cmd);
1996 /* Command BAN. This is used to manage the ban list of the channel. */
1998 SILC_CLIENT_CMD_FUNC(ban)
2000 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2001 SilcClientConnection conn = cmd->conn;
2002 SilcChannelEntry channel;
2003 SilcBuffer buffer, chidp;
2005 char *name, *ban = NULL;
2008 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2013 if (cmd->argc < 2) {
2014 cmd->client->ops->say(cmd->client, conn,
2015 "Usage: /BAN <channel> "
2016 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2021 if (cmd->argv[1][0] == '*') {
2022 if (!conn->current_channel) {
2023 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2028 channel = conn->current_channel;
2030 name = cmd->argv[1];
2032 channel = silc_client_get_channel(cmd->client, conn, name);
2034 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2040 if (cmd->argc == 3) {
2041 if (cmd->argv[2][0] == '+')
2050 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2052 /* Send the command */
2054 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
2055 1, chidp->data, chidp->len,
2056 type, ban, strlen(ban));
2058 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
2059 1, chidp->data, chidp->len);
2061 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2062 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2063 silc_buffer_free(buffer);
2064 silc_buffer_free(chidp);
2066 /* Notify application */
2070 silc_client_command_free(cmd);