5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
25 /* Client command list. */
26 SilcClientCommand silc_command_list[] =
28 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
30 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
31 SILC_CF_LAG | SILC_CF_REG, 3),
32 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
34 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
36 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
37 SILC_CLIENT_CMD(kill, KILL, "KILL",
38 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
39 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
40 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
41 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
42 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
43 SILC_CLIENT_CMD(oper, OPER, "OPER",
44 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
46 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
48 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
49 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
50 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
51 SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
52 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
54 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
56 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
58 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
60 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2),
62 { NULL, 0, NULL, 0, 0 },
65 #define SILC_NOT_CONNECTED(x, c) \
66 x->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
67 "You are not connected to a server, use /SERVER to connect");
69 /* Command operation that is called at the end of all commands.
71 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
72 cmd, TRUE, cmd->command->cmd)
74 /* Error to application. Usage: COMMAND_ERROR; */
75 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
76 cmd, FALSE, cmd->command->cmd)
78 /* Generic function to send any command. The arguments must be sent already
79 encoded into correct form and in correct order. */
81 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
82 SilcCommand command, uint16 ident,
90 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
91 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
92 NULL, 0, NULL, NULL, packet->data,
94 silc_buffer_free(packet);
97 /* Finds and returns a pointer to the command list. Return NULL if the
98 command is not found. */
100 SilcClientCommand *silc_client_command_find(const char *name)
102 SilcClientCommand *cmd;
104 for (cmd = silc_command_list; cmd->name; cmd++) {
105 if (!strcmp(cmd->name, name))
112 /* Add new pending command to be executed when reply to a command has been
113 received. The `reply_cmd' is the command that will call the `callback'
114 with `context' when reply has been received. If `ident is non-zero
115 the `callback' will be executed when received reply with command
116 identifier `ident'. */
118 void silc_client_command_pending(SilcClientConnection conn,
119 SilcCommand reply_cmd,
121 SilcClientPendingDestructor destructor,
122 SilcCommandCb callback,
125 SilcClientCommandPending *reply;
127 reply = silc_calloc(1, sizeof(*reply));
128 reply->reply_cmd = reply_cmd;
129 reply->ident = ident;
130 reply->context = context;
131 reply->callback = callback;
132 reply->destructor = destructor;
133 silc_dlist_add(conn->pending_commands, reply);
136 /* Deletes pending command by reply command type. */
138 void silc_client_command_pending_del(SilcClientConnection conn,
139 SilcCommand reply_cmd,
142 SilcClientCommandPending *r;
144 silc_dlist_start(conn->pending_commands);
145 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
146 if (r->reply_cmd == reply_cmd && r->ident == ident) {
147 silc_dlist_del(conn->pending_commands, r);
153 /* Checks for pending commands and marks callbacks to be called from
154 the command reply function. Returns TRUE if there were pending command. */
156 int silc_client_command_pending_check(SilcClientConnection conn,
157 SilcClientCommandReplyContext ctx,
161 SilcClientCommandPending *r;
163 silc_dlist_start(conn->pending_commands);
164 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
165 if (r->reply_cmd == command && r->ident == ident) {
166 ctx->context = r->context;
167 ctx->callback = r->callback;
168 ctx->destructor = r->destructor;
177 /* Allocate Command Context */
179 SilcClientCommandContext silc_client_command_alloc()
181 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
186 /* Free command context and its internals */
188 void silc_client_command_free(SilcClientCommandContext ctx)
191 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
193 if (ctx->users < 1) {
196 for (i = 0; i < ctx->argc; i++)
197 silc_free(ctx->argv[i]);
198 silc_free(ctx->argv_lens);
199 silc_free(ctx->argv_types);
204 /* Duplicate Command Context by adding reference counter. The context won't
205 be free'd untill it hits zero. */
207 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
210 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
215 /* Pending command destructor. */
217 static void silc_client_command_destructor(void *context)
219 silc_client_command_free((SilcClientCommandContext)context);
222 /* Command WHOIS. This command is used to query information about
225 SILC_CLIENT_CMD_FUNC(whois)
227 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
228 SilcClientConnection conn = cmd->conn;
232 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
237 /* Given without arguments fetches client's own information */
239 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
240 silc_client_send_command(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
242 1, 3, buffer->data, buffer->len);
243 silc_buffer_free(buffer);
247 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
248 cmd->argc - 1, ++cmd->argv,
249 ++cmd->argv_lens, ++cmd->argv_types,
251 silc_client_packet_send(cmd->client, cmd->conn->sock,
252 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
253 buffer->data, buffer->len, TRUE);
254 silc_buffer_free(buffer);
259 /* Notify application */
263 silc_client_command_free(cmd);
266 /* Command WHOWAS. This command is used to query history information about
267 specific user that used to exist in the network. */
269 SILC_CLIENT_CMD_FUNC(whowas)
271 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
272 SilcClientConnection conn = cmd->conn;
276 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
281 if (cmd->argc < 2 || cmd->argc > 3) {
282 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
283 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
288 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
289 cmd->argc - 1, ++cmd->argv,
290 ++cmd->argv_lens, ++cmd->argv_types,
292 silc_client_packet_send(cmd->client, cmd->conn->sock,
293 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
294 buffer->data, buffer->len, TRUE);
295 silc_buffer_free(buffer);
300 /* Notify application */
304 silc_client_command_free(cmd);
307 /* Command IDENTIFY. This command is used to query information about
308 specific user, especially ID's. */
310 SILC_CLIENT_CMD_FUNC(identify)
312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
313 SilcClientConnection conn = cmd->conn;
317 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
322 if (cmd->argc < 2 || cmd->argc > 3) {
328 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
329 ++conn->cmd_ident, 1,
333 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
334 ++conn->cmd_ident, 2,
340 silc_client_packet_send(cmd->client, cmd->conn->sock,
341 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
342 buffer->data, buffer->len, TRUE);
343 silc_buffer_free(buffer);
345 /* Notify application */
349 silc_client_command_free(cmd);
352 /* Command NICK. Shows current nickname/sets new nickname on current
355 SILC_CLIENT_CMD_FUNC(nick)
357 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
358 SilcClientConnection conn = cmd->conn;
362 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
368 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
369 "Usage: /NICK <nickname>");
374 if (!strcmp(conn->nickname, cmd->argv[1]))
377 /* Show current nickname */
380 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
381 "Your nickname is %s on server %s",
382 conn->nickname, conn->remote_host);
384 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
385 "Your nickname is %s", conn->nickname);
392 if (cmd->argv_lens[1] > 128)
393 cmd->argv_lens[1] = 128;
395 /* Set new nickname */
396 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
400 ++cmd->conn->cmd_ident);
401 silc_client_packet_send(cmd->client, cmd->conn->sock,
402 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
403 buffer->data, buffer->len, TRUE);
404 silc_buffer_free(buffer);
406 silc_free(conn->nickname);
407 conn->nickname = strdup(cmd->argv[1]);
409 /* Notify application */
413 silc_client_command_free(cmd);
416 /* Command LIST. Lists channels on the current server. */
418 SILC_CLIENT_CMD_FUNC(list)
420 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
421 SilcClientConnection conn = cmd->conn;
422 SilcIDCacheEntry id_cache = NULL;
423 SilcChannelEntry channel;
424 SilcBuffer buffer, idp = NULL;
428 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
433 if (cmd->argc == 2) {
436 /* Get the Channel ID of the channel */
437 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
438 channel = (SilcChannelEntry)id_cache->context;
439 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
444 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
445 ++conn->cmd_ident, 0);
447 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
448 ++conn->cmd_ident, 1,
449 1, idp->data, idp->len);
451 silc_client_packet_send(cmd->client, cmd->conn->sock,
452 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
453 buffer->data, buffer->len, TRUE);
454 silc_buffer_free(buffer);
456 silc_buffer_free(idp);
458 /* Notify application */
462 silc_client_command_free(cmd);
465 /* Command TOPIC. Sets/shows topic on a channel. */
467 SILC_CLIENT_CMD_FUNC(topic)
469 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
470 SilcClientConnection conn = cmd->conn;
471 SilcIDCacheEntry id_cache = NULL;
472 SilcChannelEntry channel;
473 SilcBuffer buffer, idp;
477 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
482 if (cmd->argc < 2 || cmd->argc > 3) {
483 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
484 "Usage: /TOPIC <channel> [<topic>]");
489 if (cmd->argv[1][0] == '*') {
490 if (!conn->current_channel) {
491 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
492 "You are not on any channel");
496 name = conn->current_channel->channel_name;
501 if (!conn->current_channel) {
502 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
503 "You are not on that channel");
508 /* Get the Channel ID of the channel */
509 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
510 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
511 "You are not on that channel");
516 channel = (SilcChannelEntry)id_cache->context;
518 /* Send TOPIC command to the server */
519 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
521 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
522 ++conn->cmd_ident, 2,
523 1, idp->data, idp->len,
525 strlen(cmd->argv[2]));
527 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
528 ++conn->cmd_ident, 1,
529 1, idp->data, idp->len);
530 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
531 0, NULL, NULL, buffer->data, buffer->len, TRUE);
532 silc_buffer_free(buffer);
533 silc_buffer_free(idp);
535 /* Notify application */
539 silc_client_command_free(cmd);
542 /* Command INVITE. Invites specific client to join a channel. This is
543 also used to mange the invite list of the channel. */
545 SILC_CLIENT_CMD_FUNC(invite)
547 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
548 SilcClient client = cmd->client;
549 SilcClientConnection conn = cmd->conn;
550 SilcClientEntry client_entry = NULL;
551 SilcChannelEntry channel;
552 SilcBuffer buffer, clidp, chidp;
554 char *nickname = NULL, *name;
558 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
564 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
565 "Usage: /INVITE <channel> [<nickname>[@server>]"
566 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
571 if (cmd->argv[1][0] == '*') {
572 if (!conn->current_channel) {
573 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
574 "You are not on any channel");
579 channel = conn->current_channel;
583 channel = silc_client_get_channel(cmd->client, conn, name);
585 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
586 "You are on that channel");
592 /* Parse the typed nickname. */
593 if (cmd->argc == 3) {
594 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
595 if (client->params->nickname_parse)
596 client->params->nickname_parse(cmd->argv[2], &nickname);
598 nickname = strdup(cmd->argv[2]);
600 /* Find client entry */
601 client_entry = silc_idlist_get_client(client, conn, nickname,
610 /* Client entry not found, it was requested thus mark this to be
612 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
614 silc_client_command_destructor,
615 silc_client_command_invite,
616 silc_client_command_dup(cmd));
621 invite = cmd->argv[2];
623 if (cmd->argv[2][0] == '+')
630 /* Send the command */
631 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
633 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
634 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
635 ++conn->cmd_ident, 3,
636 1, chidp->data, chidp->len,
637 2, clidp->data, clidp->len,
638 type, invite, invite ?
640 silc_buffer_free(clidp);
642 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
643 ++conn->cmd_ident, 2,
644 1, chidp->data, chidp->len,
645 type, invite, invite ?
649 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
650 0, NULL, NULL, buffer->data, buffer->len, TRUE);
651 silc_buffer_free(buffer);
652 silc_buffer_free(chidp);
654 /* Notify application */
659 silc_client_command_free(cmd);
664 SilcClientConnection conn;
667 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
669 QuitInternal q = (QuitInternal)context;
671 /* Close connection */
672 q->client->ops->disconnect(q->client, q->conn);
673 silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
678 /* Command QUIT. Closes connection with current server. */
680 SILC_CLIENT_CMD_FUNC(quit)
682 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
687 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
693 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
694 &cmd->argv[1], &cmd->argv_lens[1],
695 &cmd->argv_types[1], 0);
697 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
698 NULL, NULL, NULL, 0);
699 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
701 buffer->data, buffer->len, TRUE);
702 silc_buffer_free(buffer);
704 q = silc_calloc(1, sizeof(*q));
705 q->client = cmd->client;
708 /* Sleep for a while */
711 /* We quit the connection with little timeout */
712 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
713 silc_client_command_quit_cb, (void *)q,
714 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
716 /* Notify application */
720 silc_client_command_free(cmd);
723 /* Timeout callback to remove the killed client from cache */
725 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
727 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
728 SilcClient client = cmd->client;
729 SilcClientConnection conn = cmd->conn;
730 SilcClientEntry target;
731 char *nickname = NULL;
733 /* Parse the typed nickname. */
734 if (client->params->nickname_parse)
735 client->params->nickname_parse(cmd->argv[1], &nickname);
737 nickname = strdup(cmd->argv[1]);
739 /* Get the target client */
740 target = silc_idlist_get_client(cmd->client, conn, nickname,
741 cmd->argv[1], FALSE);
743 silc_client_remove_from_channels(client, conn, target);
744 silc_client_del_client(client, conn, target);
748 silc_client_command_free(cmd);
751 /* Kill command's pending command callback to actually remove the killed
752 client from our local cache. */
754 SILC_CLIENT_CMD_FUNC(kill_remove)
756 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
757 SilcClientCommandReplyContext reply =
758 (SilcClientCommandReplyContext)context2;
759 SilcCommandStatus status;
761 SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL));
762 if (status == SILC_STATUS_OK) {
763 /* Remove with timeout */
764 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
765 silc_client_command_kill_remove_later, context,
766 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
770 silc_client_command_free(cmd);
773 /* Command KILL. Router operator can use this command to remove an client
774 fromthe SILC Network. */
776 SILC_CLIENT_CMD_FUNC(kill)
778 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
779 SilcClient client = cmd->client;
780 SilcClientConnection conn = cmd->conn;
781 SilcBuffer buffer, idp;
782 SilcClientEntry target;
783 char *nickname = NULL;
786 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
792 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
793 "Usage: /KILL <nickname> [<comment>]");
798 /* Parse the typed nickname. */
799 if (client->params->nickname_parse)
800 client->params->nickname_parse(cmd->argv[1], &nickname);
802 nickname = strdup(cmd->argv[1]);
804 /* Get the target client */
805 target = silc_idlist_get_client(cmd->client, conn, nickname,
815 /* Client entry not found, it was requested thus mark this to be
817 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
819 silc_client_command_destructor,
820 silc_client_command_kill,
821 silc_client_command_dup(cmd));
826 /* Send the KILL command to the server */
827 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
829 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
830 ++conn->cmd_ident, 1,
831 1, idp->data, idp->len);
833 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
834 ++conn->cmd_ident, 2,
835 1, idp->data, idp->len,
837 strlen(cmd->argv[2]));
838 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
839 0, NULL, NULL, buffer->data, buffer->len, TRUE);
840 silc_buffer_free(buffer);
841 silc_buffer_free(idp);
843 /* Notify application */
846 /* Register a pending callback that will actually remove the killed
847 client from our cache. */
848 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
849 NULL, silc_client_command_kill_remove,
850 silc_client_command_dup(cmd));
854 silc_client_command_free(cmd);
857 /* Command INFO. Request information about specific server. If specific
858 server is not provided the current server is used. */
860 SILC_CLIENT_CMD_FUNC(info)
862 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
863 SilcClientConnection conn = cmd->conn;
868 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
874 name = strdup(cmd->argv[1]);
876 /* Send the command */
878 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
879 1, name, strlen(name));
881 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
882 NULL, NULL, NULL, 0);
883 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
884 0, NULL, NULL, buffer->data, buffer->len, TRUE);
885 silc_buffer_free(buffer);
889 /* Notify application */
893 silc_client_command_free(cmd);
896 /* Command PING. Sends ping to server. This is used to test the
897 communication channel. */
899 SILC_CLIENT_CMD_FUNC(ping)
901 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
902 SilcClientConnection conn = cmd->conn;
908 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
913 /* Send the command */
914 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
915 1, conn->remote_id_data,
916 silc_id_get_len(conn->remote_id,
918 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
919 0, NULL, NULL, buffer->data, buffer->len, TRUE);
920 silc_buffer_free(buffer);
922 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
925 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
930 /* Start counting time */
931 for (i = 0; i < conn->ping_count; i++) {
932 if (conn->ping[i].dest_id == NULL) {
933 conn->ping[i].start_time = time(NULL);
934 conn->ping[i].dest_id = id;
935 conn->ping[i].dest_name = strdup(conn->remote_host);
940 if (i >= conn->ping_count) {
941 i = conn->ping_count;
942 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
943 conn->ping[i].start_time = time(NULL);
944 conn->ping[i].dest_id = id;
945 conn->ping[i].dest_name = strdup(conn->remote_host);
949 /* Notify application */
953 silc_client_command_free(cmd);
956 /* Command JOIN. Joins to a channel. */
958 SILC_CLIENT_CMD_FUNC(join)
960 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
961 SilcClientConnection conn = cmd->conn;
962 SilcIDCacheEntry id_cache = NULL;
963 SilcBuffer buffer, idp;
966 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
971 /* See if we have joined to the requested channel already */
972 if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
974 SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
975 if (channel->on_channel)
979 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
981 if (cmd->argv_lens[1] > 256)
982 cmd->argv_lens[1] = 256;
984 /* Send JOIN command to the server */
987 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
988 1, cmd->argv[1], cmd->argv_lens[1],
989 2, idp->data, idp->len);
990 else if (cmd->argc == 3)
993 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
994 1, cmd->argv[1], cmd->argv_lens[1],
995 2, idp->data, idp->len,
996 3, cmd->argv[2], cmd->argv_lens[2]);
999 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
1000 1, cmd->argv[1], cmd->argv_lens[1],
1001 2, idp->data, idp->len,
1002 3, cmd->argv[2], cmd->argv_lens[2],
1003 4, cmd->argv[3], cmd->argv_lens[3]);
1005 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1006 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1007 silc_buffer_free(buffer);
1008 silc_buffer_free(idp);
1010 /* Notify application */
1014 silc_client_command_free(cmd);
1017 /* MOTD command. Requests motd from server. */
1019 SILC_CLIENT_CMD_FUNC(motd)
1021 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1022 SilcClientConnection conn = cmd->conn;
1026 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1031 if (cmd->argc < 1 || cmd->argc > 2) {
1032 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1033 "Usage: /MOTD [<server>]");
1038 /* Send TOPIC command to the server */
1040 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1041 1, conn->remote_host,
1042 strlen(conn->remote_host));
1044 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1047 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1048 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1049 silc_buffer_free(buffer);
1051 /* Notify application */
1055 silc_client_command_free(cmd);
1058 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1059 modes as client cannot set itself server/router operator privileges. */
1061 SILC_CLIENT_CMD_FUNC(umode)
1063 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1064 SilcClientConnection conn = cmd->conn;
1065 SilcBuffer buffer, idp;
1066 unsigned char *cp, modebuf[4];
1067 uint32 mode, add, len;
1071 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1076 if (cmd->argc < 2) {
1077 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1078 "Usage: /UMODE +|-<modes>");
1083 mode = conn->local_entry->mode;
1085 /* Are we adding or removing mode */
1086 if (cmd->argv[1][0] == '-')
1092 cp = cmd->argv[1] + 1;
1094 for (i = 0; i < len; i++) {
1099 mode |= SILC_UMODE_SERVER_OPERATOR;
1100 mode |= SILC_UMODE_ROUTER_OPERATOR;
1102 mode = SILC_UMODE_NONE;
1107 mode |= SILC_UMODE_SERVER_OPERATOR;
1109 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1113 mode |= SILC_UMODE_ROUTER_OPERATOR;
1115 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1119 mode |= SILC_UMODE_GONE;
1121 mode &= ~SILC_UMODE_GONE;
1130 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1131 SILC_PUT32_MSB(mode, modebuf);
1133 /* Send the command packet. We support sending only one mode at once
1134 that requires an argument. */
1136 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1137 1, idp->data, idp->len,
1138 2, modebuf, sizeof(modebuf));
1139 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1140 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1141 silc_buffer_free(buffer);
1142 silc_buffer_free(idp);
1144 /* Notify application */
1148 silc_client_command_free(cmd);
1151 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1152 can be set several at once. Those modes that require argument must be set
1153 separately (unless set with modes that does not require arguments). */
1155 SILC_CLIENT_CMD_FUNC(cmode)
1157 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1158 SilcClientConnection conn = cmd->conn;
1159 SilcChannelEntry channel;
1160 SilcBuffer buffer, chidp, auth = NULL;
1161 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1162 uint32 mode, add, type, len, arg_len = 0;
1166 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1171 if (cmd->argc < 3) {
1172 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1173 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1178 if (cmd->argv[1][0] == '*') {
1179 if (!conn->current_channel) {
1180 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1181 "You are not on any channel");
1186 channel = conn->current_channel;
1188 name = cmd->argv[1];
1190 channel = silc_client_get_channel(cmd->client, conn, name);
1192 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1193 "You are on that channel");
1199 mode = channel->mode;
1201 /* Are we adding or removing mode */
1202 if (cmd->argv[2][0] == '-')
1207 /* Argument type to be sent to server */
1211 cp = cmd->argv[2] + 1;
1213 for (i = 0; i < len; i++) {
1217 mode |= SILC_CHANNEL_MODE_PRIVATE;
1219 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1223 mode |= SILC_CHANNEL_MODE_SECRET;
1225 mode &= ~SILC_CHANNEL_MODE_SECRET;
1229 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1231 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1235 mode |= SILC_CHANNEL_MODE_INVITE;
1237 mode &= ~SILC_CHANNEL_MODE_INVITE;
1241 mode |= SILC_CHANNEL_MODE_TOPIC;
1243 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1248 mode |= SILC_CHANNEL_MODE_ULIMIT;
1250 if (cmd->argc < 4) {
1251 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1252 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1256 ll = atoi(cmd->argv[3]);
1257 SILC_PUT32_MSB(ll, tmp);
1261 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1266 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1268 if (cmd->argc < 4) {
1269 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1270 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1275 arg_len = cmd->argv_lens[3];
1277 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1282 mode |= SILC_CHANNEL_MODE_CIPHER;
1284 if (cmd->argc < 4) {
1285 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1286 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1291 arg_len = cmd->argv_lens[3];
1293 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1298 mode |= SILC_CHANNEL_MODE_HMAC;
1300 if (cmd->argc < 4) {
1301 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1302 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1307 arg_len = cmd->argv_lens[3];
1309 mode &= ~SILC_CHANNEL_MODE_HMAC;
1314 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1317 if (cmd->argc < 4) {
1318 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1319 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1324 if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1325 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1326 cmd->client->private_key,
1331 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1332 cmd->argv[3], cmd->argv_lens[3]);
1336 arg_len = auth->len;
1338 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1348 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1349 SILC_PUT32_MSB(mode, modebuf);
1351 /* Send the command packet. We support sending only one mode at once
1352 that requires an argument. */
1355 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1356 1, chidp->data, chidp->len,
1357 2, modebuf, sizeof(modebuf),
1358 type, arg, arg_len);
1361 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1362 1, chidp->data, chidp->len,
1363 2, modebuf, sizeof(modebuf));
1366 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1367 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1368 silc_buffer_free(buffer);
1369 silc_buffer_free(chidp);
1371 silc_buffer_free(auth);
1373 /* Notify application */
1377 silc_client_command_free(cmd);
1380 /* CUMODE command. Changes client's mode on a channel. */
1382 SILC_CLIENT_CMD_FUNC(cumode)
1384 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1385 SilcClient client = cmd->client;
1386 SilcClientConnection conn = cmd->conn;
1387 SilcChannelEntry channel;
1388 SilcChannelUser chu;
1389 SilcClientEntry client_entry;
1390 SilcBuffer buffer, clidp, chidp, auth = NULL;
1391 unsigned char *name, *cp, modebuf[4];
1392 uint32 mode = 0, add, len;
1393 char *nickname = NULL;
1397 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1402 if (cmd->argc < 4) {
1403 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1404 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1409 if (cmd->argv[1][0] == '*') {
1410 if (!conn->current_channel) {
1411 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1412 "You are not on any channel");
1417 channel = conn->current_channel;
1419 name = cmd->argv[1];
1421 channel = silc_client_get_channel(cmd->client, conn, name);
1423 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1424 "You are on that channel");
1430 /* Parse the typed nickname. */
1431 if (client->params->nickname_parse)
1432 client->params->nickname_parse(cmd->argv[3], &nickname);
1434 nickname = strdup(cmd->argv[3]);
1436 /* Find client entry */
1437 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1438 cmd->argv[3], TRUE);
1439 if (!client_entry) {
1445 silc_free(nickname);
1447 /* Client entry not found, it was requested thus mark this to be
1449 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1451 silc_client_command_destructor,
1452 silc_client_command_cumode,
1453 silc_client_command_dup(cmd));
1458 /* Get the current mode */
1459 silc_list_start(channel->clients);
1460 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1461 if (chu->client == client_entry) {
1467 /* Are we adding or removing mode */
1468 if (cmd->argv[2][0] == '-')
1474 cp = cmd->argv[2] + 1;
1476 for (i = 0; i < len; i++) {
1480 mode |= SILC_CHANNEL_UMODE_CHANFO;
1481 mode |= SILC_CHANNEL_UMODE_CHANOP;
1483 mode = SILC_CHANNEL_UMODE_NONE;
1488 if (cmd->argc == 5) {
1489 if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1490 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1491 cmd->client->private_key,
1496 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1497 cmd->argv[4], cmd->argv_lens[4]);
1500 mode |= SILC_CHANNEL_UMODE_CHANFO;
1502 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1507 mode |= SILC_CHANNEL_UMODE_CHANOP;
1509 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1518 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1519 SILC_PUT32_MSB(mode, modebuf);
1520 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1522 /* Send the command packet. We support sending only one mode at once
1523 that requires an argument. */
1524 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1526 1, chidp->data, chidp->len,
1528 3, clidp->data, clidp->len,
1529 4, auth ? auth->data : NULL,
1530 auth ? auth->len : 0);
1532 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1533 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1534 silc_buffer_free(buffer);
1535 silc_buffer_free(chidp);
1536 silc_buffer_free(clidp);
1538 silc_buffer_free(auth);
1540 /* Notify application */
1544 silc_free(nickname);
1545 silc_client_command_free(cmd);
1548 /* KICK command. Kicks a client out of channel. */
1550 SILC_CLIENT_CMD_FUNC(kick)
1552 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1553 SilcClient client = cmd->client;
1554 SilcClientConnection conn = cmd->conn;
1555 SilcIDCacheEntry id_cache = NULL;
1556 SilcChannelEntry channel;
1557 SilcBuffer buffer, idp, idp2;
1558 SilcClientEntry target;
1560 char *nickname = NULL;
1563 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1568 if (cmd->argc < 3) {
1569 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1570 "Usage: /KICK <channel> <nickname> [<comment>]");
1575 if (cmd->argv[1][0] == '*') {
1576 if (!conn->current_channel) {
1577 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1578 "You are not on any channel");
1582 name = conn->current_channel->channel_name;
1584 name = cmd->argv[1];
1587 if (!conn->current_channel) {
1588 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1589 "You are not on that channel");
1594 /* Get the Channel ID of the channel */
1595 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1596 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1597 "You are not on that channel");
1602 channel = (SilcChannelEntry)id_cache->context;
1604 /* Parse the typed nickname. */
1605 if (client->params->nickname_parse)
1606 client->params->nickname_parse(cmd->argv[2], &nickname);
1608 nickname = strdup(cmd->argv[2]);
1610 /* Get the target client */
1611 target = silc_idlist_get_client(cmd->client, conn, nickname,
1612 cmd->argv[2], FALSE);
1614 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1615 "No such client: %s",
1621 /* Send KICK command to the server */
1622 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1623 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1625 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1626 1, idp->data, idp->len,
1627 2, idp2->data, idp2->len);
1629 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1630 1, idp->data, idp->len,
1631 2, idp2->data, idp2->len,
1633 strlen(cmd->argv[3]));
1634 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1635 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1636 silc_buffer_free(buffer);
1637 silc_buffer_free(idp);
1638 silc_buffer_free(idp2);
1640 /* Notify application */
1644 silc_free(nickname);
1645 silc_client_command_free(cmd);
1648 static void silc_client_command_oper_send(unsigned char *data,
1649 uint32 data_len, void *context)
1651 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1652 SilcClientConnection conn = cmd->conn;
1653 SilcBuffer buffer, auth;
1655 if (cmd->argc >= 3) {
1656 /* Encode the public key authentication payload */
1657 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1658 cmd->client->private_key,
1663 /* Encode the password authentication payload */
1664 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1668 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1670 strlen(cmd->argv[1]),
1671 2, auth->data, auth->len);
1672 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1673 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1675 silc_buffer_free(buffer);
1676 silc_buffer_free(auth);
1678 /* Notify application */
1682 /* OPER command. Used to obtain server operator privileges. */
1684 SILC_CLIENT_CMD_FUNC(oper)
1686 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1687 SilcClientConnection conn = cmd->conn;
1690 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1695 if (cmd->argc < 2) {
1696 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1697 "Usage: /OPER <username> [-pubkey]");
1702 if (cmd->argc < 3) {
1703 /* Get passphrase */
1704 cmd->client->ops->ask_passphrase(cmd->client, conn,
1705 silc_client_command_oper_send,
1710 silc_client_command_oper_send(NULL, 0, context);
1713 silc_client_command_free(cmd);
1716 static void silc_client_command_silcoper_send(unsigned char *data,
1717 uint32 data_len, void *context)
1719 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1720 SilcClientConnection conn = cmd->conn;
1721 SilcBuffer buffer, auth;
1723 if (cmd->argc >= 3) {
1724 /* Encode the public key authentication payload */
1725 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1726 cmd->client->private_key,
1731 /* Encode the password authentication payload */
1732 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1736 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1738 strlen(cmd->argv[1]),
1739 2, auth->data, auth->len);
1740 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1741 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1743 silc_buffer_free(buffer);
1744 silc_buffer_free(auth);
1746 /* Notify application */
1750 /* SILCOPER command. Used to obtain router operator privileges. */
1752 SILC_CLIENT_CMD_FUNC(silcoper)
1754 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1755 SilcClientConnection conn = cmd->conn;
1758 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1763 if (cmd->argc < 2) {
1764 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1765 "Usage: /SILCOPER <username> [-pubkey]");
1770 if (cmd->argc < 3) {
1771 /* Get passphrase */
1772 cmd->client->ops->ask_passphrase(cmd->client, conn,
1773 silc_client_command_silcoper_send,
1778 silc_client_command_silcoper_send(NULL, 0, context);
1781 silc_client_command_free(cmd);
1784 /* CONNECT command. Connects the server to another server. */
1786 SILC_CLIENT_CMD_FUNC(connect)
1788 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1789 SilcClientConnection conn = cmd->conn;
1791 unsigned char port[4];
1795 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1800 if (cmd->argc < 2) {
1801 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1802 "Usage: /CONNECT <server> [<port>]");
1807 if (cmd->argc == 3) {
1808 tmp = atoi(cmd->argv[2]);
1809 SILC_PUT32_MSB(tmp, port);
1813 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1815 strlen(cmd->argv[1]),
1818 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1820 strlen(cmd->argv[1]));
1821 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1822 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1823 silc_buffer_free(buffer);
1825 /* Notify application */
1829 silc_client_command_free(cmd);
1832 /* Command BAN. This is used to manage the ban list of the channel. */
1834 SILC_CLIENT_CMD_FUNC(ban)
1836 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1837 SilcClientConnection conn = cmd->conn;
1838 SilcChannelEntry channel;
1839 SilcBuffer buffer, chidp;
1841 char *name, *ban = NULL;
1844 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1849 if (cmd->argc < 2) {
1850 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1851 "Usage: /BAN <channel> "
1852 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1857 if (cmd->argv[1][0] == '*') {
1858 if (!conn->current_channel) {
1859 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1860 "You are not on any channel");
1865 channel = conn->current_channel;
1867 name = cmd->argv[1];
1869 channel = silc_client_get_channel(cmd->client, conn, name);
1871 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1872 "You are on that channel");
1878 if (cmd->argc == 3) {
1879 if (cmd->argv[2][0] == '+')
1888 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1890 /* Send the command */
1892 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
1893 1, chidp->data, chidp->len,
1894 type, ban, strlen(ban));
1896 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
1897 1, chidp->data, chidp->len);
1899 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1900 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1901 silc_buffer_free(buffer);
1902 silc_buffer_free(chidp);
1904 /* Notify application */
1908 silc_client_command_free(cmd);
1911 /* CLOSE command. Close server connection to the remote server */
1913 SILC_CLIENT_CMD_FUNC(close)
1915 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1916 SilcClientConnection conn = cmd->conn;
1918 unsigned char port[4];
1922 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1927 if (cmd->argc < 2) {
1928 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1929 "Usage: /CLOSE <server> [<port>]");
1934 if (cmd->argc == 3) {
1935 tmp = atoi(cmd->argv[2]);
1936 SILC_PUT32_MSB(tmp, port);
1940 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1942 strlen(cmd->argv[1]),
1945 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1947 strlen(cmd->argv[1]));
1948 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1949 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1950 silc_buffer_free(buffer);
1952 /* Notify application */
1956 silc_client_command_free(cmd);
1959 /* SHUTDOWN command. Shutdowns the server. */
1961 SILC_CLIENT_CMD_FUNC(shutdown)
1963 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1966 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1971 /* Send the command */
1972 silc_client_send_command(cmd->client, cmd->conn,
1973 SILC_COMMAND_SHUTDOWN, 0, 0);
1975 /* Notify application */
1979 silc_client_command_free(cmd);
1982 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1984 SILC_CLIENT_CMD_FUNC(leave)
1986 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1987 SilcClientConnection conn = cmd->conn;
1988 SilcIDCacheEntry id_cache = NULL;
1989 SilcChannelEntry channel;
1990 SilcBuffer buffer, idp;
1994 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1999 if (cmd->argc != 2) {
2000 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2001 "Usage: /LEAVE <channel>");
2006 if (cmd->argv[1][0] == '*') {
2007 if (!conn->current_channel) {
2008 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2009 "You are not on any channel");
2013 name = conn->current_channel->channel_name;
2015 name = cmd->argv[1];
2018 /* Get the Channel ID of the channel */
2019 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
2020 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2021 "You are not on that channel");
2026 channel = (SilcChannelEntry)id_cache->context;
2027 channel->on_channel = FALSE;
2029 /* Send LEAVE command to the server */
2030 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
2031 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2032 1, idp->data, idp->len);
2033 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2034 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2035 silc_buffer_free(buffer);
2036 silc_buffer_free(idp);
2038 /* Notify application */
2041 if (conn->current_channel == channel)
2042 conn->current_channel = NULL;
2044 silc_client_del_channel(cmd->client, cmd->conn, channel);
2047 silc_client_command_free(cmd);
2050 /* Command USERS. Requests the USERS of the clients joined on requested
2053 SILC_CLIENT_CMD_FUNC(users)
2055 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2056 SilcClientConnection conn = cmd->conn;
2061 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2066 if (cmd->argc != 2) {
2067 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2068 "Usage: /USERS <channel>");
2073 if (cmd->argv[1][0] == '*') {
2074 if (!conn->current_channel) {
2075 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2076 "You are not on any channel");
2080 name = conn->current_channel->channel_name;
2082 name = cmd->argv[1];
2085 /* Send USERS command to the server */
2086 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2087 ++conn->cmd_ident, 1,
2088 2, name, strlen(name));
2089 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2090 NULL, 0, NULL, NULL, buffer->data,
2092 silc_buffer_free(buffer);
2094 /* Notify application */
2098 silc_client_command_free(cmd);
2101 /* Command GETKEY. Used to fetch remote client's public key. */
2103 SILC_CLIENT_CMD_FUNC(getkey)
2105 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2106 SilcClientConnection conn = cmd->conn;
2107 SilcClient client = cmd->client;
2108 SilcClientEntry client_entry = NULL;
2109 SilcServerEntry server_entry = NULL;
2110 char *nickname = NULL;
2111 SilcBuffer idp, buffer;
2114 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2119 if (cmd->argc < 2) {
2120 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2121 "Usage: /GETKEY <nickname or server name>");
2127 SilcClientCommandReplyContext reply =
2128 (SilcClientCommandReplyContext)context2;
2129 SilcCommandStatus status;
2130 unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
2131 SILC_GET16_MSB(status, tmp);
2133 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
2134 status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2135 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2137 silc_client_command_status_message(status));
2143 /* Parse the typed nickname. */
2144 if (client->params->nickname_parse)
2145 client->params->nickname_parse(cmd->argv[1], &nickname);
2147 nickname = strdup(cmd->argv[1]);
2149 /* Find client entry */
2150 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2152 if (!client_entry) {
2153 /* Check whether user requested server actually */
2154 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2156 if (!server_entry) {
2162 /* No. what ever user wants we don't have it, so resolve it. We
2163 will try to resolve both client and server, one of them is
2164 bound to be wrong. */
2166 /* This will send the IDENTIFY command */
2167 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2168 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2170 silc_client_command_destructor,
2171 silc_client_command_getkey,
2172 silc_client_command_dup(cmd));
2174 /* This sends the IDENTIFY command to resolve the server. */
2175 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
2176 ++conn->cmd_ident, 1,
2177 2, cmd->argv[1], cmd->argv_lens[1]);
2178 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2179 conn->cmd_ident, NULL,
2180 silc_client_command_getkey,
2181 silc_client_command_dup(cmd));
2184 silc_free(nickname);
2188 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2190 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2193 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2194 1, idp->data, idp->len);
2195 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2196 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2197 silc_buffer_free(buffer);
2198 silc_buffer_free(idp);
2200 /* Notify application */
2204 silc_free(nickname);
2205 silc_client_command_free(cmd);