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]);
370 conn->local_entry->nickname = conn->nickname;
376 silc_client_command_free(cmd);
379 /* Command NICK. Shows current nickname/sets new nickname on current
382 SILC_CLIENT_CMD_FUNC(nick)
384 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
385 SilcClientConnection conn = cmd->conn;
389 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
395 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
396 "Usage: /NICK <nickname>");
401 if (!strcmp(conn->nickname, cmd->argv[1]))
404 /* Show current nickname */
407 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
408 "Your nickname is %s on server %s",
409 conn->nickname, conn->remote_host);
411 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
412 "Your nickname is %s", conn->nickname);
419 if (cmd->argv_lens[1] > 128)
420 cmd->argv_lens[1] = 128;
422 /* Send the NICK command */
423 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
427 ++cmd->conn->cmd_ident);
428 silc_client_packet_send(cmd->client, cmd->conn->sock,
429 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
430 buffer->data, buffer->len, TRUE);
431 silc_buffer_free(buffer);
433 /* Register pending callback that will actually set the new nickname
434 if there were no errors returned by the server. */
435 silc_client_command_pending(conn, SILC_COMMAND_NICK,
436 cmd->conn->cmd_ident,
437 silc_client_command_destructor,
438 silc_client_command_nick_change,
439 silc_client_command_dup(cmd));
444 silc_client_command_free(cmd);
447 /* Command LIST. Lists channels on the current server. */
449 SILC_CLIENT_CMD_FUNC(list)
451 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
452 SilcClientConnection conn = cmd->conn;
453 SilcIDCacheEntry id_cache = NULL;
454 SilcChannelEntry channel;
455 SilcBuffer buffer, idp = NULL;
459 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
464 if (cmd->argc == 2) {
467 /* Get the Channel ID of the channel */
468 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
469 channel = (SilcChannelEntry)id_cache->context;
470 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
475 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
476 ++conn->cmd_ident, 0);
478 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
479 ++conn->cmd_ident, 1,
480 1, idp->data, idp->len);
482 silc_client_packet_send(cmd->client, cmd->conn->sock,
483 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
484 buffer->data, buffer->len, TRUE);
485 silc_buffer_free(buffer);
487 silc_buffer_free(idp);
489 /* Notify application */
493 silc_client_command_free(cmd);
496 /* Command TOPIC. Sets/shows topic on a channel. */
498 SILC_CLIENT_CMD_FUNC(topic)
500 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
501 SilcClientConnection conn = cmd->conn;
502 SilcIDCacheEntry id_cache = NULL;
503 SilcChannelEntry channel;
504 SilcBuffer buffer, idp;
508 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
513 if (cmd->argc < 2 || cmd->argc > 3) {
514 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
515 "Usage: /TOPIC <channel> [<topic>]");
520 if (cmd->argv[1][0] == '*') {
521 if (!conn->current_channel) {
522 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
523 "You are not on any channel");
527 name = conn->current_channel->channel_name;
532 if (!conn->current_channel) {
533 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
534 "You are not on that channel");
539 /* Get the Channel ID of the channel */
540 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
541 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
542 "You are not on that channel");
547 channel = (SilcChannelEntry)id_cache->context;
549 /* Send TOPIC command to the server */
550 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
552 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
553 ++conn->cmd_ident, 2,
554 1, idp->data, idp->len,
556 strlen(cmd->argv[2]));
558 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
559 ++conn->cmd_ident, 1,
560 1, idp->data, idp->len);
561 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
562 0, NULL, NULL, buffer->data, buffer->len, TRUE);
563 silc_buffer_free(buffer);
564 silc_buffer_free(idp);
566 /* Notify application */
570 silc_client_command_free(cmd);
573 /* Command INVITE. Invites specific client to join a channel. This is
574 also used to mange the invite list of the channel. */
576 SILC_CLIENT_CMD_FUNC(invite)
578 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
579 SilcClient client = cmd->client;
580 SilcClientConnection conn = cmd->conn;
581 SilcClientEntry client_entry = NULL;
582 SilcChannelEntry channel;
583 SilcBuffer buffer, clidp, chidp;
585 char *nickname = NULL, *name;
589 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
595 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
596 "Usage: /INVITE <channel> [<nickname>[@server>]"
597 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
602 if (cmd->argv[1][0] == '*') {
603 if (!conn->current_channel) {
604 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
605 "You are not on any channel");
610 channel = conn->current_channel;
614 channel = silc_client_get_channel(cmd->client, conn, name);
616 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
617 "You are on that channel");
623 /* Parse the typed nickname. */
624 if (cmd->argc == 3) {
625 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
626 if (client->params->nickname_parse)
627 client->params->nickname_parse(cmd->argv[2], &nickname);
629 nickname = strdup(cmd->argv[2]);
631 /* Find client entry */
632 client_entry = silc_idlist_get_client(client, conn, nickname,
641 /* Client entry not found, it was requested thus mark this to be
643 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
645 silc_client_command_destructor,
646 silc_client_command_invite,
647 silc_client_command_dup(cmd));
652 invite = cmd->argv[2];
654 if (cmd->argv[2][0] == '+')
661 /* Send the command */
662 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
664 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
665 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
666 ++conn->cmd_ident, 3,
667 1, chidp->data, chidp->len,
668 2, clidp->data, clidp->len,
669 type, invite, invite ?
671 silc_buffer_free(clidp);
673 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
674 ++conn->cmd_ident, 2,
675 1, chidp->data, chidp->len,
676 type, invite, invite ?
680 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
681 0, NULL, NULL, buffer->data, buffer->len, TRUE);
682 silc_buffer_free(buffer);
683 silc_buffer_free(chidp);
685 /* Notify application */
690 silc_client_command_free(cmd);
695 SilcClientConnection conn;
698 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
700 QuitInternal q = (QuitInternal)context;
702 /* Close connection */
703 q->client->ops->disconnect(q->client, q->conn);
704 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
709 /* Command QUIT. Closes connection with current server. */
711 SILC_CLIENT_CMD_FUNC(quit)
713 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
718 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
724 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
725 &cmd->argv[1], &cmd->argv_lens[1],
726 &cmd->argv_types[1], 0);
728 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
729 NULL, NULL, NULL, 0);
730 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
732 buffer->data, buffer->len, TRUE);
733 silc_buffer_free(buffer);
735 q = silc_calloc(1, sizeof(*q));
736 q->client = cmd->client;
739 /* Sleep for a while */
742 /* We quit the connection with little timeout */
743 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
744 silc_client_command_quit_cb, (void *)q,
745 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
747 /* Notify application */
751 silc_client_command_free(cmd);
754 /* Timeout callback to remove the killed client from cache */
756 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
758 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
759 SilcClient client = cmd->client;
760 SilcClientConnection conn = cmd->conn;
761 SilcClientEntry target;
762 char *nickname = NULL;
764 /* Parse the typed nickname. */
765 if (client->params->nickname_parse)
766 client->params->nickname_parse(cmd->argv[1], &nickname);
768 nickname = strdup(cmd->argv[1]);
770 /* Get the target client */
771 target = silc_idlist_get_client(cmd->client, conn, nickname,
772 cmd->argv[1], FALSE);
774 silc_client_remove_from_channels(client, conn, target);
775 silc_client_del_client(client, conn, target);
779 silc_client_command_free(cmd);
782 /* Kill command's pending command callback to actually remove the killed
783 client from our local cache. */
785 SILC_CLIENT_CMD_FUNC(kill_remove)
787 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
788 SilcClientCommandReplyContext reply =
789 (SilcClientCommandReplyContext)context2;
790 SilcCommandStatus status;
792 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
793 if (status == SILC_STATUS_OK) {
794 /* Remove with timeout */
795 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
796 silc_client_command_kill_remove_later, context,
797 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
801 silc_client_command_free(cmd);
804 /* Command KILL. Router operator can use this command to remove an client
805 fromthe SILC Network. */
807 SILC_CLIENT_CMD_FUNC(kill)
809 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
810 SilcClient client = cmd->client;
811 SilcClientConnection conn = cmd->conn;
812 SilcBuffer buffer, idp;
813 SilcClientEntry target;
814 char *nickname = NULL;
817 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
823 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
824 "Usage: /KILL <nickname> [<comment>]");
829 /* Parse the typed nickname. */
830 if (client->params->nickname_parse)
831 client->params->nickname_parse(cmd->argv[1], &nickname);
833 nickname = strdup(cmd->argv[1]);
835 /* Get the target client */
836 target = silc_idlist_get_client(cmd->client, conn, nickname,
846 /* Client entry not found, it was requested thus mark this to be
848 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
850 silc_client_command_destructor,
851 silc_client_command_kill,
852 silc_client_command_dup(cmd));
857 /* Send the KILL command to the server */
858 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
860 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
861 ++conn->cmd_ident, 1,
862 1, idp->data, idp->len);
864 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
865 ++conn->cmd_ident, 2,
866 1, idp->data, idp->len,
868 strlen(cmd->argv[2]));
869 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
870 0, NULL, NULL, buffer->data, buffer->len, TRUE);
871 silc_buffer_free(buffer);
872 silc_buffer_free(idp);
874 /* Notify application */
877 /* Register a pending callback that will actually remove the killed
878 client from our cache. */
879 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
880 NULL, silc_client_command_kill_remove,
881 silc_client_command_dup(cmd));
885 silc_client_command_free(cmd);
888 /* Command INFO. Request information about specific server. If specific
889 server is not provided the current server is used. */
891 SILC_CLIENT_CMD_FUNC(info)
893 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
894 SilcClientConnection conn = cmd->conn;
899 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
905 name = strdup(cmd->argv[1]);
907 /* Send the command */
909 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
910 1, name, strlen(name));
912 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
913 NULL, NULL, NULL, 0);
914 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
915 0, NULL, NULL, buffer->data, buffer->len, TRUE);
916 silc_buffer_free(buffer);
920 /* Notify application */
924 silc_client_command_free(cmd);
927 /* Command PING. Sends ping to server. This is used to test the
928 communication channel. */
930 SILC_CLIENT_CMD_FUNC(ping)
932 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
933 SilcClientConnection conn = cmd->conn;
939 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
944 /* Send the command */
945 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
946 1, conn->remote_id_data,
947 silc_id_get_len(conn->remote_id,
949 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
950 0, NULL, NULL, buffer->data, buffer->len, TRUE);
951 silc_buffer_free(buffer);
953 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
956 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
961 /* Start counting time */
962 for (i = 0; i < conn->ping_count; i++) {
963 if (conn->ping[i].dest_id == NULL) {
964 conn->ping[i].start_time = time(NULL);
965 conn->ping[i].dest_id = id;
966 conn->ping[i].dest_name = strdup(conn->remote_host);
970 if (i >= conn->ping_count) {
971 i = conn->ping_count;
972 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
973 conn->ping[i].start_time = time(NULL);
974 conn->ping[i].dest_id = id;
975 conn->ping[i].dest_name = strdup(conn->remote_host);
979 /* Notify application */
983 silc_client_command_free(cmd);
986 /* Command JOIN. Joins to a channel. */
988 SILC_CLIENT_CMD_FUNC(join)
990 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
991 SilcClientConnection conn = cmd->conn;
992 SilcIDCacheEntry id_cache = NULL;
993 SilcBuffer buffer, idp;
996 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1001 /* See if we have joined to the requested channel already */
1002 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
1004 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
1005 if (channel->on_channel)
1009 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1011 if (cmd->argv_lens[1] > 256)
1012 cmd->argv_lens[1] = 256;
1014 /* Send JOIN command to the server */
1017 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
1018 1, cmd->argv[1], cmd->argv_lens[1],
1019 2, idp->data, idp->len);
1020 else if (cmd->argc == 3)
1023 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
1024 1, cmd->argv[1], cmd->argv_lens[1],
1025 2, idp->data, idp->len,
1026 3, cmd->argv[2], cmd->argv_lens[2]);
1029 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
1030 1, cmd->argv[1], cmd->argv_lens[1],
1031 2, idp->data, idp->len,
1032 3, cmd->argv[2], cmd->argv_lens[2],
1033 4, cmd->argv[3], cmd->argv_lens[3]);
1035 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1036 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1037 silc_buffer_free(buffer);
1038 silc_buffer_free(idp);
1040 /* Notify application */
1044 silc_client_command_free(cmd);
1047 /* MOTD command. Requests motd from server. */
1049 SILC_CLIENT_CMD_FUNC(motd)
1051 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1052 SilcClientConnection conn = cmd->conn;
1056 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1061 if (cmd->argc < 1 || cmd->argc > 2) {
1062 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1063 "Usage: /MOTD [<server>]");
1068 /* Send TOPIC command to the server */
1070 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1071 1, conn->remote_host,
1072 strlen(conn->remote_host));
1074 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1077 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1078 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1079 silc_buffer_free(buffer);
1081 /* Notify application */
1085 silc_client_command_free(cmd);
1088 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1089 modes as client cannot set itself server/router operator privileges. */
1091 SILC_CLIENT_CMD_FUNC(umode)
1093 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1094 SilcClientConnection conn = cmd->conn;
1095 SilcBuffer buffer, idp;
1096 unsigned char *cp, modebuf[4];
1097 uint32 mode, add, len;
1101 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1106 if (cmd->argc < 2) {
1107 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1108 "Usage: /UMODE +|-<modes>");
1113 mode = conn->local_entry->mode;
1115 /* Are we adding or removing mode */
1116 if (cmd->argv[1][0] == '-')
1122 cp = cmd->argv[1] + 1;
1124 for (i = 0; i < len; i++) {
1129 mode |= SILC_UMODE_SERVER_OPERATOR;
1130 mode |= SILC_UMODE_ROUTER_OPERATOR;
1132 mode = SILC_UMODE_NONE;
1137 mode |= SILC_UMODE_SERVER_OPERATOR;
1139 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1143 mode |= SILC_UMODE_ROUTER_OPERATOR;
1145 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1149 mode |= SILC_UMODE_GONE;
1151 mode &= ~SILC_UMODE_GONE;
1160 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1161 SILC_PUT32_MSB(mode, modebuf);
1163 /* Send the command packet. We support sending only one mode at once
1164 that requires an argument. */
1166 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1167 1, idp->data, idp->len,
1168 2, modebuf, sizeof(modebuf));
1169 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1170 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1171 silc_buffer_free(buffer);
1172 silc_buffer_free(idp);
1174 /* Notify application */
1178 silc_client_command_free(cmd);
1181 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1182 can be set several at once. Those modes that require argument must be set
1183 separately (unless set with modes that does not require arguments). */
1185 SILC_CLIENT_CMD_FUNC(cmode)
1187 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1188 SilcClientConnection conn = cmd->conn;
1189 SilcChannelEntry channel;
1190 SilcBuffer buffer, chidp, auth = NULL;
1191 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1192 uint32 mode, add, type, len, arg_len = 0;
1196 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1201 if (cmd->argc < 3) {
1202 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1203 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1208 if (cmd->argv[1][0] == '*') {
1209 if (!conn->current_channel) {
1210 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1211 "You are not on any channel");
1216 channel = conn->current_channel;
1218 name = cmd->argv[1];
1220 channel = silc_client_get_channel(cmd->client, conn, name);
1222 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1223 "You are on that channel");
1229 mode = channel->mode;
1231 /* Are we adding or removing mode */
1232 if (cmd->argv[2][0] == '-')
1237 /* Argument type to be sent to server */
1241 cp = cmd->argv[2] + 1;
1243 for (i = 0; i < len; i++) {
1247 mode |= SILC_CHANNEL_MODE_PRIVATE;
1249 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1253 mode |= SILC_CHANNEL_MODE_SECRET;
1255 mode &= ~SILC_CHANNEL_MODE_SECRET;
1259 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1261 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1265 mode |= SILC_CHANNEL_MODE_INVITE;
1267 mode &= ~SILC_CHANNEL_MODE_INVITE;
1271 mode |= SILC_CHANNEL_MODE_TOPIC;
1273 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1278 mode |= SILC_CHANNEL_MODE_ULIMIT;
1280 if (cmd->argc < 4) {
1281 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1282 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1286 ll = atoi(cmd->argv[3]);
1287 SILC_PUT32_MSB(ll, tmp);
1291 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1296 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1298 if (cmd->argc < 4) {
1299 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1300 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1305 arg_len = cmd->argv_lens[3];
1307 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1312 mode |= SILC_CHANNEL_MODE_CIPHER;
1314 if (cmd->argc < 4) {
1315 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1316 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1321 arg_len = cmd->argv_lens[3];
1323 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1328 mode |= SILC_CHANNEL_MODE_HMAC;
1330 if (cmd->argc < 4) {
1331 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1332 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1337 arg_len = cmd->argv_lens[3];
1339 mode &= ~SILC_CHANNEL_MODE_HMAC;
1344 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1347 if (cmd->argc < 4) {
1348 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1349 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1354 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1355 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1356 cmd->client->private_key,
1361 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1362 cmd->argv[3], cmd->argv_lens[3]);
1366 arg_len = auth->len;
1368 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1378 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1379 SILC_PUT32_MSB(mode, modebuf);
1381 /* Send the command packet. We support sending only one mode at once
1382 that requires an argument. */
1385 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1386 1, chidp->data, chidp->len,
1387 2, modebuf, sizeof(modebuf),
1388 type, arg, arg_len);
1391 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1392 1, chidp->data, chidp->len,
1393 2, modebuf, sizeof(modebuf));
1396 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1397 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1398 silc_buffer_free(buffer);
1399 silc_buffer_free(chidp);
1401 silc_buffer_free(auth);
1403 /* Notify application */
1407 silc_client_command_free(cmd);
1410 /* CUMODE command. Changes client's mode on a channel. */
1412 SILC_CLIENT_CMD_FUNC(cumode)
1414 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1415 SilcClient client = cmd->client;
1416 SilcClientConnection conn = cmd->conn;
1417 SilcChannelEntry channel;
1418 SilcChannelUser chu;
1419 SilcClientEntry client_entry;
1420 SilcBuffer buffer, clidp, chidp, auth = NULL;
1421 unsigned char *name, *cp, modebuf[4];
1422 uint32 mode = 0, add, len;
1423 char *nickname = NULL;
1427 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1432 if (cmd->argc < 4) {
1433 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1434 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1439 if (cmd->argv[1][0] == '*') {
1440 if (!conn->current_channel) {
1441 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1442 "You are not on any channel");
1447 channel = conn->current_channel;
1449 name = cmd->argv[1];
1451 channel = silc_client_get_channel(cmd->client, conn, name);
1453 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1454 "You are on that channel");
1460 /* Parse the typed nickname. */
1461 if (client->params->nickname_parse)
1462 client->params->nickname_parse(cmd->argv[3], &nickname);
1464 nickname = strdup(cmd->argv[3]);
1466 /* Find client entry */
1467 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1468 cmd->argv[3], TRUE);
1469 if (!client_entry) {
1475 silc_free(nickname);
1477 /* Client entry not found, it was requested thus mark this to be
1479 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1481 silc_client_command_destructor,
1482 silc_client_command_cumode,
1483 silc_client_command_dup(cmd));
1488 /* Get the current mode */
1489 silc_list_start(channel->clients);
1490 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1491 if (chu->client == client_entry) {
1497 /* Are we adding or removing mode */
1498 if (cmd->argv[2][0] == '-')
1504 cp = cmd->argv[2] + 1;
1506 for (i = 0; i < len; i++) {
1510 mode |= SILC_CHANNEL_UMODE_CHANFO;
1511 mode |= SILC_CHANNEL_UMODE_CHANOP;
1513 mode = SILC_CHANNEL_UMODE_NONE;
1518 if (cmd->argc == 5) {
1519 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1520 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1521 cmd->client->private_key,
1526 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1527 cmd->argv[4], cmd->argv_lens[4]);
1530 mode |= SILC_CHANNEL_UMODE_CHANFO;
1532 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1537 mode |= SILC_CHANNEL_UMODE_CHANOP;
1539 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1548 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1549 SILC_PUT32_MSB(mode, modebuf);
1550 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1552 /* Send the command packet. We support sending only one mode at once
1553 that requires an argument. */
1554 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1556 1, chidp->data, chidp->len,
1558 3, clidp->data, clidp->len,
1559 4, auth ? auth->data : NULL,
1560 auth ? auth->len : 0);
1562 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1563 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1564 silc_buffer_free(buffer);
1565 silc_buffer_free(chidp);
1566 silc_buffer_free(clidp);
1568 silc_buffer_free(auth);
1570 /* Notify application */
1574 silc_free(nickname);
1575 silc_client_command_free(cmd);
1578 /* KICK command. Kicks a client out of channel. */
1580 SILC_CLIENT_CMD_FUNC(kick)
1582 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1583 SilcClient client = cmd->client;
1584 SilcClientConnection conn = cmd->conn;
1585 SilcIDCacheEntry id_cache = NULL;
1586 SilcChannelEntry channel;
1587 SilcBuffer buffer, idp, idp2;
1588 SilcClientEntry target;
1590 char *nickname = NULL;
1593 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1598 if (cmd->argc < 3) {
1599 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1600 "Usage: /KICK <channel> <nickname> [<comment>]");
1605 if (cmd->argv[1][0] == '*') {
1606 if (!conn->current_channel) {
1607 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1608 "You are not on any channel");
1612 name = conn->current_channel->channel_name;
1614 name = cmd->argv[1];
1617 if (!conn->current_channel) {
1618 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1619 "You are not on that channel");
1624 /* Get the Channel ID of the channel */
1625 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1626 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1627 "You are not on that channel");
1632 channel = (SilcChannelEntry)id_cache->context;
1634 /* Parse the typed nickname. */
1635 if (client->params->nickname_parse)
1636 client->params->nickname_parse(cmd->argv[2], &nickname);
1638 nickname = strdup(cmd->argv[2]);
1640 /* Get the target client */
1641 target = silc_idlist_get_client(cmd->client, conn, nickname,
1642 cmd->argv[2], FALSE);
1644 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1645 "No such client: %s",
1651 /* Send KICK command to the server */
1652 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1653 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1655 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1656 1, idp->data, idp->len,
1657 2, idp2->data, idp2->len);
1659 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1660 1, idp->data, idp->len,
1661 2, idp2->data, idp2->len,
1663 strlen(cmd->argv[3]));
1664 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1665 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1666 silc_buffer_free(buffer);
1667 silc_buffer_free(idp);
1668 silc_buffer_free(idp2);
1670 /* Notify application */
1674 silc_free(nickname);
1675 silc_client_command_free(cmd);
1678 static void silc_client_command_oper_send(unsigned char *data,
1679 uint32 data_len, void *context)
1681 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1682 SilcClientConnection conn = cmd->conn;
1683 SilcBuffer buffer, auth;
1685 if (cmd->argc >= 3) {
1686 /* Encode the public key authentication payload */
1687 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1688 cmd->client->private_key,
1693 /* Encode the password authentication payload */
1694 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1698 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1700 strlen(cmd->argv[1]),
1701 2, auth->data, auth->len);
1702 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1703 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1705 silc_buffer_free(buffer);
1706 silc_buffer_free(auth);
1708 /* Notify application */
1712 /* OPER command. Used to obtain server operator privileges. */
1714 SILC_CLIENT_CMD_FUNC(oper)
1716 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1717 SilcClientConnection conn = cmd->conn;
1720 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1725 if (cmd->argc < 2) {
1726 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1727 "Usage: /OPER <username> [-pubkey]");
1732 if (cmd->argc < 3) {
1733 /* Get passphrase */
1734 cmd->client->ops->ask_passphrase(cmd->client, conn,
1735 silc_client_command_oper_send,
1740 silc_client_command_oper_send(NULL, 0, context);
1743 silc_client_command_free(cmd);
1746 static void silc_client_command_silcoper_send(unsigned char *data,
1747 uint32 data_len, void *context)
1749 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1750 SilcClientConnection conn = cmd->conn;
1751 SilcBuffer buffer, auth;
1753 if (cmd->argc >= 3) {
1754 /* Encode the public key authentication payload */
1755 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1756 cmd->client->private_key,
1761 /* Encode the password authentication payload */
1762 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1766 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1768 strlen(cmd->argv[1]),
1769 2, auth->data, auth->len);
1770 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1771 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1773 silc_buffer_free(buffer);
1774 silc_buffer_free(auth);
1776 /* Notify application */
1780 /* SILCOPER command. Used to obtain router operator privileges. */
1782 SILC_CLIENT_CMD_FUNC(silcoper)
1784 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1785 SilcClientConnection conn = cmd->conn;
1788 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1793 if (cmd->argc < 2) {
1794 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1795 "Usage: /SILCOPER <username> [-pubkey]");
1800 if (cmd->argc < 3) {
1801 /* Get passphrase */
1802 cmd->client->ops->ask_passphrase(cmd->client, conn,
1803 silc_client_command_silcoper_send,
1808 silc_client_command_silcoper_send(NULL, 0, context);
1811 silc_client_command_free(cmd);
1814 /* CONNECT command. Connects the server to another server. */
1816 SILC_CLIENT_CMD_FUNC(connect)
1818 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1819 SilcClientConnection conn = cmd->conn;
1821 unsigned char port[4];
1825 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1830 if (cmd->argc < 2) {
1831 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1832 "Usage: /CONNECT <server> [<port>]");
1837 if (cmd->argc == 3) {
1838 tmp = atoi(cmd->argv[2]);
1839 SILC_PUT32_MSB(tmp, port);
1843 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1845 strlen(cmd->argv[1]),
1848 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1850 strlen(cmd->argv[1]));
1851 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1852 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1853 silc_buffer_free(buffer);
1855 /* Notify application */
1859 silc_client_command_free(cmd);
1862 /* Command BAN. This is used to manage the ban list of the channel. */
1864 SILC_CLIENT_CMD_FUNC(ban)
1866 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1867 SilcClientConnection conn = cmd->conn;
1868 SilcChannelEntry channel;
1869 SilcBuffer buffer, chidp;
1871 char *name, *ban = NULL;
1874 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1879 if (cmd->argc < 2) {
1880 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1881 "Usage: /BAN <channel> "
1882 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1887 if (cmd->argv[1][0] == '*') {
1888 if (!conn->current_channel) {
1889 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1890 "You are not on any channel");
1895 channel = conn->current_channel;
1897 name = cmd->argv[1];
1899 channel = silc_client_get_channel(cmd->client, conn, name);
1901 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1902 "You are on that channel");
1908 if (cmd->argc == 3) {
1909 if (cmd->argv[2][0] == '+')
1918 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1920 /* Send the command */
1922 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1923 1, chidp->data, chidp->len,
1924 type, ban, strlen(ban));
1926 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1927 1, chidp->data, chidp->len);
1929 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1930 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1931 silc_buffer_free(buffer);
1932 silc_buffer_free(chidp);
1934 /* Notify application */
1938 silc_client_command_free(cmd);
1941 /* CLOSE command. Close server connection to the remote server */
1943 SILC_CLIENT_CMD_FUNC(close)
1945 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1946 SilcClientConnection conn = cmd->conn;
1948 unsigned char port[4];
1952 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1957 if (cmd->argc < 2) {
1958 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1959 "Usage: /CLOSE <server> [<port>]");
1964 if (cmd->argc == 3) {
1965 tmp = atoi(cmd->argv[2]);
1966 SILC_PUT32_MSB(tmp, port);
1970 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1972 strlen(cmd->argv[1]),
1975 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1977 strlen(cmd->argv[1]));
1978 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1979 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1980 silc_buffer_free(buffer);
1982 /* Notify application */
1986 silc_client_command_free(cmd);
1989 /* SHUTDOWN command. Shutdowns the server. */
1991 SILC_CLIENT_CMD_FUNC(shutdown)
1993 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1996 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2001 /* Send the command */
2002 silc_client_send_command(cmd->client, cmd->conn,
2003 SILC_COMMAND_SHUTDOWN, 0, 0);
2005 /* Notify application */
2009 silc_client_command_free(cmd);
2012 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2014 SILC_CLIENT_CMD_FUNC(leave)
2016 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2017 SilcClientConnection conn = cmd->conn;
2018 SilcIDCacheEntry id_cache = NULL;
2019 SilcChannelEntry channel;
2020 SilcBuffer buffer, idp;
2024 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2029 if (cmd->argc != 2) {
2030 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2031 "Usage: /LEAVE <channel>");
2036 if (cmd->argv[1][0] == '*') {
2037 if (!conn->current_channel) {
2038 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2039 "You are not on any channel");
2043 name = conn->current_channel->channel_name;
2045 name = cmd->argv[1];
2048 /* Get the Channel ID of the channel */
2049 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2050 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2051 "You are not on that channel");
2056 channel = (SilcChannelEntry)id_cache->context;
2057 channel->on_channel = FALSE;
2059 /* Send LEAVE command to the server */
2060 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2061 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2062 1, idp->data, idp->len);
2063 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2064 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2065 silc_buffer_free(buffer);
2066 silc_buffer_free(idp);
2068 /* Notify application */
2071 if (conn->current_channel == channel)
2072 conn->current_channel = NULL;
2074 silc_client_del_channel(cmd->client, cmd->conn, channel);
2077 silc_client_command_free(cmd);
2080 /* Command USERS. Requests the USERS of the clients joined on requested
2083 SILC_CLIENT_CMD_FUNC(users)
2085 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2086 SilcClientConnection conn = cmd->conn;
2091 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2096 if (cmd->argc != 2) {
2097 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2098 "Usage: /USERS <channel>");
2103 if (cmd->argv[1][0] == '*') {
2104 if (!conn->current_channel) {
2105 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2106 "You are not on any channel");
2110 name = conn->current_channel->channel_name;
2112 name = cmd->argv[1];
2115 /* Send USERS command to the server */
2116 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2117 ++conn->cmd_ident, 1,
2118 2, name, strlen(name));
2119 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2120 NULL, 0, NULL, NULL, buffer->data,
2122 silc_buffer_free(buffer);
2124 /* Notify application */
2128 silc_client_command_free(cmd);
2131 /* Command GETKEY. Used to fetch remote client's public key. */
2133 SILC_CLIENT_CMD_FUNC(getkey)
2135 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2136 SilcClientConnection conn = cmd->conn;
2137 SilcClient client = cmd->client;
2138 SilcClientEntry client_entry = NULL;
2139 SilcServerEntry server_entry = NULL;
2140 char *nickname = NULL;
2141 SilcBuffer idp, buffer;
2144 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2149 if (cmd->argc < 2) {
2150 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2151 "Usage: /GETKEY <nickname or server name>");
2157 SilcClientCommandReplyContext reply =
2158 (SilcClientCommandReplyContext)context2;
2159 SilcCommandStatus status;
2160 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2161 SILC_GET16_MSB(status, tmp);
2163 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2164 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2165 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2167 silc_client_command_status_message(status));
2173 /* Parse the typed nickname. */
2174 if (client->params->nickname_parse)
2175 client->params->nickname_parse(cmd->argv[1], &nickname);
2177 nickname = strdup(cmd->argv[1]);
2179 /* Find client entry */
2180 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2182 if (!client_entry) {
2183 /* Check whether user requested server actually */
2184 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2186 if (!server_entry) {
2192 /* No. what ever user wants we don't have it, so resolve it. We
2193 will try to resolve both client and server, one of them is
2194 bound to be wrong. */
2196 /* This will send the IDENTIFY command */
2197 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2198 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2200 silc_client_command_destructor,
2201 silc_client_command_getkey,
2202 silc_client_command_dup(cmd));
2204 /* This sends the IDENTIFY command to resolve the server. */
2205 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2206 ++conn->cmd_ident, 1,
2207 2, cmd->argv[1], cmd->argv_lens[1]);
2208 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2209 conn->cmd_ident, NULL,
2210 silc_client_command_getkey,
2211 silc_client_command_dup(cmd));
2214 silc_free(nickname);
2218 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2220 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2223 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2224 1, idp->data, idp->len);
2225 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2226 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2227 silc_buffer_free(buffer);
2228 silc_buffer_free(idp);
2230 /* Notify application */
2234 silc_free(nickname);
2235 silc_client_command_free(cmd);