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) {
328 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
329 ++conn->cmd_ident, 1,
333 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
334 ++conn->cmd_ident, 2,
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);
345 /* Notify application */
349 silc_client_command_free(cmd);
352 /* Command NICK. Shows current nickname/sets new nickname on current
355 SILC_CLIENT_CMD_FUNC(nick)
357 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
358 SilcClientConnection conn = cmd->conn;
362 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
368 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
369 "Usage: /NICK <nickname>");
374 if (!strcmp(conn->nickname, cmd->argv[1]))
377 /* Show current nickname */
380 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
381 "Your nickname is %s on server %s",
382 conn->nickname, conn->remote_host);
384 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
385 "Your nickname is %s", conn->nickname);
392 /* Set new nickname */
393 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
394 cmd->argc - 1, ++cmd->argv,
395 ++cmd->argv_lens, ++cmd->argv_types,
396 ++cmd->conn->cmd_ident);
397 silc_client_packet_send(cmd->client, cmd->conn->sock,
398 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
399 buffer->data, buffer->len, TRUE);
400 silc_buffer_free(buffer);
405 silc_free(conn->nickname);
406 conn->nickname = strdup(cmd->argv[1]);
408 /* Notify application */
412 silc_client_command_free(cmd);
415 /* Command LIST. Lists channels on the current server. */
417 SILC_CLIENT_CMD_FUNC(list)
419 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
420 SilcClientConnection conn = cmd->conn;
421 SilcIDCacheEntry id_cache = NULL;
422 SilcChannelEntry channel;
423 SilcBuffer buffer, idp = NULL;
427 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
432 if (cmd->argc == 2) {
435 /* Get the Channel ID of the channel */
436 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
437 channel = (SilcChannelEntry)id_cache->context;
438 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
443 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
444 ++conn->cmd_ident, 0);
446 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
447 ++conn->cmd_ident, 1,
448 1, idp->data, idp->len);
450 silc_client_packet_send(cmd->client, cmd->conn->sock,
451 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
452 buffer->data, buffer->len, TRUE);
453 silc_buffer_free(buffer);
455 silc_buffer_free(idp);
457 /* Notify application */
461 silc_client_command_free(cmd);
464 /* Command TOPIC. Sets/shows topic on a channel. */
466 SILC_CLIENT_CMD_FUNC(topic)
468 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
469 SilcClientConnection conn = cmd->conn;
470 SilcIDCacheEntry id_cache = NULL;
471 SilcChannelEntry channel;
472 SilcBuffer buffer, idp;
476 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
481 if (cmd->argc < 2 || cmd->argc > 3) {
482 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
483 "Usage: /TOPIC <channel> [<topic>]");
488 if (cmd->argv[1][0] == '*') {
489 if (!conn->current_channel) {
490 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
491 "You are not on any channel");
495 name = conn->current_channel->channel_name;
500 if (!conn->current_channel) {
501 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
502 "You are not on that channel");
507 /* Get the Channel ID of the channel */
508 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
509 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
510 "You are not on that channel");
515 channel = (SilcChannelEntry)id_cache->context;
517 /* Send TOPIC command to the server */
518 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
520 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
521 ++conn->cmd_ident, 2,
522 1, idp->data, idp->len,
524 strlen(cmd->argv[2]));
526 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
527 ++conn->cmd_ident, 1,
528 1, idp->data, idp->len);
529 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
530 0, NULL, NULL, buffer->data, buffer->len, TRUE);
531 silc_buffer_free(buffer);
532 silc_buffer_free(idp);
534 /* Notify application */
538 silc_client_command_free(cmd);
541 /* Command INVITE. Invites specific client to join a channel. This is
542 also used to mange the invite list of the channel. */
544 SILC_CLIENT_CMD_FUNC(invite)
546 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
547 SilcClient client = cmd->client;
548 SilcClientConnection conn = cmd->conn;
549 SilcClientEntry client_entry = NULL;
550 SilcChannelEntry channel;
551 SilcBuffer buffer, clidp, chidp;
552 uint32 num = 0, type = 0;
553 char *nickname = NULL, *server = NULL, *name;
557 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
563 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
564 "Usage: /INVITE <channel> [<nickname>[@server>]"
565 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
570 if (cmd->argv[1][0] == '*') {
571 if (!conn->current_channel) {
572 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
573 "You are not on any channel");
578 channel = conn->current_channel;
582 channel = silc_client_get_channel(cmd->client, conn, name);
584 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
585 "You are on that channel");
591 /* Parse the typed nickname. */
592 if (cmd->argc == 3) {
593 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
594 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
595 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
601 /* Find client entry */
602 client_entry = silc_idlist_get_client(client, conn, nickname,
615 /* Client entry not found, it was requested thus mark this to be
617 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
619 silc_client_command_destructor,
620 silc_client_command_invite,
621 silc_client_command_dup(cmd));
626 invite = cmd->argv[2];
628 if (cmd->argv[2][0] == '+')
635 /* Send the command */
636 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
638 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
639 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
640 ++conn->cmd_ident, 3,
641 1, chidp->data, chidp->len,
642 2, clidp->data, clidp->len,
643 type, invite, invite ?
645 silc_buffer_free(clidp);
647 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
648 ++conn->cmd_ident, 2,
649 1, chidp->data, chidp->len,
650 type, invite, invite ?
654 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
655 0, NULL, NULL, buffer->data, buffer->len, TRUE);
656 silc_buffer_free(buffer);
657 silc_buffer_free(chidp);
659 /* Notify application */
667 silc_client_command_free(cmd);
672 SilcClientConnection conn;
675 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
677 QuitInternal q = (QuitInternal)context;
679 /* Close connection */
680 q->client->ops->disconnect(q->client, q->conn);
681 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
686 /* Command QUIT. Closes connection with current server. */
688 SILC_CLIENT_CMD_FUNC(quit)
690 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
695 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
701 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
702 &cmd->argv[1], &cmd->argv_lens[1],
703 &cmd->argv_types[1], 0);
705 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
706 NULL, NULL, NULL, 0);
707 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
709 buffer->data, buffer->len, TRUE);
710 silc_buffer_free(buffer);
712 q = silc_calloc(1, sizeof(*q));
713 q->client = cmd->client;
716 /* We quit the connection with little timeout */
717 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
718 silc_client_command_quit_cb, (void *)q,
719 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
721 /* Notify application */
725 silc_client_command_free(cmd);
728 /* Command KILL. Router operator can use this command to remove an client
729 fromthe SILC Network. */
731 SILC_CLIENT_CMD_FUNC(kill)
733 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
734 SilcClientConnection conn = cmd->conn;
735 SilcBuffer buffer, idp;
736 SilcClientEntry target;
738 char *nickname = NULL, *server = NULL;
741 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
747 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
748 "Usage: /KILL <nickname> [<comment>]");
753 /* Parse the typed nickname. */
754 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
755 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
761 /* Get the target client */
762 target = silc_idlist_get_client(cmd->client, conn, nickname,
774 /* Client entry not found, it was requested thus mark this to be
776 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
778 silc_client_command_destructor,
779 silc_client_command_kill,
780 silc_client_command_dup(cmd));
785 /* Send the KILL command to the server */
786 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
788 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
789 1, idp->data, idp->len);
791 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
792 1, idp->data, idp->len,
794 strlen(cmd->argv[2]));
795 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
796 0, NULL, NULL, buffer->data, buffer->len, TRUE);
797 silc_buffer_free(buffer);
798 silc_buffer_free(idp);
800 /* Notify application */
808 silc_client_command_free(cmd);
811 /* Command INFO. Request information about specific server. If specific
812 server is not provided the current server is used. */
814 SILC_CLIENT_CMD_FUNC(info)
816 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
817 SilcClientConnection conn = cmd->conn;
822 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
828 name = strdup(cmd->argv[1]);
830 /* Send the command */
832 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
833 1, name, strlen(name));
835 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
836 NULL, NULL, NULL, 0);
837 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
838 0, NULL, NULL, buffer->data, buffer->len, TRUE);
839 silc_buffer_free(buffer);
843 /* Notify application */
847 silc_client_command_free(cmd);
850 /* Command PING. Sends ping to server. This is used to test the
851 communication channel. */
853 SILC_CLIENT_CMD_FUNC(ping)
855 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
856 SilcClientConnection conn = cmd->conn;
862 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
867 /* Send the command */
868 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
869 1, conn->remote_id_data,
870 silc_id_get_len(conn->remote_id,
872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
873 0, NULL, NULL, buffer->data, buffer->len, TRUE);
874 silc_buffer_free(buffer);
876 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
879 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
884 /* Start counting time */
885 for (i = 0; i < conn->ping_count; i++) {
886 if (conn->ping[i].dest_id == NULL) {
887 conn->ping[i].start_time = time(NULL);
888 conn->ping[i].dest_id = id;
889 conn->ping[i].dest_name = strdup(conn->remote_host);
894 if (i >= conn->ping_count) {
895 i = conn->ping_count;
896 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
897 conn->ping[i].start_time = time(NULL);
898 conn->ping[i].dest_id = id;
899 conn->ping[i].dest_name = strdup(conn->remote_host);
903 /* Notify application */
907 silc_client_command_free(cmd);
910 /* Command JOIN. Joins to a channel. */
912 SILC_CLIENT_CMD_FUNC(join)
914 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
915 SilcClientConnection conn = cmd->conn;
916 SilcIDCacheEntry id_cache = NULL;
917 SilcBuffer buffer, idp;
920 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
925 /* See if we have joined to the requested channel already */
926 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
930 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
932 /* Send JOIN command to the server */
935 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
936 1, cmd->argv[1], cmd->argv_lens[1],
937 2, idp->data, idp->len);
938 else if (cmd->argc == 3)
941 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
942 1, cmd->argv[1], cmd->argv_lens[1],
943 2, idp->data, idp->len,
944 3, cmd->argv[2], cmd->argv_lens[2]);
947 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
948 1, cmd->argv[1], cmd->argv_lens[1],
949 2, idp->data, idp->len,
950 3, cmd->argv[2], cmd->argv_lens[2],
951 4, cmd->argv[3], cmd->argv_lens[3]);
953 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
954 0, NULL, NULL, buffer->data, buffer->len, TRUE);
955 silc_buffer_free(buffer);
956 silc_buffer_free(idp);
958 /* Notify application */
962 silc_client_command_free(cmd);
965 /* MOTD command. Requests motd from server. */
967 SILC_CLIENT_CMD_FUNC(motd)
969 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
970 SilcClientConnection conn = cmd->conn;
974 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
979 if (cmd->argc < 1 || cmd->argc > 2) {
980 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
981 "Usage: /MOTD [<server>]");
986 /* Send TOPIC command to the server */
988 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
989 1, conn->remote_host,
990 strlen(conn->remote_host));
992 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
995 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
996 0, NULL, NULL, buffer->data, buffer->len, TRUE);
997 silc_buffer_free(buffer);
999 /* Notify application */
1003 silc_client_command_free(cmd);
1006 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1007 modes as client cannot set itself server/router operator privileges. */
1009 SILC_CLIENT_CMD_FUNC(umode)
1011 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1012 SilcClientConnection conn = cmd->conn;
1013 SilcBuffer buffer, idp;
1014 unsigned char *cp, modebuf[4];
1015 uint32 mode, add, len;
1019 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1024 if (cmd->argc < 2) {
1025 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1026 "Usage: /UMODE +|-<modes>");
1031 mode = conn->local_entry->mode;
1033 /* Are we adding or removing mode */
1034 if (cmd->argv[1][0] == '-')
1040 cp = cmd->argv[1] + 1;
1042 for (i = 0; i < len; i++) {
1047 mode |= SILC_UMODE_SERVER_OPERATOR;
1048 mode |= SILC_UMODE_ROUTER_OPERATOR;
1050 mode = SILC_UMODE_NONE;
1055 mode |= SILC_UMODE_SERVER_OPERATOR;
1057 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1061 mode |= SILC_UMODE_ROUTER_OPERATOR;
1063 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1067 mode |= SILC_UMODE_GONE;
1069 mode &= ~SILC_UMODE_GONE;
1078 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1079 SILC_PUT32_MSB(mode, modebuf);
1081 /* Send the command packet. We support sending only one mode at once
1082 that requires an argument. */
1084 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1085 1, idp->data, idp->len,
1086 2, modebuf, sizeof(modebuf));
1087 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1088 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1089 silc_buffer_free(buffer);
1090 silc_buffer_free(idp);
1092 /* Notify application */
1096 silc_client_command_free(cmd);
1099 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1100 can be set several at once. Those modes that require argument must be set
1101 separately (unless set with modes that does not require arguments). */
1103 SILC_CLIENT_CMD_FUNC(cmode)
1105 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1106 SilcClientConnection conn = cmd->conn;
1107 SilcChannelEntry channel;
1108 SilcBuffer buffer, chidp, auth = NULL;
1109 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1110 uint32 mode, add, type, len, arg_len = 0;
1114 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1119 if (cmd->argc < 3) {
1120 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1121 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1126 if (cmd->argv[1][0] == '*') {
1127 if (!conn->current_channel) {
1128 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1129 "You are not on any channel");
1134 channel = conn->current_channel;
1136 name = cmd->argv[1];
1138 channel = silc_client_get_channel(cmd->client, conn, name);
1140 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1141 "You are on that channel");
1147 mode = channel->mode;
1149 /* Are we adding or removing mode */
1150 if (cmd->argv[2][0] == '-')
1155 /* Argument type to be sent to server */
1159 cp = cmd->argv[2] + 1;
1161 for (i = 0; i < len; i++) {
1165 mode |= SILC_CHANNEL_MODE_PRIVATE;
1167 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1171 mode |= SILC_CHANNEL_MODE_SECRET;
1173 mode &= ~SILC_CHANNEL_MODE_SECRET;
1177 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1179 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1183 mode |= SILC_CHANNEL_MODE_INVITE;
1185 mode &= ~SILC_CHANNEL_MODE_INVITE;
1189 mode |= SILC_CHANNEL_MODE_TOPIC;
1191 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1196 mode |= SILC_CHANNEL_MODE_ULIMIT;
1198 if (cmd->argc < 4) {
1199 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1200 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1204 ll = atoi(cmd->argv[3]);
1205 SILC_PUT32_MSB(ll, tmp);
1209 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1214 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1216 if (cmd->argc < 4) {
1217 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1218 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1223 arg_len = cmd->argv_lens[3];
1225 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1230 mode |= SILC_CHANNEL_MODE_CIPHER;
1232 if (cmd->argc < 4) {
1233 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1234 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1239 arg_len = cmd->argv_lens[3];
1241 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1246 mode |= SILC_CHANNEL_MODE_HMAC;
1248 if (cmd->argc < 4) {
1249 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1250 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1255 arg_len = cmd->argv_lens[3];
1257 mode &= ~SILC_CHANNEL_MODE_HMAC;
1262 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1265 if (cmd->argc < 4) {
1266 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1267 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1272 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1273 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1274 cmd->client->private_key,
1279 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1280 cmd->argv[3], cmd->argv_lens[3]);
1284 arg_len = auth->len;
1286 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1296 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1297 SILC_PUT32_MSB(mode, modebuf);
1299 /* Send the command packet. We support sending only one mode at once
1300 that requires an argument. */
1303 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1304 1, chidp->data, chidp->len,
1305 2, modebuf, sizeof(modebuf),
1306 type, arg, arg_len);
1309 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1310 1, chidp->data, chidp->len,
1311 2, modebuf, sizeof(modebuf));
1314 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1315 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1316 silc_buffer_free(buffer);
1317 silc_buffer_free(chidp);
1319 silc_buffer_free(auth);
1321 /* Notify application */
1325 silc_client_command_free(cmd);
1328 /* CUMODE command. Changes client's mode on a channel. */
1330 SILC_CLIENT_CMD_FUNC(cumode)
1332 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1333 SilcClientConnection conn = cmd->conn;
1334 SilcChannelEntry channel;
1335 SilcChannelUser chu;
1336 SilcClientEntry client_entry;
1337 SilcBuffer buffer, clidp, chidp, auth = NULL;
1338 unsigned char *name, *cp, modebuf[4];
1339 uint32 mode = 0, add, len;
1340 char *nickname = NULL, *server = NULL;
1345 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1350 if (cmd->argc < 4) {
1351 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1352 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1357 if (cmd->argv[1][0] == '*') {
1358 if (!conn->current_channel) {
1359 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1360 "You are not on any channel");
1365 channel = conn->current_channel;
1367 name = cmd->argv[1];
1369 channel = silc_client_get_channel(cmd->client, conn, name);
1371 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1372 "You are on that channel");
1378 /* Parse the typed nickname. */
1379 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1380 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
1385 /* Find client entry */
1386 client_entry = silc_idlist_get_client(cmd->client, conn,
1387 nickname, server, num, TRUE);
1388 if (!client_entry) {
1394 /* Client entry not found, it was requested thus mark this to be
1396 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1398 silc_client_command_destructor,
1399 silc_client_command_cumode,
1400 silc_client_command_dup(cmd));
1405 /* Get the current mode */
1406 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1407 if (chu->client == client_entry) {
1413 /* Are we adding or removing mode */
1414 if (cmd->argv[2][0] == '-')
1420 cp = cmd->argv[2] + 1;
1422 for (i = 0; i < len; i++) {
1426 mode |= SILC_CHANNEL_UMODE_CHANFO;
1427 mode |= SILC_CHANNEL_UMODE_CHANOP;
1429 mode = SILC_CHANNEL_UMODE_NONE;
1434 if (cmd->argc == 5) {
1435 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1436 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1437 cmd->client->private_key,
1442 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1443 cmd->argv[4], cmd->argv_lens[4]);
1446 mode |= SILC_CHANNEL_UMODE_CHANFO;
1448 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1453 mode |= SILC_CHANNEL_UMODE_CHANOP;
1455 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1464 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1465 SILC_PUT32_MSB(mode, modebuf);
1466 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1468 /* Send the command packet. We support sending only one mode at once
1469 that requires an argument. */
1470 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1471 1, chidp->data, chidp->len,
1473 3, clidp->data, clidp->len,
1474 4, auth ? auth->data : NULL,
1475 auth ? auth->len : 0);
1477 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1478 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1479 silc_buffer_free(buffer);
1480 silc_buffer_free(chidp);
1481 silc_buffer_free(clidp);
1483 silc_buffer_free(auth);
1485 /* Notify application */
1490 silc_free(nickname);
1493 silc_client_command_free(cmd);
1496 /* KICK command. Kicks a client out of channel. */
1498 SILC_CLIENT_CMD_FUNC(kick)
1500 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1501 SilcClientConnection conn = cmd->conn;
1502 SilcIDCacheEntry id_cache = NULL;
1503 SilcChannelEntry channel;
1504 SilcBuffer buffer, idp, idp2;
1505 SilcClientEntry target;
1508 char *nickname = NULL, *server = NULL;
1511 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1516 if (cmd->argc < 3) {
1517 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1518 "Usage: /KICK <channel> <nickname> [<comment>]");
1523 if (cmd->argv[1][0] == '*') {
1524 if (!conn->current_channel) {
1525 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1526 "You are not on any channel");
1530 name = conn->current_channel->channel_name;
1532 name = cmd->argv[1];
1535 if (!conn->current_channel) {
1536 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1537 "You are not on that channel");
1542 /* Get the Channel ID of the channel */
1543 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1544 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1545 "You are not on that channel");
1550 channel = (SilcChannelEntry)id_cache->context;
1552 /* Parse the typed nickname. */
1553 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1554 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1560 /* Get the target client */
1561 target = silc_idlist_get_client(cmd->client, conn, nickname,
1562 server, num, FALSE);
1564 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1565 "No such client: %s",
1571 /* Send KICK command to the server */
1572 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1573 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1575 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1576 1, idp->data, idp->len,
1577 2, idp2->data, idp2->len);
1579 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1580 1, idp->data, idp->len,
1581 2, idp2->data, idp2->len,
1583 strlen(cmd->argv[3]));
1584 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1585 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1586 silc_buffer_free(buffer);
1587 silc_buffer_free(idp);
1588 silc_buffer_free(idp2);
1590 /* Notify application */
1595 silc_free(nickname);
1598 silc_client_command_free(cmd);
1601 static void silc_client_command_oper_send(unsigned char *data,
1602 uint32 data_len, void *context)
1604 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1605 SilcClientConnection conn = cmd->conn;
1606 SilcBuffer buffer, auth;
1608 if (cmd->argc == 3) {
1609 /* Pulic key auth XXX TODO */
1612 /* Encode the authentication payload */
1613 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1617 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1619 strlen(cmd->argv[1]),
1620 2, auth->data, auth->len);
1621 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1622 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1624 silc_buffer_free(buffer);
1625 silc_buffer_free(auth);
1627 /* Notify application */
1631 /* OPER command. Used to obtain server operator privileges. */
1633 SILC_CLIENT_CMD_FUNC(oper)
1635 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1636 SilcClientConnection conn = cmd->conn;
1637 unsigned char *auth_data;
1638 uint32 auth_data_len = 0;
1641 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1646 if (cmd->argc < 2) {
1647 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1648 "Usage: /OPER <username> [<public key>]");
1653 if (cmd->argc == 3) {
1654 /* XXX Get public key */
1659 /* Get passphrase */
1660 cmd->client->ops->ask_passphrase(cmd->client, conn,
1661 silc_client_command_oper_send,
1666 silc_client_command_oper_send(auth_data, auth_data_len, context);
1668 memset(auth_data, 0, auth_data_len);
1669 silc_free(auth_data);
1671 /* Notify application */
1675 silc_client_command_free(cmd);
1678 static void silc_client_command_silcoper_send(unsigned char *data,
1679 uint32 data_len, void *context)
1681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1682 SilcClientConnection conn = cmd->conn;
1683 SilcBuffer buffer, auth;
1685 if (cmd->argc == 3) {
1686 /* Pulic key auth XXX TODO */
1689 /* Encode the authentication payload */
1690 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1694 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1696 strlen(cmd->argv[1]),
1697 2, auth->data, auth->len);
1698 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1699 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1701 silc_buffer_free(buffer);
1702 silc_buffer_free(auth);
1704 /* Notify application */
1708 /* SILCOPER command. Used to obtain router operator privileges. */
1710 SILC_CLIENT_CMD_FUNC(silcoper)
1712 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1713 SilcClientConnection conn = cmd->conn;
1714 unsigned char *auth_data;
1715 uint32 auth_data_len = 0;
1718 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1723 if (cmd->argc < 2) {
1724 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1725 "Usage: /SILCOPER <username> [<public key>]");
1730 if (cmd->argc == 3) {
1731 /* XXX Get public key */
1736 /* Get passphrase */
1737 cmd->client->ops->ask_passphrase(cmd->client, conn,
1738 silc_client_command_silcoper_send,
1743 silc_client_command_silcoper_send(auth_data, auth_data_len, context);
1745 memset(auth_data, 0, auth_data_len);
1746 silc_free(auth_data);
1748 /* Notify application */
1752 silc_client_command_free(cmd);
1755 /* CONNECT command. Connects the server to another server. */
1757 SILC_CLIENT_CMD_FUNC(connect)
1759 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1760 SilcClientConnection conn = cmd->conn;
1762 unsigned char port[4];
1766 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1771 if (cmd->argc < 2) {
1772 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1773 "Usage: /CONNECT <server> [<port>]");
1778 if (cmd->argc == 3) {
1779 tmp = atoi(cmd->argv[2]);
1780 SILC_PUT32_MSB(tmp, port);
1784 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1786 strlen(cmd->argv[1]),
1789 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1791 strlen(cmd->argv[1]));
1792 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1793 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1794 silc_buffer_free(buffer);
1796 /* Notify application */
1800 silc_client_command_free(cmd);
1803 /* Command BAN. This is used to manage the ban list of the channel. */
1805 SILC_CLIENT_CMD_FUNC(ban)
1807 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1808 SilcClientConnection conn = cmd->conn;
1809 SilcChannelEntry channel;
1810 SilcBuffer buffer, chidp;
1812 char *name, *ban = NULL;
1815 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1820 if (cmd->argc < 2) {
1821 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1822 "Usage: /BAN <channel> "
1823 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1828 if (cmd->argv[1][0] == '*') {
1829 if (!conn->current_channel) {
1830 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1831 "You are not on any channel");
1836 channel = conn->current_channel;
1838 name = cmd->argv[1];
1840 channel = silc_client_get_channel(cmd->client, conn, name);
1842 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1843 "You are on that channel");
1849 if (cmd->argc == 3) {
1850 if (cmd->argv[2][0] == '+')
1859 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1861 /* Send the command */
1863 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1864 1, chidp->data, chidp->len,
1865 type, ban, strlen(ban));
1867 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1868 1, chidp->data, chidp->len);
1870 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1871 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1872 silc_buffer_free(buffer);
1873 silc_buffer_free(chidp);
1875 /* Notify application */
1879 silc_client_command_free(cmd);
1882 /* CLOSE command. Close server connection to the remote server */
1884 SILC_CLIENT_CMD_FUNC(close)
1886 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1887 SilcClientConnection conn = cmd->conn;
1889 unsigned char port[4];
1893 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1898 if (cmd->argc < 2) {
1899 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1900 "Usage: /CLOSE <server> [<port>]");
1905 if (cmd->argc == 3) {
1906 tmp = atoi(cmd->argv[2]);
1907 SILC_PUT32_MSB(tmp, port);
1911 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1913 strlen(cmd->argv[1]),
1916 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1918 strlen(cmd->argv[1]));
1919 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1920 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1921 silc_buffer_free(buffer);
1923 /* Notify application */
1927 silc_client_command_free(cmd);
1930 /* SHUTDOWN command. Shutdowns the server. */
1932 SILC_CLIENT_CMD_FUNC(shutdown)
1934 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1937 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1942 /* Send the command */
1943 silc_client_send_command(cmd->client, cmd->conn,
1944 SILC_COMMAND_SHUTDOWN, 0, 0);
1946 /* Notify application */
1950 silc_client_command_free(cmd);
1953 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1955 SILC_CLIENT_CMD_FUNC(leave)
1957 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1958 SilcClientConnection conn = cmd->conn;
1959 SilcIDCacheEntry id_cache = NULL;
1960 SilcChannelEntry channel;
1961 SilcBuffer buffer, idp;
1965 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1970 if (cmd->argc != 2) {
1971 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1972 "Usage: /LEAVE <channel>");
1977 if (cmd->argv[1][0] == '*') {
1978 if (!conn->current_channel) {
1979 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1980 "You are not on any channel");
1984 name = conn->current_channel->channel_name;
1986 name = cmd->argv[1];
1989 /* Get the Channel ID of the channel */
1990 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1991 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1992 "You are not on that channel");
1997 channel = (SilcChannelEntry)id_cache->context;
1999 /* Send LEAVE command to the server */
2000 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2001 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2002 1, idp->data, idp->len);
2003 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2004 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2005 silc_buffer_free(buffer);
2006 silc_buffer_free(idp);
2008 /* Notify application */
2011 if (conn->current_channel == channel)
2012 conn->current_channel = NULL;
2014 silc_client_del_channel(cmd->client, cmd->conn, channel);
2017 silc_client_command_free(cmd);
2020 /* Command USERS. Requests the USERS of the clients joined on requested
2023 SILC_CLIENT_CMD_FUNC(users)
2025 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2026 SilcClientConnection conn = cmd->conn;
2031 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2036 if (cmd->argc != 2) {
2037 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2038 "Usage: /USERS <channel>");
2043 if (cmd->argv[1][0] == '*') {
2044 if (!conn->current_channel) {
2045 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2046 "You are not on any channel");
2050 name = conn->current_channel->channel_name;
2052 name = cmd->argv[1];
2055 /* Send USERS command to the server */
2056 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2057 ++conn->cmd_ident, 1,
2058 2, name, strlen(name));
2059 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2060 NULL, 0, NULL, NULL, buffer->data,
2062 silc_buffer_free(buffer);
2064 /* Notify application */
2068 silc_client_command_free(cmd);
2071 /* Command GETKEY. Used to fetch remote client's public key. */
2073 SILC_CLIENT_CMD_FUNC(getkey)
2075 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2076 SilcClientConnection conn = cmd->conn;
2077 SilcClient client = cmd->client;
2078 SilcClientEntry client_entry = NULL;
2079 SilcServerEntry server_entry = NULL;
2081 char *nickname = NULL, *server = NULL;
2082 SilcBuffer idp, buffer;
2085 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2090 if (cmd->argc < 2) {
2091 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2092 "Usage: /GETKEY <nickname or server name>");
2097 /* Parse the typed nickname. */
2098 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
2099 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
2104 /* Find client entry */
2105 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
2107 if (!client_entry) {
2108 /* Check whether user requested server actually */
2109 server_entry = silc_client_get_server(client, conn, nickname);
2111 if (!server_entry) {
2112 /* No. what ever user wants we don't have it, so resolve it. We
2113 will try to resolve both client and server, one of them is
2114 bound to be wrong. */
2116 /* This will send the IDENTIFY command */
2117 silc_idlist_get_client(client, conn, nickname, server, num, TRUE);
2118 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2120 silc_client_command_destructor,
2121 silc_client_command_getkey,
2122 silc_client_command_dup(cmd));
2124 /* This sends the INFO command to resolve the server. */
2125 silc_client_send_command(client, conn, SILC_COMMAND_INFO,
2126 ++conn->cmd_ident, 1,
2127 1, nickname, strlen(nickname));
2128 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2130 silc_client_command_destructor,
2131 silc_client_command_getkey,
2132 silc_client_command_dup(cmd));
2138 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2140 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2143 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2144 1, idp->data, idp->len);
2145 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2146 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2147 silc_buffer_free(buffer);
2148 silc_buffer_free(idp);
2150 /* Notify application */
2154 silc_client_command_free(cmd);