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;
553 char *nickname = 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 (client->params->nickname_parse)
595 client->params->nickname_parse(cmd->argv[2], &nickname);
597 nickname = strdup(cmd->argv[2]);
599 /* Find client entry */
600 client_entry = silc_idlist_get_client(client, conn, nickname,
610 /* Client entry not found, it was requested thus mark this to be
612 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
614 silc_client_command_destructor,
615 silc_client_command_invite,
616 silc_client_command_dup(cmd));
621 invite = cmd->argv[2];
623 if (cmd->argv[2][0] == '+')
630 /* Send the command */
631 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
633 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
634 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
635 ++conn->cmd_ident, 3,
636 1, chidp->data, chidp->len,
637 2, clidp->data, clidp->len,
638 type, invite, invite ?
640 silc_buffer_free(clidp);
642 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
643 ++conn->cmd_ident, 2,
644 1, chidp->data, chidp->len,
645 type, invite, invite ?
649 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
650 0, NULL, NULL, buffer->data, buffer->len, TRUE);
651 silc_buffer_free(buffer);
652 silc_buffer_free(chidp);
654 /* Notify application */
659 silc_client_command_free(cmd);
664 SilcClientConnection conn;
667 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
669 QuitInternal q = (QuitInternal)context;
671 /* Close connection */
672 q->client->ops->disconnect(q->client, q->conn);
673 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
678 /* Command QUIT. Closes connection with current server. */
680 SILC_CLIENT_CMD_FUNC(quit)
682 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
687 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
693 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
694 &cmd->argv[1], &cmd->argv_lens[1],
695 &cmd->argv_types[1], 0);
697 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
698 NULL, NULL, NULL, 0);
699 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
701 buffer->data, buffer->len, TRUE);
702 silc_buffer_free(buffer);
704 q = silc_calloc(1, sizeof(*q));
705 q->client = cmd->client;
708 /* We quit the connection with little timeout */
709 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
710 silc_client_command_quit_cb, (void *)q,
711 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
713 /* Notify application */
717 silc_client_command_free(cmd);
720 /* Command KILL. Router operator can use this command to remove an client
721 fromthe SILC Network. */
723 SILC_CLIENT_CMD_FUNC(kill)
725 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
726 SilcClient client = cmd->client;
727 SilcClientConnection conn = cmd->conn;
728 SilcBuffer buffer, idp;
729 SilcClientEntry target;
730 char *nickname = NULL;
733 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
739 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
740 "Usage: /KILL <nickname> [<comment>]");
745 /* Parse the typed nickname. */
746 if (client->params->nickname_parse)
747 client->params->nickname_parse(cmd->argv[1], &nickname);
749 nickname = strdup(cmd->argv[1]);
751 /* Get the target client */
752 target = silc_idlist_get_client(cmd->client, conn, nickname,
762 /* Client entry not found, it was requested thus mark this to be
764 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
766 silc_client_command_destructor,
767 silc_client_command_kill,
768 silc_client_command_dup(cmd));
773 /* Send the KILL command to the server */
774 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
776 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
777 1, idp->data, idp->len);
779 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
780 1, idp->data, idp->len,
782 strlen(cmd->argv[2]));
783 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
784 0, NULL, NULL, buffer->data, buffer->len, TRUE);
785 silc_buffer_free(buffer);
786 silc_buffer_free(idp);
788 /* Notify application */
793 silc_client_command_free(cmd);
796 /* Command INFO. Request information about specific server. If specific
797 server is not provided the current server is used. */
799 SILC_CLIENT_CMD_FUNC(info)
801 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
802 SilcClientConnection conn = cmd->conn;
807 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
813 name = strdup(cmd->argv[1]);
815 /* Send the command */
817 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
818 1, name, strlen(name));
820 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
821 NULL, NULL, NULL, 0);
822 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
823 0, NULL, NULL, buffer->data, buffer->len, TRUE);
824 silc_buffer_free(buffer);
828 /* Notify application */
832 silc_client_command_free(cmd);
835 /* Command PING. Sends ping to server. This is used to test the
836 communication channel. */
838 SILC_CLIENT_CMD_FUNC(ping)
840 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
841 SilcClientConnection conn = cmd->conn;
847 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
852 /* Send the command */
853 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
854 1, conn->remote_id_data,
855 silc_id_get_len(conn->remote_id,
857 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
858 0, NULL, NULL, buffer->data, buffer->len, TRUE);
859 silc_buffer_free(buffer);
861 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
864 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
869 /* Start counting time */
870 for (i = 0; i < conn->ping_count; i++) {
871 if (conn->ping[i].dest_id == NULL) {
872 conn->ping[i].start_time = time(NULL);
873 conn->ping[i].dest_id = id;
874 conn->ping[i].dest_name = strdup(conn->remote_host);
879 if (i >= conn->ping_count) {
880 i = conn->ping_count;
881 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
882 conn->ping[i].start_time = time(NULL);
883 conn->ping[i].dest_id = id;
884 conn->ping[i].dest_name = strdup(conn->remote_host);
888 /* Notify application */
892 silc_client_command_free(cmd);
895 /* Command JOIN. Joins to a channel. */
897 SILC_CLIENT_CMD_FUNC(join)
899 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
900 SilcClientConnection conn = cmd->conn;
901 SilcIDCacheEntry id_cache = NULL;
902 SilcBuffer buffer, idp;
905 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
910 /* See if we have joined to the requested channel already */
911 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
915 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
917 /* Send JOIN command to the server */
920 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
921 1, cmd->argv[1], cmd->argv_lens[1],
922 2, idp->data, idp->len);
923 else if (cmd->argc == 3)
926 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
927 1, cmd->argv[1], cmd->argv_lens[1],
928 2, idp->data, idp->len,
929 3, cmd->argv[2], cmd->argv_lens[2]);
932 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
933 1, cmd->argv[1], cmd->argv_lens[1],
934 2, idp->data, idp->len,
935 3, cmd->argv[2], cmd->argv_lens[2],
936 4, cmd->argv[3], cmd->argv_lens[3]);
938 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
939 0, NULL, NULL, buffer->data, buffer->len, TRUE);
940 silc_buffer_free(buffer);
941 silc_buffer_free(idp);
943 /* Notify application */
947 silc_client_command_free(cmd);
950 /* MOTD command. Requests motd from server. */
952 SILC_CLIENT_CMD_FUNC(motd)
954 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
955 SilcClientConnection conn = cmd->conn;
959 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
964 if (cmd->argc < 1 || cmd->argc > 2) {
965 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
966 "Usage: /MOTD [<server>]");
971 /* Send TOPIC command to the server */
973 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
974 1, conn->remote_host,
975 strlen(conn->remote_host));
977 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
980 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
981 0, NULL, NULL, buffer->data, buffer->len, TRUE);
982 silc_buffer_free(buffer);
984 /* Notify application */
988 silc_client_command_free(cmd);
991 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
992 modes as client cannot set itself server/router operator privileges. */
994 SILC_CLIENT_CMD_FUNC(umode)
996 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
997 SilcClientConnection conn = cmd->conn;
998 SilcBuffer buffer, idp;
999 unsigned char *cp, modebuf[4];
1000 uint32 mode, add, len;
1004 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1009 if (cmd->argc < 2) {
1010 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1011 "Usage: /UMODE +|-<modes>");
1016 mode = conn->local_entry->mode;
1018 /* Are we adding or removing mode */
1019 if (cmd->argv[1][0] == '-')
1025 cp = cmd->argv[1] + 1;
1027 for (i = 0; i < len; i++) {
1032 mode |= SILC_UMODE_SERVER_OPERATOR;
1033 mode |= SILC_UMODE_ROUTER_OPERATOR;
1035 mode = SILC_UMODE_NONE;
1040 mode |= SILC_UMODE_SERVER_OPERATOR;
1042 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1046 mode |= SILC_UMODE_ROUTER_OPERATOR;
1048 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1052 mode |= SILC_UMODE_GONE;
1054 mode &= ~SILC_UMODE_GONE;
1063 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1064 SILC_PUT32_MSB(mode, modebuf);
1066 /* Send the command packet. We support sending only one mode at once
1067 that requires an argument. */
1069 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1070 1, idp->data, idp->len,
1071 2, modebuf, sizeof(modebuf));
1072 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1073 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1074 silc_buffer_free(buffer);
1075 silc_buffer_free(idp);
1077 /* Notify application */
1081 silc_client_command_free(cmd);
1084 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1085 can be set several at once. Those modes that require argument must be set
1086 separately (unless set with modes that does not require arguments). */
1088 SILC_CLIENT_CMD_FUNC(cmode)
1090 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1091 SilcClientConnection conn = cmd->conn;
1092 SilcChannelEntry channel;
1093 SilcBuffer buffer, chidp, auth = NULL;
1094 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1095 uint32 mode, add, type, len, arg_len = 0;
1099 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1104 if (cmd->argc < 3) {
1105 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1106 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1111 if (cmd->argv[1][0] == '*') {
1112 if (!conn->current_channel) {
1113 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1114 "You are not on any channel");
1119 channel = conn->current_channel;
1121 name = cmd->argv[1];
1123 channel = silc_client_get_channel(cmd->client, conn, name);
1125 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1126 "You are on that channel");
1132 mode = channel->mode;
1134 /* Are we adding or removing mode */
1135 if (cmd->argv[2][0] == '-')
1140 /* Argument type to be sent to server */
1144 cp = cmd->argv[2] + 1;
1146 for (i = 0; i < len; i++) {
1150 mode |= SILC_CHANNEL_MODE_PRIVATE;
1152 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1156 mode |= SILC_CHANNEL_MODE_SECRET;
1158 mode &= ~SILC_CHANNEL_MODE_SECRET;
1162 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1164 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1168 mode |= SILC_CHANNEL_MODE_INVITE;
1170 mode &= ~SILC_CHANNEL_MODE_INVITE;
1174 mode |= SILC_CHANNEL_MODE_TOPIC;
1176 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1181 mode |= SILC_CHANNEL_MODE_ULIMIT;
1183 if (cmd->argc < 4) {
1184 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1185 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1189 ll = atoi(cmd->argv[3]);
1190 SILC_PUT32_MSB(ll, tmp);
1194 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1199 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1201 if (cmd->argc < 4) {
1202 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1203 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1208 arg_len = cmd->argv_lens[3];
1210 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1215 mode |= SILC_CHANNEL_MODE_CIPHER;
1217 if (cmd->argc < 4) {
1218 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1219 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1224 arg_len = cmd->argv_lens[3];
1226 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1231 mode |= SILC_CHANNEL_MODE_HMAC;
1233 if (cmd->argc < 4) {
1234 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1235 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1240 arg_len = cmd->argv_lens[3];
1242 mode &= ~SILC_CHANNEL_MODE_HMAC;
1247 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1250 if (cmd->argc < 4) {
1251 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1252 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1257 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1258 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1259 cmd->client->private_key,
1264 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1265 cmd->argv[3], cmd->argv_lens[3]);
1269 arg_len = auth->len;
1271 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1281 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1282 SILC_PUT32_MSB(mode, modebuf);
1284 /* Send the command packet. We support sending only one mode at once
1285 that requires an argument. */
1288 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1289 1, chidp->data, chidp->len,
1290 2, modebuf, sizeof(modebuf),
1291 type, arg, arg_len);
1294 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1295 1, chidp->data, chidp->len,
1296 2, modebuf, sizeof(modebuf));
1299 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1300 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1301 silc_buffer_free(buffer);
1302 silc_buffer_free(chidp);
1304 silc_buffer_free(auth);
1306 /* Notify application */
1310 silc_client_command_free(cmd);
1313 /* CUMODE command. Changes client's mode on a channel. */
1315 SILC_CLIENT_CMD_FUNC(cumode)
1317 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1318 SilcClient client = cmd->client;
1319 SilcClientConnection conn = cmd->conn;
1320 SilcChannelEntry channel;
1321 SilcChannelUser chu;
1322 SilcClientEntry client_entry;
1323 SilcBuffer buffer, clidp, chidp, auth = NULL;
1324 unsigned char *name, *cp, modebuf[4];
1325 uint32 mode = 0, add, len;
1326 char *nickname = NULL;
1330 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1335 if (cmd->argc < 4) {
1336 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1337 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1342 if (cmd->argv[1][0] == '*') {
1343 if (!conn->current_channel) {
1344 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1345 "You are not on any channel");
1350 channel = conn->current_channel;
1352 name = cmd->argv[1];
1354 channel = silc_client_get_channel(cmd->client, conn, name);
1356 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1357 "You are on that channel");
1363 /* Parse the typed nickname. */
1364 if (client->params->nickname_parse)
1365 client->params->nickname_parse(cmd->argv[3], &nickname);
1367 nickname = strdup(cmd->argv[3]);
1369 /* Find client entry */
1370 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1371 cmd->argv[3], TRUE);
1372 if (!client_entry) {
1373 silc_free(nickname);
1380 /* Client entry not found, it was requested thus mark this to be
1382 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1384 silc_client_command_destructor,
1385 silc_client_command_cumode,
1386 silc_client_command_dup(cmd));
1391 /* Get the current mode */
1392 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1393 if (chu->client == client_entry) {
1399 /* Are we adding or removing mode */
1400 if (cmd->argv[2][0] == '-')
1406 cp = cmd->argv[2] + 1;
1408 for (i = 0; i < len; i++) {
1412 mode |= SILC_CHANNEL_UMODE_CHANFO;
1413 mode |= SILC_CHANNEL_UMODE_CHANOP;
1415 mode = SILC_CHANNEL_UMODE_NONE;
1420 if (cmd->argc == 5) {
1421 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1422 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1423 cmd->client->private_key,
1428 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1429 cmd->argv[4], cmd->argv_lens[4]);
1432 mode |= SILC_CHANNEL_UMODE_CHANFO;
1434 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1439 mode |= SILC_CHANNEL_UMODE_CHANOP;
1441 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1450 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1451 SILC_PUT32_MSB(mode, modebuf);
1452 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1454 /* Send the command packet. We support sending only one mode at once
1455 that requires an argument. */
1456 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4,
1457 1, chidp->data, chidp->len,
1459 3, clidp->data, clidp->len,
1460 4, auth ? auth->data : NULL,
1461 auth ? auth->len : 0);
1463 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1464 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1465 silc_buffer_free(buffer);
1466 silc_buffer_free(chidp);
1467 silc_buffer_free(clidp);
1469 silc_buffer_free(auth);
1471 /* Notify application */
1475 silc_free(nickname);
1476 silc_client_command_free(cmd);
1479 /* KICK command. Kicks a client out of channel. */
1481 SILC_CLIENT_CMD_FUNC(kick)
1483 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1484 SilcClient client = cmd->client;
1485 SilcClientConnection conn = cmd->conn;
1486 SilcIDCacheEntry id_cache = NULL;
1487 SilcChannelEntry channel;
1488 SilcBuffer buffer, idp, idp2;
1489 SilcClientEntry target;
1491 char *nickname = NULL;
1494 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1499 if (cmd->argc < 3) {
1500 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1501 "Usage: /KICK <channel> <nickname> [<comment>]");
1506 if (cmd->argv[1][0] == '*') {
1507 if (!conn->current_channel) {
1508 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1509 "You are not on any channel");
1513 name = conn->current_channel->channel_name;
1515 name = cmd->argv[1];
1518 if (!conn->current_channel) {
1519 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1520 "You are not on that channel");
1525 /* Get the Channel ID of the channel */
1526 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1527 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1528 "You are not on that channel");
1533 channel = (SilcChannelEntry)id_cache->context;
1535 /* Parse the typed nickname. */
1536 if (client->params->nickname_parse)
1537 client->params->nickname_parse(cmd->argv[2], &nickname);
1539 nickname = strdup(cmd->argv[2]);
1541 /* Get the target client */
1542 target = silc_idlist_get_client(cmd->client, conn, nickname,
1543 cmd->argv[2], FALSE);
1545 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1546 "No such client: %s",
1552 /* Send KICK command to the server */
1553 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1554 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1556 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1557 1, idp->data, idp->len,
1558 2, idp2->data, idp2->len);
1560 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1561 1, idp->data, idp->len,
1562 2, idp2->data, idp2->len,
1564 strlen(cmd->argv[3]));
1565 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1566 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1567 silc_buffer_free(buffer);
1568 silc_buffer_free(idp);
1569 silc_buffer_free(idp2);
1571 /* Notify application */
1575 silc_free(nickname);
1576 silc_client_command_free(cmd);
1579 static void silc_client_command_oper_send(unsigned char *data,
1580 uint32 data_len, void *context)
1582 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1583 SilcClientConnection conn = cmd->conn;
1584 SilcBuffer buffer, auth;
1586 if (cmd->argc >= 3) {
1587 /* Encode the public key authentication payload */
1588 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1589 cmd->client->private_key,
1594 /* Encode the password authentication payload */
1595 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1599 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1601 strlen(cmd->argv[1]),
1602 2, auth->data, auth->len);
1603 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1604 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1606 silc_buffer_free(buffer);
1607 silc_buffer_free(auth);
1609 /* Notify application */
1613 /* OPER command. Used to obtain server operator privileges. */
1615 SILC_CLIENT_CMD_FUNC(oper)
1617 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1618 SilcClientConnection conn = cmd->conn;
1621 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1626 if (cmd->argc < 2) {
1627 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1628 "Usage: /OPER <username> [-pubkey]");
1633 if (cmd->argc < 3) {
1634 /* Get passphrase */
1635 cmd->client->ops->ask_passphrase(cmd->client, conn,
1636 silc_client_command_oper_send,
1641 silc_client_command_oper_send(NULL, 0, context);
1644 silc_client_command_free(cmd);
1647 static void silc_client_command_silcoper_send(unsigned char *data,
1648 uint32 data_len, void *context)
1650 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1651 SilcClientConnection conn = cmd->conn;
1652 SilcBuffer buffer, auth;
1654 if (cmd->argc >= 3) {
1655 /* Encode the public key authentication payload */
1656 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1657 cmd->client->private_key,
1662 /* Encode the password authentication payload */
1663 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1667 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1669 strlen(cmd->argv[1]),
1670 2, auth->data, auth->len);
1671 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1672 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1674 silc_buffer_free(buffer);
1675 silc_buffer_free(auth);
1677 /* Notify application */
1681 /* SILCOPER command. Used to obtain router operator privileges. */
1683 SILC_CLIENT_CMD_FUNC(silcoper)
1685 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1686 SilcClientConnection conn = cmd->conn;
1689 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1694 if (cmd->argc < 2) {
1695 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1696 "Usage: /SILCOPER <username> [-pubkey]");
1701 if (cmd->argc < 3) {
1702 /* Get passphrase */
1703 cmd->client->ops->ask_passphrase(cmd->client, conn,
1704 silc_client_command_silcoper_send,
1709 silc_client_command_silcoper_send(NULL, 0, context);
1712 silc_client_command_free(cmd);
1715 /* CONNECT command. Connects the server to another server. */
1717 SILC_CLIENT_CMD_FUNC(connect)
1719 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1720 SilcClientConnection conn = cmd->conn;
1722 unsigned char port[4];
1726 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1731 if (cmd->argc < 2) {
1732 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1733 "Usage: /CONNECT <server> [<port>]");
1738 if (cmd->argc == 3) {
1739 tmp = atoi(cmd->argv[2]);
1740 SILC_PUT32_MSB(tmp, port);
1744 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1746 strlen(cmd->argv[1]),
1749 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1751 strlen(cmd->argv[1]));
1752 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1753 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1754 silc_buffer_free(buffer);
1756 /* Notify application */
1760 silc_client_command_free(cmd);
1763 /* Command BAN. This is used to manage the ban list of the channel. */
1765 SILC_CLIENT_CMD_FUNC(ban)
1767 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1768 SilcClientConnection conn = cmd->conn;
1769 SilcChannelEntry channel;
1770 SilcBuffer buffer, chidp;
1772 char *name, *ban = NULL;
1775 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1780 if (cmd->argc < 2) {
1781 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1782 "Usage: /BAN <channel> "
1783 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1788 if (cmd->argv[1][0] == '*') {
1789 if (!conn->current_channel) {
1790 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1791 "You are not on any channel");
1796 channel = conn->current_channel;
1798 name = cmd->argv[1];
1800 channel = silc_client_get_channel(cmd->client, conn, name);
1802 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1803 "You are on that channel");
1809 if (cmd->argc == 3) {
1810 if (cmd->argv[2][0] == '+')
1819 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1821 /* Send the command */
1823 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1824 1, chidp->data, chidp->len,
1825 type, ban, strlen(ban));
1827 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1828 1, chidp->data, chidp->len);
1830 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1831 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1832 silc_buffer_free(buffer);
1833 silc_buffer_free(chidp);
1835 /* Notify application */
1839 silc_client_command_free(cmd);
1842 /* CLOSE command. Close server connection to the remote server */
1844 SILC_CLIENT_CMD_FUNC(close)
1846 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1847 SilcClientConnection conn = cmd->conn;
1849 unsigned char port[4];
1853 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1858 if (cmd->argc < 2) {
1859 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1860 "Usage: /CLOSE <server> [<port>]");
1865 if (cmd->argc == 3) {
1866 tmp = atoi(cmd->argv[2]);
1867 SILC_PUT32_MSB(tmp, port);
1871 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1873 strlen(cmd->argv[1]),
1876 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1878 strlen(cmd->argv[1]));
1879 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1880 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1881 silc_buffer_free(buffer);
1883 /* Notify application */
1887 silc_client_command_free(cmd);
1890 /* SHUTDOWN command. Shutdowns the server. */
1892 SILC_CLIENT_CMD_FUNC(shutdown)
1894 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1897 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1902 /* Send the command */
1903 silc_client_send_command(cmd->client, cmd->conn,
1904 SILC_COMMAND_SHUTDOWN, 0, 0);
1906 /* Notify application */
1910 silc_client_command_free(cmd);
1913 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1915 SILC_CLIENT_CMD_FUNC(leave)
1917 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1918 SilcClientConnection conn = cmd->conn;
1919 SilcIDCacheEntry id_cache = NULL;
1920 SilcChannelEntry channel;
1921 SilcBuffer buffer, idp;
1925 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1930 if (cmd->argc != 2) {
1931 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1932 "Usage: /LEAVE <channel>");
1937 if (cmd->argv[1][0] == '*') {
1938 if (!conn->current_channel) {
1939 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1940 "You are not on any channel");
1944 name = conn->current_channel->channel_name;
1946 name = cmd->argv[1];
1949 /* Get the Channel ID of the channel */
1950 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1951 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1952 "You are not on that channel");
1957 channel = (SilcChannelEntry)id_cache->context;
1959 /* Send LEAVE command to the server */
1960 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1961 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1962 1, idp->data, idp->len);
1963 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1964 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1965 silc_buffer_free(buffer);
1966 silc_buffer_free(idp);
1968 /* Notify application */
1971 if (conn->current_channel == channel)
1972 conn->current_channel = NULL;
1974 silc_client_del_channel(cmd->client, cmd->conn, channel);
1977 silc_client_command_free(cmd);
1980 /* Command USERS. Requests the USERS of the clients joined on requested
1983 SILC_CLIENT_CMD_FUNC(users)
1985 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1986 SilcClientConnection conn = cmd->conn;
1991 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1996 if (cmd->argc != 2) {
1997 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1998 "Usage: /USERS <channel>");
2003 if (cmd->argv[1][0] == '*') {
2004 if (!conn->current_channel) {
2005 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2006 "You are not on any channel");
2010 name = conn->current_channel->channel_name;
2012 name = cmd->argv[1];
2015 /* Send USERS command to the server */
2016 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2017 ++conn->cmd_ident, 1,
2018 2, name, strlen(name));
2019 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2020 NULL, 0, NULL, NULL, buffer->data,
2022 silc_buffer_free(buffer);
2024 /* Notify application */
2028 silc_client_command_free(cmd);
2031 /* Command GETKEY. Used to fetch remote client's public key. */
2033 SILC_CLIENT_CMD_FUNC(getkey)
2035 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2036 SilcClientConnection conn = cmd->conn;
2037 SilcClient client = cmd->client;
2038 SilcClientEntry client_entry = NULL;
2039 SilcServerEntry server_entry = NULL;
2040 char *nickname = NULL;
2041 SilcBuffer idp, buffer;
2044 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2049 if (cmd->argc < 2) {
2050 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2051 "Usage: /GETKEY <nickname or server name>");
2057 SilcClientCommandReplyContext reply =
2058 (SilcClientCommandReplyContext)context2;
2059 SilcCommandStatus status;
2060 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2061 SILC_GET16_MSB(status, tmp);
2063 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2064 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2065 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2067 silc_client_command_status_message(status));
2073 /* Parse the typed nickname. */
2074 if (client->params->nickname_parse)
2075 client->params->nickname_parse(cmd->argv[1], &nickname);
2077 nickname = strdup(cmd->argv[1]);
2079 /* Find client entry */
2080 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2082 if (!client_entry) {
2083 /* Check whether user requested server actually */
2084 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2086 if (!server_entry && !cmd->pending) {
2087 /* No. what ever user wants we don't have it, so resolve it. We
2088 will try to resolve both client and server, one of them is
2089 bound to be wrong. */
2091 /* This will send the IDENTIFY command */
2092 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2093 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2095 silc_client_command_destructor,
2096 silc_client_command_getkey,
2097 silc_client_command_dup(cmd));
2099 /* This sends the IDENTIFY command to resolve the server. */
2100 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2101 ++conn->cmd_ident, 1,
2102 2, cmd->argv[1], cmd->argv_lens[1]);
2103 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2104 conn->cmd_ident, NULL,
2105 silc_client_command_getkey,
2106 silc_client_command_dup(cmd));
2109 silc_free(nickname);
2113 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2115 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2118 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2119 1, idp->data, idp->len);
2120 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2121 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2122 silc_buffer_free(buffer);
2123 silc_buffer_free(idp);
2125 /* Notify application */
2129 silc_free(nickname);
2130 silc_client_command_free(cmd);