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),
60 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2),
62 { NULL, 0, NULL, 0, 0 },
65 #define SILC_NOT_CONNECTED(x, c) \
66 x->ops->say((x), (c), \
67 "You are not connected to a server, use /SERVER to connect");
69 /* Command operation that is called at the end of all commands.
71 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
72 cmd, TRUE, cmd->command->cmd)
74 /* Error to application. Usage: COMMAND_ERROR; */
75 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
76 cmd, FALSE, cmd->command->cmd)
78 /* Generic function to send any command. The arguments must be sent already
79 encoded into correct form and in correct order. */
81 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
82 SilcCommand command, uint16 ident,
90 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
91 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
92 NULL, 0, NULL, NULL, packet->data,
94 silc_buffer_free(packet);
97 /* Finds and returns a pointer to the command list. Return NULL if the
98 command is not found. */
100 SilcClientCommand *silc_client_command_find(const char *name)
102 SilcClientCommand *cmd;
104 for (cmd = silc_command_list; cmd->name; cmd++) {
105 if (!strcmp(cmd->name, name))
112 /* Add new pending command to be executed when reply to a command has been
113 received. The `reply_cmd' is the command that will call the `callback'
114 with `context' when reply has been received. If `ident is non-zero
115 the `callback' will be executed when received reply with command
116 identifier `ident'. */
118 void silc_client_command_pending(SilcClientConnection conn,
119 SilcCommand reply_cmd,
121 SilcClientPendingDestructor destructor,
122 SilcCommandCb callback,
125 SilcClientCommandPending *reply;
127 reply = silc_calloc(1, sizeof(*reply));
128 reply->reply_cmd = reply_cmd;
129 reply->ident = ident;
130 reply->context = context;
131 reply->callback = callback;
132 reply->destructor = destructor;
133 silc_dlist_add(conn->pending_commands, reply);
136 /* Deletes pending command by reply command type. */
138 void silc_client_command_pending_del(SilcClientConnection conn,
139 SilcCommand reply_cmd,
142 SilcClientCommandPending *r;
144 silc_dlist_start(conn->pending_commands);
145 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
146 if (r->reply_cmd == reply_cmd && r->ident == ident) {
147 silc_dlist_del(conn->pending_commands, r);
153 /* Checks for pending commands and marks callbacks to be called from
154 the command reply function. Returns TRUE if there were pending command. */
156 int silc_client_command_pending_check(SilcClientConnection conn,
157 SilcClientCommandReplyContext ctx,
161 SilcClientCommandPending *r;
163 silc_dlist_start(conn->pending_commands);
164 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
165 if (r->reply_cmd == command && r->ident == ident) {
166 ctx->context = r->context;
167 ctx->callback = r->callback;
168 ctx->destructor = r->destructor;
177 /* Allocate Command Context */
179 SilcClientCommandContext silc_client_command_alloc()
181 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
186 /* Free command context and its internals */
188 void silc_client_command_free(SilcClientCommandContext ctx)
191 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
193 if (ctx->users < 1) {
196 for (i = 0; i < ctx->argc; i++)
197 silc_free(ctx->argv[i]);
198 silc_free(ctx->argv_lens);
199 silc_free(ctx->argv_types);
204 /* Duplicate Command Context by adding reference counter. The context won't
205 be free'd untill it hits zero. */
207 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
210 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
215 /* Pending command destructor. */
217 static void silc_client_command_destructor(void *context)
219 silc_client_command_free((SilcClientCommandContext)context);
222 /* silc_client_get_client completion callback */
223 void silc_client_command_completion(SilcClient client,
224 SilcClientConnection conn,
225 SilcClientEntry clients,
226 uint32 clients_count,
232 /* Command WHOIS. This command is used to query information about
235 SILC_CLIENT_CMD_FUNC(whois)
237 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
238 SilcClientConnection conn = cmd->conn;
242 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
247 if (cmd->argc < 2 || cmd->argc > 3) {
248 cmd->client->ops->say(cmd->client, conn,
249 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
254 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
255 cmd->argc - 1, ++cmd->argv,
256 ++cmd->argv_lens, ++cmd->argv_types,
258 silc_client_packet_send(cmd->client, cmd->conn->sock,
259 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
260 buffer->data, buffer->len, TRUE);
261 silc_buffer_free(buffer);
266 /* Notify application */
270 silc_client_command_free(cmd);
273 /* Command WHOWAS. This command is used to query history information about
274 specific user that used to exist in the network. */
276 SILC_CLIENT_CMD_FUNC(whowas)
278 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
279 SilcClientConnection conn = cmd->conn;
283 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
288 if (cmd->argc < 2 || cmd->argc > 3) {
289 cmd->client->ops->say(cmd->client, conn,
290 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
295 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
296 cmd->argc - 1, ++cmd->argv,
297 ++cmd->argv_lens, ++cmd->argv_types,
299 silc_client_packet_send(cmd->client, cmd->conn->sock,
300 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
301 buffer->data, buffer->len, TRUE);
302 silc_buffer_free(buffer);
307 /* Notify application */
311 silc_client_command_free(cmd);
314 /* Command IDENTIFY. This command is used to query information about
315 specific user, especially ID's. */
317 SILC_CLIENT_CMD_FUNC(identify)
319 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
320 SilcClientConnection conn = cmd->conn;
324 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
329 if (cmd->argc < 2 || cmd->argc > 3) {
330 cmd->client->ops->say(cmd->client, conn,
331 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
336 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
337 cmd->argc - 1, ++cmd->argv,
338 ++cmd->argv_lens, ++cmd->argv_types,
340 silc_client_packet_send(cmd->client, cmd->conn->sock,
341 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
342 buffer->data, buffer->len, TRUE);
343 silc_buffer_free(buffer);
348 /* Notify application */
352 silc_client_command_free(cmd);
355 /* Command NICK. Shows current nickname/sets new nickname on current
358 SILC_CLIENT_CMD_FUNC(nick)
360 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
361 SilcClientConnection conn = cmd->conn;
365 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
370 if (!strcmp(conn->nickname, cmd->argv[1]))
373 /* Show current nickname */
376 cmd->client->ops->say(cmd->client, conn,
377 "Your nickname is %s on server %s",
378 conn->nickname, conn->remote_host);
380 cmd->client->ops->say(cmd->client, conn,
381 "Your nickname is %s", conn->nickname);
384 /* XXX Notify application */
389 /* Set new nickname */
390 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
391 cmd->argc - 1, ++cmd->argv,
392 ++cmd->argv_lens, ++cmd->argv_types,
393 ++cmd->conn->cmd_ident);
394 silc_client_packet_send(cmd->client, cmd->conn->sock,
395 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
396 buffer->data, buffer->len, TRUE);
397 silc_buffer_free(buffer);
402 silc_free(conn->nickname);
403 conn->nickname = strdup(cmd->argv[1]);
405 /* Notify application */
409 silc_client_command_free(cmd);
412 /* Command LIST. Lists channels on the current server. */
414 SILC_CLIENT_CMD_FUNC(list)
416 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
417 SilcClientConnection conn = cmd->conn;
418 SilcIDCacheEntry id_cache = NULL;
419 SilcChannelEntry channel;
420 SilcBuffer buffer, idp = NULL;
424 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
429 if (cmd->argc == 2) {
432 /* Get the Channel ID of the channel */
433 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
434 channel = (SilcChannelEntry)id_cache->context;
435 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
440 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
441 ++conn->cmd_ident, 0);
443 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
444 ++conn->cmd_ident, 1,
445 1, idp->data, idp->len);
447 silc_client_packet_send(cmd->client, cmd->conn->sock,
448 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
449 buffer->data, buffer->len, TRUE);
450 silc_buffer_free(buffer);
452 silc_buffer_free(idp);
454 /* Notify application */
458 silc_client_command_free(cmd);
461 /* Command TOPIC. Sets/shows topic on a channel. */
463 SILC_CLIENT_CMD_FUNC(topic)
465 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
466 SilcClientConnection conn = cmd->conn;
467 SilcIDCacheEntry id_cache = NULL;
468 SilcChannelEntry channel;
469 SilcBuffer buffer, idp;
473 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
478 if (cmd->argc < 2 || cmd->argc > 3) {
479 cmd->client->ops->say(cmd->client, conn,
480 "Usage: /TOPIC <channel> [<topic>]");
485 if (cmd->argv[1][0] == '*') {
486 if (!conn->current_channel) {
487 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
491 name = conn->current_channel->channel_name;
496 if (!conn->current_channel) {
497 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
502 /* Get the Channel ID of the channel */
503 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
504 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
509 channel = (SilcChannelEntry)id_cache->context;
511 /* Send TOPIC command to the server */
512 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
514 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
515 ++conn->cmd_ident, 2,
516 1, idp->data, idp->len,
518 strlen(cmd->argv[2]));
520 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
521 ++conn->cmd_ident, 1,
522 1, idp->data, idp->len);
523 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
524 0, NULL, NULL, buffer->data, buffer->len, TRUE);
525 silc_buffer_free(buffer);
526 silc_buffer_free(idp);
528 /* Notify application */
532 silc_client_command_free(cmd);
535 /* Command INVITE. Invites specific client to join a channel. This is
536 also used to mange the invite list of the channel. */
538 SILC_CLIENT_CMD_FUNC(invite)
540 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
541 SilcClient client = cmd->client;
542 SilcClientConnection conn = cmd->conn;
543 SilcClientEntry client_entry = NULL;
544 SilcChannelEntry channel;
545 SilcBuffer buffer, clidp, chidp;
546 uint32 num = 0, type = 0;
547 char *nickname = NULL, *server = NULL, *name;
551 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
557 cmd->client->ops->say(cmd->client, conn,
558 "Usage: /INVITE <channel> [<nickname>[@server>]"
559 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
564 if (cmd->argv[1][0] == '*') {
565 if (!conn->current_channel) {
566 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
571 channel = conn->current_channel;
575 channel = silc_client_get_channel(cmd->client, conn, name);
577 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
583 /* Parse the typed nickname. */
584 if (cmd->argc == 3) {
585 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
586 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
587 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
592 /* Find client entry */
593 client_entry = silc_idlist_get_client(client, conn, nickname,
606 /* Client entry not found, it was requested thus mark this to be
608 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
610 silc_client_command_destructor,
611 silc_client_command_invite,
612 silc_client_command_dup(cmd));
617 cmd->client->ops->say(cmd->client, conn,
618 "Inviting %s to channel %s", cmd->argv[2],
619 channel->channel_name);
621 invite = cmd->argv[2];
623 if (cmd->argv[2][0] == '+')
630 /* Send the command */
631 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
633 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
634 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
635 ++conn->cmd_ident, 3,
636 1, chidp->data, chidp->len,
637 2, clidp->data, clidp->len,
638 type, invite, invite ?
640 silc_buffer_free(clidp);
642 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
643 ++conn->cmd_ident, 2,
644 1, chidp->data, chidp->len,
645 type, invite, invite ?
649 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
650 0, NULL, NULL, buffer->data, buffer->len, TRUE);
651 silc_buffer_free(buffer);
652 silc_buffer_free(chidp);
654 /* Notify application */
662 silc_client_command_free(cmd);
667 SilcClientConnection conn;
670 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
672 QuitInternal q = (QuitInternal)context;
674 /* Close connection */
675 q->client->ops->disconnect(q->client, q->conn);
676 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
681 /* Command QUIT. Closes connection with current server. */
683 SILC_CLIENT_CMD_FUNC(quit)
685 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
690 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
696 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
697 &cmd->argv[1], &cmd->argv_lens[1],
698 &cmd->argv_types[1], 0);
700 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
701 NULL, NULL, NULL, 0);
702 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
704 buffer->data, buffer->len, TRUE);
705 silc_buffer_free(buffer);
707 q = silc_calloc(1, sizeof(*q));
708 q->client = cmd->client;
711 /* We quit the connection with little timeout */
712 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
713 silc_client_command_quit_cb, (void *)q,
714 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
716 /* Notify application */
720 silc_client_command_free(cmd);
723 /* Command KILL. Router operator can use this command to remove an client
724 fromthe SILC Network. */
726 SILC_CLIENT_CMD_FUNC(kill)
728 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
729 SilcClientConnection conn = cmd->conn;
730 SilcBuffer buffer, idp;
731 SilcClientEntry target;
733 char *nickname = NULL, *server = NULL;
736 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
742 cmd->client->ops->say(cmd->client, conn,
743 "Usage: /KILL <nickname> [<comment>]");
748 /* Parse the typed nickname. */
749 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
750 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
755 /* Get the target client */
756 target = silc_idlist_get_client(cmd->client, conn, nickname,
768 /* Client entry not found, it was requested thus mark this to be
770 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
772 silc_client_command_destructor,
773 silc_client_command_kill,
774 silc_client_command_dup(cmd));
779 /* Send the KILL command to the server */
780 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
782 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
783 1, idp->data, idp->len);
785 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
786 1, idp->data, idp->len,
788 strlen(cmd->argv[2]));
789 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
790 0, NULL, NULL, buffer->data, buffer->len, TRUE);
791 silc_buffer_free(buffer);
792 silc_buffer_free(idp);
794 /* Notify application */
802 silc_client_command_free(cmd);
805 /* Command INFO. Request information about specific server. If specific
806 server is not provided the current server is used. */
808 SILC_CLIENT_CMD_FUNC(info)
810 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
811 SilcClientConnection conn = cmd->conn;
816 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
822 name = strdup(cmd->argv[1]);
824 /* Send the command */
826 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
827 1, name, strlen(name));
829 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
830 NULL, NULL, NULL, 0);
831 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
832 0, NULL, NULL, buffer->data, buffer->len, TRUE);
833 silc_buffer_free(buffer);
837 /* Notify application */
841 silc_client_command_free(cmd);
844 /* Command PING. Sends ping to server. This is used to test the
845 communication channel. */
847 SILC_CLIENT_CMD_FUNC(ping)
849 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
850 SilcClientConnection conn = cmd->conn;
857 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
862 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
863 name = strdup(conn->remote_host);
865 /* Send the command */
866 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
867 1, conn->remote_id_data,
868 silc_id_get_len(conn->remote_id,
870 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
871 0, NULL, NULL, buffer->data, buffer->len, TRUE);
872 silc_buffer_free(buffer);
874 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
877 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
882 /* Start counting time */
883 for (i = 0; i < conn->ping_count; i++) {
884 if (conn->ping[i].dest_id == NULL) {
885 conn->ping[i].start_time = time(NULL);
886 conn->ping[i].dest_id = id;
887 conn->ping[i].dest_name = name;
892 if (i >= conn->ping_count) {
893 i = conn->ping_count;
894 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
895 conn->ping[i].start_time = time(NULL);
896 conn->ping[i].dest_id = id;
897 conn->ping[i].dest_name = name;
901 /* Notify application */
905 silc_client_command_free(cmd);
908 SILC_CLIENT_CMD_FUNC(notice)
912 /* Command JOIN. Joins to a channel. */
914 SILC_CLIENT_CMD_FUNC(join)
916 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
917 SilcClientConnection conn = cmd->conn;
918 SilcIDCacheEntry id_cache = NULL;
919 SilcBuffer buffer, idp;
922 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
928 /* Show channels currently joined to */
933 /* See if we have joined to the requested channel already */
934 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
937 cmd->client->ops->say(cmd->client, conn,
938 "You are talking to channel %s", cmd->argv[1]);
939 conn->current_channel = (SilcChannelEntry)id_cache->context;
940 cmd->client->screen->bottom_line->channel = cmd->argv[1];
941 silc_screen_print_bottom_line(cmd->client->screen, 0);
946 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
948 /* Send JOIN command to the server */
951 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
952 1, cmd->argv[1], cmd->argv_lens[1],
953 2, idp->data, idp->len);
954 else if (cmd->argc == 3)
957 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
958 1, cmd->argv[1], cmd->argv_lens[1],
959 2, idp->data, idp->len,
960 3, cmd->argv[2], cmd->argv_lens[2]);
963 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
964 1, cmd->argv[1], cmd->argv_lens[1],
965 2, idp->data, idp->len,
966 3, cmd->argv[2], cmd->argv_lens[2],
967 4, cmd->argv[3], cmd->argv_lens[3]);
969 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
970 0, NULL, NULL, buffer->data, buffer->len, TRUE);
971 silc_buffer_free(buffer);
972 silc_buffer_free(idp);
974 /* Notify application */
978 silc_client_command_free(cmd);
981 /* MOTD command. Requests motd from server. */
983 SILC_CLIENT_CMD_FUNC(motd)
985 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
986 SilcClientConnection conn = cmd->conn;
990 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
995 if (cmd->argc < 1 || cmd->argc > 2) {
996 cmd->client->ops->say(cmd->client, conn,
997 "Usage: /MOTD [<server>]");
1002 /* Send TOPIC command to the server */
1004 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1005 1, conn->remote_host,
1006 strlen(conn->remote_host));
1008 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1011 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1012 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1013 silc_buffer_free(buffer);
1015 /* Notify application */
1019 silc_client_command_free(cmd);
1022 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1023 modes as client cannot set itself server/router operator privileges. */
1025 SILC_CLIENT_CMD_FUNC(umode)
1027 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1028 SilcClientConnection conn = cmd->conn;
1029 SilcBuffer buffer, idp;
1030 unsigned char *cp, modebuf[4];
1031 uint32 mode, add, len;
1035 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1040 if (cmd->argc < 2) {
1041 cmd->client->ops->say(cmd->client, conn,
1042 "Usage: /UMODE +|-<modes>");
1047 mode = conn->local_entry->mode;
1049 /* Are we adding or removing mode */
1050 if (cmd->argv[1][0] == '-')
1056 cp = cmd->argv[1] + 1;
1058 for (i = 0; i < len; i++) {
1063 mode |= SILC_UMODE_SERVER_OPERATOR;
1064 mode |= SILC_UMODE_ROUTER_OPERATOR;
1066 mode = SILC_UMODE_NONE;
1071 mode |= SILC_UMODE_SERVER_OPERATOR;
1073 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1077 mode |= SILC_UMODE_ROUTER_OPERATOR;
1079 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1083 mode |= SILC_UMODE_GONE;
1085 mode &= ~SILC_UMODE_GONE;
1094 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1095 SILC_PUT32_MSB(mode, modebuf);
1097 /* Send the command packet. We support sending only one mode at once
1098 that requires an argument. */
1100 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1101 1, idp->data, idp->len,
1102 2, modebuf, sizeof(modebuf));
1103 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1104 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1105 silc_buffer_free(buffer);
1106 silc_buffer_free(idp);
1108 /* Notify application */
1112 silc_client_command_free(cmd);
1115 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1116 can be set several at once. Those modes that require argument must be set
1117 separately (unless set with modes that does not require arguments). */
1119 SILC_CLIENT_CMD_FUNC(cmode)
1121 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1122 SilcClientConnection conn = cmd->conn;
1123 SilcChannelEntry channel;
1124 SilcBuffer buffer, chidp, auth = NULL;
1125 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1126 uint32 mode, add, type, len, arg_len = 0;
1130 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1135 if (cmd->argc < 3) {
1136 cmd->client->ops->say(cmd->client, conn,
1137 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1142 if (cmd->argv[1][0] == '*') {
1143 if (!conn->current_channel) {
1144 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1149 channel = conn->current_channel;
1151 name = cmd->argv[1];
1153 channel = silc_client_get_channel(cmd->client, conn, name);
1155 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1161 mode = channel->mode;
1163 /* Are we adding or removing mode */
1164 if (cmd->argv[2][0] == '-')
1169 /* Argument type to be sent to server */
1173 cp = cmd->argv[2] + 1;
1175 for (i = 0; i < len; i++) {
1179 mode |= SILC_CHANNEL_MODE_PRIVATE;
1181 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1185 mode |= SILC_CHANNEL_MODE_SECRET;
1187 mode &= ~SILC_CHANNEL_MODE_SECRET;
1191 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1193 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1197 mode |= SILC_CHANNEL_MODE_INVITE;
1199 mode &= ~SILC_CHANNEL_MODE_INVITE;
1203 mode |= SILC_CHANNEL_MODE_TOPIC;
1205 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1210 mode |= SILC_CHANNEL_MODE_ULIMIT;
1212 ll = atoi(cmd->argv[3]);
1213 SILC_PUT32_MSB(ll, tmp);
1217 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1222 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1225 arg_len = cmd->argv_lens[3];
1227 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1232 mode |= SILC_CHANNEL_MODE_CIPHER;
1235 arg_len = cmd->argv_lens[3];
1237 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1242 mode |= SILC_CHANNEL_MODE_HMAC;
1245 arg_len = cmd->argv_lens[3];
1247 mode &= ~SILC_CHANNEL_MODE_HMAC;
1252 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1255 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1256 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1257 cmd->client->private_key,
1262 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1263 cmd->argv[3], cmd->argv_lens[3]);
1267 arg_len = auth->len;
1269 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1279 if (type && cmd->argc < 3) {
1284 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1285 SILC_PUT32_MSB(mode, modebuf);
1287 /* Send the command packet. We support sending only one mode at once
1288 that requires an argument. */
1291 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1292 1, chidp->data, chidp->len,
1293 2, modebuf, sizeof(modebuf),
1294 type, arg, arg_len);
1297 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1298 1, chidp->data, chidp->len,
1299 2, modebuf, sizeof(modebuf));
1302 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1303 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1304 silc_buffer_free(buffer);
1305 silc_buffer_free(chidp);
1307 silc_buffer_free(auth);
1309 /* Notify application */
1313 silc_client_command_free(cmd);
1316 /* CUMODE command. Changes client's mode on a channel. */
1318 SILC_CLIENT_CMD_FUNC(cumode)
1320 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1321 SilcClientConnection conn = cmd->conn;
1322 SilcChannelEntry channel;
1323 SilcChannelUser chu;
1324 SilcClientEntry client_entry;
1325 SilcBuffer buffer, clidp, chidp, auth = NULL;
1326 unsigned char *name, *cp, modebuf[4];
1327 uint32 mode = 0, add, len;
1328 char *nickname = NULL, *server = NULL;
1333 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1338 if (cmd->argc < 4) {
1339 cmd->client->ops->say(cmd->client, conn,
1340 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1345 if (cmd->argv[1][0] == '*') {
1346 if (!conn->current_channel) {
1347 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1352 channel = conn->current_channel;
1354 name = cmd->argv[1];
1356 channel = silc_client_get_channel(cmd->client, conn, name);
1358 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1364 /* Parse the typed nickname. */
1365 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1366 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1371 /* Find client entry */
1372 client_entry = silc_idlist_get_client(cmd->client, conn,
1373 nickname, server, num, TRUE);
1374 if (!client_entry) {
1380 /* Client entry not found, it was requested thus mark this to be
1382 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1384 silc_client_command_destructor,
1385 silc_client_command_cumode,
1386 silc_client_command_dup(cmd));
1391 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1392 if (chu->client == client_entry) {
1398 /* Are we adding or removing mode */
1399 if (cmd->argv[2][0] == '-')
1405 cp = cmd->argv[2] + 1;
1407 for (i = 0; i < len; i++) {
1411 mode |= SILC_CHANNEL_UMODE_CHANFO;
1412 mode |= SILC_CHANNEL_UMODE_CHANOP;
1414 mode = SILC_CHANNEL_UMODE_NONE;
1419 if (cmd->argc == 5) {
1420 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1421 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1422 cmd->client->private_key,
1427 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1428 cmd->argv[4], cmd->argv_lens[4]);
1431 mode |= SILC_CHANNEL_UMODE_CHANFO;
1433 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1438 mode |= SILC_CHANNEL_UMODE_CHANOP;
1440 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1449 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1450 SILC_PUT32_MSB(mode, modebuf);
1451 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1453 /* Send the command packet. We support sending only one mode at once
1454 that requires an argument. */
1455 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1456 1, chidp->data, chidp->len,
1458 3, clidp->data, clidp->len,
1459 4, auth ? auth->data : NULL,
1460 auth ? auth->len : 0);
1462 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1463 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1464 silc_buffer_free(buffer);
1465 silc_buffer_free(chidp);
1466 silc_buffer_free(clidp);
1468 silc_buffer_free(auth);
1470 /* Notify application */
1475 silc_free(nickname);
1478 silc_client_command_free(cmd);
1481 /* KICK command. Kicks a client out of channel. */
1483 SILC_CLIENT_CMD_FUNC(kick)
1485 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1486 SilcClientConnection conn = cmd->conn;
1487 SilcIDCacheEntry id_cache = NULL;
1488 SilcChannelEntry channel;
1489 SilcBuffer buffer, idp, idp2;
1490 SilcClientEntry target;
1493 char *nickname = NULL, *server = NULL;
1496 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1501 if (cmd->argc < 3) {
1502 cmd->client->ops->say(cmd->client, conn,
1503 "Usage: /KICK <channel> <nickname> [<comment>]");
1508 if (cmd->argv[1][0] == '*') {
1509 if (!conn->current_channel) {
1510 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1514 name = conn->current_channel->channel_name;
1516 name = cmd->argv[1];
1519 if (!conn->current_channel) {
1520 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1525 /* Get the Channel ID of the channel */
1526 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1527 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1532 channel = (SilcChannelEntry)id_cache->context;
1534 /* Parse the typed nickname. */
1535 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1536 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1541 /* Get the target client */
1542 target = silc_idlist_get_client(cmd->client, conn, nickname,
1543 server, num, FALSE);
1545 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1551 /* Send KICK command to the server */
1552 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1553 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1555 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1556 1, idp->data, idp->len,
1557 2, idp2->data, idp2->len);
1559 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1560 1, idp->data, idp->len,
1561 2, idp2->data, idp2->len,
1563 strlen(cmd->argv[3]));
1564 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1565 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1566 silc_buffer_free(buffer);
1567 silc_buffer_free(idp);
1568 silc_buffer_free(idp2);
1570 /* Notify application */
1575 silc_free(nickname);
1578 silc_client_command_free(cmd);
1581 /* OPER command. Used to obtain server operator privileges. */
1583 SILC_CLIENT_CMD_FUNC(oper)
1585 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1586 SilcClientConnection conn = cmd->conn;
1588 unsigned char *auth_data;
1592 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1597 if (cmd->argc < 2) {
1598 cmd->client->ops->say(cmd->client, conn,
1599 "Usage: /OPER <username> [<public key>]");
1604 if (cmd->argc == 3) {
1605 /* XXX Get public key */
1610 /* Get passphrase */
1612 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1618 /* Encode the authentication payload */
1619 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1620 auth_data, strlen(auth_data));
1623 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1625 strlen(cmd->argv[1]),
1626 2, auth->data, auth->len);
1627 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1628 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1630 silc_buffer_free(buffer);
1631 silc_buffer_free(auth);
1632 memset(auth_data, 0, strlen(auth_data));
1633 silc_free(auth_data);
1635 /* Notify application */
1639 silc_client_command_free(cmd);
1642 /* SILCOPER command. Used to obtain router operator privileges. */
1644 SILC_CLIENT_CMD_FUNC(silcoper)
1646 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1647 SilcClientConnection conn = cmd->conn;
1649 unsigned char *auth_data;
1653 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1658 if (cmd->argc < 2) {
1659 cmd->client->ops->say(cmd->client, conn,
1660 "Usage: /SILCOPER <username> [<public key>]");
1665 if (cmd->argc == 3) {
1666 /* XXX Get public key */
1671 /* Get passphrase */
1673 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1679 /* Encode the authentication payload */
1680 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1681 auth_data, strlen(auth_data));
1684 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1686 strlen(cmd->argv[1]),
1687 2, auth->data, auth->len);
1688 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1689 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1691 silc_buffer_free(buffer);
1692 silc_buffer_free(auth);
1693 memset(auth_data, 0, strlen(auth_data));
1694 silc_free(auth_data);
1696 /* Notify application */
1700 silc_client_command_free(cmd);
1703 /* CONNECT command. Connects the server to another server. */
1705 SILC_CLIENT_CMD_FUNC(connect)
1707 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1708 SilcClientConnection conn = cmd->conn;
1710 unsigned char port[4];
1714 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1719 if (cmd->argc < 2) {
1720 cmd->client->ops->say(cmd->client, conn,
1721 "Usage: /CONNECT <server> [<port>]");
1726 if (cmd->argc == 3) {
1727 tmp = atoi(cmd->argv[2]);
1728 SILC_PUT32_MSB(tmp, port);
1732 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1734 strlen(cmd->argv[1]),
1737 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1739 strlen(cmd->argv[1]));
1740 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1741 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1742 silc_buffer_free(buffer);
1744 /* Notify application */
1748 silc_client_command_free(cmd);
1751 /* Command BAN. This is used to manage the ban list of the channel. */
1753 SILC_CLIENT_CMD_FUNC(ban)
1755 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1756 SilcClientConnection conn = cmd->conn;
1757 SilcChannelEntry channel;
1758 SilcBuffer buffer, chidp;
1760 char *name, *ban = NULL;
1763 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1768 if (cmd->argc < 2) {
1769 cmd->client->ops->say(cmd->client, conn,
1770 "Usage: /BAN <channel> "
1771 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1776 if (cmd->argv[1][0] == '*') {
1777 if (!conn->current_channel) {
1778 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1783 channel = conn->current_channel;
1785 name = cmd->argv[1];
1787 channel = silc_client_get_channel(cmd->client, conn, name);
1789 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1795 if (cmd->argc == 3) {
1796 if (cmd->argv[2][0] == '+')
1805 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1807 /* Send the command */
1809 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1810 1, chidp->data, chidp->len,
1811 type, ban, strlen(ban));
1813 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1814 1, chidp->data, chidp->len);
1816 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1817 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1818 silc_buffer_free(buffer);
1819 silc_buffer_free(chidp);
1821 /* Notify application */
1825 silc_client_command_free(cmd);
1828 /* CLOSE command. Close server connection to the remote server */
1830 SILC_CLIENT_CMD_FUNC(close)
1832 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1833 SilcClientConnection conn = cmd->conn;
1835 unsigned char port[4];
1839 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1844 if (cmd->argc < 2) {
1845 cmd->client->ops->say(cmd->client, conn,
1846 "Usage: /CLOSE <server> [<port>]");
1851 if (cmd->argc == 3) {
1852 tmp = atoi(cmd->argv[2]);
1853 SILC_PUT32_MSB(tmp, port);
1857 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1859 strlen(cmd->argv[1]),
1862 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1864 strlen(cmd->argv[1]));
1865 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1866 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1867 silc_buffer_free(buffer);
1869 /* Notify application */
1873 silc_client_command_free(cmd);
1876 /* SHUTDOWN command. Shutdowns the server. */
1878 SILC_CLIENT_CMD_FUNC(shutdown)
1880 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1883 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1888 /* Send the command */
1889 silc_client_send_command(cmd->client, cmd->conn,
1890 SILC_COMMAND_SHUTDOWN, 0, 0);
1892 /* Notify application */
1896 silc_client_command_free(cmd);
1899 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1901 SILC_CLIENT_CMD_FUNC(leave)
1903 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1904 SilcClientConnection conn = cmd->conn;
1905 SilcIDCacheEntry id_cache = NULL;
1906 SilcChannelEntry channel;
1907 SilcBuffer buffer, idp;
1911 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1916 if (cmd->argc != 2) {
1917 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1922 if (cmd->argv[1][0] == '*') {
1923 if (!conn->current_channel) {
1924 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1928 name = conn->current_channel->channel_name;
1930 name = cmd->argv[1];
1933 if (!conn->current_channel) {
1934 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1939 /* Get the Channel ID of the channel */
1940 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1941 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1946 channel = (SilcChannelEntry)id_cache->context;
1948 /* Send LEAVE command to the server */
1949 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1950 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1951 1, idp->data, idp->len);
1952 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1953 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1954 silc_buffer_free(buffer);
1955 silc_buffer_free(idp);
1957 /* Notify application */
1960 conn->current_channel = NULL;
1962 silc_idcache_del_by_id(conn->channel_cache, channel->id);
1963 silc_free(channel->channel_name);
1964 silc_free(channel->id);
1965 silc_free(channel->key);
1966 silc_cipher_free(channel->channel_key);
1970 silc_client_command_free(cmd);
1973 /* Command USERS. Requests the USERS of the clients joined on requested
1976 SILC_CLIENT_CMD_FUNC(users)
1978 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1979 SilcClientConnection conn = cmd->conn;
1980 SilcIDCacheEntry id_cache = NULL;
1981 SilcChannelEntry channel;
1982 SilcBuffer buffer, idp;
1986 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1991 if (cmd->argc != 2) {
1992 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1997 if (cmd->argv[1][0] == '*') {
1998 if (!conn->current_channel) {
1999 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2003 name = conn->current_channel->channel_name;
2005 name = cmd->argv[1];
2008 if (!conn->current_channel) {
2009 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2014 /* Get the Channel ID of the channel */
2015 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2016 /* XXX should resolve the channel ID; LIST command */
2017 cmd->client->ops->say(cmd->client, conn,
2018 "You are not on that channel", name);
2023 channel = (SilcChannelEntry)id_cache->context;
2025 if (!cmd->pending) {
2026 /* Send USERS command to the server */
2027 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2028 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2029 ++conn->cmd_ident, 1,
2030 1, idp->data, idp->len);
2031 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2032 NULL, 0, NULL, NULL, buffer->data,
2034 silc_buffer_free(buffer);
2035 silc_buffer_free(idp);
2037 /* Register pending callback which will recall this command callback with
2038 same context and reprocesses the command. When reprocessing we actually
2039 display the information on the screen. */
2040 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2041 silc_client_command_destructor,
2042 silc_client_command_users,
2043 silc_client_command_dup(cmd));
2044 cmd->pending = TRUE;
2048 /* Notify application */
2052 silc_client_command_free(cmd);
2055 /* Command GETKEY. Used to fetch remote client's public key. */
2057 SILC_CLIENT_CMD_FUNC(getkey)
2059 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2060 SilcClientConnection conn = cmd->conn;
2061 SilcClient client = cmd->client;
2062 SilcClientEntry client_entry = NULL;
2064 char *nickname = NULL, *server = NULL;
2065 SilcBuffer idp, buffer;
2068 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2073 if (cmd->argc < 2) {
2074 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2079 /* Parse the typed nickname. */
2080 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2081 client->ops->say(client, conn, "Bad nickname");
2086 /* Find client entry */
2087 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2089 if (!client_entry) {
2090 /* Client entry not found, it was requested thus mark this to be
2092 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2094 silc_client_command_destructor,
2095 silc_client_command_getkey,
2096 silc_client_command_dup(cmd));
2101 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2102 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2103 1, idp->data, idp->len);
2104 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2105 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2106 silc_buffer_free(buffer);
2107 silc_buffer_free(idp);
2109 /* Notify application */
2113 silc_client_command_free(cmd);