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 /* Pending callbcak that will be called after the NICK command was
353 replied by the server. This sets the nickname if there were no
356 SILC_CLIENT_CMD_FUNC(nick_change)
358 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
359 SilcClientConnection conn = cmd->conn;
360 SilcClientCommandReplyContext reply =
361 (SilcClientCommandReplyContext)context2;
362 SilcCommandStatus status;
364 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
365 if (status == SILC_STATUS_OK) {
366 /* Set the nickname */
368 silc_free(conn->nickname);
369 conn->nickname = strdup(cmd->argv[1]);
372 silc_client_command_free(cmd);
375 /* Command NICK. Shows current nickname/sets new nickname on current
378 SILC_CLIENT_CMD_FUNC(nick)
380 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
381 SilcClientConnection conn = cmd->conn;
385 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
391 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
392 "Usage: /NICK <nickname>");
397 if (!strcmp(conn->nickname, cmd->argv[1]))
400 /* Show current nickname */
403 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
404 "Your nickname is %s on server %s",
405 conn->nickname, conn->remote_host);
407 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
408 "Your nickname is %s", conn->nickname);
415 if (cmd->argv_lens[1] > 128)
416 cmd->argv_lens[1] = 128;
418 /* Send the NICK command */
419 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
423 ++cmd->conn->cmd_ident);
424 silc_client_packet_send(cmd->client, cmd->conn->sock,
425 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
426 buffer->data, buffer->len, TRUE);
427 silc_buffer_free(buffer);
429 /* Register pending callback that will actually set the new nickname
430 if there were no errors returned by the server. */
431 silc_client_command_pending(conn, SILC_COMMAND_NICK,
432 cmd->conn->cmd_ident,
433 silc_client_command_destructor,
434 silc_client_command_nick_change,
435 silc_client_command_dup(cmd));
438 /* Notify application */
442 silc_client_command_free(cmd);
445 /* Command LIST. Lists channels on the current server. */
447 SILC_CLIENT_CMD_FUNC(list)
449 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
450 SilcClientConnection conn = cmd->conn;
451 SilcIDCacheEntry id_cache = NULL;
452 SilcChannelEntry channel;
453 SilcBuffer buffer, idp = NULL;
457 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
462 if (cmd->argc == 2) {
465 /* Get the Channel ID of the channel */
466 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
467 channel = (SilcChannelEntry)id_cache->context;
468 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
473 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
474 ++conn->cmd_ident, 0);
476 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
477 ++conn->cmd_ident, 1,
478 1, idp->data, idp->len);
480 silc_client_packet_send(cmd->client, cmd->conn->sock,
481 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
482 buffer->data, buffer->len, TRUE);
483 silc_buffer_free(buffer);
485 silc_buffer_free(idp);
487 /* Notify application */
491 silc_client_command_free(cmd);
494 /* Command TOPIC. Sets/shows topic on a channel. */
496 SILC_CLIENT_CMD_FUNC(topic)
498 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
499 SilcClientConnection conn = cmd->conn;
500 SilcIDCacheEntry id_cache = NULL;
501 SilcChannelEntry channel;
502 SilcBuffer buffer, idp;
506 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
511 if (cmd->argc < 2 || cmd->argc > 3) {
512 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
513 "Usage: /TOPIC <channel> [<topic>]");
518 if (cmd->argv[1][0] == '*') {
519 if (!conn->current_channel) {
520 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
521 "You are not on any channel");
525 name = conn->current_channel->channel_name;
530 if (!conn->current_channel) {
531 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
532 "You are not on that channel");
537 /* Get the Channel ID of the channel */
538 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
539 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
540 "You are not on that channel");
545 channel = (SilcChannelEntry)id_cache->context;
547 /* Send TOPIC command to the server */
548 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
550 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
551 ++conn->cmd_ident, 2,
552 1, idp->data, idp->len,
554 strlen(cmd->argv[2]));
556 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
557 ++conn->cmd_ident, 1,
558 1, idp->data, idp->len);
559 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
560 0, NULL, NULL, buffer->data, buffer->len, TRUE);
561 silc_buffer_free(buffer);
562 silc_buffer_free(idp);
564 /* Notify application */
568 silc_client_command_free(cmd);
571 /* Command INVITE. Invites specific client to join a channel. This is
572 also used to mange the invite list of the channel. */
574 SILC_CLIENT_CMD_FUNC(invite)
576 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
577 SilcClient client = cmd->client;
578 SilcClientConnection conn = cmd->conn;
579 SilcClientEntry client_entry = NULL;
580 SilcChannelEntry channel;
581 SilcBuffer buffer, clidp, chidp;
583 char *nickname = NULL, *name;
587 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
593 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
594 "Usage: /INVITE <channel> [<nickname>[@server>]"
595 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
600 if (cmd->argv[1][0] == '*') {
601 if (!conn->current_channel) {
602 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
603 "You are not on any channel");
608 channel = conn->current_channel;
612 channel = silc_client_get_channel(cmd->client, conn, name);
614 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
615 "You are on that channel");
621 /* Parse the typed nickname. */
622 if (cmd->argc == 3) {
623 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
624 if (client->params->nickname_parse)
625 client->params->nickname_parse(cmd->argv[2], &nickname);
627 nickname = strdup(cmd->argv[2]);
629 /* Find client entry */
630 client_entry = silc_idlist_get_client(client, conn, nickname,
639 /* Client entry not found, it was requested thus mark this to be
641 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
643 silc_client_command_destructor,
644 silc_client_command_invite,
645 silc_client_command_dup(cmd));
650 invite = cmd->argv[2];
652 if (cmd->argv[2][0] == '+')
659 /* Send the command */
660 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
662 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
663 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
664 ++conn->cmd_ident, 3,
665 1, chidp->data, chidp->len,
666 2, clidp->data, clidp->len,
667 type, invite, invite ?
669 silc_buffer_free(clidp);
671 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
672 ++conn->cmd_ident, 2,
673 1, chidp->data, chidp->len,
674 type, invite, invite ?
678 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
679 0, NULL, NULL, buffer->data, buffer->len, TRUE);
680 silc_buffer_free(buffer);
681 silc_buffer_free(chidp);
683 /* Notify application */
688 silc_client_command_free(cmd);
693 SilcClientConnection conn;
696 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
698 QuitInternal q = (QuitInternal)context;
700 /* Close connection */
701 q->client->ops->disconnect(q->client, q->conn);
702 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
707 /* Command QUIT. Closes connection with current server. */
709 SILC_CLIENT_CMD_FUNC(quit)
711 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
716 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
722 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
723 &cmd->argv[1], &cmd->argv_lens[1],
724 &cmd->argv_types[1], 0);
726 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
727 NULL, NULL, NULL, 0);
728 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
730 buffer->data, buffer->len, TRUE);
731 silc_buffer_free(buffer);
733 q = silc_calloc(1, sizeof(*q));
734 q->client = cmd->client;
737 /* Sleep for a while */
740 /* We quit the connection with little timeout */
741 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
742 silc_client_command_quit_cb, (void *)q,
743 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
745 /* Notify application */
749 silc_client_command_free(cmd);
752 /* Timeout callback to remove the killed client from cache */
754 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
756 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
757 SilcClient client = cmd->client;
758 SilcClientConnection conn = cmd->conn;
759 SilcClientEntry target;
760 char *nickname = NULL;
762 /* Parse the typed nickname. */
763 if (client->params->nickname_parse)
764 client->params->nickname_parse(cmd->argv[1], &nickname);
766 nickname = strdup(cmd->argv[1]);
768 /* Get the target client */
769 target = silc_idlist_get_client(cmd->client, conn, nickname,
770 cmd->argv[1], FALSE);
772 silc_client_remove_from_channels(client, conn, target);
773 silc_client_del_client(client, conn, target);
777 silc_client_command_free(cmd);
780 /* Kill command's pending command callback to actually remove the killed
781 client from our local cache. */
783 SILC_CLIENT_CMD_FUNC(kill_remove)
785 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
786 SilcClientCommandReplyContext reply =
787 (SilcClientCommandReplyContext)context2;
788 SilcCommandStatus status;
790 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
791 if (status == SILC_STATUS_OK) {
792 /* Remove with timeout */
793 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
794 silc_client_command_kill_remove_later, context,
795 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
799 silc_client_command_free(cmd);
802 /* Command KILL. Router operator can use this command to remove an client
803 fromthe SILC Network. */
805 SILC_CLIENT_CMD_FUNC(kill)
807 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
808 SilcClient client = cmd->client;
809 SilcClientConnection conn = cmd->conn;
810 SilcBuffer buffer, idp;
811 SilcClientEntry target;
812 char *nickname = NULL;
815 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
821 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
822 "Usage: /KILL <nickname> [<comment>]");
827 /* Parse the typed nickname. */
828 if (client->params->nickname_parse)
829 client->params->nickname_parse(cmd->argv[1], &nickname);
831 nickname = strdup(cmd->argv[1]);
833 /* Get the target client */
834 target = silc_idlist_get_client(cmd->client, conn, nickname,
844 /* Client entry not found, it was requested thus mark this to be
846 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
848 silc_client_command_destructor,
849 silc_client_command_kill,
850 silc_client_command_dup(cmd));
855 /* Send the KILL command to the server */
856 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
858 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
859 ++conn->cmd_ident, 1,
860 1, idp->data, idp->len);
862 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
863 ++conn->cmd_ident, 2,
864 1, idp->data, idp->len,
866 strlen(cmd->argv[2]));
867 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
868 0, NULL, NULL, buffer->data, buffer->len, TRUE);
869 silc_buffer_free(buffer);
870 silc_buffer_free(idp);
872 /* Notify application */
875 /* Register a pending callback that will actually remove the killed
876 client from our cache. */
877 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
878 NULL, silc_client_command_kill_remove,
879 silc_client_command_dup(cmd));
883 silc_client_command_free(cmd);
886 /* Command INFO. Request information about specific server. If specific
887 server is not provided the current server is used. */
889 SILC_CLIENT_CMD_FUNC(info)
891 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
892 SilcClientConnection conn = cmd->conn;
897 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
903 name = strdup(cmd->argv[1]);
905 /* Send the command */
907 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
908 1, name, strlen(name));
910 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
911 NULL, NULL, NULL, 0);
912 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
913 0, NULL, NULL, buffer->data, buffer->len, TRUE);
914 silc_buffer_free(buffer);
918 /* Notify application */
922 silc_client_command_free(cmd);
925 /* Command PING. Sends ping to server. This is used to test the
926 communication channel. */
928 SILC_CLIENT_CMD_FUNC(ping)
930 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
931 SilcClientConnection conn = cmd->conn;
937 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
942 /* Send the command */
943 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
944 1, conn->remote_id_data,
945 silc_id_get_len(conn->remote_id,
947 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
948 0, NULL, NULL, buffer->data, buffer->len, TRUE);
949 silc_buffer_free(buffer);
951 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
954 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
959 /* Start counting time */
960 for (i = 0; i < conn->ping_count; i++) {
961 if (conn->ping[i].dest_id == NULL) {
962 conn->ping[i].start_time = time(NULL);
963 conn->ping[i].dest_id = id;
964 conn->ping[i].dest_name = strdup(conn->remote_host);
968 if (i >= conn->ping_count) {
969 i = conn->ping_count;
970 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
971 conn->ping[i].start_time = time(NULL);
972 conn->ping[i].dest_id = id;
973 conn->ping[i].dest_name = strdup(conn->remote_host);
977 /* Notify application */
981 silc_client_command_free(cmd);
984 /* Command JOIN. Joins to a channel. */
986 SILC_CLIENT_CMD_FUNC(join)
988 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
989 SilcClientConnection conn = cmd->conn;
990 SilcIDCacheEntry id_cache = NULL;
991 SilcBuffer buffer, idp;
994 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
999 /* See if we have joined to the requested channel already */
1000 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
1002 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
1003 if (channel->on_channel)
1007 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1009 if (cmd->argv_lens[1] > 256)
1010 cmd->argv_lens[1] = 256;
1012 /* Send JOIN command to the server */
1015 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
1016 1, cmd->argv[1], cmd->argv_lens[1],
1017 2, idp->data, idp->len);
1018 else if (cmd->argc == 3)
1021 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
1022 1, cmd->argv[1], cmd->argv_lens[1],
1023 2, idp->data, idp->len,
1024 3, cmd->argv[2], cmd->argv_lens[2]);
1027 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
1028 1, cmd->argv[1], cmd->argv_lens[1],
1029 2, idp->data, idp->len,
1030 3, cmd->argv[2], cmd->argv_lens[2],
1031 4, cmd->argv[3], cmd->argv_lens[3]);
1033 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1034 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1035 silc_buffer_free(buffer);
1036 silc_buffer_free(idp);
1038 /* Notify application */
1042 silc_client_command_free(cmd);
1045 /* MOTD command. Requests motd from server. */
1047 SILC_CLIENT_CMD_FUNC(motd)
1049 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1050 SilcClientConnection conn = cmd->conn;
1054 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1059 if (cmd->argc < 1 || cmd->argc > 2) {
1060 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1061 "Usage: /MOTD [<server>]");
1066 /* Send TOPIC command to the server */
1068 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1069 1, conn->remote_host,
1070 strlen(conn->remote_host));
1072 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1075 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1076 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1077 silc_buffer_free(buffer);
1079 /* Notify application */
1083 silc_client_command_free(cmd);
1086 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1087 modes as client cannot set itself server/router operator privileges. */
1089 SILC_CLIENT_CMD_FUNC(umode)
1091 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1092 SilcClientConnection conn = cmd->conn;
1093 SilcBuffer buffer, idp;
1094 unsigned char *cp, modebuf[4];
1095 uint32 mode, add, len;
1099 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1104 if (cmd->argc < 2) {
1105 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1106 "Usage: /UMODE +|-<modes>");
1111 mode = conn->local_entry->mode;
1113 /* Are we adding or removing mode */
1114 if (cmd->argv[1][0] == '-')
1120 cp = cmd->argv[1] + 1;
1122 for (i = 0; i < len; i++) {
1127 mode |= SILC_UMODE_SERVER_OPERATOR;
1128 mode |= SILC_UMODE_ROUTER_OPERATOR;
1130 mode = SILC_UMODE_NONE;
1135 mode |= SILC_UMODE_SERVER_OPERATOR;
1137 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1141 mode |= SILC_UMODE_ROUTER_OPERATOR;
1143 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1147 mode |= SILC_UMODE_GONE;
1149 mode &= ~SILC_UMODE_GONE;
1158 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1159 SILC_PUT32_MSB(mode, modebuf);
1161 /* Send the command packet. We support sending only one mode at once
1162 that requires an argument. */
1164 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1165 1, idp->data, idp->len,
1166 2, modebuf, sizeof(modebuf));
1167 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1168 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1169 silc_buffer_free(buffer);
1170 silc_buffer_free(idp);
1172 /* Notify application */
1176 silc_client_command_free(cmd);
1179 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1180 can be set several at once. Those modes that require argument must be set
1181 separately (unless set with modes that does not require arguments). */
1183 SILC_CLIENT_CMD_FUNC(cmode)
1185 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1186 SilcClientConnection conn = cmd->conn;
1187 SilcChannelEntry channel;
1188 SilcBuffer buffer, chidp, auth = NULL;
1189 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1190 uint32 mode, add, type, len, arg_len = 0;
1194 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1199 if (cmd->argc < 3) {
1200 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1201 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1206 if (cmd->argv[1][0] == '*') {
1207 if (!conn->current_channel) {
1208 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1209 "You are not on any channel");
1214 channel = conn->current_channel;
1216 name = cmd->argv[1];
1218 channel = silc_client_get_channel(cmd->client, conn, name);
1220 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1221 "You are on that channel");
1227 mode = channel->mode;
1229 /* Are we adding or removing mode */
1230 if (cmd->argv[2][0] == '-')
1235 /* Argument type to be sent to server */
1239 cp = cmd->argv[2] + 1;
1241 for (i = 0; i < len; i++) {
1245 mode |= SILC_CHANNEL_MODE_PRIVATE;
1247 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1251 mode |= SILC_CHANNEL_MODE_SECRET;
1253 mode &= ~SILC_CHANNEL_MODE_SECRET;
1257 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1259 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1263 mode |= SILC_CHANNEL_MODE_INVITE;
1265 mode &= ~SILC_CHANNEL_MODE_INVITE;
1269 mode |= SILC_CHANNEL_MODE_TOPIC;
1271 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1276 mode |= SILC_CHANNEL_MODE_ULIMIT;
1278 if (cmd->argc < 4) {
1279 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1280 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1284 ll = atoi(cmd->argv[3]);
1285 SILC_PUT32_MSB(ll, tmp);
1289 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1294 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1296 if (cmd->argc < 4) {
1297 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1298 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1303 arg_len = cmd->argv_lens[3];
1305 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1310 mode |= SILC_CHANNEL_MODE_CIPHER;
1312 if (cmd->argc < 4) {
1313 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1314 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1319 arg_len = cmd->argv_lens[3];
1321 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1326 mode |= SILC_CHANNEL_MODE_HMAC;
1328 if (cmd->argc < 4) {
1329 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1330 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1335 arg_len = cmd->argv_lens[3];
1337 mode &= ~SILC_CHANNEL_MODE_HMAC;
1342 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1345 if (cmd->argc < 4) {
1346 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1347 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1352 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1353 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1354 cmd->client->private_key,
1359 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1360 cmd->argv[3], cmd->argv_lens[3]);
1364 arg_len = auth->len;
1366 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1376 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1377 SILC_PUT32_MSB(mode, modebuf);
1379 /* Send the command packet. We support sending only one mode at once
1380 that requires an argument. */
1383 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1384 1, chidp->data, chidp->len,
1385 2, modebuf, sizeof(modebuf),
1386 type, arg, arg_len);
1389 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1390 1, chidp->data, chidp->len,
1391 2, modebuf, sizeof(modebuf));
1394 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1395 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1396 silc_buffer_free(buffer);
1397 silc_buffer_free(chidp);
1399 silc_buffer_free(auth);
1401 /* Notify application */
1405 silc_client_command_free(cmd);
1408 /* CUMODE command. Changes client's mode on a channel. */
1410 SILC_CLIENT_CMD_FUNC(cumode)
1412 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1413 SilcClient client = cmd->client;
1414 SilcClientConnection conn = cmd->conn;
1415 SilcChannelEntry channel;
1416 SilcChannelUser chu;
1417 SilcClientEntry client_entry;
1418 SilcBuffer buffer, clidp, chidp, auth = NULL;
1419 unsigned char *name, *cp, modebuf[4];
1420 uint32 mode = 0, add, len;
1421 char *nickname = NULL;
1425 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1430 if (cmd->argc < 4) {
1431 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1432 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1437 if (cmd->argv[1][0] == '*') {
1438 if (!conn->current_channel) {
1439 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1440 "You are not on any channel");
1445 channel = conn->current_channel;
1447 name = cmd->argv[1];
1449 channel = silc_client_get_channel(cmd->client, conn, name);
1451 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1452 "You are on that channel");
1458 /* Parse the typed nickname. */
1459 if (client->params->nickname_parse)
1460 client->params->nickname_parse(cmd->argv[3], &nickname);
1462 nickname = strdup(cmd->argv[3]);
1464 /* Find client entry */
1465 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1466 cmd->argv[3], TRUE);
1467 if (!client_entry) {
1473 silc_free(nickname);
1475 /* Client entry not found, it was requested thus mark this to be
1477 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1479 silc_client_command_destructor,
1480 silc_client_command_cumode,
1481 silc_client_command_dup(cmd));
1486 /* Get the current mode */
1487 silc_list_start(channel->clients);
1488 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1489 if (chu->client == client_entry) {
1495 /* Are we adding or removing mode */
1496 if (cmd->argv[2][0] == '-')
1502 cp = cmd->argv[2] + 1;
1504 for (i = 0; i < len; i++) {
1508 mode |= SILC_CHANNEL_UMODE_CHANFO;
1509 mode |= SILC_CHANNEL_UMODE_CHANOP;
1511 mode = SILC_CHANNEL_UMODE_NONE;
1516 if (cmd->argc == 5) {
1517 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1518 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1519 cmd->client->private_key,
1524 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1525 cmd->argv[4], cmd->argv_lens[4]);
1528 mode |= SILC_CHANNEL_UMODE_CHANFO;
1530 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1535 mode |= SILC_CHANNEL_UMODE_CHANOP;
1537 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1546 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1547 SILC_PUT32_MSB(mode, modebuf);
1548 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1550 /* Send the command packet. We support sending only one mode at once
1551 that requires an argument. */
1552 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1554 1, chidp->data, chidp->len,
1556 3, clidp->data, clidp->len,
1557 4, auth ? auth->data : NULL,
1558 auth ? auth->len : 0);
1560 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1561 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1562 silc_buffer_free(buffer);
1563 silc_buffer_free(chidp);
1564 silc_buffer_free(clidp);
1566 silc_buffer_free(auth);
1568 /* Notify application */
1572 silc_free(nickname);
1573 silc_client_command_free(cmd);
1576 /* KICK command. Kicks a client out of channel. */
1578 SILC_CLIENT_CMD_FUNC(kick)
1580 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1581 SilcClient client = cmd->client;
1582 SilcClientConnection conn = cmd->conn;
1583 SilcIDCacheEntry id_cache = NULL;
1584 SilcChannelEntry channel;
1585 SilcBuffer buffer, idp, idp2;
1586 SilcClientEntry target;
1588 char *nickname = NULL;
1591 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1596 if (cmd->argc < 3) {
1597 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1598 "Usage: /KICK <channel> <nickname> [<comment>]");
1603 if (cmd->argv[1][0] == '*') {
1604 if (!conn->current_channel) {
1605 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1606 "You are not on any channel");
1610 name = conn->current_channel->channel_name;
1612 name = cmd->argv[1];
1615 if (!conn->current_channel) {
1616 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1617 "You are not on that channel");
1622 /* Get the Channel ID of the channel */
1623 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1624 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1625 "You are not on that channel");
1630 channel = (SilcChannelEntry)id_cache->context;
1632 /* Parse the typed nickname. */
1633 if (client->params->nickname_parse)
1634 client->params->nickname_parse(cmd->argv[2], &nickname);
1636 nickname = strdup(cmd->argv[2]);
1638 /* Get the target client */
1639 target = silc_idlist_get_client(cmd->client, conn, nickname,
1640 cmd->argv[2], FALSE);
1642 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1643 "No such client: %s",
1649 /* Send KICK command to the server */
1650 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1651 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1653 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1654 1, idp->data, idp->len,
1655 2, idp2->data, idp2->len);
1657 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1658 1, idp->data, idp->len,
1659 2, idp2->data, idp2->len,
1661 strlen(cmd->argv[3]));
1662 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1663 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1664 silc_buffer_free(buffer);
1665 silc_buffer_free(idp);
1666 silc_buffer_free(idp2);
1668 /* Notify application */
1672 silc_free(nickname);
1673 silc_client_command_free(cmd);
1676 static void silc_client_command_oper_send(unsigned char *data,
1677 uint32 data_len, void *context)
1679 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1680 SilcClientConnection conn = cmd->conn;
1681 SilcBuffer buffer, auth;
1683 if (cmd->argc >= 3) {
1684 /* Encode the public key authentication payload */
1685 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1686 cmd->client->private_key,
1691 /* Encode the password authentication payload */
1692 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1696 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1698 strlen(cmd->argv[1]),
1699 2, auth->data, auth->len);
1700 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1701 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1703 silc_buffer_free(buffer);
1704 silc_buffer_free(auth);
1706 /* Notify application */
1710 /* OPER command. Used to obtain server operator privileges. */
1712 SILC_CLIENT_CMD_FUNC(oper)
1714 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1715 SilcClientConnection conn = cmd->conn;
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: /OPER <username> [-pubkey]");
1730 if (cmd->argc < 3) {
1731 /* Get passphrase */
1732 cmd->client->ops->ask_passphrase(cmd->client, conn,
1733 silc_client_command_oper_send,
1738 silc_client_command_oper_send(NULL, 0, context);
1741 silc_client_command_free(cmd);
1744 static void silc_client_command_silcoper_send(unsigned char *data,
1745 uint32 data_len, void *context)
1747 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1748 SilcClientConnection conn = cmd->conn;
1749 SilcBuffer buffer, auth;
1751 if (cmd->argc >= 3) {
1752 /* Encode the public key authentication payload */
1753 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1754 cmd->client->private_key,
1759 /* Encode the password authentication payload */
1760 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1764 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1766 strlen(cmd->argv[1]),
1767 2, auth->data, auth->len);
1768 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1769 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1771 silc_buffer_free(buffer);
1772 silc_buffer_free(auth);
1774 /* Notify application */
1778 /* SILCOPER command. Used to obtain router operator privileges. */
1780 SILC_CLIENT_CMD_FUNC(silcoper)
1782 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1783 SilcClientConnection conn = cmd->conn;
1786 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1791 if (cmd->argc < 2) {
1792 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1793 "Usage: /SILCOPER <username> [-pubkey]");
1798 if (cmd->argc < 3) {
1799 /* Get passphrase */
1800 cmd->client->ops->ask_passphrase(cmd->client, conn,
1801 silc_client_command_silcoper_send,
1806 silc_client_command_silcoper_send(NULL, 0, context);
1809 silc_client_command_free(cmd);
1812 /* CONNECT command. Connects the server to another server. */
1814 SILC_CLIENT_CMD_FUNC(connect)
1816 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1817 SilcClientConnection conn = cmd->conn;
1819 unsigned char port[4];
1823 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1828 if (cmd->argc < 2) {
1829 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1830 "Usage: /CONNECT <server> [<port>]");
1835 if (cmd->argc == 3) {
1836 tmp = atoi(cmd->argv[2]);
1837 SILC_PUT32_MSB(tmp, port);
1841 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1843 strlen(cmd->argv[1]),
1846 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1848 strlen(cmd->argv[1]));
1849 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1850 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1851 silc_buffer_free(buffer);
1853 /* Notify application */
1857 silc_client_command_free(cmd);
1860 /* Command BAN. This is used to manage the ban list of the channel. */
1862 SILC_CLIENT_CMD_FUNC(ban)
1864 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1865 SilcClientConnection conn = cmd->conn;
1866 SilcChannelEntry channel;
1867 SilcBuffer buffer, chidp;
1869 char *name, *ban = NULL;
1872 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1877 if (cmd->argc < 2) {
1878 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1879 "Usage: /BAN <channel> "
1880 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1885 if (cmd->argv[1][0] == '*') {
1886 if (!conn->current_channel) {
1887 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1888 "You are not on any channel");
1893 channel = conn->current_channel;
1895 name = cmd->argv[1];
1897 channel = silc_client_get_channel(cmd->client, conn, name);
1899 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1900 "You are on that channel");
1906 if (cmd->argc == 3) {
1907 if (cmd->argv[2][0] == '+')
1916 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1918 /* Send the command */
1920 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1921 1, chidp->data, chidp->len,
1922 type, ban, strlen(ban));
1924 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1925 1, chidp->data, chidp->len);
1927 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1928 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1929 silc_buffer_free(buffer);
1930 silc_buffer_free(chidp);
1932 /* Notify application */
1936 silc_client_command_free(cmd);
1939 /* CLOSE command. Close server connection to the remote server */
1941 SILC_CLIENT_CMD_FUNC(close)
1943 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1944 SilcClientConnection conn = cmd->conn;
1946 unsigned char port[4];
1950 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1955 if (cmd->argc < 2) {
1956 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1957 "Usage: /CLOSE <server> [<port>]");
1962 if (cmd->argc == 3) {
1963 tmp = atoi(cmd->argv[2]);
1964 SILC_PUT32_MSB(tmp, port);
1968 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1970 strlen(cmd->argv[1]),
1973 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1975 strlen(cmd->argv[1]));
1976 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1977 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1978 silc_buffer_free(buffer);
1980 /* Notify application */
1984 silc_client_command_free(cmd);
1987 /* SHUTDOWN command. Shutdowns the server. */
1989 SILC_CLIENT_CMD_FUNC(shutdown)
1991 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1994 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1999 /* Send the command */
2000 silc_client_send_command(cmd->client, cmd->conn,
2001 SILC_COMMAND_SHUTDOWN, 0, 0);
2003 /* Notify application */
2007 silc_client_command_free(cmd);
2010 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2012 SILC_CLIENT_CMD_FUNC(leave)
2014 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2015 SilcClientConnection conn = cmd->conn;
2016 SilcIDCacheEntry id_cache = NULL;
2017 SilcChannelEntry channel;
2018 SilcBuffer buffer, idp;
2022 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2027 if (cmd->argc != 2) {
2028 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2029 "Usage: /LEAVE <channel>");
2034 if (cmd->argv[1][0] == '*') {
2035 if (!conn->current_channel) {
2036 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2037 "You are not on any channel");
2041 name = conn->current_channel->channel_name;
2043 name = cmd->argv[1];
2046 /* Get the Channel ID of the channel */
2047 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2048 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2049 "You are not on that channel");
2054 channel = (SilcChannelEntry)id_cache->context;
2055 channel->on_channel = FALSE;
2057 /* Send LEAVE command to the server */
2058 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2059 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2060 1, idp->data, idp->len);
2061 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2062 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2063 silc_buffer_free(buffer);
2064 silc_buffer_free(idp);
2066 /* Notify application */
2069 if (conn->current_channel == channel)
2070 conn->current_channel = NULL;
2072 silc_client_del_channel(cmd->client, cmd->conn, channel);
2075 silc_client_command_free(cmd);
2078 /* Command USERS. Requests the USERS of the clients joined on requested
2081 SILC_CLIENT_CMD_FUNC(users)
2083 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2084 SilcClientConnection conn = cmd->conn;
2089 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2094 if (cmd->argc != 2) {
2095 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2096 "Usage: /USERS <channel>");
2101 if (cmd->argv[1][0] == '*') {
2102 if (!conn->current_channel) {
2103 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2104 "You are not on any channel");
2108 name = conn->current_channel->channel_name;
2110 name = cmd->argv[1];
2113 /* Send USERS command to the server */
2114 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2115 ++conn->cmd_ident, 1,
2116 2, name, strlen(name));
2117 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2118 NULL, 0, NULL, NULL, buffer->data,
2120 silc_buffer_free(buffer);
2122 /* Notify application */
2126 silc_client_command_free(cmd);
2129 /* Command GETKEY. Used to fetch remote client's public key. */
2131 SILC_CLIENT_CMD_FUNC(getkey)
2133 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2134 SilcClientConnection conn = cmd->conn;
2135 SilcClient client = cmd->client;
2136 SilcClientEntry client_entry = NULL;
2137 SilcServerEntry server_entry = NULL;
2138 char *nickname = NULL;
2139 SilcBuffer idp, buffer;
2142 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2147 if (cmd->argc < 2) {
2148 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2149 "Usage: /GETKEY <nickname or server name>");
2155 SilcClientCommandReplyContext reply =
2156 (SilcClientCommandReplyContext)context2;
2157 SilcCommandStatus status;
2158 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2159 SILC_GET16_MSB(status, tmp);
2161 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2162 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2163 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2165 silc_client_command_status_message(status));
2171 /* Parse the typed nickname. */
2172 if (client->params->nickname_parse)
2173 client->params->nickname_parse(cmd->argv[1], &nickname);
2175 nickname = strdup(cmd->argv[1]);
2177 /* Find client entry */
2178 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2180 if (!client_entry) {
2181 /* Check whether user requested server actually */
2182 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2184 if (!server_entry) {
2190 /* No. what ever user wants we don't have it, so resolve it. We
2191 will try to resolve both client and server, one of them is
2192 bound to be wrong. */
2194 /* This will send the IDENTIFY command */
2195 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2196 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2198 silc_client_command_destructor,
2199 silc_client_command_getkey,
2200 silc_client_command_dup(cmd));
2202 /* This sends the IDENTIFY command to resolve the server. */
2203 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2204 ++conn->cmd_ident, 1,
2205 2, cmd->argv[1], cmd->argv_lens[1]);
2206 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2207 conn->cmd_ident, NULL,
2208 silc_client_command_getkey,
2209 silc_client_command_dup(cmd));
2212 silc_free(nickname);
2216 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2218 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2221 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2222 1, idp->data, idp->len);
2223 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2224 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2225 silc_buffer_free(buffer);
2226 silc_buffer_free(idp);
2228 /* Notify application */
2232 silc_free(nickname);
2233 silc_client_command_free(cmd);