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 static void silc_client_command_oper_send(unsigned char *data,
1582 uint32 data_len, void *context)
1584 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1585 SilcClientConnection conn = cmd->conn;
1586 SilcBuffer buffer, auth;
1588 if (cmd->argc == 3) {
1589 /* Pulic key auth XXX TODO */
1592 /* Encode the authentication payload */
1593 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1597 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1599 strlen(cmd->argv[1]),
1600 2, auth->data, auth->len);
1601 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1602 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1604 silc_buffer_free(buffer);
1605 silc_buffer_free(auth);
1607 /* Notify application */
1611 /* OPER command. Used to obtain server operator privileges. */
1613 SILC_CLIENT_CMD_FUNC(oper)
1615 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1616 SilcClientConnection conn = cmd->conn;
1617 unsigned char *auth_data;
1618 uint32 auth_data_len = 0;
1621 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1626 if (cmd->argc < 2) {
1627 cmd->client->ops->say(cmd->client, conn,
1628 "Usage: /OPER <username> [<public key>]");
1633 if (cmd->argc == 3) {
1634 /* XXX Get public key */
1639 /* Get passphrase */
1640 cmd->client->ops->ask_passphrase(cmd->client, conn,
1641 silc_client_command_oper_send,
1646 silc_client_command_oper_send(auth_data, auth_data_len, context);
1648 memset(auth_data, 0, auth_data_len);
1649 silc_free(auth_data);
1651 /* Notify application */
1655 silc_client_command_free(cmd);
1658 static void silc_client_command_silcoper_send(unsigned char *data,
1659 uint32 data_len, void *context)
1661 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1662 SilcClientConnection conn = cmd->conn;
1663 SilcBuffer buffer, auth;
1665 if (cmd->argc == 3) {
1666 /* Pulic key auth XXX TODO */
1669 /* Encode the authentication payload */
1670 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1674 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1676 strlen(cmd->argv[1]),
1677 2, auth->data, auth->len);
1678 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1679 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1681 silc_buffer_free(buffer);
1682 silc_buffer_free(auth);
1684 /* Notify application */
1688 /* SILCOPER command. Used to obtain router operator privileges. */
1690 SILC_CLIENT_CMD_FUNC(silcoper)
1692 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1693 SilcClientConnection conn = cmd->conn;
1694 unsigned char *auth_data;
1695 uint32 auth_data_len = 0;
1698 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1703 if (cmd->argc < 2) {
1704 cmd->client->ops->say(cmd->client, conn,
1705 "Usage: /SILCOPER <username> [<public key>]");
1710 if (cmd->argc == 3) {
1711 /* XXX Get public key */
1716 /* Get passphrase */
1717 cmd->client->ops->ask_passphrase(cmd->client, conn,
1718 silc_client_command_silcoper_send,
1723 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1725 memset(auth_data, 0, auth_data_len);
1726 silc_free(auth_data);
1728 /* Notify application */
1732 silc_client_command_free(cmd);
1735 /* CONNECT command. Connects the server to another server. */
1737 SILC_CLIENT_CMD_FUNC(connect)
1739 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1740 SilcClientConnection conn = cmd->conn;
1742 unsigned char port[4];
1746 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1751 if (cmd->argc < 2) {
1752 cmd->client->ops->say(cmd->client, conn,
1753 "Usage: /CONNECT <server> [<port>]");
1758 if (cmd->argc == 3) {
1759 tmp = atoi(cmd->argv[2]);
1760 SILC_PUT32_MSB(tmp, port);
1764 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1766 strlen(cmd->argv[1]),
1769 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1771 strlen(cmd->argv[1]));
1772 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1773 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1774 silc_buffer_free(buffer);
1776 /* Notify application */
1780 silc_client_command_free(cmd);
1783 /* Command BAN. This is used to manage the ban list of the channel. */
1785 SILC_CLIENT_CMD_FUNC(ban)
1787 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1788 SilcClientConnection conn = cmd->conn;
1789 SilcChannelEntry channel;
1790 SilcBuffer buffer, chidp;
1792 char *name, *ban = NULL;
1795 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1800 if (cmd->argc < 2) {
1801 cmd->client->ops->say(cmd->client, conn,
1802 "Usage: /BAN <channel> "
1803 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1808 if (cmd->argv[1][0] == '*') {
1809 if (!conn->current_channel) {
1810 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1815 channel = conn->current_channel;
1817 name = cmd->argv[1];
1819 channel = silc_client_get_channel(cmd->client, conn, name);
1821 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1827 if (cmd->argc == 3) {
1828 if (cmd->argv[2][0] == '+')
1837 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1839 /* Send the command */
1841 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1842 1, chidp->data, chidp->len,
1843 type, ban, strlen(ban));
1845 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1846 1, chidp->data, chidp->len);
1848 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1849 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1850 silc_buffer_free(buffer);
1851 silc_buffer_free(chidp);
1853 /* Notify application */
1857 silc_client_command_free(cmd);
1860 /* CLOSE command. Close server connection to the remote server */
1862 SILC_CLIENT_CMD_FUNC(close)
1864 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1865 SilcClientConnection conn = cmd->conn;
1867 unsigned char port[4];
1871 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1876 if (cmd->argc < 2) {
1877 cmd->client->ops->say(cmd->client, conn,
1878 "Usage: /CLOSE <server> [<port>]");
1883 if (cmd->argc == 3) {
1884 tmp = atoi(cmd->argv[2]);
1885 SILC_PUT32_MSB(tmp, port);
1889 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1891 strlen(cmd->argv[1]),
1894 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1896 strlen(cmd->argv[1]));
1897 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1898 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1899 silc_buffer_free(buffer);
1901 /* Notify application */
1905 silc_client_command_free(cmd);
1908 /* SHUTDOWN command. Shutdowns the server. */
1910 SILC_CLIENT_CMD_FUNC(shutdown)
1912 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1915 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1920 /* Send the command */
1921 silc_client_send_command(cmd->client, cmd->conn,
1922 SILC_COMMAND_SHUTDOWN, 0, 0);
1924 /* Notify application */
1928 silc_client_command_free(cmd);
1931 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1933 SILC_CLIENT_CMD_FUNC(leave)
1935 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1936 SilcClientConnection conn = cmd->conn;
1937 SilcIDCacheEntry id_cache = NULL;
1938 SilcChannelEntry channel;
1939 SilcBuffer buffer, idp;
1943 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1948 if (cmd->argc != 2) {
1949 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1954 if (cmd->argv[1][0] == '*') {
1955 if (!conn->current_channel) {
1956 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1960 name = conn->current_channel->channel_name;
1962 name = cmd->argv[1];
1965 if (!conn->current_channel) {
1966 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1971 /* Get the Channel ID of the channel */
1972 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1973 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1978 channel = (SilcChannelEntry)id_cache->context;
1980 /* Send LEAVE command to the server */
1981 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1982 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1983 1, idp->data, idp->len);
1984 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1985 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1986 silc_buffer_free(buffer);
1987 silc_buffer_free(idp);
1989 /* Notify application */
1992 conn->current_channel = NULL;
1994 silc_idcache_del_by_id(conn->channel_cache, channel->id);
1995 silc_free(channel->channel_name);
1996 silc_free(channel->id);
1997 silc_free(channel->key);
1998 silc_cipher_free(channel->channel_key);
2002 silc_client_command_free(cmd);
2005 /* Command USERS. Requests the USERS of the clients joined on requested
2008 SILC_CLIENT_CMD_FUNC(users)
2010 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2011 SilcClientConnection conn = cmd->conn;
2012 SilcIDCacheEntry id_cache = NULL;
2013 SilcChannelEntry channel;
2014 SilcBuffer buffer, idp;
2018 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2023 if (cmd->argc != 2) {
2024 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
2029 if (cmd->argv[1][0] == '*') {
2030 if (!conn->current_channel) {
2031 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2035 name = conn->current_channel->channel_name;
2037 name = cmd->argv[1];
2040 if (!conn->current_channel) {
2041 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
2046 /* Get the Channel ID of the channel */
2047 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2048 /* XXX should resolve the channel ID; LIST command */
2049 cmd->client->ops->say(cmd->client, conn,
2050 "You are not on that channel", name);
2055 channel = (SilcChannelEntry)id_cache->context;
2057 if (!cmd->pending) {
2058 /* Send USERS command to the server */
2059 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2060 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2061 ++conn->cmd_ident, 1,
2062 1, idp->data, idp->len);
2063 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2064 NULL, 0, NULL, NULL, buffer->data,
2066 silc_buffer_free(buffer);
2067 silc_buffer_free(idp);
2069 /* Register pending callback which will recall this command callback with
2070 same context and reprocesses the command. When reprocessing we actually
2071 display the information on the screen. */
2072 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
2073 silc_client_command_destructor,
2074 silc_client_command_users,
2075 silc_client_command_dup(cmd));
2076 cmd->pending = TRUE;
2080 /* Notify application */
2084 silc_client_command_free(cmd);
2087 /* Command GETKEY. Used to fetch remote client's public key. */
2089 SILC_CLIENT_CMD_FUNC(getkey)
2091 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2092 SilcClientConnection conn = cmd->conn;
2093 SilcClient client = cmd->client;
2094 SilcClientEntry client_entry = NULL;
2096 char *nickname = NULL, *server = NULL;
2097 SilcBuffer idp, buffer;
2100 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2105 if (cmd->argc < 2) {
2106 client->ops->say(client, conn, "Usage: /GETKEY <nickname>");
2111 /* Parse the typed nickname. */
2112 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2113 client->ops->say(client, conn, "Bad nickname");
2118 /* Find client entry */
2119 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2121 if (!client_entry) {
2122 /* Client entry not found, it was requested thus mark this to be
2124 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2126 silc_client_command_destructor,
2127 silc_client_command_getkey,
2128 silc_client_command_dup(cmd));
2133 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2134 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2135 1, idp->data, idp->len);
2136 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2137 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2138 silc_buffer_free(buffer);
2139 silc_buffer_free(idp);
2141 /* Notify application */
2145 silc_client_command_free(cmd);