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(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
52 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
54 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
56 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
58 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
61 { NULL, 0, NULL, 0, 0 },
64 #define SILC_NOT_CONNECTED(x, c) \
65 x->ops->say((x), (c), \
66 "You are not connected to a server, use /SERVER to connect");
68 /* Command operation that is called at the end of all commands.
70 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
71 cmd, TRUE, cmd->command->cmd)
73 /* Error to application. Usage: COMMAND_ERROR; */
74 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
75 cmd, FALSE, cmd->command->cmd)
77 /* Generic function to send any command. The arguments must be sent already
78 encoded into correct form and in correct order. */
80 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
81 SilcCommand command, unsigned short ident,
82 unsigned int argc, ...)
89 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
90 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
91 NULL, 0, NULL, NULL, packet->data,
93 silc_buffer_free(packet);
96 /* Finds and returns a pointer to the command list. Return NULL if the
97 command is not found. */
99 SilcClientCommand *silc_client_command_find(const char *name)
101 SilcClientCommand *cmd;
103 for (cmd = silc_command_list; cmd->name; cmd++) {
104 if (!strcmp(cmd->name, name))
111 /* Add new pending command to be executed when reply to a command has been
112 received. The `reply_cmd' is the command that will call the `callback'
113 with `context' when reply has been received. If `ident is non-zero
114 the `callback' will be executed when received reply with command
115 identifier `ident'. */
117 void silc_client_command_pending(SilcClientConnection conn,
118 SilcCommand reply_cmd,
119 unsigned short ident,
120 SilcClientPendingDestructor destructor,
121 SilcCommandCb callback,
124 SilcClientCommandPending *reply;
126 reply = silc_calloc(1, sizeof(*reply));
127 reply->reply_cmd = reply_cmd;
128 reply->ident = ident;
129 reply->context = context;
130 reply->callback = callback;
131 reply->destructor = destructor;
132 silc_dlist_add(conn->pending_commands, reply);
135 /* Deletes pending command by reply command type. */
137 void silc_client_command_pending_del(SilcClientConnection conn,
138 SilcCommand reply_cmd,
139 unsigned short ident)
141 SilcClientCommandPending *r;
143 silc_dlist_start(conn->pending_commands);
144 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
145 if (r->reply_cmd == reply_cmd && r->ident == ident) {
146 silc_dlist_del(conn->pending_commands, r);
152 /* Checks for pending commands and marks callbacks to be called from
153 the command reply function. Returns TRUE if there were pending command. */
155 int silc_client_command_pending_check(SilcClientConnection conn,
156 SilcClientCommandReplyContext ctx,
158 unsigned short ident)
160 SilcClientCommandPending *r;
162 silc_dlist_start(conn->pending_commands);
163 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
164 if (r->reply_cmd == command && r->ident == ident) {
165 ctx->context = r->context;
166 ctx->callback = r->callback;
167 ctx->destructor = r->destructor;
176 /* Allocate Command Context */
178 SilcClientCommandContext silc_client_command_alloc()
180 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
185 /* Free command context and its internals */
187 void silc_client_command_free(SilcClientCommandContext ctx)
190 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
192 if (ctx->users < 1) {
195 for (i = 0; i < ctx->argc; i++)
196 silc_free(ctx->argv[i]);
201 /* Duplicate Command Context by adding reference counter. The context won't
202 be free'd untill it hits zero. */
204 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
207 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
212 /* Pending command destructor. */
214 static void silc_client_command_destructor(void *context)
216 silc_client_command_free((SilcClientCommandContext)context);
219 /* silc_client_get_client completion callback */
220 void silc_client_command_completion(SilcClient client,
221 SilcClientConnection conn,
222 SilcClientEntry clients,
223 unsigned int clients_count,
229 /* Command WHOIS. This command is used to query information about
232 SILC_CLIENT_CMD_FUNC(whois)
234 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
235 SilcClientConnection conn = cmd->conn;
239 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
244 if (cmd->argc < 2 || cmd->argc > 3) {
245 cmd->client->ops->say(cmd->client, conn,
246 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
251 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
252 cmd->argc - 1, ++cmd->argv,
253 ++cmd->argv_lens, ++cmd->argv_types,
255 silc_client_packet_send(cmd->client, cmd->conn->sock,
256 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
257 buffer->data, buffer->len, TRUE);
258 silc_buffer_free(buffer);
263 /* Notify application */
267 silc_client_command_free(cmd);
270 /* Command WHOWAS. This command is used to query history information about
271 specific user that used to exist in the network. */
273 SILC_CLIENT_CMD_FUNC(whowas)
275 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
276 SilcClientConnection conn = cmd->conn;
280 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
285 if (cmd->argc < 2 || cmd->argc > 3) {
286 cmd->client->ops->say(cmd->client, conn,
287 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
292 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
293 cmd->argc - 1, ++cmd->argv,
294 ++cmd->argv_lens, ++cmd->argv_types,
296 silc_client_packet_send(cmd->client, cmd->conn->sock,
297 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
298 buffer->data, buffer->len, TRUE);
299 silc_buffer_free(buffer);
304 /* Notify application */
308 silc_client_command_free(cmd);
311 /* Command IDENTIFY. This command is used to query information about
312 specific user, especially ID's. */
314 SILC_CLIENT_CMD_FUNC(identify)
316 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
317 SilcClientConnection conn = cmd->conn;
321 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
326 if (cmd->argc < 2 || cmd->argc > 3) {
327 cmd->client->ops->say(cmd->client, conn,
328 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
333 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
334 cmd->argc - 1, ++cmd->argv,
335 ++cmd->argv_lens, ++cmd->argv_types,
337 silc_client_packet_send(cmd->client, cmd->conn->sock,
338 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
339 buffer->data, buffer->len, TRUE);
340 silc_buffer_free(buffer);
345 /* Notify application */
349 silc_client_command_free(cmd);
352 /* Command NICK. Shows current nickname/sets new nickname on current
355 SILC_CLIENT_CMD_FUNC(nick)
357 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
358 SilcClientConnection conn = cmd->conn;
362 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
367 if (!strcmp(conn->nickname, cmd->argv[1]))
370 /* Show current nickname */
373 cmd->client->ops->say(cmd->client, conn,
374 "Your nickname is %s on server %s",
375 conn->nickname, conn->remote_host);
377 cmd->client->ops->say(cmd->client, conn,
378 "Your nickname is %s", conn->nickname);
381 /* XXX Notify application */
386 /* Set new nickname */
387 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
388 cmd->argc - 1, ++cmd->argv,
389 ++cmd->argv_lens, ++cmd->argv_types,
390 ++cmd->conn->cmd_ident);
391 silc_client_packet_send(cmd->client, cmd->conn->sock,
392 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
393 buffer->data, buffer->len, TRUE);
394 silc_buffer_free(buffer);
399 silc_free(conn->nickname);
400 conn->nickname = strdup(cmd->argv[1]);
402 /* Notify application */
406 silc_client_command_free(cmd);
409 /* Command LIST. Lists channels on the current server. */
411 SILC_CLIENT_CMD_FUNC(list)
413 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
414 SilcClientConnection conn = cmd->conn;
415 SilcIDCacheEntry id_cache = NULL;
416 SilcChannelEntry channel;
417 SilcBuffer buffer, idp = NULL;
421 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
426 if (cmd->argc == 2) {
429 /* Get the Channel ID of the channel */
430 if (silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
431 channel = (SilcChannelEntry)id_cache->context;
432 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
437 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
438 ++conn->cmd_ident, 0);
440 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
441 ++conn->cmd_ident, 1,
442 1, idp->data, idp->len);
444 silc_client_packet_send(cmd->client, cmd->conn->sock,
445 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
446 buffer->data, buffer->len, TRUE);
447 silc_buffer_free(buffer);
449 silc_buffer_free(idp);
451 /* Notify application */
455 silc_client_command_free(cmd);
458 /* Command TOPIC. Sets/shows topic on a channel. */
460 SILC_CLIENT_CMD_FUNC(topic)
462 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
463 SilcClientConnection conn = cmd->conn;
464 SilcIDCacheEntry id_cache = NULL;
465 SilcChannelEntry channel;
466 SilcBuffer buffer, idp;
470 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
475 if (cmd->argc < 2 || cmd->argc > 3) {
476 cmd->client->ops->say(cmd->client, conn,
477 "Usage: /TOPIC <channel> [<topic>]");
482 if (cmd->argv[1][0] == '*') {
483 if (!conn->current_channel) {
484 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
488 name = conn->current_channel->channel_name;
493 if (!conn->current_channel) {
494 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
499 /* Get the Channel ID of the channel */
500 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
501 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
506 channel = (SilcChannelEntry)id_cache->context;
508 /* Send TOPIC command to the server */
509 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
511 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
512 1, idp->data, idp->len,
514 strlen(cmd->argv[2]));
516 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
517 1, idp->data, idp->len,
519 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
520 0, NULL, NULL, buffer->data, buffer->len, TRUE);
521 silc_buffer_free(buffer);
522 silc_buffer_free(idp);
524 /* Notify application */
528 silc_client_command_free(cmd);
531 /* Command INVITE. Invites specific client to join a channel. This is
532 also used to mange the invite list of the channel. */
534 SILC_CLIENT_CMD_FUNC(invite)
536 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
537 SilcClient client = cmd->client;
538 SilcClientConnection conn = cmd->conn;
539 SilcClientEntry client_entry = NULL;
540 SilcChannelEntry channel;
541 SilcBuffer buffer, clidp, chidp;
542 unsigned int num = 0, type = 0;
543 char *nickname = NULL, *server = NULL, *name;
547 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
553 cmd->client->ops->say(cmd->client, conn,
554 "Usage: /INVITE <channel> [<nickname>[@server>]"
555 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
560 if (cmd->argv[1][0] == '*') {
561 if (!conn->current_channel) {
562 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
567 channel = conn->current_channel;
571 channel = silc_client_get_channel(cmd->client, conn, name);
573 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
579 /* Parse the typed nickname. */
580 if (cmd->argc == 3) {
581 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
582 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
583 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
588 /* Find client entry */
589 client_entry = silc_idlist_get_client(client, conn, nickname,
602 /* Client entry not found, it was requested thus mark this to be
604 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
606 silc_client_command_destructor,
607 silc_client_command_invite,
608 silc_client_command_dup(cmd));
613 cmd->client->ops->say(cmd->client, conn,
614 "Inviting %s to channel %s", cmd->argv[2],
615 channel->channel_name);
617 invite = cmd->argv[2];
619 if (cmd->argv[2][0] == '+')
626 /* Send the command */
627 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
629 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
630 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
631 ++conn->cmd_ident, 3,
632 1, chidp->data, chidp->len,
633 2, clidp->data, clidp->len,
634 type, invite, invite ?
636 silc_buffer_free(clidp);
638 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
639 ++conn->cmd_ident, 2,
640 1, chidp->data, chidp->len,
641 type, invite, invite ?
645 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
646 0, NULL, NULL, buffer->data, buffer->len, TRUE);
647 silc_buffer_free(buffer);
648 silc_buffer_free(chidp);
650 /* Notify application */
658 silc_client_command_free(cmd);
663 SilcClientConnection conn;
666 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
668 QuitInternal q = (QuitInternal)context;
670 /* Close connection */
671 q->client->ops->disconnect(q->client, q->conn);
672 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
677 /* Command QUIT. Closes connection with current server. */
679 SILC_CLIENT_CMD_FUNC(quit)
681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
686 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
692 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
693 &cmd->argv[1], &cmd->argv_lens[1],
694 &cmd->argv_types[1], 0);
696 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
697 NULL, NULL, NULL, 0);
698 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
700 buffer->data, buffer->len, TRUE);
701 silc_buffer_free(buffer);
703 q = silc_calloc(1, sizeof(*q));
704 q->client = cmd->client;
707 /* We quit the connection with little timeout */
708 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
709 silc_client_command_quit_cb, (void *)q,
710 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
712 /* Notify application */
716 silc_client_command_free(cmd);
719 /* Command KILL. Router operator can use this command to remove an client
720 fromthe SILC Network. */
722 SILC_CLIENT_CMD_FUNC(kill)
724 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
725 SilcClientConnection conn = cmd->conn;
726 SilcBuffer buffer, idp;
727 SilcClientEntry target;
728 unsigned int num = 0;
729 char *nickname = NULL, *server = NULL;
732 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
738 cmd->client->ops->say(cmd->client, conn,
739 "Usage: /KILL <nickname> [<comment>]");
744 /* Parse the typed nickname. */
745 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
746 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
751 /* Get the target client */
752 target = silc_idlist_get_client(cmd->client, conn, nickname,
764 /* Client entry not found, it was requested thus mark this to be
766 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
768 silc_client_command_destructor,
769 silc_client_command_kill,
770 silc_client_command_dup(cmd));
775 /* Send the KILL command to the server */
776 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
778 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
779 1, idp->data, idp->len);
781 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
782 1, idp->data, idp->len,
784 strlen(cmd->argv[2]));
785 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
786 0, NULL, NULL, buffer->data, buffer->len, TRUE);
787 silc_buffer_free(buffer);
788 silc_buffer_free(idp);
790 /* Notify application */
798 silc_client_command_free(cmd);
801 /* Command INFO. Request information about specific server. If specific
802 server is not provided the current server is used. */
804 SILC_CLIENT_CMD_FUNC(info)
806 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
807 SilcClientConnection conn = cmd->conn;
812 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
818 name = strdup(cmd->argv[1]);
820 /* Send the command */
822 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
823 1, name, strlen(name));
825 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
826 NULL, NULL, NULL, 0);
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);
833 /* Notify application */
837 silc_client_command_free(cmd);
840 /* Command PING. Sends ping to server. This is used to test the
841 communication channel. */
843 SILC_CLIENT_CMD_FUNC(ping)
845 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
846 SilcClientConnection conn = cmd->conn;
853 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
858 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
859 name = strdup(conn->remote_host);
861 /* Send the command */
862 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
863 1, conn->remote_id_data,
865 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
866 0, NULL, NULL, buffer->data, buffer->len, TRUE);
867 silc_buffer_free(buffer);
869 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
872 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
877 /* Start counting time */
878 for (i = 0; i < conn->ping_count; i++) {
879 if (conn->ping[i].dest_id == NULL) {
880 conn->ping[i].start_time = time(NULL);
881 conn->ping[i].dest_id = id;
882 conn->ping[i].dest_name = name;
887 if (i >= conn->ping_count) {
888 i = conn->ping_count;
889 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
890 conn->ping[i].start_time = time(NULL);
891 conn->ping[i].dest_id = id;
892 conn->ping[i].dest_name = name;
896 /* Notify application */
900 silc_client_command_free(cmd);
903 SILC_CLIENT_CMD_FUNC(notice)
907 /* Command JOIN. Joins to a channel. */
909 SILC_CLIENT_CMD_FUNC(join)
911 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
912 SilcClientConnection conn = cmd->conn;
913 SilcIDCacheEntry id_cache = NULL;
914 SilcBuffer buffer, idp;
917 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
923 /* Show channels currently joined to */
928 /* See if we have joined to the requested channel already */
929 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
931 cmd->client->ops->say(cmd->client, conn,
932 "You are talking to channel %s", cmd->argv[1]);
933 conn->current_channel = (SilcChannelEntry)id_cache->context;
935 cmd->client->screen->bottom_line->channel = cmd->argv[1];
936 silc_screen_print_bottom_line(cmd->client->screen, 0);
941 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
943 /* Send JOIN command to the server */
946 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
947 1, cmd->argv[1], cmd->argv_lens[1],
948 2, idp->data, idp->len);
949 else if (cmd->argc == 3)
952 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
953 1, cmd->argv[1], cmd->argv_lens[1],
954 2, idp->data, idp->len,
955 3, cmd->argv[2], cmd->argv_lens[2]);
958 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
959 1, cmd->argv[1], cmd->argv_lens[1],
960 2, idp->data, idp->len,
961 3, cmd->argv[2], cmd->argv_lens[2],
962 4, cmd->argv[3], cmd->argv_lens[3]);
964 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
965 0, NULL, NULL, buffer->data, buffer->len, TRUE);
966 silc_buffer_free(buffer);
967 silc_buffer_free(idp);
969 /* Notify application */
973 silc_client_command_free(cmd);
976 /* MOTD command. Requests motd from server. */
978 SILC_CLIENT_CMD_FUNC(motd)
980 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
981 SilcClientConnection conn = cmd->conn;
985 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
990 if (cmd->argc < 1 || cmd->argc > 2) {
991 cmd->client->ops->say(cmd->client, conn,
992 "Usage: /MOTD [<server>]");
997 /* Send TOPIC command to the server */
999 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1000 1, conn->remote_host,
1001 strlen(conn->remote_host));
1003 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1006 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1007 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1008 silc_buffer_free(buffer);
1010 /* Notify application */
1014 silc_client_command_free(cmd);
1017 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1018 modes as client cannot set itself server/router operator privileges. */
1020 SILC_CLIENT_CMD_FUNC(umode)
1022 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1023 SilcClientConnection conn = cmd->conn;
1024 SilcBuffer buffer, idp;
1025 unsigned char *cp, modebuf[4];
1026 unsigned int mode, add, len;
1030 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1035 if (cmd->argc < 2) {
1036 cmd->client->ops->say(cmd->client, conn,
1037 "Usage: /UMODE +|-<modes>");
1042 mode = conn->local_entry->mode;
1044 /* Are we adding or removing mode */
1045 if (cmd->argv[1][0] == '-')
1051 cp = cmd->argv[1] + 1;
1053 for (i = 0; i < len; i++) {
1058 mode |= SILC_UMODE_SERVER_OPERATOR;
1059 mode |= SILC_UMODE_ROUTER_OPERATOR;
1061 mode = SILC_UMODE_NONE;
1066 mode |= SILC_UMODE_SERVER_OPERATOR;
1068 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1072 mode |= SILC_UMODE_ROUTER_OPERATOR;
1074 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1078 mode |= SILC_UMODE_GONE;
1080 mode &= ~SILC_UMODE_GONE;
1089 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1090 SILC_PUT32_MSB(mode, modebuf);
1092 /* Send the command packet. We support sending only one mode at once
1093 that requires an argument. */
1095 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1096 1, idp->data, idp->len,
1097 2, modebuf, sizeof(modebuf));
1098 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1099 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1100 silc_buffer_free(buffer);
1101 silc_buffer_free(idp);
1103 /* Notify application */
1107 silc_client_command_free(cmd);
1110 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1111 can be set several at once. Those modes that require argument must be set
1112 separately (unless set with modes that does not require arguments). */
1114 SILC_CLIENT_CMD_FUNC(cmode)
1116 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1117 SilcClientConnection conn = cmd->conn;
1118 SilcChannelEntry channel;
1119 SilcBuffer buffer, chidp, auth = NULL;
1120 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1121 unsigned int mode, add, type, len, arg_len = 0;
1125 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1130 if (cmd->argc < 3) {
1131 cmd->client->ops->say(cmd->client, conn,
1132 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1137 if (cmd->argv[1][0] == '*') {
1138 if (!conn->current_channel) {
1139 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1144 channel = conn->current_channel;
1146 name = cmd->argv[1];
1148 channel = silc_client_get_channel(cmd->client, conn, name);
1150 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1156 mode = channel->mode;
1158 /* Are we adding or removing mode */
1159 if (cmd->argv[2][0] == '-')
1164 /* Argument type to be sent to server */
1168 cp = cmd->argv[2] + 1;
1170 for (i = 0; i < len; i++) {
1174 mode |= SILC_CHANNEL_MODE_PRIVATE;
1176 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1180 mode |= SILC_CHANNEL_MODE_SECRET;
1182 mode &= ~SILC_CHANNEL_MODE_SECRET;
1186 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1188 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1192 mode |= SILC_CHANNEL_MODE_INVITE;
1194 mode &= ~SILC_CHANNEL_MODE_INVITE;
1198 mode |= SILC_CHANNEL_MODE_TOPIC;
1200 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1205 mode |= SILC_CHANNEL_MODE_ULIMIT;
1207 ll = atoi(cmd->argv[3]);
1208 SILC_PUT32_MSB(ll, tmp);
1212 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1217 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1220 arg_len = cmd->argv_lens[3];
1222 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1227 mode |= SILC_CHANNEL_MODE_CIPHER;
1230 arg_len = cmd->argv_lens[3];
1232 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1237 mode |= SILC_CHANNEL_MODE_HMAC;
1240 arg_len = cmd->argv_lens[3];
1242 mode &= ~SILC_CHANNEL_MODE_HMAC;
1247 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1250 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1251 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1252 cmd->client->private_key,
1257 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1258 cmd->argv[3], cmd->argv_lens[3]);
1262 arg_len = auth->len;
1264 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1274 if (type && cmd->argc < 3) {
1279 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1280 SILC_PUT32_MSB(mode, modebuf);
1282 /* Send the command packet. We support sending only one mode at once
1283 that requires an argument. */
1286 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1287 1, chidp->data, chidp->len,
1288 2, modebuf, sizeof(modebuf),
1289 type, arg, arg_len);
1292 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1293 1, chidp->data, chidp->len,
1294 2, modebuf, sizeof(modebuf));
1297 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1298 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1299 silc_buffer_free(buffer);
1300 silc_buffer_free(chidp);
1302 silc_buffer_free(auth);
1304 /* Notify application */
1308 silc_client_command_free(cmd);
1311 /* CUMODE command. Changes client's mode on a channel. */
1313 SILC_CLIENT_CMD_FUNC(cumode)
1315 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1316 SilcClientConnection conn = cmd->conn;
1317 SilcChannelEntry channel;
1318 SilcChannelUser chu;
1319 SilcClientEntry client_entry;
1320 SilcBuffer buffer, clidp, chidp, auth = NULL;
1321 unsigned char *name, *cp, modebuf[4];
1322 unsigned int mode = 0, add, len;
1323 char *nickname = NULL, *server = NULL;
1324 unsigned int num = 0;
1328 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1333 if (cmd->argc < 4) {
1334 cmd->client->ops->say(cmd->client, conn,
1335 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1340 if (cmd->argv[1][0] == '*') {
1341 if (!conn->current_channel) {
1342 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1347 channel = conn->current_channel;
1349 name = cmd->argv[1];
1351 channel = silc_client_get_channel(cmd->client, conn, name);
1353 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1359 /* Parse the typed nickname. */
1360 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1361 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1366 /* Find client entry */
1367 client_entry = silc_idlist_get_client(cmd->client, conn,
1368 nickname, server, num, TRUE);
1369 if (!client_entry) {
1375 /* Client entry not found, it was requested thus mark this to be
1377 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1379 silc_client_command_destructor,
1380 silc_client_command_cumode,
1381 silc_client_command_dup(cmd));
1386 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1387 if (chu->client == client_entry) {
1393 /* Are we adding or removing mode */
1394 if (cmd->argv[2][0] == '-')
1400 cp = cmd->argv[2] + 1;
1402 for (i = 0; i < len; i++) {
1406 mode |= SILC_CHANNEL_UMODE_CHANFO;
1407 mode |= SILC_CHANNEL_UMODE_CHANOP;
1409 mode = SILC_CHANNEL_UMODE_NONE;
1414 if (cmd->argc == 5) {
1415 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1416 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1417 cmd->client->private_key,
1422 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1423 cmd->argv[4], cmd->argv_lens[4]);
1426 mode |= SILC_CHANNEL_UMODE_CHANFO;
1428 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1433 mode |= SILC_CHANNEL_UMODE_CHANOP;
1435 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1444 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1445 SILC_PUT32_MSB(mode, modebuf);
1446 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1448 /* Send the command packet. We support sending only one mode at once
1449 that requires an argument. */
1450 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1451 1, chidp->data, chidp->len,
1453 3, clidp->data, clidp->len,
1454 4, auth ? auth->data : NULL,
1455 auth ? auth->len : 0);
1457 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1458 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1459 silc_buffer_free(buffer);
1460 silc_buffer_free(chidp);
1461 silc_buffer_free(clidp);
1463 silc_buffer_free(auth);
1465 /* Notify application */
1470 silc_free(nickname);
1473 silc_client_command_free(cmd);
1476 /* KICK command. Kicks a client out of channel. */
1478 SILC_CLIENT_CMD_FUNC(kick)
1480 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1481 SilcClientConnection conn = cmd->conn;
1482 SilcIDCacheEntry id_cache = NULL;
1483 SilcChannelEntry channel;
1484 SilcBuffer buffer, idp, idp2;
1485 SilcClientEntry target;
1487 unsigned int num = 0;
1488 char *nickname = NULL, *server = NULL;
1491 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1496 if (cmd->argc < 3) {
1497 cmd->client->ops->say(cmd->client, conn,
1498 "Usage: /KICK <channel> <nickname> [<comment>]");
1503 if (cmd->argv[1][0] == '*') {
1504 if (!conn->current_channel) {
1505 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1509 name = conn->current_channel->channel_name;
1511 name = cmd->argv[1];
1514 if (!conn->current_channel) {
1515 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1520 /* Get the Channel ID of the channel */
1521 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1522 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1527 channel = (SilcChannelEntry)id_cache->context;
1529 /* Parse the typed nickname. */
1530 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1531 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1536 /* Get the target client */
1537 target = silc_idlist_get_client(cmd->client, conn, nickname,
1538 server, num, FALSE);
1540 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1546 /* Send KICK command to the server */
1547 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1548 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1550 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1551 1, idp->data, idp->len,
1552 2, idp2->data, idp2->len);
1554 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1555 1, idp->data, idp->len,
1556 2, idp2->data, idp2->len,
1558 strlen(cmd->argv[3]));
1559 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1560 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1561 silc_buffer_free(buffer);
1562 silc_buffer_free(idp);
1563 silc_buffer_free(idp2);
1565 /* Notify application */
1570 silc_free(nickname);
1573 silc_client_command_free(cmd);
1576 /* OPER command. Used to obtain server operator privileges. */
1578 SILC_CLIENT_CMD_FUNC(oper)
1580 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1581 SilcClientConnection conn = cmd->conn;
1583 unsigned char *auth_data;
1587 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1592 if (cmd->argc < 2) {
1593 cmd->client->ops->say(cmd->client, conn,
1594 "Usage: /OPER <username> [<public key>]");
1599 if (cmd->argc == 3) {
1600 /* XXX Get public key */
1605 /* Get passphrase */
1607 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1613 /* Encode the authentication payload */
1614 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1615 auth_data, strlen(auth_data));
1618 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1620 strlen(cmd->argv[1]),
1621 2, auth->data, auth->len);
1622 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1623 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1625 silc_buffer_free(buffer);
1626 silc_buffer_free(auth);
1627 memset(auth_data, 0, strlen(auth_data));
1628 silc_free(auth_data);
1630 /* Notify application */
1634 silc_client_command_free(cmd);
1637 /* SILCOPER command. Used to obtain router operator privileges. */
1639 SILC_CLIENT_CMD_FUNC(silcoper)
1641 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1642 SilcClientConnection conn = cmd->conn;
1644 unsigned char *auth_data;
1648 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1653 if (cmd->argc < 2) {
1654 cmd->client->ops->say(cmd->client, conn,
1655 "Usage: /SILCOPER <username> [<public key>]");
1660 if (cmd->argc == 3) {
1661 /* XXX Get public key */
1666 /* Get passphrase */
1668 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1674 /* Encode the authentication payload */
1675 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1676 auth_data, strlen(auth_data));
1679 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1681 strlen(cmd->argv[1]),
1682 2, auth->data, auth->len);
1683 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1684 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1686 silc_buffer_free(buffer);
1687 silc_buffer_free(auth);
1688 memset(auth_data, 0, strlen(auth_data));
1689 silc_free(auth_data);
1691 /* Notify application */
1695 silc_client_command_free(cmd);
1698 /* CONNECT command. Connects the server to another server. */
1700 SILC_CLIENT_CMD_FUNC(connect)
1702 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1703 SilcClientConnection conn = cmd->conn;
1705 unsigned char port[4];
1709 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1714 if (cmd->argc < 2) {
1715 cmd->client->ops->say(cmd->client, conn,
1716 "Usage: /CONNECT <server> [<port>]");
1721 if (cmd->argc == 3) {
1722 tmp = atoi(cmd->argv[2]);
1723 SILC_PUT32_MSB(tmp, port);
1727 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1729 strlen(cmd->argv[1]),
1732 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1734 strlen(cmd->argv[1]));
1735 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1736 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1737 silc_buffer_free(buffer);
1739 /* Notify application */
1743 silc_client_command_free(cmd);
1746 /* Command BAN. This is used to manage the ban list of the channel. */
1748 SILC_CLIENT_CMD_FUNC(ban)
1750 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1751 SilcClientConnection conn = cmd->conn;
1752 SilcChannelEntry channel;
1753 SilcBuffer buffer, chidp;
1755 char *name, *ban = NULL;
1758 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1763 if (cmd->argc < 2) {
1764 cmd->client->ops->say(cmd->client, conn,
1765 "Usage: /BAN <channel> "
1766 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1771 if (cmd->argv[1][0] == '*') {
1772 if (!conn->current_channel) {
1773 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1778 channel = conn->current_channel;
1780 name = cmd->argv[1];
1782 channel = silc_client_get_channel(cmd->client, conn, name);
1784 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1790 if (cmd->argc == 3) {
1791 if (cmd->argv[2][0] == '+')
1800 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1802 /* Send the command */
1804 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1805 1, chidp->data, chidp->len,
1806 type, ban, strlen(ban));
1808 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1809 1, chidp->data, chidp->len);
1811 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1812 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1813 silc_buffer_free(buffer);
1814 silc_buffer_free(chidp);
1816 /* Notify application */
1820 silc_client_command_free(cmd);
1823 /* CLOSE command. Close server connection to the remote server */
1825 SILC_CLIENT_CMD_FUNC(close)
1827 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1828 SilcClientConnection conn = cmd->conn;
1830 unsigned char port[4];
1834 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1839 if (cmd->argc < 2) {
1840 cmd->client->ops->say(cmd->client, conn,
1841 "Usage: /CLOSE <server> [<port>]");
1846 if (cmd->argc == 3) {
1847 tmp = atoi(cmd->argv[2]);
1848 SILC_PUT32_MSB(tmp, port);
1852 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1854 strlen(cmd->argv[1]),
1857 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1859 strlen(cmd->argv[1]));
1860 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1861 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1862 silc_buffer_free(buffer);
1864 /* Notify application */
1868 silc_client_command_free(cmd);
1871 /* SHUTDOWN command. Shutdowns the server. */
1873 SILC_CLIENT_CMD_FUNC(shutdown)
1875 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1878 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1883 /* Send the command */
1884 silc_client_send_command(cmd->client, cmd->conn,
1885 SILC_COMMAND_SHUTDOWN, 0, 0);
1887 /* Notify application */
1891 silc_client_command_free(cmd);
1894 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1896 SILC_CLIENT_CMD_FUNC(leave)
1898 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1899 SilcClientConnection conn = cmd->conn;
1900 SilcIDCacheEntry id_cache = NULL;
1901 SilcChannelEntry channel;
1902 SilcBuffer buffer, idp;
1906 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1911 if (cmd->argc != 2) {
1912 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1917 if (cmd->argv[1][0] == '*') {
1918 if (!conn->current_channel) {
1919 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1923 name = conn->current_channel->channel_name;
1925 name = cmd->argv[1];
1928 if (!conn->current_channel) {
1929 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1934 /* Get the Channel ID of the channel */
1935 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1936 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1941 channel = (SilcChannelEntry)id_cache->context;
1943 /* Send LEAVE command to the server */
1944 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1945 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1946 1, idp->data, idp->len);
1947 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1948 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1949 silc_buffer_free(buffer);
1950 silc_buffer_free(idp);
1952 /* We won't talk anymore on this channel */
1953 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1955 conn->current_channel = NULL;
1957 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1958 silc_free(channel->channel_name);
1959 silc_free(channel->id);
1960 silc_free(channel->key);
1961 silc_cipher_free(channel->channel_key);
1964 /* Notify application */
1968 silc_client_command_free(cmd);
1971 /* Command USERS. Requests the USERS of the clients joined on requested
1974 SILC_CLIENT_CMD_FUNC(users)
1976 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1977 SilcClientConnection conn = cmd->conn;
1978 SilcIDCacheEntry id_cache = NULL;
1979 SilcChannelEntry channel;
1980 SilcBuffer buffer, idp;
1984 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1989 if (cmd->argc != 2) {
1990 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1995 if (cmd->argv[1][0] == '*') {
1996 if (!conn->current_channel) {
1997 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2001 name = conn->current_channel->channel_name;
2003 name = cmd->argv[1];
2006 if (!conn->current_channel) {
2007 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2012 /* Get the Channel ID of the channel */
2013 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
2014 /* XXX should resolve the channel ID; LIST command */
2015 cmd->client->ops->say(cmd->client, conn,
2016 "You are not on that channel", name);
2021 channel = (SilcChannelEntry)id_cache->context;
2023 if (!cmd->pending) {
2024 /* Send USERS command to the server */
2025 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2026 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2027 ++conn->cmd_ident, 1,
2028 1, idp->data, idp->len);
2029 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2030 NULL, 0, NULL, NULL, buffer->data,
2032 silc_buffer_free(buffer);
2033 silc_buffer_free(idp);
2035 /* Register pending callback which will recall this command callback with
2036 same context and reprocesses the command. When reprocessing we actually
2037 display the information on the screen. */
2038 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2039 silc_client_command_destructor,
2040 silc_client_command_users,
2041 silc_client_command_dup(cmd));
2042 cmd->pending = TRUE;
2046 /* Notify application */
2050 silc_client_command_free(cmd);