5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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"
24 /* Client command list. */
25 SilcClientCommand silc_command_list[] =
27 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
28 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
30 SILC_CF_LAG | SILC_CF_REG, 3),
31 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
32 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
34 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
36 SILC_CLIENT_CMD(kill, KILL, "KILL",
37 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
38 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
39 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
40 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
41 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
42 SILC_CLIENT_CMD(oper, OPER, "OPER",
43 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
44 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 4),
45 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
46 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
48 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
49 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
50 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
51 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
52 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
54 SILC_CLIENT_CMD(die, DIE, "DIE",
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
56 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
58 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
61 { NULL, 0, NULL, 0, 0 },
64 #define SILC_NOT_CONNECTED(x, c) \
65 x->ops->say((x), (c), \
66 "You are not connected to a server, use /SERVER to connect");
68 /* Command operation that is called at the end of all commands.
70 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
71 cmd, TRUE, cmd->command->cmd)
73 /* Error to application. Usage: COMMAND_ERROR; */
74 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
75 cmd, FALSE, cmd->command->cmd)
77 /* List of pending commands. */
78 SilcClientCommandPending *silc_command_pending = NULL;
80 /* Generic function to send any command. The arguments must be sent already
81 encoded into correct form in correct order. */
83 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
84 SilcCommand command, unsigned int argc, ...)
91 packet = silc_command_payload_encode_vap(command, 0, argc, ap);
92 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
93 NULL, 0, NULL, NULL, packet->data,
95 silc_buffer_free(packet);
98 /* Finds and returns a pointer to the command list. Return NULL if the
99 command is not found. */
101 SilcClientCommand *silc_client_command_find(const char *name)
103 SilcClientCommand *cmd;
105 for (cmd = silc_command_list; cmd->name; cmd++) {
106 if (!strcmp(cmd->name, name))
113 /* Add new pending command to the list of pending commands. Currently
114 pending commands are executed from command replies, thus we can
115 execute any command after receiving some specific command reply.
117 The argument `reply_cmd' is the command reply from where the callback
118 function is to be called, thus, it IS NOT the command to be executed.
120 XXX: If needed in the future this support may be extended for
121 commands as well, when any command could be executed after executing
122 some specific command. */
124 void silc_client_command_pending(SilcCommand reply_cmd,
125 SilcClientCommandCallback callback,
128 SilcClientCommandPending *reply, *r;
130 reply = silc_calloc(1, sizeof(*reply));
131 reply->reply_cmd = reply_cmd;
132 reply->context = context;
133 reply->callback = callback;
135 if (silc_command_pending == NULL) {
136 silc_command_pending = reply;
140 for (r = silc_command_pending; r; r = r->next) {
141 if (r->next == NULL) {
148 /* Deletes pending command by reply command type. */
150 void silc_client_command_pending_del(SilcCommand reply_cmd)
152 SilcClientCommandPending *r, *tmp;
154 if (silc_command_pending) {
155 if (silc_command_pending->reply_cmd == reply_cmd) {
156 silc_free(silc_command_pending);
157 silc_command_pending = NULL;
161 for (r = silc_command_pending; r; r = r->next) {
162 if (r->next && r->next->reply_cmd == reply_cmd) {
164 r->next = r->next->next;
172 /* Free command context and its internals */
174 void silc_client_command_free(SilcClientCommandContext cmd)
179 for (i = 0; i < cmd->argc; i++)
180 silc_free(cmd->argv[i]);
185 /* Command WHOIS. This command is used to query information about
188 SILC_CLIENT_CMD_FUNC(whois)
190 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
191 SilcClientConnection conn = cmd->conn;
195 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
200 if (cmd->argc < 2 || cmd->argc > 3) {
201 cmd->client->ops->say(cmd->client, conn,
202 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
207 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
208 cmd->argc - 1, ++cmd->argv,
209 ++cmd->argv_lens, ++cmd->argv_types,
211 silc_client_packet_send(cmd->client, cmd->conn->sock,
212 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
213 buffer->data, buffer->len, TRUE);
214 silc_buffer_free(buffer);
219 /* Notify application */
223 silc_client_command_free(cmd);
226 SILC_CLIENT_CMD_FUNC(whowas)
230 /* Command IDENTIFY. This command is used to query information about
231 specific user, especially ID's. */
233 SILC_CLIENT_CMD_FUNC(identify)
235 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
236 SilcClientConnection conn = cmd->conn;
240 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
245 if (cmd->argc < 2 || cmd->argc > 3) {
246 cmd->client->ops->say(cmd->client, conn,
247 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
252 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
253 cmd->argc - 1, ++cmd->argv,
254 ++cmd->argv_lens, ++cmd->argv_types,
256 silc_client_packet_send(cmd->client, cmd->conn->sock,
257 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
258 buffer->data, buffer->len, TRUE);
259 silc_buffer_free(buffer);
264 /* Notify application */
268 silc_client_command_free(cmd);
271 /* Command NICK. Shows current nickname/sets new nickname on current
274 SILC_CLIENT_CMD_FUNC(nick)
276 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
277 SilcClientConnection conn = cmd->conn;
281 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
286 if (!strcmp(conn->nickname, cmd->argv[1]))
289 /* Show current nickname */
292 cmd->client->ops->say(cmd->client, conn,
293 "Your nickname is %s on server %s",
294 conn->nickname, conn->remote_host);
296 cmd->client->ops->say(cmd->client, conn,
297 "Your nickname is %s", conn->nickname);
300 /* XXX Notify application */
305 /* Set new nickname */
306 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
307 cmd->argc - 1, ++cmd->argv,
308 ++cmd->argv_lens, ++cmd->argv_types,
310 silc_client_packet_send(cmd->client, cmd->conn->sock,
311 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
312 buffer->data, buffer->len, TRUE);
313 silc_buffer_free(buffer);
318 silc_free(conn->nickname);
319 conn->nickname = strdup(cmd->argv[1]);
321 /* Notify application */
325 silc_client_command_free(cmd);
328 SILC_CLIENT_CMD_FUNC(list)
332 /* Command TOPIC. Sets/shows topic on a channel. */
334 SILC_CLIENT_CMD_FUNC(topic)
336 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
337 SilcClientConnection conn = cmd->conn;
338 SilcIDCacheEntry id_cache = NULL;
339 SilcChannelEntry channel;
340 SilcBuffer buffer, idp;
344 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
349 if (cmd->argc < 2 || cmd->argc > 3) {
350 cmd->client->ops->say(cmd->client, conn,
351 "Usage: /TOPIC <channel> [<topic>]");
356 if (cmd->argv[1][0] == '*') {
357 if (!conn->current_channel) {
358 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
362 name = conn->current_channel->channel_name;
367 if (!conn->current_channel) {
368 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
373 /* Get the Channel ID of the channel */
374 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
375 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
380 channel = (SilcChannelEntry)id_cache->context;
382 /* Send TOPIC command to the server */
383 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
385 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
386 1, idp->data, idp->len,
388 strlen(cmd->argv[2]));
390 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
391 1, idp->data, idp->len,
393 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
394 0, NULL, NULL, buffer->data, buffer->len, TRUE);
395 silc_buffer_free(buffer);
396 silc_buffer_free(idp);
398 /* Notify application */
402 silc_client_command_free(cmd);
405 /* Command INVITE. Invites specific client to join a channel. */
407 SILC_CLIENT_CMD_FUNC(invite)
409 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
410 SilcClient client = cmd->client;
411 SilcClientConnection conn = cmd->conn;
412 SilcClientEntry client_entry;
413 SilcChannelEntry channel_entry;
414 SilcBuffer buffer, clidp, chidp;
415 unsigned int num = 0;
416 char *nickname = NULL, *server = NULL;
419 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
424 if (cmd->argc != 3) {
425 cmd->client->ops->say(cmd->client, conn,
426 "Usage: /INVITE <nickname>[@<server>] <channel>");
431 /* Parse the typed nickname. */
432 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
433 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
438 /* Find client entry */
439 client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
446 /* Client entry not found, it was requested thus mark this to be
448 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
449 silc_client_command_invite, context);
453 /* Find channel entry */
454 channel_entry = silc_idlist_get_channel(client, conn, cmd->argv[2]);
455 if (!channel_entry) {
456 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
462 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
463 chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
464 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
465 1, clidp->data, clidp->len,
466 2, chidp->data, chidp->len);
467 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
468 0, NULL, NULL, buffer->data, buffer->len, TRUE);
469 silc_buffer_free(buffer);
470 silc_buffer_free(clidp);
471 silc_buffer_free(chidp);
473 cmd->client->ops->say(cmd->client, conn,
474 "Inviting %s to channel %s", cmd->argv[1],
477 /* Notify application */
481 silc_client_command_free(cmd);
484 /* Command QUIT. Closes connection with current server. */
486 SILC_CLIENT_CMD_FUNC(quit)
488 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
492 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
497 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
498 ++cmd->argv, ++cmd->argv_lens,
499 ++cmd->argv_types, 0);
500 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
502 buffer->data, buffer->len, TRUE);
503 silc_buffer_free(buffer);
508 /* Close connection */
509 silc_client_close_connection(cmd->client, cmd->conn->sock);
510 cmd->client->ops->disconnect(cmd->client, cmd->conn);
512 /* Notify application */
516 silc_client_command_free(cmd);
519 SILC_CLIENT_CMD_FUNC(kill)
523 /* Command INFO. Request information about specific server. If specific
524 server is not provided the current server is used. */
526 SILC_CLIENT_CMD_FUNC(info)
528 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
529 SilcClientConnection conn = cmd->conn;
534 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
540 name = strdup(conn->remote_host);
542 name = strdup(cmd->argv[1]);
544 /* Send the command */
545 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
546 1, name, strlen(name));
547 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
548 0, NULL, NULL, buffer->data, buffer->len, TRUE);
549 silc_buffer_free(buffer);
551 /* Notify application */
555 silc_client_command_free(cmd);
558 SILC_CLIENT_CMD_FUNC(connect)
562 /* Command PING. Sends ping to server. This is used to test the
563 communication channel. */
565 SILC_CLIENT_CMD_FUNC(ping)
567 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
568 SilcClientConnection conn = cmd->conn;
575 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
580 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
581 name = strdup(conn->remote_host);
583 /* Send the command */
584 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
585 1, conn->remote_id_data,
587 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
588 0, NULL, NULL, buffer->data, buffer->len, TRUE);
589 silc_buffer_free(buffer);
591 id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
593 /* Start counting time */
594 for (i = 0; i < conn->ping_count; i++) {
595 if (conn->ping[i].dest_id == NULL) {
596 conn->ping[i].start_time = time(NULL);
597 conn->ping[i].dest_id = id;
598 conn->ping[i].dest_name = name;
603 if (i >= conn->ping_count) {
604 i = conn->ping_count;
605 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
606 conn->ping[i].start_time = time(NULL);
607 conn->ping[i].dest_id = id;
608 conn->ping[i].dest_name = name;
612 /* Notify application */
616 silc_client_command_free(cmd);
619 SILC_CLIENT_CMD_FUNC(oper)
623 SILC_CLIENT_CMD_FUNC(trace)
627 SILC_CLIENT_CMD_FUNC(notice)
631 /* Command JOIN. Joins to a channel. */
633 SILC_CLIENT_CMD_FUNC(join)
635 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
636 SilcClientConnection conn = cmd->conn;
637 SilcIDCacheEntry id_cache = NULL;
641 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
647 /* Show channels currently joined to */
652 /* See if we have joined to the requested channel already */
653 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
655 cmd->client->ops->say(cmd->client, conn,
656 "You are talking to channel %s", cmd->argv[1]);
657 conn->current_channel = (SilcChannelEntry)id_cache->context;
659 cmd->client->screen->bottom_line->channel = cmd->argv[1];
660 silc_screen_print_bottom_line(cmd->client->screen, 0);
665 /* Send JOIN command to the server */
668 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 1,
669 1, cmd->argv[1], cmd->argv_lens[1]);
670 else if (cmd->argc == 3)
673 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
674 1, cmd->argv[1], cmd->argv_lens[1],
675 2, cmd->argv[2], cmd->argv_lens[2]);
678 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
679 1, cmd->argv[1], cmd->argv_lens[1],
680 2, cmd->argv[2], cmd->argv_lens[2],
681 3, cmd->argv[3], cmd->argv_lens[3]);
683 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
684 0, NULL, NULL, buffer->data, buffer->len, TRUE);
685 silc_buffer_free(buffer);
687 /* Notify application */
691 silc_client_command_free(cmd);
694 /* MOTD command. Requests motd from server. */
696 SILC_CLIENT_CMD_FUNC(motd)
698 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
699 SilcClientConnection conn = cmd->conn;
703 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
708 if (cmd->argc < 1 || cmd->argc > 1) {
709 cmd->client->ops->say(cmd->client, conn,
715 /* Send TOPIC command to the server */
716 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
717 2, conn->remote_host,
718 strlen(conn->remote_host));
719 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
720 0, NULL, NULL, buffer->data, buffer->len, TRUE);
721 silc_buffer_free(buffer);
723 /* Notify application */
727 silc_client_command_free(cmd);
730 /* UMODE. Set user mode in SILC. */
732 SILC_CLIENT_CMD_FUNC(umode)
737 /* CMODE command. Sets channel mode. Modes that does not require any arguments
738 can be set several at once. Those modes that require argument must be set
739 separately (unless set with modes that does not require arguments). */
741 SILC_CLIENT_CMD_FUNC(cmode)
743 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
744 SilcClientConnection conn = cmd->conn;
745 SilcChannelEntry channel;
746 SilcBuffer buffer, chidp;
747 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
748 unsigned int mode, add, type, len, arg_len = 0;
752 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
758 cmd->client->ops->say(cmd->client, conn,
759 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
764 if (cmd->argv[1][0] == '*') {
765 if (!conn->current_channel) {
766 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
771 channel = conn->current_channel;
775 channel = silc_idlist_get_channel(cmd->client, conn, name);
777 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
783 mode = channel->mode;
785 /* Are we adding or removing mode */
786 if (cmd->argv[2][0] == '-')
791 /* Argument type to be sent to server */
795 cp = cmd->argv[2] + 1;
797 for (i = 0; i < len; i++) {
801 mode |= SILC_CHANNEL_MODE_PRIVATE;
803 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
807 mode |= SILC_CHANNEL_MODE_SECRET;
809 mode &= ~SILC_CHANNEL_MODE_SECRET;
813 mode |= SILC_CHANNEL_MODE_PRIVKEY;
815 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
819 mode |= SILC_CHANNEL_MODE_INVITE;
821 mode &= ~SILC_CHANNEL_MODE_INVITE;
825 mode |= SILC_CHANNEL_MODE_TOPIC;
827 mode &= ~SILC_CHANNEL_MODE_TOPIC;
832 mode |= SILC_CHANNEL_MODE_ULIMIT;
834 ll = atoi(cmd->argv[3]);
835 SILC_PUT32_MSB(ll, tmp);
839 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
844 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
847 arg_len = cmd->argv_lens[3];
849 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
854 mode |= SILC_CHANNEL_MODE_BAN;
857 arg_len = cmd->argv_lens[3];
859 mode &= ~SILC_CHANNEL_MODE_BAN;
864 mode |= SILC_CHANNEL_MODE_INVITE_LIST;
867 arg_len = cmd->argv_lens[3];
869 mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
874 mode |= SILC_CHANNEL_MODE_CIPHER;
877 arg_len = cmd->argv_lens[3];
879 mode &= ~SILC_CHANNEL_MODE_CIPHER;
889 if (type && cmd->argc < 3) {
894 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
895 SILC_PUT32_MSB(mode, modebuf);
897 /* Send the command packet. We support sending only one mode at once
898 that requires an argument. */
901 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
902 1, chidp->data, chidp->len,
903 2, modebuf, sizeof(modebuf),
907 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
908 1, chidp->data, chidp->len,
909 2, modebuf, sizeof(modebuf));
912 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
913 0, NULL, NULL, buffer->data, buffer->len, TRUE);
914 silc_buffer_free(buffer);
915 silc_buffer_free(chidp);
917 /* Notify application */
921 silc_client_command_free(cmd);
924 /* CUMODE command. Changes client's mode on a channel. */
926 SILC_CLIENT_CMD_FUNC(cumode)
928 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
929 SilcClientConnection conn = cmd->conn;
930 SilcChannelEntry channel;
931 SilcClientEntry client_entry;
932 SilcBuffer buffer, clidp, chidp;
933 unsigned char *name, *cp, modebuf[4];
934 unsigned int mode = 0, add, len;
935 char *nickname = NULL, *server = NULL;
936 unsigned int num = 0;
940 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
946 cmd->client->ops->say(cmd->client, conn,
947 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
952 if (cmd->argv[1][0] == '*') {
953 if (!conn->current_channel) {
954 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
959 channel = conn->current_channel;
963 channel = silc_idlist_get_channel(cmd->client, conn, name);
965 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
971 /* Parse the typed nickname. */
972 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
973 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
978 /* Find client entry */
979 client_entry = silc_idlist_get_client(cmd->client, conn,
980 nickname, server, num);
982 /* Client entry not found, it was requested thus mark this to be
984 silc_client_command_pending(SILC_COMMAND_CUMODE,
985 silc_client_command_cumode, context);
989 for (i = 0; i < channel->clients_count; i++)
990 if (channel->clients[i].client == client_entry) {
991 mode = channel->clients[i].mode;
995 /* Are we adding or removing mode */
996 if (cmd->argv[2][0] == '-')
1002 cp = cmd->argv[2] + 1;
1004 for (i = 0; i < len; i++) {
1008 mode |= SILC_CHANNEL_UMODE_CHANFO;
1009 mode |= SILC_CHANNEL_UMODE_CHANOP;
1011 mode = SILC_CHANNEL_UMODE_NONE;
1016 mode |= SILC_CHANNEL_UMODE_CHANFO;
1018 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1022 mode |= SILC_CHANNEL_UMODE_CHANOP;
1024 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1033 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1034 SILC_PUT32_MSB(mode, modebuf);
1035 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1037 /* Send the command packet. We support sending only one mode at once
1038 that requires an argument. */
1039 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
1040 1, chidp->data, chidp->len,
1042 3, clidp->data, clidp->len);
1044 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1045 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1046 silc_buffer_free(buffer);
1047 silc_buffer_free(chidp);
1048 silc_buffer_free(clidp);
1050 /* Notify application */
1054 silc_client_command_free(cmd);
1057 /* KICK command. Kicks a client out of channel. */
1059 SILC_CLIENT_CMD_FUNC(kick)
1061 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1062 SilcClientConnection conn = cmd->conn;
1066 SILC_CLIENT_CMD_FUNC(restart)
1070 SILC_CLIENT_CMD_FUNC(close)
1074 SILC_CLIENT_CMD_FUNC(die)
1078 SILC_CLIENT_CMD_FUNC(silcoper)
1082 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1084 SILC_CLIENT_CMD_FUNC(leave)
1086 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1087 SilcClientConnection conn = cmd->conn;
1088 SilcIDCacheEntry id_cache = NULL;
1089 SilcChannelEntry channel;
1090 SilcBuffer buffer, idp;
1094 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1099 if (cmd->argc != 2) {
1100 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1105 if (cmd->argv[1][0] == '*') {
1106 if (!conn->current_channel) {
1107 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1111 name = conn->current_channel->channel_name;
1113 name = cmd->argv[1];
1116 if (!conn->current_channel) {
1117 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1122 /* Get the Channel ID of the channel */
1123 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1124 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1129 channel = (SilcChannelEntry)id_cache->context;
1131 /* Send LEAVE command to the server */
1132 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1133 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1134 1, idp->data, idp->len);
1135 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1136 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1137 silc_buffer_free(buffer);
1138 silc_buffer_free(idp);
1140 /* We won't talk anymore on this channel */
1141 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1143 conn->current_channel = NULL;
1145 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1146 silc_free(channel->channel_name);
1147 silc_free(channel->id);
1148 silc_free(channel->key);
1149 silc_cipher_free(channel->channel_key);
1152 /* Notify application */
1156 silc_client_command_free(cmd);
1159 /* Command NAMES. Requests the names of the clients joined on requested
1162 SILC_CLIENT_CMD_FUNC(names)
1164 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1165 SilcClientConnection conn = cmd->conn;
1166 SilcIDCacheEntry id_cache = NULL;
1167 SilcBuffer buffer, idp;
1171 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1176 if (cmd->argc != 2) {
1177 cmd->client->ops->say(cmd->client, conn, "Usage: /NAMES <channel>");
1182 if (cmd->argv[1][0] == '*')
1183 name = conn->current_channel->channel_name;
1185 name = cmd->argv[1];
1187 /* Get the Channel ID of the channel */
1188 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1189 /* XXX should resolve the channel ID; LIST command */
1190 cmd->client->ops->say(cmd->client, conn,
1191 "You are not on that channel", name);
1196 /* Send NAMES command to the server */
1197 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1198 buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
1199 1, idp->data, idp->len);
1200 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1201 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1202 silc_buffer_free(buffer);
1203 silc_buffer_free(idp);
1205 /* Register dummy pending command that will tell the reply command
1206 that user called this command. Server may send reply to this command
1207 even if user did not send this command thus we want to handle things
1208 differently when user sent the command. This is dummy and won't be
1210 /* XXX this is kludge and should be removed after pending command reply
1211 support is added. Currently only commands may be pending not command
1213 silc_client_command_pending(SILC_COMMAND_NAMES,
1214 silc_client_command_names, NULL);
1216 /* Notify application */
1220 silc_client_command_free(cmd);