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(restart, RESTART, "RESTART",
52 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
53 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
54 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
55 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
56 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
57 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
58 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
59 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
60 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
61 SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
63 { NULL, 0, NULL, 0, 0 },
66 #define SILC_NOT_CONNECTED(x, c) \
67 x->ops->say((x), (c), \
68 "You are not connected to a server, use /SERVER to connect");
70 /* Command operation that is called at the end of all commands.
72 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
73 cmd, TRUE, cmd->command->cmd)
75 /* Error to application. Usage: COMMAND_ERROR; */
76 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
77 cmd, FALSE, cmd->command->cmd)
79 /* Generic function to send any command. The arguments must be sent already
80 encoded into correct form and in correct order. */
82 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
83 SilcCommand command, unsigned short ident,
84 unsigned int argc, ...)
91 packet = silc_command_payload_encode_vap(command, ident, 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 be executed when reply to a command has been
114 received. The `reply_cmd' is the command that will call the `callback'
115 with `context' when reply has been received. If `ident is non-zero
116 the `callback' will be executed when received reply with command
117 identifier `ident'. */
119 void silc_client_command_pending(SilcClientConnection conn,
120 SilcCommand reply_cmd,
121 unsigned short ident,
122 SilcClientPendingDestructor destructor,
123 SilcCommandCb callback,
126 SilcClientCommandPending *reply;
128 reply = silc_calloc(1, sizeof(*reply));
129 reply->reply_cmd = reply_cmd;
130 reply->ident = ident;
131 reply->context = context;
132 reply->callback = callback;
133 reply->destructor = destructor;
134 silc_dlist_add(conn->pending_commands, reply);
137 /* Deletes pending command by reply command type. */
139 void silc_client_command_pending_del(SilcClientConnection conn,
140 SilcCommand reply_cmd,
141 unsigned short ident)
143 SilcClientCommandPending *r;
145 silc_dlist_start(conn->pending_commands);
146 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
147 if (r->reply_cmd == reply_cmd && r->ident == ident) {
148 silc_dlist_del(conn->pending_commands, r);
154 /* Checks for pending commands and marks callbacks to be called from
155 the command reply function. Returns TRUE if there were pending command. */
157 int silc_client_command_pending_check(SilcClientConnection conn,
158 SilcClientCommandReplyContext ctx,
160 unsigned short ident)
162 SilcClientCommandPending *r;
164 silc_dlist_start(conn->pending_commands);
165 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
166 if (r->reply_cmd == command && r->ident == ident) {
167 ctx->context = r->context;
168 ctx->callback = r->callback;
169 ctx->destructor = r->destructor;
178 /* Allocate Command Context */
180 SilcClientCommandContext silc_client_command_alloc()
182 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
187 /* Free command context and its internals */
189 void silc_client_command_free(SilcClientCommandContext ctx)
192 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
194 if (ctx->users < 1) {
197 for (i = 0; i < ctx->argc; i++)
198 silc_free(ctx->argv[i]);
203 /* Duplicate Command Context by adding reference counter. The context won't
204 be free'd untill it hits zero. */
206 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
209 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
214 /* Pending command destructor. */
216 static void silc_client_command_destructor(void *context)
218 silc_client_command_free((SilcClientCommandContext)context);
221 /* silc_client_get_client completion callback */
222 void silc_client_command_completion(SilcClient client,
223 SilcClientConnection conn,
224 SilcClientEntry clients,
225 unsigned int clients_count,
231 /* Command WHOIS. This command is used to query information about
234 SILC_CLIENT_CMD_FUNC(whois)
236 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
237 SilcClientConnection conn = cmd->conn;
241 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
246 if (cmd->argc < 2 || cmd->argc > 3) {
247 cmd->client->ops->say(cmd->client, conn,
248 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
253 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
254 cmd->argc - 1, ++cmd->argv,
255 ++cmd->argv_lens, ++cmd->argv_types,
257 silc_client_packet_send(cmd->client, cmd->conn->sock,
258 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
259 buffer->data, buffer->len, TRUE);
260 silc_buffer_free(buffer);
265 /* Notify application */
269 silc_client_command_free(cmd);
272 /* Command WHOWAS. This command is used to query history information about
273 specific user that used to exist in the network. */
275 SILC_CLIENT_CMD_FUNC(whowas)
277 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
278 SilcClientConnection conn = cmd->conn;
282 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
287 if (cmd->argc < 2 || cmd->argc > 3) {
288 cmd->client->ops->say(cmd->client, conn,
289 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
294 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
295 cmd->argc - 1, ++cmd->argv,
296 ++cmd->argv_lens, ++cmd->argv_types,
298 silc_client_packet_send(cmd->client, cmd->conn->sock,
299 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
300 buffer->data, buffer->len, TRUE);
301 silc_buffer_free(buffer);
306 /* Notify application */
310 silc_client_command_free(cmd);
313 /* Command IDENTIFY. This command is used to query information about
314 specific user, especially ID's. */
316 SILC_CLIENT_CMD_FUNC(identify)
318 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
319 SilcClientConnection conn = cmd->conn;
323 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
328 if (cmd->argc < 2 || cmd->argc > 3) {
329 cmd->client->ops->say(cmd->client, conn,
330 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
335 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
336 cmd->argc - 1, ++cmd->argv,
337 ++cmd->argv_lens, ++cmd->argv_types,
339 silc_client_packet_send(cmd->client, cmd->conn->sock,
340 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
341 buffer->data, buffer->len, TRUE);
342 silc_buffer_free(buffer);
347 /* Notify application */
351 silc_client_command_free(cmd);
354 /* Command NICK. Shows current nickname/sets new nickname on current
357 SILC_CLIENT_CMD_FUNC(nick)
359 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
360 SilcClientConnection conn = cmd->conn;
364 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
369 if (!strcmp(conn->nickname, cmd->argv[1]))
372 /* Show current nickname */
375 cmd->client->ops->say(cmd->client, conn,
376 "Your nickname is %s on server %s",
377 conn->nickname, conn->remote_host);
379 cmd->client->ops->say(cmd->client, conn,
380 "Your nickname is %s", conn->nickname);
383 /* XXX Notify application */
388 /* Set new nickname */
389 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
390 cmd->argc - 1, ++cmd->argv,
391 ++cmd->argv_lens, ++cmd->argv_types,
392 ++cmd->conn->cmd_ident);
393 silc_client_packet_send(cmd->client, cmd->conn->sock,
394 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
395 buffer->data, buffer->len, TRUE);
396 silc_buffer_free(buffer);
401 silc_free(conn->nickname);
402 conn->nickname = strdup(cmd->argv[1]);
404 /* Notify application */
408 silc_client_command_free(cmd);
411 /* Command LIST. Lists channels on the current server. */
413 SILC_CLIENT_CMD_FUNC(list)
415 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
416 SilcClientConnection conn = cmd->conn;
417 SilcIDCacheEntry id_cache = NULL;
418 SilcChannelEntry channel;
419 SilcBuffer buffer, idp = NULL;
423 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
428 if (cmd->argc == 2) {
431 /* Get the Channel ID of the channel */
432 if (silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
433 channel = (SilcChannelEntry)id_cache->context;
434 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
439 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
440 ++conn->cmd_ident, 0);
442 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
443 ++conn->cmd_ident, 1,
444 1, idp->data, idp->len);
446 silc_client_packet_send(cmd->client, cmd->conn->sock,
447 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
448 buffer->data, buffer->len, TRUE);
449 silc_buffer_free(buffer);
451 silc_buffer_free(idp);
453 /* Notify application */
457 silc_client_command_free(cmd);
460 /* Command TOPIC. Sets/shows topic on a channel. */
462 SILC_CLIENT_CMD_FUNC(topic)
464 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
465 SilcClientConnection conn = cmd->conn;
466 SilcIDCacheEntry id_cache = NULL;
467 SilcChannelEntry channel;
468 SilcBuffer buffer, idp;
472 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
477 if (cmd->argc < 2 || cmd->argc > 3) {
478 cmd->client->ops->say(cmd->client, conn,
479 "Usage: /TOPIC <channel> [<topic>]");
484 if (cmd->argv[1][0] == '*') {
485 if (!conn->current_channel) {
486 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
490 name = conn->current_channel->channel_name;
495 if (!conn->current_channel) {
496 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
501 /* Get the Channel ID of the channel */
502 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
503 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
508 channel = (SilcChannelEntry)id_cache->context;
510 /* Send TOPIC command to the server */
511 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
513 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
514 1, idp->data, idp->len,
516 strlen(cmd->argv[2]));
518 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
519 1, idp->data, idp->len,
521 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
522 0, NULL, NULL, buffer->data, buffer->len, TRUE);
523 silc_buffer_free(buffer);
524 silc_buffer_free(idp);
526 /* Notify application */
530 silc_client_command_free(cmd);
533 /* Command INVITE. Invites specific client to join a channel. */
535 SILC_CLIENT_CMD_FUNC(invite)
537 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
538 SilcClient client = cmd->client;
539 SilcClientConnection conn = cmd->conn;
540 SilcClientEntry client_entry;
541 SilcChannelEntry channel_entry;
542 SilcBuffer buffer, clidp, chidp;
543 unsigned int num = 0;
544 char *nickname = NULL, *server = NULL;
547 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
552 if (cmd->argc != 3) {
553 cmd->client->ops->say(cmd->client, conn,
554 "Usage: /INVITE <nickname>[@<server>] <channel>");
559 /* Parse the typed nickname. */
560 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
561 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
566 /* Find client entry */
567 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
575 /* Client entry not found, it was requested thus mark this to be
577 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
578 silc_client_command_destructor,
579 silc_client_command_invite,
580 silc_client_command_dup(cmd));
585 /* Find channel entry */
586 channel_entry = silc_client_get_channel(client, conn, cmd->argv[2]);
587 if (!channel_entry) {
588 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
594 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
595 chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
596 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
597 1, clidp->data, clidp->len,
598 2, chidp->data, chidp->len);
599 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
600 0, NULL, NULL, buffer->data, buffer->len, TRUE);
601 silc_buffer_free(buffer);
602 silc_buffer_free(clidp);
603 silc_buffer_free(chidp);
605 cmd->client->ops->say(cmd->client, conn,
606 "Inviting %s to channel %s", cmd->argv[1],
609 /* Notify application */
617 silc_client_command_free(cmd);
622 SilcClientConnection conn;
625 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
627 QuitInternal q = (QuitInternal)context;
629 /* Close connection */
630 q->client->ops->disconnect(q->client, q->conn);
631 silc_client_close_connection(q->client, q->conn->sock->user_data);
636 /* Command QUIT. Closes connection with current server. */
638 SILC_CLIENT_CMD_FUNC(quit)
640 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
645 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
651 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
652 &cmd->argv[1], &cmd->argv_lens[1],
653 &cmd->argv_types[1], 0);
655 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
656 NULL, NULL, NULL, 0);
657 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
659 buffer->data, buffer->len, TRUE);
660 silc_buffer_free(buffer);
662 q = silc_calloc(1, sizeof(*q));
663 q->client = cmd->client;
666 /* We quit the connection with little timeout */
667 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
668 silc_client_command_quit_cb, (void *)q,
669 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
671 /* Notify application */
675 silc_client_command_free(cmd);
678 /* Command KILL. Router operator can use this command to remove an client
679 fromthe SILC Network. */
681 SILC_CLIENT_CMD_FUNC(kill)
683 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
684 SilcClientConnection conn = cmd->conn;
685 SilcBuffer buffer, idp;
686 SilcClientEntry target;
687 unsigned int num = 0;
688 char *nickname = NULL, *server = NULL;
691 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
697 cmd->client->ops->say(cmd->client, conn,
698 "Usage: /KILL <nickname> [<comment>]");
703 /* Parse the typed nickname. */
704 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
705 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
710 /* Get the target client */
711 target = silc_idlist_get_client(cmd->client, conn, nickname,
718 /* Client entry not found, it was requested thus mark this to be
720 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
722 silc_client_command_destructor,
723 silc_client_command_kill,
724 silc_client_command_dup(cmd));
729 /* Send the KILL command to the server */
730 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
732 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
733 1, idp->data, idp->len);
735 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
736 1, idp->data, idp->len,
738 strlen(cmd->argv[2]));
739 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
740 0, NULL, NULL, buffer->data, buffer->len, TRUE);
741 silc_buffer_free(buffer);
742 silc_buffer_free(idp);
744 /* Notify application */
747 /* Remove the client entry to be killed */
748 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
750 if (target->nickname)
751 silc_free(target->nickname);
753 silc_free(target->server);
755 silc_free(target->id);
756 if (target->send_key)
757 silc_cipher_free(target->send_key);
758 if (target->receive_key)
759 silc_cipher_free(target->receive_key);
767 silc_client_command_free(cmd);
770 /* Command INFO. Request information about specific server. If specific
771 server is not provided the current server is used. */
773 SILC_CLIENT_CMD_FUNC(info)
775 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
776 SilcClientConnection conn = cmd->conn;
781 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
787 name = strdup(conn->remote_host);
789 name = strdup(cmd->argv[1]);
791 /* Send the command */
792 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
793 1, name, strlen(name));
794 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
795 0, NULL, NULL, buffer->data, buffer->len, TRUE);
796 silc_buffer_free(buffer);
798 /* Notify application */
802 silc_client_command_free(cmd);
805 /* Command PING. Sends ping to server. This is used to test the
806 communication channel. */
808 SILC_CLIENT_CMD_FUNC(ping)
810 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
811 SilcClientConnection conn = cmd->conn;
818 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
823 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
824 name = strdup(conn->remote_host);
826 /* Send the command */
827 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
828 1, conn->remote_id_data,
830 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
831 0, NULL, NULL, buffer->data, buffer->len, TRUE);
832 silc_buffer_free(buffer);
834 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
837 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
842 /* Start counting time */
843 for (i = 0; i < conn->ping_count; i++) {
844 if (conn->ping[i].dest_id == NULL) {
845 conn->ping[i].start_time = time(NULL);
846 conn->ping[i].dest_id = id;
847 conn->ping[i].dest_name = name;
852 if (i >= conn->ping_count) {
853 i = conn->ping_count;
854 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
855 conn->ping[i].start_time = time(NULL);
856 conn->ping[i].dest_id = id;
857 conn->ping[i].dest_name = name;
861 /* Notify application */
865 silc_client_command_free(cmd);
868 SILC_CLIENT_CMD_FUNC(notice)
872 /* Command JOIN. Joins to a channel. */
874 SILC_CLIENT_CMD_FUNC(join)
876 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
877 SilcClientConnection conn = cmd->conn;
878 SilcIDCacheEntry id_cache = NULL;
879 SilcBuffer buffer, idp;
882 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
888 /* Show channels currently joined to */
893 /* See if we have joined to the requested channel already */
894 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
896 cmd->client->ops->say(cmd->client, conn,
897 "You are talking to channel %s", cmd->argv[1]);
898 conn->current_channel = (SilcChannelEntry)id_cache->context;
900 cmd->client->screen->bottom_line->channel = cmd->argv[1];
901 silc_screen_print_bottom_line(cmd->client->screen, 0);
906 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
908 /* Send JOIN command to the server */
911 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
912 1, cmd->argv[1], cmd->argv_lens[1],
913 2, idp->data, idp->len);
914 else if (cmd->argc == 3)
917 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
918 1, cmd->argv[1], cmd->argv_lens[1],
919 2, idp->data, idp->len,
920 3, cmd->argv[2], cmd->argv_lens[2]);
923 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
924 1, cmd->argv[1], cmd->argv_lens[1],
925 2, idp->data, idp->len,
926 3, cmd->argv[2], cmd->argv_lens[2],
927 4, cmd->argv[3], cmd->argv_lens[3]);
929 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
930 0, NULL, NULL, buffer->data, buffer->len, TRUE);
931 silc_buffer_free(buffer);
932 silc_buffer_free(idp);
934 /* Notify application */
938 silc_client_command_free(cmd);
941 /* MOTD command. Requests motd from server. */
943 SILC_CLIENT_CMD_FUNC(motd)
945 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
946 SilcClientConnection conn = cmd->conn;
950 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
955 if (cmd->argc < 1 || cmd->argc > 2) {
956 cmd->client->ops->say(cmd->client, conn,
957 "Usage: /MOTD [<server>]");
962 /* Send TOPIC command to the server */
964 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
965 1, conn->remote_host,
966 strlen(conn->remote_host));
968 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
971 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
972 0, NULL, NULL, buffer->data, buffer->len, TRUE);
973 silc_buffer_free(buffer);
975 /* Notify application */
979 silc_client_command_free(cmd);
982 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
983 modes as client cannot set itself server/router operator privileges. */
985 SILC_CLIENT_CMD_FUNC(umode)
987 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
988 SilcClientConnection conn = cmd->conn;
989 SilcBuffer buffer, idp;
990 unsigned char *cp, modebuf[4];
991 unsigned int mode, add, len;
995 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1000 if (cmd->argc < 2) {
1001 cmd->client->ops->say(cmd->client, conn,
1002 "Usage: /UMODE +|-<modes>");
1007 mode = conn->local_entry->mode;
1009 /* Are we adding or removing mode */
1010 if (cmd->argv[1][0] == '-')
1016 cp = cmd->argv[1] + 1;
1018 for (i = 0; i < len; i++) {
1023 mode |= SILC_UMODE_SERVER_OPERATOR;
1024 mode |= SILC_UMODE_ROUTER_OPERATOR;
1026 mode = SILC_UMODE_NONE;
1031 mode |= SILC_UMODE_SERVER_OPERATOR;
1033 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1037 mode |= SILC_UMODE_ROUTER_OPERATOR;
1039 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1048 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1049 SILC_PUT32_MSB(mode, modebuf);
1051 /* Send the command packet. We support sending only one mode at once
1052 that requires an argument. */
1054 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1055 1, idp->data, idp->len,
1056 2, modebuf, sizeof(modebuf));
1057 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1058 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1059 silc_buffer_free(buffer);
1060 silc_buffer_free(idp);
1062 /* Notify application */
1066 silc_client_command_free(cmd);
1069 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1070 can be set several at once. Those modes that require argument must be set
1071 separately (unless set with modes that does not require arguments). */
1073 SILC_CLIENT_CMD_FUNC(cmode)
1075 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1076 SilcClientConnection conn = cmd->conn;
1077 SilcChannelEntry channel;
1078 SilcBuffer buffer, chidp;
1079 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1080 unsigned int mode, add, type, len, arg_len = 0;
1084 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1089 if (cmd->argc < 3) {
1090 cmd->client->ops->say(cmd->client, conn,
1091 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1096 if (cmd->argv[1][0] == '*') {
1097 if (!conn->current_channel) {
1098 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1103 channel = conn->current_channel;
1105 name = cmd->argv[1];
1107 channel = silc_client_get_channel(cmd->client, conn, name);
1109 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1115 mode = channel->mode;
1117 /* Are we adding or removing mode */
1118 if (cmd->argv[2][0] == '-')
1123 /* Argument type to be sent to server */
1127 cp = cmd->argv[2] + 1;
1129 for (i = 0; i < len; i++) {
1133 mode |= SILC_CHANNEL_MODE_PRIVATE;
1135 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1139 mode |= SILC_CHANNEL_MODE_SECRET;
1141 mode &= ~SILC_CHANNEL_MODE_SECRET;
1145 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1147 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1151 mode |= SILC_CHANNEL_MODE_INVITE;
1153 mode &= ~SILC_CHANNEL_MODE_INVITE;
1157 mode |= SILC_CHANNEL_MODE_TOPIC;
1159 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1164 mode |= SILC_CHANNEL_MODE_ULIMIT;
1166 ll = atoi(cmd->argv[3]);
1167 SILC_PUT32_MSB(ll, tmp);
1171 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1176 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1179 arg_len = cmd->argv_lens[3];
1181 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1186 mode |= SILC_CHANNEL_MODE_CIPHER;
1189 arg_len = cmd->argv_lens[3];
1191 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1201 if (type && cmd->argc < 3) {
1206 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1207 SILC_PUT32_MSB(mode, modebuf);
1209 /* Send the command packet. We support sending only one mode at once
1210 that requires an argument. */
1213 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1214 1, chidp->data, chidp->len,
1215 2, modebuf, sizeof(modebuf),
1216 type, arg, arg_len);
1219 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1220 1, chidp->data, chidp->len,
1221 2, modebuf, sizeof(modebuf));
1224 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1225 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1226 silc_buffer_free(buffer);
1227 silc_buffer_free(chidp);
1229 /* Notify application */
1233 silc_client_command_free(cmd);
1236 /* CUMODE command. Changes client's mode on a channel. */
1238 SILC_CLIENT_CMD_FUNC(cumode)
1240 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1241 SilcClientConnection conn = cmd->conn;
1242 SilcChannelEntry channel;
1243 SilcChannelUser chu;
1244 SilcClientEntry client_entry;
1245 SilcBuffer buffer, clidp, chidp;
1246 unsigned char *name, *cp, modebuf[4];
1247 unsigned int mode = 0, add, len;
1248 char *nickname = NULL, *server = NULL;
1249 unsigned int num = 0;
1253 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1258 if (cmd->argc < 4) {
1259 cmd->client->ops->say(cmd->client, conn,
1260 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1265 if (cmd->argv[1][0] == '*') {
1266 if (!conn->current_channel) {
1267 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1272 channel = conn->current_channel;
1274 name = cmd->argv[1];
1276 channel = silc_client_get_channel(cmd->client, conn, name);
1278 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1284 /* Parse the typed nickname. */
1285 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1286 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1291 /* Find client entry */
1292 client_entry = silc_idlist_get_client(cmd->client, conn,
1293 nickname, server, num, TRUE);
1294 if (!client_entry) {
1295 /* Client entry not found, it was requested thus mark this to be
1297 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1299 silc_client_command_destructor,
1300 silc_client_command_cumode,
1301 silc_client_command_dup(cmd));
1306 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1307 if (chu->client == client_entry) {
1313 /* Are we adding or removing mode */
1314 if (cmd->argv[2][0] == '-')
1320 cp = cmd->argv[2] + 1;
1322 for (i = 0; i < len; i++) {
1326 mode |= SILC_CHANNEL_UMODE_CHANFO;
1327 mode |= SILC_CHANNEL_UMODE_CHANOP;
1329 mode = SILC_CHANNEL_UMODE_NONE;
1334 mode |= SILC_CHANNEL_UMODE_CHANFO;
1336 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1340 mode |= SILC_CHANNEL_UMODE_CHANOP;
1342 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1351 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1352 SILC_PUT32_MSB(mode, modebuf);
1353 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1355 /* Send the command packet. We support sending only one mode at once
1356 that requires an argument. */
1357 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
1358 1, chidp->data, chidp->len,
1360 3, clidp->data, clidp->len);
1362 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1363 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1364 silc_buffer_free(buffer);
1365 silc_buffer_free(chidp);
1366 silc_buffer_free(clidp);
1368 /* Notify application */
1373 silc_free(nickname);
1376 silc_client_command_free(cmd);
1379 /* KICK command. Kicks a client out of channel. */
1381 SILC_CLIENT_CMD_FUNC(kick)
1383 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1384 SilcClientConnection conn = cmd->conn;
1385 SilcIDCacheEntry id_cache = NULL;
1386 SilcChannelEntry channel;
1387 SilcBuffer buffer, idp, idp2;
1388 SilcClientEntry target;
1390 unsigned int num = 0;
1391 char *nickname = NULL, *server = NULL;
1394 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1399 if (cmd->argc < 3) {
1400 cmd->client->ops->say(cmd->client, conn,
1401 "Usage: /KICK <channel> <nickname> [<comment>]");
1406 if (cmd->argv[1][0] == '*') {
1407 if (!conn->current_channel) {
1408 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1412 name = conn->current_channel->channel_name;
1414 name = cmd->argv[1];
1417 if (!conn->current_channel) {
1418 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1423 /* Get the Channel ID of the channel */
1424 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1425 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1430 channel = (SilcChannelEntry)id_cache->context;
1432 /* Parse the typed nickname. */
1433 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1434 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1439 /* Get the target client */
1440 target = silc_idlist_get_client(cmd->client, conn, nickname,
1441 server, num, FALSE);
1443 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1449 /* Send KICK command to the server */
1450 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1451 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1453 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1454 1, idp->data, idp->len,
1455 2, idp2->data, idp2->len);
1457 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1458 1, idp->data, idp->len,
1459 2, idp2->data, idp2->len,
1461 strlen(cmd->argv[3]));
1462 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1463 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1464 silc_buffer_free(buffer);
1465 silc_buffer_free(idp);
1466 silc_buffer_free(idp2);
1468 /* Notify application */
1473 silc_free(nickname);
1476 silc_client_command_free(cmd);
1479 /* OPER command. Used to obtain server operator privileges. */
1481 SILC_CLIENT_CMD_FUNC(oper)
1483 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1484 SilcClientConnection conn = cmd->conn;
1486 unsigned char *auth_data;
1490 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1495 if (cmd->argc < 2) {
1496 cmd->client->ops->say(cmd->client, conn,
1497 "Usage: /OPER <username> [<public key>]");
1502 if (cmd->argc == 3) {
1503 /* XXX Get public key */
1508 /* Get passphrase */
1510 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1516 /* Encode the authentication payload */
1517 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1518 auth_data, strlen(auth_data));
1521 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1523 strlen(cmd->argv[1]),
1524 2, auth->data, auth->len);
1525 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1526 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1528 silc_buffer_free(buffer);
1529 silc_buffer_free(auth);
1530 memset(auth_data, 0, strlen(auth_data));
1531 silc_free(auth_data);
1533 /* Notify application */
1537 silc_client_command_free(cmd);
1540 /* SILCOPER command. Used to obtain router operator privileges. */
1542 SILC_CLIENT_CMD_FUNC(silcoper)
1544 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1545 SilcClientConnection conn = cmd->conn;
1547 unsigned char *auth_data;
1551 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1556 if (cmd->argc < 2) {
1557 cmd->client->ops->say(cmd->client, conn,
1558 "Usage: /SILCOPER <username> [<public key>]");
1563 if (cmd->argc == 3) {
1564 /* XXX Get public key */
1569 /* Get passphrase */
1571 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1577 /* Encode the authentication payload */
1578 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1579 auth_data, strlen(auth_data));
1582 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1584 strlen(cmd->argv[1]),
1585 2, auth->data, auth->len);
1586 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1587 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1589 silc_buffer_free(buffer);
1590 silc_buffer_free(auth);
1591 memset(auth_data, 0, strlen(auth_data));
1592 silc_free(auth_data);
1594 /* Notify application */
1598 silc_client_command_free(cmd);
1601 /* CONNECT command. Connects the server to another server. */
1603 SILC_CLIENT_CMD_FUNC(connect)
1605 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1606 SilcClientConnection conn = cmd->conn;
1608 unsigned char port[4];
1612 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1617 if (cmd->argc < 2) {
1618 cmd->client->ops->say(cmd->client, conn,
1619 "Usage: /CONNECT <server> [<port>]");
1624 if (cmd->argc == 3) {
1625 tmp = atoi(cmd->argv[2]);
1626 SILC_PUT32_MSB(tmp, port);
1630 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1632 strlen(cmd->argv[1]),
1635 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1637 strlen(cmd->argv[1]));
1638 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1639 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1640 silc_buffer_free(buffer);
1642 /* Notify application */
1646 silc_client_command_free(cmd);
1649 SILC_CLIENT_CMD_FUNC(restart)
1653 /* CLOSE command. Close server connection to the remote server */
1655 SILC_CLIENT_CMD_FUNC(close)
1657 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1658 SilcClientConnection conn = cmd->conn;
1660 unsigned char port[4];
1664 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1669 if (cmd->argc < 2) {
1670 cmd->client->ops->say(cmd->client, conn,
1671 "Usage: /CLOSE <server> [<port>]");
1676 if (cmd->argc == 3) {
1677 tmp = atoi(cmd->argv[2]);
1678 SILC_PUT32_MSB(tmp, port);
1682 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1684 strlen(cmd->argv[1]),
1687 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1689 strlen(cmd->argv[1]));
1690 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1691 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1692 silc_buffer_free(buffer);
1694 /* Notify application */
1698 silc_client_command_free(cmd);
1701 /* SHUTDOWN command. Shutdowns the server. */
1703 SILC_CLIENT_CMD_FUNC(shutdown)
1705 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1708 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1713 /* Send the command */
1714 silc_client_send_command(cmd->client, cmd->conn,
1715 SILC_COMMAND_SHUTDOWN, 0, 0);
1717 /* Notify application */
1721 silc_client_command_free(cmd);
1724 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1726 SILC_CLIENT_CMD_FUNC(leave)
1728 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1729 SilcClientConnection conn = cmd->conn;
1730 SilcIDCacheEntry id_cache = NULL;
1731 SilcChannelEntry channel;
1732 SilcBuffer buffer, idp;
1736 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1741 if (cmd->argc != 2) {
1742 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1747 if (cmd->argv[1][0] == '*') {
1748 if (!conn->current_channel) {
1749 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1753 name = conn->current_channel->channel_name;
1755 name = cmd->argv[1];
1758 if (!conn->current_channel) {
1759 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1764 /* Get the Channel ID of the channel */
1765 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1766 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1771 channel = (SilcChannelEntry)id_cache->context;
1773 /* Send LEAVE command to the server */
1774 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1775 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1776 1, idp->data, idp->len);
1777 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1778 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1779 silc_buffer_free(buffer);
1780 silc_buffer_free(idp);
1782 /* We won't talk anymore on this channel */
1783 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1785 conn->current_channel = NULL;
1787 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1788 silc_free(channel->channel_name);
1789 silc_free(channel->id);
1790 silc_free(channel->key);
1791 silc_cipher_free(channel->channel_key);
1794 /* Notify application */
1798 silc_client_command_free(cmd);
1801 /* Command USERS. Requests the USERS of the clients joined on requested
1804 SILC_CLIENT_CMD_FUNC(users)
1806 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1807 SilcClientConnection conn = cmd->conn;
1808 SilcIDCacheEntry id_cache = NULL;
1809 SilcChannelEntry channel;
1810 SilcBuffer buffer, idp;
1811 char *name, *line = NULL;
1812 unsigned int line_len = 0;
1815 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1820 if (cmd->argc != 2) {
1821 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1826 if (cmd->argv[1][0] == '*') {
1827 if (!conn->current_channel) {
1828 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1832 name = conn->current_channel->channel_name;
1834 name = cmd->argv[1];
1837 if (!conn->current_channel) {
1838 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1843 /* Get the Channel ID of the channel */
1844 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1845 /* XXX should resolve the channel ID; LIST command */
1846 cmd->client->ops->say(cmd->client, conn,
1847 "You are not on that channel", name);
1852 channel = (SilcChannelEntry)id_cache->context;
1854 if (!cmd->pending) {
1855 /* Send USERS command to the server */
1856 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1857 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1858 ++conn->cmd_ident, 1,
1859 1, idp->data, idp->len);
1860 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1861 NULL, 0, NULL, NULL, buffer->data,
1863 silc_buffer_free(buffer);
1864 silc_buffer_free(idp);
1866 /* Register pending callback which will recall this command callback with
1867 same context and reprocesses the command. When reprocessing we actually
1868 display the information on the screen. */
1869 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1870 silc_client_command_destructor,
1871 silc_client_command_users,
1872 silc_client_command_dup(cmd));
1873 cmd->pending = TRUE;
1878 /* Pending command. Now we've resolved the information from server and
1879 we are ready to display the information on screen. */
1881 SilcChannelUser chu;
1883 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1884 channel->channel_name);
1886 line = silc_calloc(4096, sizeof(*line));
1888 silc_list_start(channel->clients);
1889 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1890 SilcClientEntry e = chu->client;
1891 char *m, tmp[80], len1;
1893 memset(line, 0, sizeof(line_len));
1895 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1897 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1898 line = silc_calloc(line_len, sizeof(*line));
1901 memset(tmp, 0, sizeof(tmp));
1902 m = silc_client_chumode_char(chu->mode);
1904 strncat(line, " ", 1);
1905 strncat(line, e->nickname, strlen(e->nickname));
1906 strncat(line, e->server ? "@" : "", 1);
1910 len1 = strlen(e->server);
1911 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1913 len1 = strlen(line);
1915 memset(&line[29], 0, len1 - 29);
1917 for (i = 0; i < 30 - len1 - 1; i++)
1921 strncat(line, " H", 3);
1922 strcat(tmp, m ? m : "");
1923 strncat(line, tmp, strlen(tmp));
1925 if (strlen(tmp) < 5)
1926 for (i = 0; i < 5 - strlen(tmp); i++)
1929 strcat(line, e->username ? e->username : "");
1931 cmd->client->ops->say(cmd->client, conn, "%s", line);
1941 /* Notify application */
1945 silc_client_command_free(cmd);
1948 /* Command BAN. This is used to manage the ban list of the channel. */
1950 SILC_CLIENT_CMD_FUNC(ban)
1952 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1953 SilcClientConnection conn = cmd->conn;
1954 SilcChannelEntry channel;
1955 SilcBuffer buffer, chidp;
1957 char *name, *ban = NULL;
1960 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1965 if (cmd->argc < 2) {
1966 cmd->client->ops->say(cmd->client, conn,
1967 "Usage: /BAN <channel> "
1968 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1973 if (cmd->argv[1][0] == '*') {
1974 if (!conn->current_channel) {
1975 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1980 channel = conn->current_channel;
1982 name = cmd->argv[1];
1984 channel = silc_client_get_channel(cmd->client, conn, name);
1986 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1992 if (cmd->argc == 3) {
1993 if (cmd->argv[2][0] == '+')
2002 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2004 /* Send the command */
2006 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2,
2007 1, chidp->data, chidp->len,
2008 type, ban, strlen(ban));
2010 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1,
2011 1, chidp->data, chidp->len);
2013 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2014 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2015 silc_buffer_free(buffer);
2016 silc_buffer_free(chidp);
2018 /* Notify application */
2022 silc_client_command_free(cmd);