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]);
375 silc_client_command_free(cmd);
378 /* Command NICK. Shows current nickname/sets new nickname on current
381 SILC_CLIENT_CMD_FUNC(nick)
383 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
384 SilcClientConnection conn = cmd->conn;
388 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
394 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
395 "Usage: /NICK <nickname>");
400 if (!strcmp(conn->nickname, cmd->argv[1]))
403 /* Show current nickname */
406 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
407 "Your nickname is %s on server %s",
408 conn->nickname, conn->remote_host);
410 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
411 "Your nickname is %s", conn->nickname);
418 if (cmd->argv_lens[1] > 128)
419 cmd->argv_lens[1] = 128;
421 /* Send the NICK command */
422 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
426 ++cmd->conn->cmd_ident);
427 silc_client_packet_send(cmd->client, cmd->conn->sock,
428 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
429 buffer->data, buffer->len, TRUE);
430 silc_buffer_free(buffer);
432 /* Register pending callback that will actually set the new nickname
433 if there were no errors returned by the server. */
434 silc_client_command_pending(conn, SILC_COMMAND_NICK,
435 cmd->conn->cmd_ident,
436 silc_client_command_destructor,
437 silc_client_command_nick_change,
438 silc_client_command_dup(cmd));
443 silc_client_command_free(cmd);
446 /* Command LIST. Lists channels on the current server. */
448 SILC_CLIENT_CMD_FUNC(list)
450 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
451 SilcClientConnection conn = cmd->conn;
452 SilcIDCacheEntry id_cache = NULL;
453 SilcChannelEntry channel;
454 SilcBuffer buffer, idp = NULL;
458 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
463 if (cmd->argc == 2) {
466 /* Get the Channel ID of the channel */
467 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
468 channel = (SilcChannelEntry)id_cache->context;
469 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
474 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
475 ++conn->cmd_ident, 0);
477 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
478 ++conn->cmd_ident, 1,
479 1, idp->data, idp->len);
481 silc_client_packet_send(cmd->client, cmd->conn->sock,
482 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
483 buffer->data, buffer->len, TRUE);
484 silc_buffer_free(buffer);
486 silc_buffer_free(idp);
488 /* Notify application */
492 silc_client_command_free(cmd);
495 /* Command TOPIC. Sets/shows topic on a channel. */
497 SILC_CLIENT_CMD_FUNC(topic)
499 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
500 SilcClientConnection conn = cmd->conn;
501 SilcIDCacheEntry id_cache = NULL;
502 SilcChannelEntry channel;
503 SilcBuffer buffer, idp;
507 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
512 if (cmd->argc < 2 || cmd->argc > 3) {
513 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
514 "Usage: /TOPIC <channel> [<topic>]");
519 if (cmd->argv[1][0] == '*') {
520 if (!conn->current_channel) {
521 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
522 "You are not on any channel");
526 name = conn->current_channel->channel_name;
531 if (!conn->current_channel) {
532 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
533 "You are not on that channel");
538 /* Get the Channel ID of the channel */
539 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
540 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
541 "You are not on that channel");
546 channel = (SilcChannelEntry)id_cache->context;
548 /* Send TOPIC command to the server */
549 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
551 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
552 ++conn->cmd_ident, 2,
553 1, idp->data, idp->len,
555 strlen(cmd->argv[2]));
557 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
558 ++conn->cmd_ident, 1,
559 1, idp->data, idp->len);
560 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
561 0, NULL, NULL, buffer->data, buffer->len, TRUE);
562 silc_buffer_free(buffer);
563 silc_buffer_free(idp);
565 /* Notify application */
569 silc_client_command_free(cmd);
572 /* Command INVITE. Invites specific client to join a channel. This is
573 also used to mange the invite list of the channel. */
575 SILC_CLIENT_CMD_FUNC(invite)
577 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
578 SilcClient client = cmd->client;
579 SilcClientConnection conn = cmd->conn;
580 SilcClientEntry client_entry = NULL;
581 SilcChannelEntry channel;
582 SilcBuffer buffer, clidp, chidp;
584 char *nickname = NULL, *name;
588 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
594 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
595 "Usage: /INVITE <channel> [<nickname>[@server>]"
596 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
601 if (cmd->argv[1][0] == '*') {
602 if (!conn->current_channel) {
603 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
604 "You are not on any channel");
609 channel = conn->current_channel;
613 channel = silc_client_get_channel(cmd->client, conn, name);
615 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
616 "You are on that channel");
622 /* Parse the typed nickname. */
623 if (cmd->argc == 3) {
624 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
625 if (client->params->nickname_parse)
626 client->params->nickname_parse(cmd->argv[2], &nickname);
628 nickname = strdup(cmd->argv[2]);
630 /* Find client entry */
631 client_entry = silc_idlist_get_client(client, conn, nickname,
640 /* Client entry not found, it was requested thus mark this to be
642 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
644 silc_client_command_destructor,
645 silc_client_command_invite,
646 silc_client_command_dup(cmd));
651 invite = cmd->argv[2];
653 if (cmd->argv[2][0] == '+')
660 /* Send the command */
661 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
663 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
664 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
665 ++conn->cmd_ident, 3,
666 1, chidp->data, chidp->len,
667 2, clidp->data, clidp->len,
668 type, invite, invite ?
670 silc_buffer_free(clidp);
672 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
673 ++conn->cmd_ident, 2,
674 1, chidp->data, chidp->len,
675 type, invite, invite ?
679 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
680 0, NULL, NULL, buffer->data, buffer->len, TRUE);
681 silc_buffer_free(buffer);
682 silc_buffer_free(chidp);
684 /* Notify application */
689 silc_client_command_free(cmd);
694 SilcClientConnection conn;
697 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
699 QuitInternal q = (QuitInternal)context;
701 /* Close connection */
702 q->client->ops->disconnect(q->client, q->conn);
703 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
708 /* Command QUIT. Closes connection with current server. */
710 SILC_CLIENT_CMD_FUNC(quit)
712 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
717 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
723 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
724 &cmd->argv[1], &cmd->argv_lens[1],
725 &cmd->argv_types[1], 0);
727 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
728 NULL, NULL, NULL, 0);
729 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
731 buffer->data, buffer->len, TRUE);
732 silc_buffer_free(buffer);
734 q = silc_calloc(1, sizeof(*q));
735 q->client = cmd->client;
738 /* Sleep for a while */
741 /* We quit the connection with little timeout */
742 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
743 silc_client_command_quit_cb, (void *)q,
744 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
746 /* Notify application */
750 silc_client_command_free(cmd);
753 /* Timeout callback to remove the killed client from cache */
755 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
757 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
758 SilcClient client = cmd->client;
759 SilcClientConnection conn = cmd->conn;
760 SilcClientEntry target;
761 char *nickname = NULL;
763 /* Parse the typed nickname. */
764 if (client->params->nickname_parse)
765 client->params->nickname_parse(cmd->argv[1], &nickname);
767 nickname = strdup(cmd->argv[1]);
769 /* Get the target client */
770 target = silc_idlist_get_client(cmd->client, conn, nickname,
771 cmd->argv[1], FALSE);
773 silc_client_remove_from_channels(client, conn, target);
774 silc_client_del_client(client, conn, target);
778 silc_client_command_free(cmd);
781 /* Kill command's pending command callback to actually remove the killed
782 client from our local cache. */
784 SILC_CLIENT_CMD_FUNC(kill_remove)
786 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
787 SilcClientCommandReplyContext reply =
788 (SilcClientCommandReplyContext)context2;
789 SilcCommandStatus status;
791 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
792 if (status == SILC_STATUS_OK) {
793 /* Remove with timeout */
794 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
795 silc_client_command_kill_remove_later, context,
796 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
800 silc_client_command_free(cmd);
803 /* Command KILL. Router operator can use this command to remove an client
804 fromthe SILC Network. */
806 SILC_CLIENT_CMD_FUNC(kill)
808 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
809 SilcClient client = cmd->client;
810 SilcClientConnection conn = cmd->conn;
811 SilcBuffer buffer, idp;
812 SilcClientEntry target;
813 char *nickname = NULL;
816 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
822 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
823 "Usage: /KILL <nickname> [<comment>]");
828 /* Parse the typed nickname. */
829 if (client->params->nickname_parse)
830 client->params->nickname_parse(cmd->argv[1], &nickname);
832 nickname = strdup(cmd->argv[1]);
834 /* Get the target client */
835 target = silc_idlist_get_client(cmd->client, conn, nickname,
845 /* Client entry not found, it was requested thus mark this to be
847 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
849 silc_client_command_destructor,
850 silc_client_command_kill,
851 silc_client_command_dup(cmd));
856 /* Send the KILL command to the server */
857 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
859 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
860 ++conn->cmd_ident, 1,
861 1, idp->data, idp->len);
863 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
864 ++conn->cmd_ident, 2,
865 1, idp->data, idp->len,
867 strlen(cmd->argv[2]));
868 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
869 0, NULL, NULL, buffer->data, buffer->len, TRUE);
870 silc_buffer_free(buffer);
871 silc_buffer_free(idp);
873 /* Notify application */
876 /* Register a pending callback that will actually remove the killed
877 client from our cache. */
878 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
879 NULL, silc_client_command_kill_remove,
880 silc_client_command_dup(cmd));
884 silc_client_command_free(cmd);
887 /* Command INFO. Request information about specific server. If specific
888 server is not provided the current server is used. */
890 SILC_CLIENT_CMD_FUNC(info)
892 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
893 SilcClientConnection conn = cmd->conn;
898 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
904 name = strdup(cmd->argv[1]);
906 /* Send the command */
908 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
909 1, name, strlen(name));
911 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
912 NULL, NULL, NULL, 0);
913 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
914 0, NULL, NULL, buffer->data, buffer->len, TRUE);
915 silc_buffer_free(buffer);
919 /* Notify application */
923 silc_client_command_free(cmd);
926 /* Command PING. Sends ping to server. This is used to test the
927 communication channel. */
929 SILC_CLIENT_CMD_FUNC(ping)
931 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
932 SilcClientConnection conn = cmd->conn;
938 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
943 /* Send the command */
944 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
945 1, conn->remote_id_data,
946 silc_id_get_len(conn->remote_id,
948 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
949 0, NULL, NULL, buffer->data, buffer->len, TRUE);
950 silc_buffer_free(buffer);
952 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
955 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
960 /* Start counting time */
961 for (i = 0; i < conn->ping_count; i++) {
962 if (conn->ping[i].dest_id == NULL) {
963 conn->ping[i].start_time = time(NULL);
964 conn->ping[i].dest_id = id;
965 conn->ping[i].dest_name = strdup(conn->remote_host);
969 if (i >= conn->ping_count) {
970 i = conn->ping_count;
971 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
972 conn->ping[i].start_time = time(NULL);
973 conn->ping[i].dest_id = id;
974 conn->ping[i].dest_name = strdup(conn->remote_host);
978 /* Notify application */
982 silc_client_command_free(cmd);
985 /* Command JOIN. Joins to a channel. */
987 SILC_CLIENT_CMD_FUNC(join)
989 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
990 SilcClientConnection conn = cmd->conn;
991 SilcIDCacheEntry id_cache = NULL;
992 SilcBuffer buffer, idp;
995 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1000 /* See if we have joined to the requested channel already */
1001 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
1003 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
1004 if (channel->on_channel)
1008 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1010 if (cmd->argv_lens[1] > 256)
1011 cmd->argv_lens[1] = 256;
1013 /* Send JOIN command to the server */
1016 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
1017 1, cmd->argv[1], cmd->argv_lens[1],
1018 2, idp->data, idp->len);
1019 else if (cmd->argc == 3)
1022 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
1023 1, cmd->argv[1], cmd->argv_lens[1],
1024 2, idp->data, idp->len,
1025 3, cmd->argv[2], cmd->argv_lens[2]);
1028 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
1029 1, cmd->argv[1], cmd->argv_lens[1],
1030 2, idp->data, idp->len,
1031 3, cmd->argv[2], cmd->argv_lens[2],
1032 4, cmd->argv[3], cmd->argv_lens[3]);
1034 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1035 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1036 silc_buffer_free(buffer);
1037 silc_buffer_free(idp);
1039 /* Notify application */
1043 silc_client_command_free(cmd);
1046 /* MOTD command. Requests motd from server. */
1048 SILC_CLIENT_CMD_FUNC(motd)
1050 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1051 SilcClientConnection conn = cmd->conn;
1055 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1060 if (cmd->argc < 1 || cmd->argc > 2) {
1061 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1062 "Usage: /MOTD [<server>]");
1067 /* Send TOPIC command to the server */
1069 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1070 1, conn->remote_host,
1071 strlen(conn->remote_host));
1073 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1076 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1077 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1078 silc_buffer_free(buffer);
1080 /* Notify application */
1084 silc_client_command_free(cmd);
1087 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1088 modes as client cannot set itself server/router operator privileges. */
1090 SILC_CLIENT_CMD_FUNC(umode)
1092 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1093 SilcClientConnection conn = cmd->conn;
1094 SilcBuffer buffer, idp;
1095 unsigned char *cp, modebuf[4];
1096 uint32 mode, add, len;
1100 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1105 if (cmd->argc < 2) {
1106 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1107 "Usage: /UMODE +|-<modes>");
1112 mode = conn->local_entry->mode;
1114 /* Are we adding or removing mode */
1115 if (cmd->argv[1][0] == '-')
1121 cp = cmd->argv[1] + 1;
1123 for (i = 0; i < len; i++) {
1128 mode |= SILC_UMODE_SERVER_OPERATOR;
1129 mode |= SILC_UMODE_ROUTER_OPERATOR;
1131 mode = SILC_UMODE_NONE;
1136 mode |= SILC_UMODE_SERVER_OPERATOR;
1138 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1142 mode |= SILC_UMODE_ROUTER_OPERATOR;
1144 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1148 mode |= SILC_UMODE_GONE;
1150 mode &= ~SILC_UMODE_GONE;
1159 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1160 SILC_PUT32_MSB(mode, modebuf);
1162 /* Send the command packet. We support sending only one mode at once
1163 that requires an argument. */
1165 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1166 1, idp->data, idp->len,
1167 2, modebuf, sizeof(modebuf));
1168 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1169 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1170 silc_buffer_free(buffer);
1171 silc_buffer_free(idp);
1173 /* Notify application */
1177 silc_client_command_free(cmd);
1180 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1181 can be set several at once. Those modes that require argument must be set
1182 separately (unless set with modes that does not require arguments). */
1184 SILC_CLIENT_CMD_FUNC(cmode)
1186 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1187 SilcClientConnection conn = cmd->conn;
1188 SilcChannelEntry channel;
1189 SilcBuffer buffer, chidp, auth = NULL;
1190 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1191 uint32 mode, add, type, len, arg_len = 0;
1195 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1200 if (cmd->argc < 3) {
1201 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1202 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1207 if (cmd->argv[1][0] == '*') {
1208 if (!conn->current_channel) {
1209 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1210 "You are not on any channel");
1215 channel = conn->current_channel;
1217 name = cmd->argv[1];
1219 channel = silc_client_get_channel(cmd->client, conn, name);
1221 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1222 "You are on that channel");
1228 mode = channel->mode;
1230 /* Are we adding or removing mode */
1231 if (cmd->argv[2][0] == '-')
1236 /* Argument type to be sent to server */
1240 cp = cmd->argv[2] + 1;
1242 for (i = 0; i < len; i++) {
1246 mode |= SILC_CHANNEL_MODE_PRIVATE;
1248 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1252 mode |= SILC_CHANNEL_MODE_SECRET;
1254 mode &= ~SILC_CHANNEL_MODE_SECRET;
1258 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1260 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1264 mode |= SILC_CHANNEL_MODE_INVITE;
1266 mode &= ~SILC_CHANNEL_MODE_INVITE;
1270 mode |= SILC_CHANNEL_MODE_TOPIC;
1272 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1277 mode |= SILC_CHANNEL_MODE_ULIMIT;
1279 if (cmd->argc < 4) {
1280 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1281 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1285 ll = atoi(cmd->argv[3]);
1286 SILC_PUT32_MSB(ll, tmp);
1290 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1295 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1297 if (cmd->argc < 4) {
1298 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1299 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1304 arg_len = cmd->argv_lens[3];
1306 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1311 mode |= SILC_CHANNEL_MODE_CIPHER;
1313 if (cmd->argc < 4) {
1314 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1315 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1320 arg_len = cmd->argv_lens[3];
1322 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1327 mode |= SILC_CHANNEL_MODE_HMAC;
1329 if (cmd->argc < 4) {
1330 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1331 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1336 arg_len = cmd->argv_lens[3];
1338 mode &= ~SILC_CHANNEL_MODE_HMAC;
1343 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1346 if (cmd->argc < 4) {
1347 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1348 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1353 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1354 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1355 cmd->client->private_key,
1360 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1361 cmd->argv[3], cmd->argv_lens[3]);
1365 arg_len = auth->len;
1367 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1377 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1378 SILC_PUT32_MSB(mode, modebuf);
1380 /* Send the command packet. We support sending only one mode at once
1381 that requires an argument. */
1384 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1385 1, chidp->data, chidp->len,
1386 2, modebuf, sizeof(modebuf),
1387 type, arg, arg_len);
1390 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1391 1, chidp->data, chidp->len,
1392 2, modebuf, sizeof(modebuf));
1395 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1396 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1397 silc_buffer_free(buffer);
1398 silc_buffer_free(chidp);
1400 silc_buffer_free(auth);
1402 /* Notify application */
1406 silc_client_command_free(cmd);
1409 /* CUMODE command. Changes client's mode on a channel. */
1411 SILC_CLIENT_CMD_FUNC(cumode)
1413 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1414 SilcClient client = cmd->client;
1415 SilcClientConnection conn = cmd->conn;
1416 SilcChannelEntry channel;
1417 SilcChannelUser chu;
1418 SilcClientEntry client_entry;
1419 SilcBuffer buffer, clidp, chidp, auth = NULL;
1420 unsigned char *name, *cp, modebuf[4];
1421 uint32 mode = 0, add, len;
1422 char *nickname = NULL;
1426 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1431 if (cmd->argc < 4) {
1432 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1433 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1438 if (cmd->argv[1][0] == '*') {
1439 if (!conn->current_channel) {
1440 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1441 "You are not on any channel");
1446 channel = conn->current_channel;
1448 name = cmd->argv[1];
1450 channel = silc_client_get_channel(cmd->client, conn, name);
1452 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1453 "You are on that channel");
1459 /* Parse the typed nickname. */
1460 if (client->params->nickname_parse)
1461 client->params->nickname_parse(cmd->argv[3], &nickname);
1463 nickname = strdup(cmd->argv[3]);
1465 /* Find client entry */
1466 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1467 cmd->argv[3], TRUE);
1468 if (!client_entry) {
1474 silc_free(nickname);
1476 /* Client entry not found, it was requested thus mark this to be
1478 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1480 silc_client_command_destructor,
1481 silc_client_command_cumode,
1482 silc_client_command_dup(cmd));
1487 /* Get the current mode */
1488 silc_list_start(channel->clients);
1489 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1490 if (chu->client == client_entry) {
1496 /* Are we adding or removing mode */
1497 if (cmd->argv[2][0] == '-')
1503 cp = cmd->argv[2] + 1;
1505 for (i = 0; i < len; i++) {
1509 mode |= SILC_CHANNEL_UMODE_CHANFO;
1510 mode |= SILC_CHANNEL_UMODE_CHANOP;
1512 mode = SILC_CHANNEL_UMODE_NONE;
1517 if (cmd->argc == 5) {
1518 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1519 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1520 cmd->client->private_key,
1525 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1526 cmd->argv[4], cmd->argv_lens[4]);
1529 mode |= SILC_CHANNEL_UMODE_CHANFO;
1531 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1536 mode |= SILC_CHANNEL_UMODE_CHANOP;
1538 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1547 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1548 SILC_PUT32_MSB(mode, modebuf);
1549 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1551 /* Send the command packet. We support sending only one mode at once
1552 that requires an argument. */
1553 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1555 1, chidp->data, chidp->len,
1557 3, clidp->data, clidp->len,
1558 4, auth ? auth->data : NULL,
1559 auth ? auth->len : 0);
1561 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1562 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1563 silc_buffer_free(buffer);
1564 silc_buffer_free(chidp);
1565 silc_buffer_free(clidp);
1567 silc_buffer_free(auth);
1569 /* Notify application */
1573 silc_free(nickname);
1574 silc_client_command_free(cmd);
1577 /* KICK command. Kicks a client out of channel. */
1579 SILC_CLIENT_CMD_FUNC(kick)
1581 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1582 SilcClient client = cmd->client;
1583 SilcClientConnection conn = cmd->conn;
1584 SilcIDCacheEntry id_cache = NULL;
1585 SilcChannelEntry channel;
1586 SilcBuffer buffer, idp, idp2;
1587 SilcClientEntry target;
1589 char *nickname = NULL;
1592 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1597 if (cmd->argc < 3) {
1598 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1599 "Usage: /KICK <channel> <nickname> [<comment>]");
1604 if (cmd->argv[1][0] == '*') {
1605 if (!conn->current_channel) {
1606 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1607 "You are not on any channel");
1611 name = conn->current_channel->channel_name;
1613 name = cmd->argv[1];
1616 if (!conn->current_channel) {
1617 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1618 "You are not on that channel");
1623 /* Get the Channel ID of the channel */
1624 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1625 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1626 "You are not on that channel");
1631 channel = (SilcChannelEntry)id_cache->context;
1633 /* Parse the typed nickname. */
1634 if (client->params->nickname_parse)
1635 client->params->nickname_parse(cmd->argv[2], &nickname);
1637 nickname = strdup(cmd->argv[2]);
1639 /* Get the target client */
1640 target = silc_idlist_get_client(cmd->client, conn, nickname,
1641 cmd->argv[2], FALSE);
1643 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1644 "No such client: %s",
1650 /* Send KICK command to the server */
1651 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1652 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1654 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1655 1, idp->data, idp->len,
1656 2, idp2->data, idp2->len);
1658 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1659 1, idp->data, idp->len,
1660 2, idp2->data, idp2->len,
1662 strlen(cmd->argv[3]));
1663 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1664 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1665 silc_buffer_free(buffer);
1666 silc_buffer_free(idp);
1667 silc_buffer_free(idp2);
1669 /* Notify application */
1673 silc_free(nickname);
1674 silc_client_command_free(cmd);
1677 static void silc_client_command_oper_send(unsigned char *data,
1678 uint32 data_len, void *context)
1680 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1681 SilcClientConnection conn = cmd->conn;
1682 SilcBuffer buffer, auth;
1684 if (cmd->argc >= 3) {
1685 /* Encode the public key authentication payload */
1686 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1687 cmd->client->private_key,
1692 /* Encode the password authentication payload */
1693 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1697 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1699 strlen(cmd->argv[1]),
1700 2, auth->data, auth->len);
1701 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1702 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1704 silc_buffer_free(buffer);
1705 silc_buffer_free(auth);
1707 /* Notify application */
1711 /* OPER command. Used to obtain server operator privileges. */
1713 SILC_CLIENT_CMD_FUNC(oper)
1715 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1716 SilcClientConnection conn = cmd->conn;
1719 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1724 if (cmd->argc < 2) {
1725 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1726 "Usage: /OPER <username> [-pubkey]");
1731 if (cmd->argc < 3) {
1732 /* Get passphrase */
1733 cmd->client->ops->ask_passphrase(cmd->client, conn,
1734 silc_client_command_oper_send,
1739 silc_client_command_oper_send(NULL, 0, context);
1742 silc_client_command_free(cmd);
1745 static void silc_client_command_silcoper_send(unsigned char *data,
1746 uint32 data_len, void *context)
1748 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1749 SilcClientConnection conn = cmd->conn;
1750 SilcBuffer buffer, auth;
1752 if (cmd->argc >= 3) {
1753 /* Encode the public key authentication payload */
1754 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1755 cmd->client->private_key,
1760 /* Encode the password authentication payload */
1761 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1765 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1767 strlen(cmd->argv[1]),
1768 2, auth->data, auth->len);
1769 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1770 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1772 silc_buffer_free(buffer);
1773 silc_buffer_free(auth);
1775 /* Notify application */
1779 /* SILCOPER command. Used to obtain router operator privileges. */
1781 SILC_CLIENT_CMD_FUNC(silcoper)
1783 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1784 SilcClientConnection conn = cmd->conn;
1787 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1792 if (cmd->argc < 2) {
1793 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1794 "Usage: /SILCOPER <username> [-pubkey]");
1799 if (cmd->argc < 3) {
1800 /* Get passphrase */
1801 cmd->client->ops->ask_passphrase(cmd->client, conn,
1802 silc_client_command_silcoper_send,
1807 silc_client_command_silcoper_send(NULL, 0, context);
1810 silc_client_command_free(cmd);
1813 /* CONNECT command. Connects the server to another server. */
1815 SILC_CLIENT_CMD_FUNC(connect)
1817 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1818 SilcClientConnection conn = cmd->conn;
1820 unsigned char port[4];
1824 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1829 if (cmd->argc < 2) {
1830 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1831 "Usage: /CONNECT <server> [<port>]");
1836 if (cmd->argc == 3) {
1837 tmp = atoi(cmd->argv[2]);
1838 SILC_PUT32_MSB(tmp, port);
1842 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1844 strlen(cmd->argv[1]),
1847 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1849 strlen(cmd->argv[1]));
1850 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1851 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1852 silc_buffer_free(buffer);
1854 /* Notify application */
1858 silc_client_command_free(cmd);
1861 /* Command BAN. This is used to manage the ban list of the channel. */
1863 SILC_CLIENT_CMD_FUNC(ban)
1865 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1866 SilcClientConnection conn = cmd->conn;
1867 SilcChannelEntry channel;
1868 SilcBuffer buffer, chidp;
1870 char *name, *ban = NULL;
1873 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1878 if (cmd->argc < 2) {
1879 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1880 "Usage: /BAN <channel> "
1881 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1886 if (cmd->argv[1][0] == '*') {
1887 if (!conn->current_channel) {
1888 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1889 "You are not on any channel");
1894 channel = conn->current_channel;
1896 name = cmd->argv[1];
1898 channel = silc_client_get_channel(cmd->client, conn, name);
1900 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1901 "You are on that channel");
1907 if (cmd->argc == 3) {
1908 if (cmd->argv[2][0] == '+')
1917 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1919 /* Send the command */
1921 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1922 1, chidp->data, chidp->len,
1923 type, ban, strlen(ban));
1925 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1926 1, chidp->data, chidp->len);
1928 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1929 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1930 silc_buffer_free(buffer);
1931 silc_buffer_free(chidp);
1933 /* Notify application */
1937 silc_client_command_free(cmd);
1940 /* CLOSE command. Close server connection to the remote server */
1942 SILC_CLIENT_CMD_FUNC(close)
1944 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1945 SilcClientConnection conn = cmd->conn;
1947 unsigned char port[4];
1951 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1956 if (cmd->argc < 2) {
1957 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1958 "Usage: /CLOSE <server> [<port>]");
1963 if (cmd->argc == 3) {
1964 tmp = atoi(cmd->argv[2]);
1965 SILC_PUT32_MSB(tmp, port);
1969 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1971 strlen(cmd->argv[1]),
1974 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1976 strlen(cmd->argv[1]));
1977 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1978 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1979 silc_buffer_free(buffer);
1981 /* Notify application */
1985 silc_client_command_free(cmd);
1988 /* SHUTDOWN command. Shutdowns the server. */
1990 SILC_CLIENT_CMD_FUNC(shutdown)
1992 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1995 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2000 /* Send the command */
2001 silc_client_send_command(cmd->client, cmd->conn,
2002 SILC_COMMAND_SHUTDOWN, 0, 0);
2004 /* Notify application */
2008 silc_client_command_free(cmd);
2011 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2013 SILC_CLIENT_CMD_FUNC(leave)
2015 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2016 SilcClientConnection conn = cmd->conn;
2017 SilcIDCacheEntry id_cache = NULL;
2018 SilcChannelEntry channel;
2019 SilcBuffer buffer, idp;
2023 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2028 if (cmd->argc != 2) {
2029 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2030 "Usage: /LEAVE <channel>");
2035 if (cmd->argv[1][0] == '*') {
2036 if (!conn->current_channel) {
2037 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2038 "You are not on any channel");
2042 name = conn->current_channel->channel_name;
2044 name = cmd->argv[1];
2047 /* Get the Channel ID of the channel */
2048 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2049 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2050 "You are not on that channel");
2055 channel = (SilcChannelEntry)id_cache->context;
2056 channel->on_channel = FALSE;
2058 /* Send LEAVE command to the server */
2059 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2060 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2061 1, idp->data, idp->len);
2062 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2063 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2064 silc_buffer_free(buffer);
2065 silc_buffer_free(idp);
2067 /* Notify application */
2070 if (conn->current_channel == channel)
2071 conn->current_channel = NULL;
2073 silc_client_del_channel(cmd->client, cmd->conn, channel);
2076 silc_client_command_free(cmd);
2079 /* Command USERS. Requests the USERS of the clients joined on requested
2082 SILC_CLIENT_CMD_FUNC(users)
2084 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2085 SilcClientConnection conn = cmd->conn;
2090 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2095 if (cmd->argc != 2) {
2096 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2097 "Usage: /USERS <channel>");
2102 if (cmd->argv[1][0] == '*') {
2103 if (!conn->current_channel) {
2104 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2105 "You are not on any channel");
2109 name = conn->current_channel->channel_name;
2111 name = cmd->argv[1];
2114 /* Send USERS command to the server */
2115 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2116 ++conn->cmd_ident, 1,
2117 2, name, strlen(name));
2118 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2119 NULL, 0, NULL, NULL, buffer->data,
2121 silc_buffer_free(buffer);
2123 /* Notify application */
2127 silc_client_command_free(cmd);
2130 /* Command GETKEY. Used to fetch remote client's public key. */
2132 SILC_CLIENT_CMD_FUNC(getkey)
2134 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2135 SilcClientConnection conn = cmd->conn;
2136 SilcClient client = cmd->client;
2137 SilcClientEntry client_entry = NULL;
2138 SilcServerEntry server_entry = NULL;
2139 char *nickname = NULL;
2140 SilcBuffer idp, buffer;
2143 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2148 if (cmd->argc < 2) {
2149 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2150 "Usage: /GETKEY <nickname or server name>");
2156 SilcClientCommandReplyContext reply =
2157 (SilcClientCommandReplyContext)context2;
2158 SilcCommandStatus status;
2159 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2160 SILC_GET16_MSB(status, tmp);
2162 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2163 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2164 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2166 silc_client_command_status_message(status));
2172 /* Parse the typed nickname. */
2173 if (client->params->nickname_parse)
2174 client->params->nickname_parse(cmd->argv[1], &nickname);
2176 nickname = strdup(cmd->argv[1]);
2178 /* Find client entry */
2179 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2181 if (!client_entry) {
2182 /* Check whether user requested server actually */
2183 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2185 if (!server_entry) {
2191 /* No. what ever user wants we don't have it, so resolve it. We
2192 will try to resolve both client and server, one of them is
2193 bound to be wrong. */
2195 /* This will send the IDENTIFY command */
2196 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2197 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2199 silc_client_command_destructor,
2200 silc_client_command_getkey,
2201 silc_client_command_dup(cmd));
2203 /* This sends the IDENTIFY command to resolve the server. */
2204 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2205 ++conn->cmd_ident, 1,
2206 2, cmd->argv[1], cmd->argv_lens[1]);
2207 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2208 conn->cmd_ident, NULL,
2209 silc_client_command_getkey,
2210 silc_client_command_dup(cmd));
2213 silc_free(nickname);
2217 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2219 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2222 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2223 1, idp->data, idp->len);
2224 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2225 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2226 silc_buffer_free(buffer);
2227 silc_buffer_free(idp);
2229 /* Notify application */
2233 silc_free(nickname);
2234 silc_client_command_free(cmd);