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), SILC_CLIENT_MESSAGE_ERROR, \
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 /* Command WHOIS. This command is used to query information about
225 SILC_CLIENT_CMD_FUNC(whois)
227 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
228 SilcClientConnection conn = cmd->conn;
232 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
237 /* Given without arguments fetches client's own information */
239 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
240 silc_client_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
242 1, 3, buffer->data, buffer->len);
243 silc_buffer_free(buffer);
247 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
248 cmd->argc - 1, ++cmd->argv,
249 ++cmd->argv_lens, ++cmd->argv_types,
251 silc_client_packet_send(cmd->client, cmd->conn->sock,
252 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
253 buffer->data, buffer->len, TRUE);
254 silc_buffer_free(buffer);
259 /* Notify application */
263 silc_client_command_free(cmd);
266 /* Command WHOWAS. This command is used to query history information about
267 specific user that used to exist in the network. */
269 SILC_CLIENT_CMD_FUNC(whowas)
271 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
272 SilcClientConnection conn = cmd->conn;
276 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
281 if (cmd->argc < 2 || cmd->argc > 3) {
282 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
283 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
288 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
289 cmd->argc - 1, ++cmd->argv,
290 ++cmd->argv_lens, ++cmd->argv_types,
292 silc_client_packet_send(cmd->client, cmd->conn->sock,
293 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
294 buffer->data, buffer->len, TRUE);
295 silc_buffer_free(buffer);
300 /* Notify application */
304 silc_client_command_free(cmd);
307 /* Command IDENTIFY. This command is used to query information about
308 specific user, especially ID's. */
310 SILC_CLIENT_CMD_FUNC(identify)
312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
313 SilcClientConnection conn = cmd->conn;
317 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
322 if (cmd->argc < 2 || cmd->argc > 3) {
323 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
324 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
330 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
331 ++conn->cmd_ident, 1,
335 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
336 ++conn->cmd_ident, 2,
342 silc_client_packet_send(cmd->client, cmd->conn->sock,
343 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
344 buffer->data, buffer->len, TRUE);
345 silc_buffer_free(buffer);
347 /* Notify application */
351 silc_client_command_free(cmd);
354 /* Command NICK. Shows current nickname/sets new nickname on current
357 SILC_CLIENT_CMD_FUNC(nick)
359 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
360 SilcClientConnection conn = cmd->conn;
364 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
370 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
371 "Usage: /NICK <nickname>");
376 if (!strcmp(conn->nickname, cmd->argv[1]))
379 /* Show current nickname */
382 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
383 "Your nickname is %s on server %s",
384 conn->nickname, conn->remote_host);
386 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
387 "Your nickname is %s", conn->nickname);
394 /* Set new nickname */
395 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
396 cmd->argc - 1, ++cmd->argv,
397 ++cmd->argv_lens, ++cmd->argv_types,
398 ++cmd->conn->cmd_ident);
399 silc_client_packet_send(cmd->client, cmd->conn->sock,
400 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
401 buffer->data, buffer->len, TRUE);
402 silc_buffer_free(buffer);
407 silc_free(conn->nickname);
408 conn->nickname = strdup(cmd->argv[1]);
410 /* Notify application */
414 silc_client_command_free(cmd);
417 /* Command LIST. Lists channels on the current server. */
419 SILC_CLIENT_CMD_FUNC(list)
421 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
422 SilcClientConnection conn = cmd->conn;
423 SilcIDCacheEntry id_cache = NULL;
424 SilcChannelEntry channel;
425 SilcBuffer buffer, idp = NULL;
429 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
434 if (cmd->argc == 2) {
437 /* Get the Channel ID of the channel */
438 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
439 channel = (SilcChannelEntry)id_cache->context;
440 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
445 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
446 ++conn->cmd_ident, 0);
448 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
449 ++conn->cmd_ident, 1,
450 1, idp->data, idp->len);
452 silc_client_packet_send(cmd->client, cmd->conn->sock,
453 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
454 buffer->data, buffer->len, TRUE);
455 silc_buffer_free(buffer);
457 silc_buffer_free(idp);
459 /* Notify application */
463 silc_client_command_free(cmd);
466 /* Command TOPIC. Sets/shows topic on a channel. */
468 SILC_CLIENT_CMD_FUNC(topic)
470 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
471 SilcClientConnection conn = cmd->conn;
472 SilcIDCacheEntry id_cache = NULL;
473 SilcChannelEntry channel;
474 SilcBuffer buffer, idp;
478 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
483 if (cmd->argc < 2 || cmd->argc > 3) {
484 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
485 "Usage: /TOPIC <channel> [<topic>]");
490 if (cmd->argv[1][0] == '*') {
491 if (!conn->current_channel) {
492 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
493 "You are not on any channel");
497 name = conn->current_channel->channel_name;
502 if (!conn->current_channel) {
503 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
504 "You are not on that channel");
509 /* Get the Channel ID of the channel */
510 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
511 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
512 "You are not on that channel");
517 channel = (SilcChannelEntry)id_cache->context;
519 /* Send TOPIC command to the server */
520 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
522 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
523 ++conn->cmd_ident, 2,
524 1, idp->data, idp->len,
526 strlen(cmd->argv[2]));
528 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
529 ++conn->cmd_ident, 1,
530 1, idp->data, idp->len);
531 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
532 0, NULL, NULL, buffer->data, buffer->len, TRUE);
533 silc_buffer_free(buffer);
534 silc_buffer_free(idp);
536 /* Notify application */
540 silc_client_command_free(cmd);
543 /* Command INVITE. Invites specific client to join a channel. This is
544 also used to mange the invite list of the channel. */
546 SILC_CLIENT_CMD_FUNC(invite)
548 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
549 SilcClient client = cmd->client;
550 SilcClientConnection conn = cmd->conn;
551 SilcClientEntry client_entry = NULL;
552 SilcChannelEntry channel;
553 SilcBuffer buffer, clidp, chidp;
554 uint32 num = 0, type = 0;
555 char *nickname = NULL, *server = NULL, *name;
559 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
565 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
566 "Usage: /INVITE <channel> [<nickname>[@server>]"
567 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
572 if (cmd->argv[1][0] == '*') {
573 if (!conn->current_channel) {
574 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
575 "You are not on any channel");
580 channel = conn->current_channel;
584 channel = silc_client_get_channel(cmd->client, conn, name);
586 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
587 "You are on that channel");
593 /* Parse the typed nickname. */
594 if (cmd->argc == 3) {
595 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
596 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
597 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
603 /* Find client entry */
604 client_entry = silc_idlist_get_client(client, conn, nickname,
617 /* Client entry not found, it was requested thus mark this to be
619 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
621 silc_client_command_destructor,
622 silc_client_command_invite,
623 silc_client_command_dup(cmd));
628 invite = cmd->argv[2];
630 if (cmd->argv[2][0] == '+')
637 /* Send the command */
638 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
640 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
641 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
642 ++conn->cmd_ident, 3,
643 1, chidp->data, chidp->len,
644 2, clidp->data, clidp->len,
645 type, invite, invite ?
647 silc_buffer_free(clidp);
649 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
650 ++conn->cmd_ident, 2,
651 1, chidp->data, chidp->len,
652 type, invite, invite ?
656 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
657 0, NULL, NULL, buffer->data, buffer->len, TRUE);
658 silc_buffer_free(buffer);
659 silc_buffer_free(chidp);
661 /* Notify application */
669 silc_client_command_free(cmd);
674 SilcClientConnection conn;
677 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
679 QuitInternal q = (QuitInternal)context;
681 /* Close connection */
682 q->client->ops->disconnect(q->client, q->conn);
683 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
688 /* Command QUIT. Closes connection with current server. */
690 SILC_CLIENT_CMD_FUNC(quit)
692 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
697 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
703 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
704 &cmd->argv[1], &cmd->argv_lens[1],
705 &cmd->argv_types[1], 0);
707 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
708 NULL, NULL, NULL, 0);
709 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
711 buffer->data, buffer->len, TRUE);
712 silc_buffer_free(buffer);
714 q = silc_calloc(1, sizeof(*q));
715 q->client = cmd->client;
718 /* We quit the connection with little timeout */
719 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
720 silc_client_command_quit_cb, (void *)q,
721 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
723 /* Notify application */
727 silc_client_command_free(cmd);
730 /* Command KILL. Router operator can use this command to remove an client
731 fromthe SILC Network. */
733 SILC_CLIENT_CMD_FUNC(kill)
735 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
736 SilcClientConnection conn = cmd->conn;
737 SilcBuffer buffer, idp;
738 SilcClientEntry target;
740 char *nickname = NULL, *server = NULL;
743 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
749 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
750 "Usage: /KILL <nickname> [<comment>]");
755 /* Parse the typed nickname. */
756 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
757 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
763 /* Get the target client */
764 target = silc_idlist_get_client(cmd->client, conn, nickname,
776 /* Client entry not found, it was requested thus mark this to be
778 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
780 silc_client_command_destructor,
781 silc_client_command_kill,
782 silc_client_command_dup(cmd));
787 /* Send the KILL command to the server */
788 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
790 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
791 1, idp->data, idp->len);
793 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
794 1, idp->data, idp->len,
796 strlen(cmd->argv[2]));
797 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
798 0, NULL, NULL, buffer->data, buffer->len, TRUE);
799 silc_buffer_free(buffer);
800 silc_buffer_free(idp);
802 /* Notify application */
810 silc_client_command_free(cmd);
813 /* Command INFO. Request information about specific server. If specific
814 server is not provided the current server is used. */
816 SILC_CLIENT_CMD_FUNC(info)
818 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
819 SilcClientConnection conn = cmd->conn;
824 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
830 name = strdup(cmd->argv[1]);
832 /* Send the command */
834 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
835 1, name, strlen(name));
837 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
838 NULL, NULL, NULL, 0);
839 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
840 0, NULL, NULL, buffer->data, buffer->len, TRUE);
841 silc_buffer_free(buffer);
845 /* Notify application */
849 silc_client_command_free(cmd);
852 /* Command PING. Sends ping to server. This is used to test the
853 communication channel. */
855 SILC_CLIENT_CMD_FUNC(ping)
857 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
858 SilcClientConnection conn = cmd->conn;
864 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
869 /* Send the command */
870 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
871 1, conn->remote_id_data,
872 silc_id_get_len(conn->remote_id,
874 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
875 0, NULL, NULL, buffer->data, buffer->len, TRUE);
876 silc_buffer_free(buffer);
878 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
881 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
886 /* Start counting time */
887 for (i = 0; i < conn->ping_count; i++) {
888 if (conn->ping[i].dest_id == NULL) {
889 conn->ping[i].start_time = time(NULL);
890 conn->ping[i].dest_id = id;
891 conn->ping[i].dest_name = strdup(conn->remote_host);
896 if (i >= conn->ping_count) {
897 i = conn->ping_count;
898 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
899 conn->ping[i].start_time = time(NULL);
900 conn->ping[i].dest_id = id;
901 conn->ping[i].dest_name = strdup(conn->remote_host);
905 /* Notify application */
909 silc_client_command_free(cmd);
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);
927 /* See if we have joined to the requested channel already */
928 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
932 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
934 /* Send JOIN command to the server */
937 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
938 1, cmd->argv[1], cmd->argv_lens[1],
939 2, idp->data, idp->len);
940 else if (cmd->argc == 3)
943 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
944 1, cmd->argv[1], cmd->argv_lens[1],
945 2, idp->data, idp->len,
946 3, cmd->argv[2], cmd->argv_lens[2]);
949 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
950 1, cmd->argv[1], cmd->argv_lens[1],
951 2, idp->data, idp->len,
952 3, cmd->argv[2], cmd->argv_lens[2],
953 4, cmd->argv[3], cmd->argv_lens[3]);
955 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
956 0, NULL, NULL, buffer->data, buffer->len, TRUE);
957 silc_buffer_free(buffer);
958 silc_buffer_free(idp);
960 /* Notify application */
964 silc_client_command_free(cmd);
967 /* MOTD command. Requests motd from server. */
969 SILC_CLIENT_CMD_FUNC(motd)
971 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
972 SilcClientConnection conn = cmd->conn;
976 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
981 if (cmd->argc < 1 || cmd->argc > 2) {
982 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
983 "Usage: /MOTD [<server>]");
988 /* Send TOPIC command to the server */
990 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
991 1, conn->remote_host,
992 strlen(conn->remote_host));
994 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
997 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
998 0, NULL, NULL, buffer->data, buffer->len, TRUE);
999 silc_buffer_free(buffer);
1001 /* Notify application */
1005 silc_client_command_free(cmd);
1008 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1009 modes as client cannot set itself server/router operator privileges. */
1011 SILC_CLIENT_CMD_FUNC(umode)
1013 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1014 SilcClientConnection conn = cmd->conn;
1015 SilcBuffer buffer, idp;
1016 unsigned char *cp, modebuf[4];
1017 uint32 mode, add, len;
1021 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1026 if (cmd->argc < 2) {
1027 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1028 "Usage: /UMODE +|-<modes>");
1033 mode = conn->local_entry->mode;
1035 /* Are we adding or removing mode */
1036 if (cmd->argv[1][0] == '-')
1042 cp = cmd->argv[1] + 1;
1044 for (i = 0; i < len; i++) {
1049 mode |= SILC_UMODE_SERVER_OPERATOR;
1050 mode |= SILC_UMODE_ROUTER_OPERATOR;
1052 mode = SILC_UMODE_NONE;
1057 mode |= SILC_UMODE_SERVER_OPERATOR;
1059 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1063 mode |= SILC_UMODE_ROUTER_OPERATOR;
1065 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1069 mode |= SILC_UMODE_GONE;
1071 mode &= ~SILC_UMODE_GONE;
1080 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1081 SILC_PUT32_MSB(mode, modebuf);
1083 /* Send the command packet. We support sending only one mode at once
1084 that requires an argument. */
1086 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1087 1, idp->data, idp->len,
1088 2, modebuf, sizeof(modebuf));
1089 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1090 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1091 silc_buffer_free(buffer);
1092 silc_buffer_free(idp);
1094 /* Notify application */
1098 silc_client_command_free(cmd);
1101 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1102 can be set several at once. Those modes that require argument must be set
1103 separately (unless set with modes that does not require arguments). */
1105 SILC_CLIENT_CMD_FUNC(cmode)
1107 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1108 SilcClientConnection conn = cmd->conn;
1109 SilcChannelEntry channel;
1110 SilcBuffer buffer, chidp, auth = NULL;
1111 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1112 uint32 mode, add, type, len, arg_len = 0;
1116 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1121 if (cmd->argc < 3) {
1122 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1123 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1128 if (cmd->argv[1][0] == '*') {
1129 if (!conn->current_channel) {
1130 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1131 "You are not on any channel");
1136 channel = conn->current_channel;
1138 name = cmd->argv[1];
1140 channel = silc_client_get_channel(cmd->client, conn, name);
1142 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1143 "You are on that channel");
1149 mode = channel->mode;
1151 /* Are we adding or removing mode */
1152 if (cmd->argv[2][0] == '-')
1157 /* Argument type to be sent to server */
1161 cp = cmd->argv[2] + 1;
1163 for (i = 0; i < len; i++) {
1167 mode |= SILC_CHANNEL_MODE_PRIVATE;
1169 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1173 mode |= SILC_CHANNEL_MODE_SECRET;
1175 mode &= ~SILC_CHANNEL_MODE_SECRET;
1179 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1181 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1185 mode |= SILC_CHANNEL_MODE_INVITE;
1187 mode &= ~SILC_CHANNEL_MODE_INVITE;
1191 mode |= SILC_CHANNEL_MODE_TOPIC;
1193 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1198 mode |= SILC_CHANNEL_MODE_ULIMIT;
1200 if (cmd->argc < 4) {
1201 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1202 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1206 ll = atoi(cmd->argv[3]);
1207 SILC_PUT32_MSB(ll, tmp);
1211 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1216 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1218 if (cmd->argc < 4) {
1219 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1220 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1225 arg_len = cmd->argv_lens[3];
1227 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1232 mode |= SILC_CHANNEL_MODE_CIPHER;
1234 if (cmd->argc < 4) {
1235 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1236 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1241 arg_len = cmd->argv_lens[3];
1243 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1248 mode |= SILC_CHANNEL_MODE_HMAC;
1250 if (cmd->argc < 4) {
1251 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1252 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1257 arg_len = cmd->argv_lens[3];
1259 mode &= ~SILC_CHANNEL_MODE_HMAC;
1264 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1267 if (cmd->argc < 4) {
1268 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1269 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1274 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1275 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1276 cmd->client->private_key,
1281 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1282 cmd->argv[3], cmd->argv_lens[3]);
1286 arg_len = auth->len;
1288 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1298 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1299 SILC_PUT32_MSB(mode, modebuf);
1301 /* Send the command packet. We support sending only one mode at once
1302 that requires an argument. */
1305 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1306 1, chidp->data, chidp->len,
1307 2, modebuf, sizeof(modebuf),
1308 type, arg, arg_len);
1311 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1312 1, chidp->data, chidp->len,
1313 2, modebuf, sizeof(modebuf));
1316 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1317 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1318 silc_buffer_free(buffer);
1319 silc_buffer_free(chidp);
1321 silc_buffer_free(auth);
1323 /* Notify application */
1327 silc_client_command_free(cmd);
1330 /* CUMODE command. Changes client's mode on a channel. */
1332 SILC_CLIENT_CMD_FUNC(cumode)
1334 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1335 SilcClientConnection conn = cmd->conn;
1336 SilcChannelEntry channel;
1337 SilcChannelUser chu;
1338 SilcClientEntry client_entry;
1339 SilcBuffer buffer, clidp, chidp, auth = NULL;
1340 unsigned char *name, *cp, modebuf[4];
1341 uint32 mode = 0, add, len;
1342 char *nickname = NULL, *server = NULL;
1347 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1352 if (cmd->argc < 4) {
1353 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1354 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1359 if (cmd->argv[1][0] == '*') {
1360 if (!conn->current_channel) {
1361 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1362 "You are not on any channel");
1367 channel = conn->current_channel;
1369 name = cmd->argv[1];
1371 channel = silc_client_get_channel(cmd->client, conn, name);
1373 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1374 "You are on that channel");
1380 /* Parse the typed nickname. */
1381 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1382 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
1387 /* Find client entry */
1388 client_entry = silc_idlist_get_client(cmd->client, conn,
1389 nickname, server, num, TRUE);
1390 if (!client_entry) {
1396 /* Client entry not found, it was requested thus mark this to be
1398 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1400 silc_client_command_destructor,
1401 silc_client_command_cumode,
1402 silc_client_command_dup(cmd));
1407 /* Get the current mode */
1408 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1409 if (chu->client == client_entry) {
1415 /* Are we adding or removing mode */
1416 if (cmd->argv[2][0] == '-')
1422 cp = cmd->argv[2] + 1;
1424 for (i = 0; i < len; i++) {
1428 mode |= SILC_CHANNEL_UMODE_CHANFO;
1429 mode |= SILC_CHANNEL_UMODE_CHANOP;
1431 mode = SILC_CHANNEL_UMODE_NONE;
1436 if (cmd->argc == 5) {
1437 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1438 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1439 cmd->client->private_key,
1444 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1445 cmd->argv[4], cmd->argv_lens[4]);
1448 mode |= SILC_CHANNEL_UMODE_CHANFO;
1450 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1455 mode |= SILC_CHANNEL_UMODE_CHANOP;
1457 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1466 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1467 SILC_PUT32_MSB(mode, modebuf);
1468 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1470 /* Send the command packet. We support sending only one mode at once
1471 that requires an argument. */
1472 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1473 1, chidp->data, chidp->len,
1475 3, clidp->data, clidp->len,
1476 4, auth ? auth->data : NULL,
1477 auth ? auth->len : 0);
1479 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1480 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1481 silc_buffer_free(buffer);
1482 silc_buffer_free(chidp);
1483 silc_buffer_free(clidp);
1485 silc_buffer_free(auth);
1487 /* Notify application */
1492 silc_free(nickname);
1495 silc_client_command_free(cmd);
1498 /* KICK command. Kicks a client out of channel. */
1500 SILC_CLIENT_CMD_FUNC(kick)
1502 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1503 SilcClientConnection conn = cmd->conn;
1504 SilcIDCacheEntry id_cache = NULL;
1505 SilcChannelEntry channel;
1506 SilcBuffer buffer, idp, idp2;
1507 SilcClientEntry target;
1510 char *nickname = NULL, *server = NULL;
1513 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1518 if (cmd->argc < 3) {
1519 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1520 "Usage: /KICK <channel> <nickname> [<comment>]");
1525 if (cmd->argv[1][0] == '*') {
1526 if (!conn->current_channel) {
1527 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1528 "You are not on any channel");
1532 name = conn->current_channel->channel_name;
1534 name = cmd->argv[1];
1537 if (!conn->current_channel) {
1538 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1539 "You are not on that channel");
1544 /* Get the Channel ID of the channel */
1545 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1546 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1547 "You are not on that channel");
1552 channel = (SilcChannelEntry)id_cache->context;
1554 /* Parse the typed nickname. */
1555 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1556 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1562 /* Get the target client */
1563 target = silc_idlist_get_client(cmd->client, conn, nickname,
1564 server, num, FALSE);
1566 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1567 "No such client: %s",
1573 /* Send KICK command to the server */
1574 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1575 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1577 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1578 1, idp->data, idp->len,
1579 2, idp2->data, idp2->len);
1581 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1582 1, idp->data, idp->len,
1583 2, idp2->data, idp2->len,
1585 strlen(cmd->argv[3]));
1586 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1587 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1588 silc_buffer_free(buffer);
1589 silc_buffer_free(idp);
1590 silc_buffer_free(idp2);
1592 /* Notify application */
1597 silc_free(nickname);
1600 silc_client_command_free(cmd);
1603 static void silc_client_command_oper_send(unsigned char *data,
1604 uint32 data_len, void *context)
1606 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1607 SilcClientConnection conn = cmd->conn;
1608 SilcBuffer buffer, auth;
1610 if (cmd->argc == 3) {
1611 /* Pulic key auth XXX TODO */
1614 /* Encode the authentication payload */
1615 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1619 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1621 strlen(cmd->argv[1]),
1622 2, auth->data, auth->len);
1623 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1624 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1626 silc_buffer_free(buffer);
1627 silc_buffer_free(auth);
1629 /* Notify application */
1633 /* OPER command. Used to obtain server operator privileges. */
1635 SILC_CLIENT_CMD_FUNC(oper)
1637 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1638 SilcClientConnection conn = cmd->conn;
1639 unsigned char *auth_data;
1640 uint32 auth_data_len = 0;
1643 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1648 if (cmd->argc < 2) {
1649 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1650 "Usage: /OPER <username> [<public key>]");
1655 if (cmd->argc == 3) {
1656 /* XXX Get public key */
1661 /* Get passphrase */
1662 cmd->client->ops->ask_passphrase(cmd->client, conn,
1663 silc_client_command_oper_send,
1668 silc_client_command_oper_send(auth_data, auth_data_len, context);
1670 memset(auth_data, 0, auth_data_len);
1671 silc_free(auth_data);
1673 /* Notify application */
1677 silc_client_command_free(cmd);
1680 static void silc_client_command_silcoper_send(unsigned char *data,
1681 uint32 data_len, void *context)
1683 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1684 SilcClientConnection conn = cmd->conn;
1685 SilcBuffer buffer, auth;
1687 if (cmd->argc == 3) {
1688 /* Pulic key auth XXX TODO */
1691 /* Encode the authentication payload */
1692 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1696 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1698 strlen(cmd->argv[1]),
1699 2, auth->data, auth->len);
1700 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1701 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1703 silc_buffer_free(buffer);
1704 silc_buffer_free(auth);
1706 /* Notify application */
1710 /* SILCOPER command. Used to obtain router operator privileges. */
1712 SILC_CLIENT_CMD_FUNC(silcoper)
1714 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1715 SilcClientConnection conn = cmd->conn;
1716 unsigned char *auth_data;
1717 uint32 auth_data_len = 0;
1720 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1725 if (cmd->argc < 2) {
1726 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1727 "Usage: /SILCOPER <username> [<public key>]");
1732 if (cmd->argc == 3) {
1733 /* XXX Get public key */
1738 /* Get passphrase */
1739 cmd->client->ops->ask_passphrase(cmd->client, conn,
1740 silc_client_command_silcoper_send,
1745 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1747 memset(auth_data, 0, auth_data_len);
1748 silc_free(auth_data);
1750 /* Notify application */
1754 silc_client_command_free(cmd);
1757 /* CONNECT command. Connects the server to another server. */
1759 SILC_CLIENT_CMD_FUNC(connect)
1761 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1762 SilcClientConnection conn = cmd->conn;
1764 unsigned char port[4];
1768 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1773 if (cmd->argc < 2) {
1774 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1775 "Usage: /CONNECT <server> [<port>]");
1780 if (cmd->argc == 3) {
1781 tmp = atoi(cmd->argv[2]);
1782 SILC_PUT32_MSB(tmp, port);
1786 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1788 strlen(cmd->argv[1]),
1791 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1793 strlen(cmd->argv[1]));
1794 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1795 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1796 silc_buffer_free(buffer);
1798 /* Notify application */
1802 silc_client_command_free(cmd);
1805 /* Command BAN. This is used to manage the ban list of the channel. */
1807 SILC_CLIENT_CMD_FUNC(ban)
1809 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1810 SilcClientConnection conn = cmd->conn;
1811 SilcChannelEntry channel;
1812 SilcBuffer buffer, chidp;
1814 char *name, *ban = NULL;
1817 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1822 if (cmd->argc < 2) {
1823 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1824 "Usage: /BAN <channel> "
1825 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1830 if (cmd->argv[1][0] == '*') {
1831 if (!conn->current_channel) {
1832 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1833 "You are not on any channel");
1838 channel = conn->current_channel;
1840 name = cmd->argv[1];
1842 channel = silc_client_get_channel(cmd->client, conn, name);
1844 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1845 "You are on that channel");
1851 if (cmd->argc == 3) {
1852 if (cmd->argv[2][0] == '+')
1861 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1863 /* Send the command */
1865 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1866 1, chidp->data, chidp->len,
1867 type, ban, strlen(ban));
1869 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1870 1, chidp->data, chidp->len);
1872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1874 silc_buffer_free(buffer);
1875 silc_buffer_free(chidp);
1877 /* Notify application */
1881 silc_client_command_free(cmd);
1884 /* CLOSE command. Close server connection to the remote server */
1886 SILC_CLIENT_CMD_FUNC(close)
1888 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1889 SilcClientConnection conn = cmd->conn;
1891 unsigned char port[4];
1895 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1900 if (cmd->argc < 2) {
1901 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1902 "Usage: /CLOSE <server> [<port>]");
1907 if (cmd->argc == 3) {
1908 tmp = atoi(cmd->argv[2]);
1909 SILC_PUT32_MSB(tmp, port);
1913 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1915 strlen(cmd->argv[1]),
1918 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1920 strlen(cmd->argv[1]));
1921 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1922 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1923 silc_buffer_free(buffer);
1925 /* Notify application */
1929 silc_client_command_free(cmd);
1932 /* SHUTDOWN command. Shutdowns the server. */
1934 SILC_CLIENT_CMD_FUNC(shutdown)
1936 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1939 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1944 /* Send the command */
1945 silc_client_send_command(cmd->client, cmd->conn,
1946 SILC_COMMAND_SHUTDOWN, 0, 0);
1948 /* Notify application */
1952 silc_client_command_free(cmd);
1955 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1957 SILC_CLIENT_CMD_FUNC(leave)
1959 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1960 SilcClientConnection conn = cmd->conn;
1961 SilcIDCacheEntry id_cache = NULL;
1962 SilcChannelEntry channel;
1963 SilcBuffer buffer, idp;
1967 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1972 if (cmd->argc != 2) {
1973 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1974 "Usage: /LEAVE <channel>");
1979 if (cmd->argv[1][0] == '*') {
1980 if (!conn->current_channel) {
1981 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1982 "You are not on any channel");
1986 name = conn->current_channel->channel_name;
1988 name = cmd->argv[1];
1991 /* Get the Channel ID of the channel */
1992 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1993 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1994 "You are not on that channel");
1999 channel = (SilcChannelEntry)id_cache->context;
2001 /* Send LEAVE command to the server */
2002 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2003 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2004 1, idp->data, idp->len);
2005 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2006 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2007 silc_buffer_free(buffer);
2008 silc_buffer_free(idp);
2010 /* Notify application */
2013 if (conn->current_channel == channel)
2014 conn->current_channel = NULL;
2016 silc_idcache_del_by_id(conn->channel_cache, channel->id);
2017 silc_free(channel->channel_name);
2018 silc_free(channel->id);
2019 silc_free(channel->key);
2020 silc_cipher_free(channel->channel_key);
2024 silc_client_command_free(cmd);
2027 /* Command USERS. Requests the USERS of the clients joined on requested
2030 SILC_CLIENT_CMD_FUNC(users)
2032 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2033 SilcClientConnection conn = cmd->conn;
2038 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2043 if (cmd->argc != 2) {
2044 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2045 "Usage: /USERS <channel>");
2050 if (cmd->argv[1][0] == '*') {
2051 if (!conn->current_channel) {
2052 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2053 "You are not on any channel");
2057 name = conn->current_channel->channel_name;
2059 name = cmd->argv[1];
2062 /* Send USERS command to the server */
2063 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2064 ++conn->cmd_ident, 1,
2065 2, name, strlen(name));
2066 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2067 NULL, 0, NULL, NULL, buffer->data,
2069 silc_buffer_free(buffer);
2071 /* Notify application */
2075 silc_client_command_free(cmd);
2078 /* Command GETKEY. Used to fetch remote client's public key. */
2080 SILC_CLIENT_CMD_FUNC(getkey)
2082 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2083 SilcClientConnection conn = cmd->conn;
2084 SilcClient client = cmd->client;
2085 SilcClientEntry client_entry = NULL;
2086 SilcServerEntry server_entry = NULL;
2088 char *nickname = NULL, *server = NULL;
2089 SilcBuffer idp, buffer;
2092 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2097 if (cmd->argc < 2) {
2098 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2099 "Usage: /GETKEY <nickname or server name>");
2104 /* Parse the typed nickname. */
2105 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2106 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
2111 /* Find client entry */
2112 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2114 if (!client_entry) {
2115 /* Check whether user requested server actually */
2116 server_entry = silc_client_get_server(client, conn, nickname);
2118 if (!server_entry) {
2119 /* No. what ever user wants we don't have it, so resolve it. We
2120 will try to resolve both client and server, one of them is
2121 bound to be wrong. */
2123 /* This will send the IDENTIFY command */
2124 silc_idlist_get_client(client, conn, nickname, server, num, TRUE);
2125 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2127 silc_client_command_destructor,
2128 silc_client_command_getkey,
2129 silc_client_command_dup(cmd));
2131 /* This sends the INFO command to resolve the server. */
2132 silc_client_send_command(client, conn, SILC_COMMAND_INFO,
2133 ++conn->cmd_ident, 1,
2134 1, nickname, strlen(nickname));
2135 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2137 silc_client_command_destructor,
2138 silc_client_command_getkey,
2139 silc_client_command_dup(cmd));
2145 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2147 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2150 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2151 1, idp->data, idp->len);
2152 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2153 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2154 silc_buffer_free(buffer);
2155 silc_buffer_free(idp);
2157 /* Notify application */
2161 silc_client_command_free(cmd);