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, NULL, 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;
1076 mode |= SILC_UMODE_GONE;
1078 mode &= ~SILC_UMODE_GONE;
1087 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1088 SILC_PUT32_MSB(mode, modebuf);
1090 /* Send the command packet. We support sending only one mode at once
1091 that requires an argument. */
1093 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1094 1, idp->data, idp->len,
1095 2, modebuf, sizeof(modebuf));
1096 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1097 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1098 silc_buffer_free(buffer);
1099 silc_buffer_free(idp);
1101 /* Notify application */
1105 silc_client_command_free(cmd);
1108 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1109 can be set several at once. Those modes that require argument must be set
1110 separately (unless set with modes that does not require arguments). */
1112 SILC_CLIENT_CMD_FUNC(cmode)
1114 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1115 SilcClientConnection conn = cmd->conn;
1116 SilcChannelEntry channel;
1117 SilcBuffer buffer, chidp, auth = NULL;
1118 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1119 unsigned int mode, add, type, len, arg_len = 0;
1123 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1128 if (cmd->argc < 3) {
1129 cmd->client->ops->say(cmd->client, conn,
1130 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1135 if (cmd->argv[1][0] == '*') {
1136 if (!conn->current_channel) {
1137 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1142 channel = conn->current_channel;
1144 name = cmd->argv[1];
1146 channel = silc_client_get_channel(cmd->client, conn, name);
1148 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1154 mode = channel->mode;
1156 /* Are we adding or removing mode */
1157 if (cmd->argv[2][0] == '-')
1162 /* Argument type to be sent to server */
1166 cp = cmd->argv[2] + 1;
1168 for (i = 0; i < len; i++) {
1172 mode |= SILC_CHANNEL_MODE_PRIVATE;
1174 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1178 mode |= SILC_CHANNEL_MODE_SECRET;
1180 mode &= ~SILC_CHANNEL_MODE_SECRET;
1184 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1186 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1190 mode |= SILC_CHANNEL_MODE_INVITE;
1192 mode &= ~SILC_CHANNEL_MODE_INVITE;
1196 mode |= SILC_CHANNEL_MODE_TOPIC;
1198 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1203 mode |= SILC_CHANNEL_MODE_ULIMIT;
1205 ll = atoi(cmd->argv[3]);
1206 SILC_PUT32_MSB(ll, tmp);
1210 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1215 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1218 arg_len = cmd->argv_lens[3];
1220 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1225 mode |= SILC_CHANNEL_MODE_CIPHER;
1228 arg_len = cmd->argv_lens[3];
1230 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1235 mode |= SILC_CHANNEL_MODE_HMAC;
1238 arg_len = cmd->argv_lens[3];
1240 mode &= ~SILC_CHANNEL_MODE_HMAC;
1245 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1248 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1249 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1250 cmd->client->private_key,
1255 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1256 cmd->argv[3], cmd->argv_lens[3]);
1260 arg_len = auth->len;
1262 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1272 if (type && cmd->argc < 3) {
1277 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1278 SILC_PUT32_MSB(mode, modebuf);
1280 /* Send the command packet. We support sending only one mode at once
1281 that requires an argument. */
1284 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1285 1, chidp->data, chidp->len,
1286 2, modebuf, sizeof(modebuf),
1287 type, arg, arg_len);
1290 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1291 1, chidp->data, chidp->len,
1292 2, modebuf, sizeof(modebuf));
1295 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1296 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1297 silc_buffer_free(buffer);
1298 silc_buffer_free(chidp);
1300 silc_buffer_free(auth);
1302 /* Notify application */
1306 silc_client_command_free(cmd);
1309 /* CUMODE command. Changes client's mode on a channel. */
1311 SILC_CLIENT_CMD_FUNC(cumode)
1313 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1314 SilcClientConnection conn = cmd->conn;
1315 SilcChannelEntry channel;
1316 SilcChannelUser chu;
1317 SilcClientEntry client_entry;
1318 SilcBuffer buffer, clidp, chidp, auth = NULL;
1319 unsigned char *name, *cp, modebuf[4];
1320 unsigned int mode = 0, add, len;
1321 char *nickname = NULL, *server = NULL;
1322 unsigned int num = 0;
1326 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1331 if (cmd->argc < 4) {
1332 cmd->client->ops->say(cmd->client, conn,
1333 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1338 if (cmd->argv[1][0] == '*') {
1339 if (!conn->current_channel) {
1340 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1345 channel = conn->current_channel;
1347 name = cmd->argv[1];
1349 channel = silc_client_get_channel(cmd->client, conn, name);
1351 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1357 /* Parse the typed nickname. */
1358 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1359 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1364 /* Find client entry */
1365 client_entry = silc_idlist_get_client(cmd->client, conn,
1366 nickname, server, num, TRUE);
1367 if (!client_entry) {
1373 /* Client entry not found, it was requested thus mark this to be
1375 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1377 silc_client_command_destructor,
1378 silc_client_command_cumode,
1379 silc_client_command_dup(cmd));
1384 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1385 if (chu->client == client_entry) {
1391 /* Are we adding or removing mode */
1392 if (cmd->argv[2][0] == '-')
1398 cp = cmd->argv[2] + 1;
1400 for (i = 0; i < len; i++) {
1404 mode |= SILC_CHANNEL_UMODE_CHANFO;
1405 mode |= SILC_CHANNEL_UMODE_CHANOP;
1407 mode = SILC_CHANNEL_UMODE_NONE;
1412 if (cmd->argc == 5) {
1413 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1414 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1415 cmd->client->private_key,
1420 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1421 cmd->argv[4], cmd->argv_lens[4]);
1424 mode |= SILC_CHANNEL_UMODE_CHANFO;
1426 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1431 mode |= SILC_CHANNEL_UMODE_CHANOP;
1433 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1442 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1443 SILC_PUT32_MSB(mode, modebuf);
1444 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1446 /* Send the command packet. We support sending only one mode at once
1447 that requires an argument. */
1448 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1449 1, chidp->data, chidp->len,
1451 3, clidp->data, clidp->len,
1452 4, auth ? auth->data : NULL,
1453 auth ? auth->len : 0);
1455 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1456 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1457 silc_buffer_free(buffer);
1458 silc_buffer_free(chidp);
1459 silc_buffer_free(clidp);
1461 silc_buffer_free(auth);
1463 /* Notify application */
1468 silc_free(nickname);
1471 silc_client_command_free(cmd);
1474 /* KICK command. Kicks a client out of channel. */
1476 SILC_CLIENT_CMD_FUNC(kick)
1478 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1479 SilcClientConnection conn = cmd->conn;
1480 SilcIDCacheEntry id_cache = NULL;
1481 SilcChannelEntry channel;
1482 SilcBuffer buffer, idp, idp2;
1483 SilcClientEntry target;
1485 unsigned int num = 0;
1486 char *nickname = NULL, *server = NULL;
1489 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1494 if (cmd->argc < 3) {
1495 cmd->client->ops->say(cmd->client, conn,
1496 "Usage: /KICK <channel> <nickname> [<comment>]");
1501 if (cmd->argv[1][0] == '*') {
1502 if (!conn->current_channel) {
1503 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1507 name = conn->current_channel->channel_name;
1509 name = cmd->argv[1];
1512 if (!conn->current_channel) {
1513 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1518 /* Get the Channel ID of the channel */
1519 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1520 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1525 channel = (SilcChannelEntry)id_cache->context;
1527 /* Parse the typed nickname. */
1528 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1529 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1534 /* Get the target client */
1535 target = silc_idlist_get_client(cmd->client, conn, nickname,
1536 server, num, FALSE);
1538 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1544 /* Send KICK command to the server */
1545 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1546 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1548 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1549 1, idp->data, idp->len,
1550 2, idp2->data, idp2->len);
1552 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1553 1, idp->data, idp->len,
1554 2, idp2->data, idp2->len,
1556 strlen(cmd->argv[3]));
1557 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1558 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1559 silc_buffer_free(buffer);
1560 silc_buffer_free(idp);
1561 silc_buffer_free(idp2);
1563 /* Notify application */
1568 silc_free(nickname);
1571 silc_client_command_free(cmd);
1574 /* OPER command. Used to obtain server operator privileges. */
1576 SILC_CLIENT_CMD_FUNC(oper)
1578 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1579 SilcClientConnection conn = cmd->conn;
1581 unsigned char *auth_data;
1585 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1590 if (cmd->argc < 2) {
1591 cmd->client->ops->say(cmd->client, conn,
1592 "Usage: /OPER <username> [<public key>]");
1597 if (cmd->argc == 3) {
1598 /* XXX Get public key */
1603 /* Get passphrase */
1605 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1611 /* Encode the authentication payload */
1612 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1613 auth_data, strlen(auth_data));
1616 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1618 strlen(cmd->argv[1]),
1619 2, auth->data, auth->len);
1620 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1621 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1623 silc_buffer_free(buffer);
1624 silc_buffer_free(auth);
1625 memset(auth_data, 0, strlen(auth_data));
1626 silc_free(auth_data);
1628 /* Notify application */
1632 silc_client_command_free(cmd);
1635 /* SILCOPER command. Used to obtain router operator privileges. */
1637 SILC_CLIENT_CMD_FUNC(silcoper)
1639 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1640 SilcClientConnection conn = cmd->conn;
1642 unsigned char *auth_data;
1646 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1651 if (cmd->argc < 2) {
1652 cmd->client->ops->say(cmd->client, conn,
1653 "Usage: /SILCOPER <username> [<public key>]");
1658 if (cmd->argc == 3) {
1659 /* XXX Get public key */
1664 /* Get passphrase */
1666 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1672 /* Encode the authentication payload */
1673 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1674 auth_data, strlen(auth_data));
1677 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1679 strlen(cmd->argv[1]),
1680 2, auth->data, auth->len);
1681 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1682 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1684 silc_buffer_free(buffer);
1685 silc_buffer_free(auth);
1686 memset(auth_data, 0, strlen(auth_data));
1687 silc_free(auth_data);
1689 /* Notify application */
1693 silc_client_command_free(cmd);
1696 /* CONNECT command. Connects the server to another server. */
1698 SILC_CLIENT_CMD_FUNC(connect)
1700 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1701 SilcClientConnection conn = cmd->conn;
1703 unsigned char port[4];
1707 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1712 if (cmd->argc < 2) {
1713 cmd->client->ops->say(cmd->client, conn,
1714 "Usage: /CONNECT <server> [<port>]");
1719 if (cmd->argc == 3) {
1720 tmp = atoi(cmd->argv[2]);
1721 SILC_PUT32_MSB(tmp, port);
1725 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1727 strlen(cmd->argv[1]),
1730 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1732 strlen(cmd->argv[1]));
1733 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1734 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1735 silc_buffer_free(buffer);
1737 /* Notify application */
1741 silc_client_command_free(cmd);
1744 /* RESTART command. Restarts the server. You must be server operator
1745 to be able to use this command. */
1747 SILC_CLIENT_CMD_FUNC(restart)
1749 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1753 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1758 buffer = silc_command_payload_encode(SILC_COMMAND_RESTART, 0,
1759 NULL, NULL, NULL, 0);
1760 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
1761 NULL, 0, NULL, NULL,
1762 buffer->data, buffer->len, TRUE);
1763 silc_buffer_free(buffer);
1765 /* Notify application */
1769 silc_client_command_free(cmd);
1772 /* CLOSE command. Close server connection to the remote server */
1774 SILC_CLIENT_CMD_FUNC(close)
1776 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1777 SilcClientConnection conn = cmd->conn;
1779 unsigned char port[4];
1783 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1788 if (cmd->argc < 2) {
1789 cmd->client->ops->say(cmd->client, conn,
1790 "Usage: /CLOSE <server> [<port>]");
1795 if (cmd->argc == 3) {
1796 tmp = atoi(cmd->argv[2]);
1797 SILC_PUT32_MSB(tmp, port);
1801 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1803 strlen(cmd->argv[1]),
1806 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1808 strlen(cmd->argv[1]));
1809 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1810 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1811 silc_buffer_free(buffer);
1813 /* Notify application */
1817 silc_client_command_free(cmd);
1820 /* SHUTDOWN command. Shutdowns the server. */
1822 SILC_CLIENT_CMD_FUNC(shutdown)
1824 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1827 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1832 /* Send the command */
1833 silc_client_send_command(cmd->client, cmd->conn,
1834 SILC_COMMAND_SHUTDOWN, 0, 0);
1836 /* Notify application */
1840 silc_client_command_free(cmd);
1843 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1845 SILC_CLIENT_CMD_FUNC(leave)
1847 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1848 SilcClientConnection conn = cmd->conn;
1849 SilcIDCacheEntry id_cache = NULL;
1850 SilcChannelEntry channel;
1851 SilcBuffer buffer, idp;
1855 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1860 if (cmd->argc != 2) {
1861 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1866 if (cmd->argv[1][0] == '*') {
1867 if (!conn->current_channel) {
1868 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1872 name = conn->current_channel->channel_name;
1874 name = cmd->argv[1];
1877 if (!conn->current_channel) {
1878 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1883 /* Get the Channel ID of the channel */
1884 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1885 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1890 channel = (SilcChannelEntry)id_cache->context;
1892 /* Send LEAVE command to the server */
1893 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1894 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1895 1, idp->data, idp->len);
1896 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1897 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1898 silc_buffer_free(buffer);
1899 silc_buffer_free(idp);
1901 /* We won't talk anymore on this channel */
1902 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1904 conn->current_channel = NULL;
1906 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1907 silc_free(channel->channel_name);
1908 silc_free(channel->id);
1909 silc_free(channel->key);
1910 silc_cipher_free(channel->channel_key);
1913 /* Notify application */
1917 silc_client_command_free(cmd);
1920 /* Command USERS. Requests the USERS of the clients joined on requested
1923 SILC_CLIENT_CMD_FUNC(users)
1925 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1926 SilcClientConnection conn = cmd->conn;
1927 SilcIDCacheEntry id_cache = NULL;
1928 SilcChannelEntry channel;
1929 SilcBuffer buffer, idp;
1930 char *name, *line = NULL;
1931 unsigned int line_len = 0;
1934 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1939 if (cmd->argc != 2) {
1940 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1945 if (cmd->argv[1][0] == '*') {
1946 if (!conn->current_channel) {
1947 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1951 name = conn->current_channel->channel_name;
1953 name = cmd->argv[1];
1956 if (!conn->current_channel) {
1957 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1962 /* Get the Channel ID of the channel */
1963 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1964 /* XXX should resolve the channel ID; LIST command */
1965 cmd->client->ops->say(cmd->client, conn,
1966 "You are not on that channel", name);
1971 channel = (SilcChannelEntry)id_cache->context;
1973 if (!cmd->pending) {
1974 /* Send USERS command to the server */
1975 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1976 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1977 ++conn->cmd_ident, 1,
1978 1, idp->data, idp->len);
1979 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1980 NULL, 0, NULL, NULL, buffer->data,
1982 silc_buffer_free(buffer);
1983 silc_buffer_free(idp);
1985 /* Register pending callback which will recall this command callback with
1986 same context and reprocesses the command. When reprocessing we actually
1987 display the information on the screen. */
1988 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1989 silc_client_command_destructor,
1990 silc_client_command_users,
1991 silc_client_command_dup(cmd));
1992 cmd->pending = TRUE;
1997 /* Pending command. Now we've resolved the information from server and
1998 we are ready to display the information on screen. */
2000 SilcChannelUser chu;
2002 cmd->client->ops->say(cmd->client, conn, "Users on %s",
2003 channel->channel_name);
2005 line = silc_calloc(4096, sizeof(*line));
2007 silc_list_start(channel->clients);
2008 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2009 SilcClientEntry e = chu->client;
2010 char *m, tmp[80], len1;
2012 memset(line, 0, sizeof(line_len));
2014 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
2016 line_len += strlen(e->nickname) + strlen(e->server) + 100;
2017 line = silc_calloc(line_len, sizeof(*line));
2020 memset(tmp, 0, sizeof(tmp));
2021 m = silc_client_chumode_char(chu->mode);
2023 strncat(line, " ", 1);
2024 strncat(line, e->nickname, strlen(e->nickname));
2025 strncat(line, e->server ? "@" : "", 1);
2029 len1 = strlen(e->server);
2030 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
2032 len1 = strlen(line);
2034 memset(&line[29], 0, len1 - 29);
2036 for (i = 0; i < 30 - len1 - 1; i++)
2040 if (e->mode & SILC_UMODE_GONE)
2044 strcat(tmp, m ? m : "");
2045 strncat(line, tmp, strlen(tmp));
2047 if (strlen(tmp) < 5)
2048 for (i = 0; i < 5 - strlen(tmp); i++)
2051 strcat(line, e->username ? e->username : "");
2053 cmd->client->ops->say(cmd->client, conn, "%s", line);
2063 /* Notify application */
2067 silc_client_command_free(cmd);
2070 /* Command BAN. This is used to manage the ban list of the channel. */
2072 SILC_CLIENT_CMD_FUNC(ban)
2074 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2075 SilcClientConnection conn = cmd->conn;
2076 SilcChannelEntry channel;
2077 SilcBuffer buffer, chidp;
2079 char *name, *ban = NULL;
2082 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2087 if (cmd->argc < 2) {
2088 cmd->client->ops->say(cmd->client, conn,
2089 "Usage: /BAN <channel> "
2090 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2095 if (cmd->argv[1][0] == '*') {
2096 if (!conn->current_channel) {
2097 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2102 channel = conn->current_channel;
2104 name = cmd->argv[1];
2106 channel = silc_client_get_channel(cmd->client, conn, name);
2108 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2114 if (cmd->argc == 3) {
2115 if (cmd->argv[2][0] == '+')
2124 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2126 /* Send the command */
2128 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
2129 1, chidp->data, chidp->len,
2130 type, ban, strlen(ban));
2132 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
2133 1, chidp->data, chidp->len);
2135 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2136 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2137 silc_buffer_free(buffer);
2138 silc_buffer_free(chidp);
2140 /* Notify application */
2144 silc_client_command_free(cmd);