5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 #define SILC_NOT_CONNECTED(x, c) \
26 x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27 "You are not connected to a server, use /SERVER to connect");
29 /* Command operation that is called at the end of all commands.
30 Usage: COMMAND(status); */
31 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
32 cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
34 /* Error to application. Usage: COMMAND_ERROR(status); */
35 #define COMMAND_ERROR(status) \
36 cmd->client->internal->ops->command(cmd->client, \
37 cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
39 #define SAY cmd->client->internal->ops->say
41 /* Generic function to send any command. The arguments must be sent already
42 encoded into correct form and in correct order. */
44 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
45 SilcCommand command, SilcUInt16 ident,
53 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
54 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
55 NULL, 0, NULL, NULL, packet->data,
57 silc_buffer_free(packet);
60 /* Finds and returns a pointer to the command list. Return NULL if the
61 command is not found. */
63 SilcClientCommand silc_client_command_find(SilcClient client,
66 SilcClientCommand cmd;
68 silc_list_start(client->internal->commands);
69 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
70 if (cmd->name && !strcmp(cmd->name, name))
77 /* Calls the command (executes it). Application can call this after
78 it has allocated the SilcClientCommandContext with the function
79 silc_client_command_alloc and found the command from the client
80 library by calling silc_client_command_find. This will execute
83 void silc_client_command_call(SilcClientCommand command,
84 SilcClientCommandContext cmd)
86 (*command->command)((void *)cmd, NULL);
89 /* Add new pending command to be executed when reply to a command has been
90 received. The `reply_cmd' is the command that will call the `callback'
91 with `context' when reply has been received. It can be SILC_COMMAND_NONE
92 to match any command with the `ident'. If `ident' is non-zero
93 the `callback' will be executed when received reply with command
94 identifier `ident'. If there already exists pending command for the
95 specified command, ident, callback and context this function has no
98 void silc_client_command_pending(SilcClientConnection conn,
99 SilcCommand reply_cmd,
101 SilcCommandCb callback,
104 SilcClientCommandPending *reply;
106 reply = silc_calloc(1, sizeof(*reply));
107 reply->reply_cmd = reply_cmd;
108 reply->ident = ident;
109 reply->context = context;
110 reply->callback = callback;
111 silc_dlist_add(conn->pending_commands, reply);
114 /* Deletes pending command by reply command type. */
116 void silc_client_command_pending_del(SilcClientConnection conn,
117 SilcCommand reply_cmd,
120 SilcClientCommandPending *r;
122 if (!conn->pending_commands)
125 silc_dlist_start(conn->pending_commands);
126 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
127 if (r->reply_cmd == reply_cmd && r->ident == ident) {
128 silc_dlist_del(conn->pending_commands, r);
134 /* Checks for pending commands and marks callbacks to be called from
135 the command reply function. */
137 SilcClientCommandPendingCallbacks
138 silc_client_command_pending_check(SilcClientConnection conn,
139 SilcClientCommandReplyContext ctx,
142 SilcUInt32 *callbacks_count)
144 SilcClientCommandPending *r;
145 SilcClientCommandPendingCallbacks callbacks = NULL;
148 silc_dlist_start(conn->pending_commands);
149 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
150 if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
151 && r->ident == ident) {
152 callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
153 callbacks[i].context = r->context;
154 callbacks[i].callback = r->callback;
160 *callbacks_count = i;
164 /* Allocate Command Context */
166 SilcClientCommandContext silc_client_command_alloc(void)
168 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
173 /* Free command context and its internals */
175 void silc_client_command_free(SilcClientCommandContext ctx)
178 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
180 if (ctx->users < 1) {
183 for (i = 0; i < ctx->argc; i++)
184 silc_free(ctx->argv[i]);
185 silc_free(ctx->argv_lens);
186 silc_free(ctx->argv_types);
191 /* Duplicate Command Context by adding reference counter. The context won't
192 be free'd untill it hits zero. */
194 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
197 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
202 /* Command WHOIS. This command is used to query information about
205 SILC_CLIENT_CMD_FUNC(whois)
207 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
208 SilcClientConnection conn = cmd->conn;
210 unsigned char count[4];
213 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
214 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
218 /* Given without arguments fetches client's own information */
220 buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
221 silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
223 1, 4, buffer->data, buffer->len);
224 silc_buffer_free(buffer);
228 if (cmd->argc == 2) {
229 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
230 ++conn->cmd_ident, 1,
234 int c = atoi(cmd->argv[2]);
235 memset(count, 0, sizeof(count));
236 SILC_PUT32_MSB(c, count);
237 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
238 ++conn->cmd_ident, 2,
239 1, cmd->argv[1], cmd->argv_lens[1],
240 2, count, sizeof(count));
242 silc_client_packet_send(cmd->client, cmd->conn->sock,
243 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
244 buffer->data, buffer->len, TRUE);
245 silc_buffer_free(buffer);
247 /* Notify application */
248 COMMAND(SILC_STATUS_OK);
251 silc_client_command_free(cmd);
254 /* Command WHOWAS. This command is used to query history information about
255 specific user that used to exist in the network. */
257 SILC_CLIENT_CMD_FUNC(whowas)
259 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
260 SilcClientConnection conn = cmd->conn;
262 unsigned char count[4];
265 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
266 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
270 if (cmd->argc < 2 || cmd->argc > 3) {
271 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
272 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
273 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
274 SILC_STATUS_ERR_TOO_MANY_PARAMS));
278 if (cmd->argc == 2) {
279 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
280 ++conn->cmd_ident, 1,
284 int c = atoi(cmd->argv[2]);
285 memset(count, 0, sizeof(count));
286 SILC_PUT32_MSB(c, count);
287 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
288 ++conn->cmd_ident, 2,
289 1, cmd->argv[1], cmd->argv_lens[1],
290 2, count, sizeof(count));
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);
297 /* Notify application */
298 COMMAND(SILC_STATUS_OK);
301 silc_client_command_free(cmd);
304 /* Command IDENTIFY. This command is used to query information about
305 specific user, especially ID's.
307 NOTE: This command is used only internally by the client library
308 and application MUST NOT call this command directly. */
310 SILC_CLIENT_CMD_FUNC(identify)
312 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
313 SilcClientConnection conn = cmd->conn;
315 unsigned char count[4];
318 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
319 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
323 if (cmd->argc < 2 || cmd->argc > 3)
326 if (cmd->argc == 2) {
327 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
328 ++conn->cmd_ident, 1,
332 int c = atoi(cmd->argv[2]);
333 memset(count, 0, sizeof(count));
334 SILC_PUT32_MSB(c, count);
335 buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
336 ++conn->cmd_ident, 2,
339 4, count, sizeof(count));
342 silc_client_packet_send(cmd->client, cmd->conn->sock,
343 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
344 buffer->data, buffer->len, TRUE);
345 silc_buffer_free(buffer);
348 silc_client_command_free(cmd);
351 /* Command NICK. Shows current nickname/sets new nickname on current
354 SILC_CLIENT_CMD_FUNC(nick)
356 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
357 SilcClientConnection conn = cmd->conn;
361 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
362 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
368 "Usage: /NICK <nickname>");
369 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
373 if (!strcmp(conn->nickname, cmd->argv[1]))
376 /* Show current nickname */
379 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
380 "Your nickname is %s on server %s",
381 conn->nickname, conn->remote_host);
383 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
384 "Your nickname is %s", conn->nickname);
387 COMMAND(SILC_STATUS_OK);
391 if (cmd->argv_lens[1] > 128)
392 cmd->argv_lens[1] = 128;
394 /* Send the NICK command */
395 buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
399 ++cmd->conn->cmd_ident);
400 silc_client_packet_send(cmd->client, cmd->conn->sock,
401 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
402 buffer->data, buffer->len, TRUE);
403 silc_buffer_free(buffer);
406 silc_client_command_free(cmd);
409 /* Command LIST. Lists channels on the current server. */
411 SILC_CLIENT_CMD_FUNC(list)
413 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
414 SilcClientConnection conn = cmd->conn;
415 SilcIDCacheEntry id_cache = NULL;
416 SilcChannelEntry channel;
417 SilcBuffer buffer, idp = NULL;
421 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
422 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
426 if (cmd->argc == 2) {
429 /* Get the Channel ID of the channel */
430 if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
431 channel = (SilcChannelEntry)id_cache->context;
432 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
437 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
438 ++conn->cmd_ident, 0);
440 buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
441 ++conn->cmd_ident, 1,
442 1, idp->data, idp->len);
444 silc_client_packet_send(cmd->client, cmd->conn->sock,
445 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
446 buffer->data, buffer->len, TRUE);
447 silc_buffer_free(buffer);
449 silc_buffer_free(idp);
451 /* Notify application */
452 COMMAND(SILC_STATUS_OK);
455 silc_client_command_free(cmd);
458 /* Command TOPIC. Sets/shows topic on a channel. */
460 SILC_CLIENT_CMD_FUNC(topic)
462 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
463 SilcClientConnection conn = cmd->conn;
464 SilcIDCacheEntry id_cache = NULL;
465 SilcChannelEntry channel;
466 SilcBuffer buffer, idp;
470 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
471 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
475 if (cmd->argc < 2 || cmd->argc > 3) {
476 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
477 "Usage: /TOPIC <channel> [<topic>]");
478 COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
479 SILC_STATUS_ERR_TOO_MANY_PARAMS));
483 if (cmd->argv[1][0] == '*') {
484 if (!conn->current_channel) {
485 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
486 "You are not on any channel");
487 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
490 name = conn->current_channel->channel_name;
495 if (!conn->current_channel) {
496 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
497 "You are not on that channel");
498 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
502 /* Get the Channel ID of the channel */
503 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
504 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
505 "You are not on that channel");
506 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
510 channel = (SilcChannelEntry)id_cache->context;
512 /* Send TOPIC command to the server */
513 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
515 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
516 ++conn->cmd_ident, 2,
517 1, idp->data, idp->len,
519 strlen(cmd->argv[2]));
521 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
522 ++conn->cmd_ident, 1,
523 1, idp->data, idp->len);
524 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
525 0, NULL, NULL, buffer->data, buffer->len, TRUE);
526 silc_buffer_free(buffer);
527 silc_buffer_free(idp);
529 /* Notify application */
530 COMMAND(SILC_STATUS_OK);
533 silc_client_command_free(cmd);
536 /* Command INVITE. Invites specific client to join a channel. This is
537 also used to mange the invite list of the channel. */
539 SILC_CLIENT_CMD_FUNC(invite)
541 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
542 SilcClient client = cmd->client;
543 SilcClientConnection conn = cmd->conn;
544 SilcClientEntry client_entry = NULL;
545 SilcChannelEntry channel;
546 SilcBuffer buffer, clidp, chidp;
548 char *nickname = NULL, *name;
552 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
553 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
558 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
559 "Usage: /INVITE <channel> [<nickname>[@server>]"
560 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
561 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
565 if (cmd->argv[1][0] == '*') {
566 if (!conn->current_channel) {
567 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
568 "You are not on any channel");
569 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
573 channel = conn->current_channel;
577 channel = silc_client_get_channel(cmd->client, conn, name);
579 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
580 "You are on that channel");
581 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
586 /* Parse the typed nickname. */
587 if (cmd->argc == 3) {
588 if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
589 if (client->internal->params->nickname_parse)
590 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
592 nickname = strdup(cmd->argv[2]);
594 /* Find client entry */
595 client_entry = silc_idlist_get_client(client, conn, nickname,
599 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
603 /* Client entry not found, it was requested thus mark this to be
605 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
607 silc_client_command_invite,
608 silc_client_command_dup(cmd));
613 invite = cmd->argv[2];
615 if (cmd->argv[2][0] == '+')
622 /* Send the command */
623 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
625 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
626 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
627 ++conn->cmd_ident, 3,
628 1, chidp->data, chidp->len,
629 2, clidp->data, clidp->len,
630 type, invite, invite ?
632 silc_buffer_free(clidp);
634 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
635 ++conn->cmd_ident, 2,
636 1, chidp->data, chidp->len,
637 type, invite, invite ?
641 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
642 0, NULL, NULL, buffer->data, buffer->len, TRUE);
643 silc_buffer_free(buffer);
644 silc_buffer_free(chidp);
646 /* Notify application */
647 COMMAND(SILC_STATUS_OK);
651 silc_client_command_free(cmd);
656 SilcClientConnection conn;
659 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
661 QuitInternal q = (QuitInternal)context;
663 /* Close connection */
664 q->client->internal->ops->disconnect(q->client, q->conn);
665 silc_client_close_connection(q->client, q->conn->sock->user_data);
670 /* Command QUIT. Closes connection with current server. */
672 SILC_CLIENT_CMD_FUNC(quit)
674 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
679 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
680 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
685 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
686 &cmd->argv[1], &cmd->argv_lens[1],
687 &cmd->argv_types[1], 0);
689 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
690 NULL, NULL, NULL, 0);
691 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
693 buffer->data, buffer->len, TRUE);
694 silc_buffer_free(buffer);
696 q = silc_calloc(1, sizeof(*q));
697 q->client = cmd->client;
700 /* Sleep for a while */
703 /* We quit the connection with little timeout */
704 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
705 silc_client_command_quit_cb, (void *)q,
706 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
708 /* Notify application */
709 COMMAND(SILC_STATUS_OK);
712 silc_client_command_free(cmd);
715 /* Timeout callback to remove the killed client from cache */
717 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
719 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
720 SilcClient client = cmd->client;
721 SilcClientConnection conn = cmd->conn;
722 SilcClientEntry target;
723 char *nickname = NULL;
725 /* Parse the typed nickname. */
726 if (client->internal->params->nickname_parse)
727 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
729 nickname = strdup(cmd->argv[1]);
731 /* Get the target client */
732 target = silc_idlist_get_client(cmd->client, conn, nickname,
733 cmd->argv[1], FALSE);
735 /* Remove the client from all channels and free it */
736 silc_client_del_client(client, conn, target);
739 silc_client_command_free(cmd);
742 /* Kill command's pending command callback to actually remove the killed
743 client from our local cache. */
745 SILC_CLIENT_CMD_FUNC(kill_remove)
747 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
748 SilcClientCommandReplyContext reply =
749 (SilcClientCommandReplyContext)context2;
752 silc_command_get_status(reply->payload, &status, NULL);
753 if (status == SILC_STATUS_OK) {
754 /* Remove with timeout */
755 silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
756 silc_client_command_kill_remove_later, context,
757 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
761 silc_client_command_free(cmd);
764 /* Command KILL. Router operator can use this command to remove an client
765 fromthe SILC Network. */
767 SILC_CLIENT_CMD_FUNC(kill)
769 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
770 SilcClient client = cmd->client;
771 SilcClientConnection conn = cmd->conn;
772 SilcBuffer buffer, idp;
773 SilcClientEntry target;
774 char *nickname = NULL;
777 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
778 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
783 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
784 "Usage: /KILL <nickname> [<comment>]");
785 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
789 /* Parse the typed nickname. */
790 if (client->internal->params->nickname_parse)
791 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
793 nickname = strdup(cmd->argv[1]);
795 /* Get the target client */
796 target = silc_idlist_get_client(cmd->client, conn, nickname,
800 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
804 /* Client entry not found, it was requested thus mark this to be
806 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
808 silc_client_command_kill,
809 silc_client_command_dup(cmd));
814 /* Send the KILL command to the server */
815 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
817 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
818 ++conn->cmd_ident, 1,
819 1, idp->data, idp->len);
821 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL,
822 ++conn->cmd_ident, 2,
823 1, idp->data, idp->len,
825 strlen(cmd->argv[2]));
826 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
827 0, NULL, NULL, buffer->data, buffer->len, TRUE);
828 silc_buffer_free(buffer);
829 silc_buffer_free(idp);
831 /* Notify application */
832 COMMAND(SILC_STATUS_OK);
834 /* Register a pending callback that will actually remove the killed
835 client from our cache. */
836 silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
837 silc_client_command_kill_remove,
838 silc_client_command_dup(cmd));
842 silc_client_command_free(cmd);
845 /* Command INFO. Request information about specific server. If specific
846 server is not provided the current server is used. */
848 SILC_CLIENT_CMD_FUNC(info)
850 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
851 SilcClientConnection conn = cmd->conn;
856 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
857 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
862 name = strdup(cmd->argv[1]);
864 /* Send the command */
866 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
867 1, name, strlen(name));
869 buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
870 NULL, NULL, NULL, 0);
871 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
872 0, NULL, NULL, buffer->data, buffer->len, TRUE);
873 silc_buffer_free(buffer);
877 /* Notify application */
878 COMMAND(SILC_STATUS_OK);
881 silc_client_command_free(cmd);
884 /* Command PING. Sends ping to server. This is used to test the
885 communication channel. */
887 SILC_CLIENT_CMD_FUNC(ping)
889 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
890 SilcClientConnection conn = cmd->conn;
896 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
897 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
901 /* Send the command */
902 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
903 1, conn->remote_id_data,
904 silc_id_get_len(conn->remote_id,
906 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
907 0, NULL, NULL, buffer->data, buffer->len, TRUE);
908 silc_buffer_free(buffer);
910 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
913 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
914 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
918 /* Start counting time */
919 for (i = 0; i < conn->ping_count; i++) {
920 if (conn->ping[i].dest_id == NULL) {
921 conn->ping[i].start_time = time(NULL);
922 conn->ping[i].dest_id = id;
923 conn->ping[i].dest_name = strdup(conn->remote_host);
927 if (i >= conn->ping_count) {
928 i = conn->ping_count;
929 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
930 conn->ping[i].start_time = time(NULL);
931 conn->ping[i].dest_id = id;
932 conn->ping[i].dest_name = strdup(conn->remote_host);
936 /* Notify application */
937 COMMAND(SILC_STATUS_OK);
940 silc_client_command_free(cmd);
943 /* Command JOIN. Joins to a channel. */
945 SILC_CLIENT_CMD_FUNC(join)
947 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
948 SilcClientConnection conn = cmd->conn;
949 SilcChannelEntry channel;
950 SilcBuffer buffer, idp, auth = NULL;
951 char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
952 int i, passphrase_len = 0;
955 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
956 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
961 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
965 /* See if we have joined to the requested channel already */
966 channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
967 if (channel && silc_client_on_channel(channel, conn->local_entry))
970 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
972 if (cmd->argv_lens[1] > 256)
973 cmd->argv_lens[1] = 256;
977 for (i = 2; i < cmd->argc; i++) {
978 if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
979 cipher = cmd->argv[i + 1];
981 } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
982 hmac = cmd->argv[i + 1];
984 } else if (!strcasecmp(cmd->argv[i], "-founder")) {
985 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
986 cmd->client->private_key,
988 cmd->client->internal->
994 /* Passphrases must be UTF-8 encoded, so encode if it is not */
995 if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
996 passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
997 cmd->argv_lens[i], 0);
998 pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
999 passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1000 0, pu8, passphrase_len);
1003 passphrase = strdup(cmd->argv[i]);
1004 passphrase_len = cmd->argv_lens[i];
1009 /* Send JOIN command to the server */
1011 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1012 1, name, strlen(name),
1013 2, idp->data, idp->len,
1014 3, passphrase, passphrase_len,
1015 4, cipher, cipher ? strlen(cipher) : 0,
1016 5, hmac, hmac ? strlen(hmac) : 0,
1017 6, auth ? auth->data : NULL,
1018 auth ? auth->len : 0);
1019 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1020 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1021 silc_buffer_free(buffer);
1022 silc_buffer_free(idp);
1024 silc_buffer_free(auth);
1025 silc_free(passphrase);
1027 /* Notify application */
1028 COMMAND(SILC_STATUS_OK);
1031 silc_client_command_free(cmd);
1034 /* MOTD command. Requests motd from server. */
1036 SILC_CLIENT_CMD_FUNC(motd)
1038 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1039 SilcClientConnection conn = cmd->conn;
1043 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1044 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1048 if (cmd->argc < 1 || cmd->argc > 2) {
1049 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1050 "Usage: /MOTD [<server>]");
1051 COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1052 SILC_STATUS_ERR_TOO_MANY_PARAMS));
1056 /* Send TOPIC command to the server */
1058 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1059 1, conn->remote_host,
1060 strlen(conn->remote_host));
1062 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
1065 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1066 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1067 silc_buffer_free(buffer);
1069 /* Notify application */
1070 COMMAND(SILC_STATUS_OK);
1073 silc_client_command_free(cmd);
1076 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1077 modes as client cannot set itself server/router operator privileges. */
1079 SILC_CLIENT_CMD_FUNC(umode)
1081 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1082 SilcClientConnection conn = cmd->conn;
1083 SilcBuffer buffer, idp;
1084 unsigned char *cp, modebuf[4];
1085 SilcUInt32 mode, add, len;
1089 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1090 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1094 if (cmd->argc < 2) {
1095 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1096 "Usage: /UMODE +|-<modes>");
1097 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1101 mode = conn->local_entry->mode;
1103 /* Are we adding or removing mode */
1104 if (cmd->argv[1][0] == '-')
1110 cp = cmd->argv[1] + 1;
1112 for (i = 0; i < len; i++) {
1117 mode |= SILC_UMODE_SERVER_OPERATOR;
1118 mode |= SILC_UMODE_ROUTER_OPERATOR;
1119 mode |= SILC_UMODE_GONE;
1120 mode |= SILC_UMODE_INDISPOSED;
1121 mode |= SILC_UMODE_BUSY;
1122 mode |= SILC_UMODE_PAGE;
1123 mode |= SILC_UMODE_HYPER;
1124 mode |= SILC_UMODE_ROBOT;
1125 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1126 mode |= SILC_UMODE_REJECT_WATCHING;
1128 mode = SILC_UMODE_NONE;
1133 mode |= SILC_UMODE_SERVER_OPERATOR;
1135 mode &= ~SILC_UMODE_SERVER_OPERATOR;
1139 mode |= SILC_UMODE_ROUTER_OPERATOR;
1141 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1145 mode |= SILC_UMODE_GONE;
1147 mode &= ~SILC_UMODE_GONE;
1151 mode |= SILC_UMODE_INDISPOSED;
1153 mode &= ~SILC_UMODE_INDISPOSED;
1157 mode |= SILC_UMODE_BUSY;
1159 mode &= ~SILC_UMODE_BUSY;
1163 mode |= SILC_UMODE_PAGE;
1165 mode &= ~SILC_UMODE_PAGE;
1169 mode |= SILC_UMODE_HYPER;
1171 mode &= ~SILC_UMODE_HYPER;
1175 mode |= SILC_UMODE_ROBOT;
1177 mode &= ~SILC_UMODE_ROBOT;
1181 mode |= SILC_UMODE_BLOCK_PRIVMSG;
1183 mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1187 mode |= SILC_UMODE_REJECT_WATCHING;
1189 mode &= ~SILC_UMODE_REJECT_WATCHING;
1193 mode |= SILC_UMODE_BLOCK_INVITE;
1195 mode &= ~SILC_UMODE_BLOCK_INVITE;
1198 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1204 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1205 SILC_PUT32_MSB(mode, modebuf);
1207 /* Send the command packet. We support sending only one mode at once
1208 that requires an argument. */
1210 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1211 1, idp->data, idp->len,
1212 2, modebuf, sizeof(modebuf));
1213 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1214 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1215 silc_buffer_free(buffer);
1216 silc_buffer_free(idp);
1218 /* Notify application */
1219 COMMAND(SILC_STATUS_OK);
1222 silc_client_command_free(cmd);
1225 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1226 can be set several at once. Those modes that require argument must be set
1227 separately (unless set with modes that does not require arguments). */
1229 SILC_CLIENT_CMD_FUNC(cmode)
1231 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1232 SilcClientConnection conn = cmd->conn;
1233 SilcChannelEntry channel;
1234 SilcBuffer buffer, chidp, auth = NULL;
1235 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1236 SilcUInt32 mode, add, type, len, arg_len = 0;
1240 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1241 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1245 if (cmd->argc < 3) {
1246 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1247 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1248 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1252 if (cmd->argv[1][0] == '*') {
1253 if (!conn->current_channel) {
1254 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1255 "You are not on any channel");
1256 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1260 channel = conn->current_channel;
1262 name = cmd->argv[1];
1264 channel = silc_client_get_channel(cmd->client, conn, name);
1266 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1267 "You are on that channel");
1268 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1273 mode = channel->mode;
1275 /* Are we adding or removing mode */
1276 if (cmd->argv[2][0] == '-')
1281 /* Argument type to be sent to server */
1285 cp = cmd->argv[2] + 1;
1287 for (i = 0; i < len; i++) {
1291 mode |= SILC_CHANNEL_MODE_PRIVATE;
1293 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1297 mode |= SILC_CHANNEL_MODE_SECRET;
1299 mode &= ~SILC_CHANNEL_MODE_SECRET;
1303 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1305 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1309 mode |= SILC_CHANNEL_MODE_INVITE;
1311 mode &= ~SILC_CHANNEL_MODE_INVITE;
1315 mode |= SILC_CHANNEL_MODE_TOPIC;
1317 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1321 mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1323 mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1327 mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1329 mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1334 mode |= SILC_CHANNEL_MODE_ULIMIT;
1336 if (cmd->argc < 4) {
1337 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1338 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1339 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1342 ll = atoi(cmd->argv[3]);
1343 SILC_PUT32_MSB(ll, tmp);
1347 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1352 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1354 if (cmd->argc < 4) {
1355 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1356 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1357 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1361 arg_len = cmd->argv_lens[3];
1363 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1368 mode |= SILC_CHANNEL_MODE_CIPHER;
1370 if (cmd->argc < 4) {
1371 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1372 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1373 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1377 arg_len = cmd->argv_lens[3];
1379 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1384 mode |= SILC_CHANNEL_MODE_HMAC;
1386 if (cmd->argc < 4) {
1387 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1388 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1389 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1393 arg_len = cmd->argv_lens[3];
1395 mode &= ~SILC_CHANNEL_MODE_HMAC;
1400 mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1402 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1403 cmd->client->private_key,
1405 cmd->client->internal->
1410 arg_len = auth->len;
1412 mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1416 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1422 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1423 SILC_PUT32_MSB(mode, modebuf);
1425 /* Send the command packet. We support sending only one mode at once
1426 that requires an argument. */
1429 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1430 1, chidp->data, chidp->len,
1431 2, modebuf, sizeof(modebuf),
1432 type, arg, arg_len);
1435 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1436 1, chidp->data, chidp->len,
1437 2, modebuf, sizeof(modebuf));
1440 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1441 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1442 silc_buffer_free(buffer);
1443 silc_buffer_free(chidp);
1445 silc_buffer_free(auth);
1447 /* Notify application */
1448 COMMAND(SILC_STATUS_OK);
1451 silc_client_command_free(cmd);
1454 /* CUMODE command. Changes client's mode on a channel. */
1456 SILC_CLIENT_CMD_FUNC(cumode)
1458 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1459 SilcClient client = cmd->client;
1460 SilcClientConnection conn = cmd->conn;
1461 SilcChannelEntry channel;
1462 SilcChannelUser chu;
1463 SilcClientEntry client_entry;
1464 SilcBuffer buffer, clidp, chidp, auth = NULL;
1465 unsigned char *name, *cp, modebuf[4];
1466 SilcUInt32 mode = 0, add, len;
1467 char *nickname = NULL;
1471 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1472 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1476 if (cmd->argc < 4) {
1477 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1478 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1479 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 if (cmd->argv[1][0] == '*') {
1484 if (!conn->current_channel) {
1485 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1486 "You are not on any channel");
1487 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1491 channel = conn->current_channel;
1493 name = cmd->argv[1];
1495 channel = silc_client_get_channel(cmd->client, conn, name);
1497 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1498 "You are on that channel");
1499 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1504 /* Parse the typed nickname. */
1505 if (client->internal->params->nickname_parse)
1506 client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1508 nickname = strdup(cmd->argv[3]);
1510 /* Find client entry */
1511 client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1512 cmd->argv[3], TRUE);
1513 if (!client_entry) {
1515 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1519 /* Client entry not found, it was requested thus mark this to be
1521 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1523 silc_client_command_cumode,
1524 silc_client_command_dup(cmd));
1529 /* Get the current mode */
1530 chu = silc_client_on_channel(channel, client_entry);
1534 /* Are we adding or removing mode */
1535 if (cmd->argv[2][0] == '-')
1541 cp = cmd->argv[2] + 1;
1543 for (i = 0; i < len; i++) {
1547 mode |= SILC_CHANNEL_UMODE_CHANFO;
1548 mode |= SILC_CHANNEL_UMODE_CHANOP;
1549 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1550 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1551 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1553 mode = SILC_CHANNEL_UMODE_NONE;
1558 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1559 cmd->client->private_key,
1561 cmd->client->internal->
1565 mode |= SILC_CHANNEL_UMODE_CHANFO;
1567 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1572 mode |= SILC_CHANNEL_UMODE_CHANOP;
1574 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1578 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1580 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1584 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1586 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1590 mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1592 mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1595 COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1601 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1602 SILC_PUT32_MSB(mode, modebuf);
1603 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1605 /* Send the command packet. We support sending only one mode at once
1606 that requires an argument. */
1607 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
1609 1, chidp->data, chidp->len,
1611 3, clidp->data, clidp->len,
1612 4, auth ? auth->data : NULL,
1613 auth ? auth->len : 0);
1615 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1616 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1617 silc_buffer_free(buffer);
1618 silc_buffer_free(chidp);
1619 silc_buffer_free(clidp);
1621 silc_buffer_free(auth);
1623 /* Notify application */
1624 COMMAND(SILC_STATUS_OK);
1627 silc_free(nickname);
1628 silc_client_command_free(cmd);
1631 /* KICK command. Kicks a client out of channel. */
1633 SILC_CLIENT_CMD_FUNC(kick)
1635 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1636 SilcClient client = cmd->client;
1637 SilcClientConnection conn = cmd->conn;
1638 SilcIDCacheEntry id_cache = NULL;
1639 SilcChannelEntry channel;
1640 SilcBuffer buffer, idp, idp2;
1641 SilcClientEntry target;
1643 char *nickname = NULL;
1646 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1647 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1651 if (cmd->argc < 3) {
1652 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1653 "Usage: /KICK <channel> <nickname> [<comment>]");
1654 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1658 if (cmd->argv[1][0] == '*') {
1659 if (!conn->current_channel) {
1660 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1661 "You are not on any channel");
1662 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1665 name = conn->current_channel->channel_name;
1667 name = cmd->argv[1];
1670 if (!conn->current_channel) {
1671 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1672 "You are not on that channel");
1673 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1677 /* Get the Channel ID of the channel */
1678 if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1679 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1680 "You are not on that channel");
1681 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1685 channel = (SilcChannelEntry)id_cache->context;
1687 /* Parse the typed nickname. */
1688 if (client->internal->params->nickname_parse)
1689 client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1691 nickname = strdup(cmd->argv[2]);
1693 /* Get the target client */
1694 target = silc_idlist_get_client(cmd->client, conn, nickname,
1695 cmd->argv[2], FALSE);
1697 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1698 "No such client: %s", cmd->argv[2]);
1699 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1703 /* Send KICK command to the server */
1704 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1705 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1707 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1708 1, idp->data, idp->len,
1709 2, idp2->data, idp2->len);
1711 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1712 1, idp->data, idp->len,
1713 2, idp2->data, idp2->len,
1715 strlen(cmd->argv[3]));
1716 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1717 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1718 silc_buffer_free(buffer);
1719 silc_buffer_free(idp);
1720 silc_buffer_free(idp2);
1722 /* Notify application */
1723 COMMAND(SILC_STATUS_OK);
1726 silc_free(nickname);
1727 silc_client_command_free(cmd);
1730 static void silc_client_command_oper_send(unsigned char *data,
1731 SilcUInt32 data_len, void *context)
1733 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1734 SilcClientConnection conn = cmd->conn;
1735 SilcBuffer buffer, auth;
1737 if (cmd->argc >= 3) {
1738 /* Encode the public key authentication payload */
1739 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1740 cmd->client->private_key,
1741 cmd->client->rng, conn->hash,
1745 /* Encode the password authentication payload */
1746 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1750 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1752 strlen(cmd->argv[1]),
1753 2, auth ? auth->data : NULL,
1754 auth ? auth->len : 0);
1755 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1756 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1758 silc_buffer_free(buffer);
1759 silc_buffer_free(auth);
1761 /* Notify application */
1762 COMMAND(SILC_STATUS_OK);
1765 /* OPER command. Used to obtain server operator privileges. */
1767 SILC_CLIENT_CMD_FUNC(oper)
1769 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1770 SilcClientConnection conn = cmd->conn;
1773 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1774 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1778 if (cmd->argc < 2) {
1779 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1780 "Usage: /OPER <username> [-pubkey]");
1781 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1785 if (cmd->argc < 3) {
1786 /* Get passphrase */
1787 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1788 silc_client_command_oper_send,
1793 silc_client_command_oper_send(NULL, 0, context);
1796 silc_client_command_free(cmd);
1799 static void silc_client_command_silcoper_send(unsigned char *data,
1800 SilcUInt32 data_len,
1803 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1804 SilcClientConnection conn = cmd->conn;
1805 SilcBuffer buffer, auth;
1807 if (cmd->argc >= 3) {
1808 /* Encode the public key authentication payload */
1809 auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1810 cmd->client->private_key,
1811 cmd->client->rng, conn->hash,
1815 /* Encode the password authentication payload */
1816 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1820 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1822 strlen(cmd->argv[1]),
1823 2, auth ? auth->data : NULL,
1824 auth ? auth->len : 0);
1825 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1826 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1828 silc_buffer_free(buffer);
1829 silc_buffer_free(auth);
1831 /* Notify application */
1832 COMMAND(SILC_STATUS_OK);
1835 /* SILCOPER command. Used to obtain router operator privileges. */
1837 SILC_CLIENT_CMD_FUNC(silcoper)
1839 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1840 SilcClientConnection conn = cmd->conn;
1843 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1844 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1848 if (cmd->argc < 2) {
1849 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1850 "Usage: /SILCOPER <username> [-pubkey]");
1851 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1855 if (cmd->argc < 3) {
1856 /* Get passphrase */
1857 cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1858 silc_client_command_silcoper_send,
1863 silc_client_command_silcoper_send(NULL, 0, context);
1866 silc_client_command_free(cmd);
1869 /* Command BAN. This is used to manage the ban list of the channel. */
1871 SILC_CLIENT_CMD_FUNC(ban)
1873 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1874 SilcClientConnection conn = cmd->conn;
1875 SilcChannelEntry channel;
1876 SilcBuffer buffer, chidp;
1878 char *name, *ban = NULL;
1881 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1882 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1886 if (cmd->argc < 2) {
1887 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1888 "Usage: /BAN <channel> "
1889 "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1890 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1894 if (cmd->argv[1][0] == '*') {
1895 if (!conn->current_channel) {
1896 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1897 "You are not on any channel");
1898 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1902 channel = conn->current_channel;
1904 name = cmd->argv[1];
1906 channel = silc_client_get_channel(cmd->client, conn, name);
1908 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1909 "You are noton that channel");
1910 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1915 if (cmd->argc == 3) {
1916 if (cmd->argv[2][0] == '+')
1925 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1927 /* Send the command */
1928 buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
1929 ++conn->cmd_ident, 2,
1930 1, chidp->data, chidp->len,
1931 type, ban, ban ? strlen(ban) : 0);
1932 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1933 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1934 silc_buffer_free(buffer);
1935 silc_buffer_free(chidp);
1937 /* Notify application */
1938 COMMAND(SILC_STATUS_OK);
1941 silc_client_command_free(cmd);
1944 /* Command DETACH. This is used to detach from the server */
1946 SILC_CLIENT_CMD_FUNC(detach)
1948 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1949 SilcClientConnection conn = cmd->conn;
1953 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1954 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1958 buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1959 ++conn->cmd_ident, 0);
1960 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1961 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1962 silc_buffer_free(buffer);
1964 /* Notify application */
1965 COMMAND(SILC_STATUS_OK);
1968 silc_client_command_free(cmd);
1971 /* Command WATCH. */
1973 SILC_CLIENT_CMD_FUNC(watch)
1975 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1976 SilcClientConnection conn = cmd->conn;
1977 SilcBuffer buffer, idp = NULL;
1981 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1982 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1986 if (cmd->argc < 3) {
1987 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1991 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1993 if (!strcasecmp(cmd->argv[1], "-add")) {
1995 } else if (!strcasecmp(cmd->argv[1], "-del")) {
1998 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2002 buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
2003 ++conn->cmd_ident, 2,
2004 1, idp->data, idp->len,
2007 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2008 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2009 silc_buffer_free(buffer);
2011 /* Notify application */
2012 COMMAND(SILC_STATUS_OK);
2016 silc_buffer_free(idp);
2017 silc_client_command_free(cmd);
2020 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2022 SILC_CLIENT_CMD_FUNC(leave)
2024 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2025 SilcClientConnection conn = cmd->conn;
2026 SilcChannelEntry channel;
2027 SilcChannelUser chu;
2028 SilcBuffer buffer, idp;
2032 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2033 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2037 if (cmd->argc != 2) {
2038 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2039 "Usage: /LEAVE <channel>");
2040 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2044 if (cmd->argv[1][0] == '*') {
2045 if (!conn->current_channel) {
2046 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2047 "You are not on any channel");
2048 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2051 name = conn->current_channel->channel_name;
2053 name = cmd->argv[1];
2056 /* Get the channel entry */
2057 channel = silc_client_get_channel(cmd->client, conn, name);
2059 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2060 "You are not on that channel");
2061 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2065 /* Remove us from channel */
2066 chu = silc_client_on_channel(channel, conn->local_entry);
2068 silc_hash_table_del(chu->client->channels, chu->channel);
2069 silc_hash_table_del(chu->channel->user_list, chu->client);
2073 /* Send LEAVE command to the server */
2074 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2075 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
2076 1, idp->data, idp->len);
2077 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2078 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2079 silc_buffer_free(buffer);
2080 silc_buffer_free(idp);
2082 /* Notify application */
2083 COMMAND(SILC_STATUS_OK);
2085 if (conn->current_channel == channel)
2086 conn->current_channel = NULL;
2088 silc_client_del_channel(cmd->client, cmd->conn, channel);
2091 silc_client_command_free(cmd);
2094 /* Command USERS. Requests the USERS of the clients joined on requested
2097 SILC_CLIENT_CMD_FUNC(users)
2099 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2100 SilcClientConnection conn = cmd->conn;
2105 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2106 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2110 if (cmd->argc != 2) {
2111 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2112 "Usage: /USERS <channel>");
2113 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2117 if (cmd->argv[1][0] == '*') {
2118 if (!conn->current_channel) {
2119 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2120 "You are not on any channel");
2121 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2124 name = conn->current_channel->channel_name;
2126 name = cmd->argv[1];
2129 /* Send USERS command to the server */
2130 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
2131 ++conn->cmd_ident, 1,
2132 2, name, strlen(name));
2133 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
2134 NULL, 0, NULL, NULL, buffer->data,
2136 silc_buffer_free(buffer);
2138 /* Notify application */
2139 COMMAND(SILC_STATUS_OK);
2142 silc_client_command_free(cmd);
2145 /* Command GETKEY. Used to fetch remote client's public key. */
2147 SILC_CLIENT_CMD_FUNC(getkey)
2149 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2150 SilcClientConnection conn = cmd->conn;
2151 SilcClient client = cmd->client;
2152 SilcClientEntry client_entry = NULL;
2153 SilcServerEntry server_entry = NULL;
2154 char *nickname = NULL;
2155 SilcBuffer idp, buffer;
2157 SILC_LOG_DEBUG(("Start"));
2160 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2161 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2165 if (cmd->argc < 2) {
2166 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
2167 "Usage: /GETKEY <nickname or server name>");
2168 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2172 /* Parse the typed nickname. */
2173 if (client->internal->params->nickname_parse)
2174 client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2176 nickname = strdup(cmd->argv[1]);
2178 /* Find client entry */
2179 client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2181 if (!client_entry) {
2182 /* Check whether user requested server actually */
2183 server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2185 if (!server_entry) {
2186 /* No. what ever user wants we don't have it, so resolve it. We
2187 will first try to resolve the client, and if that fails then
2188 we'll try to resolve the server. */
2190 if (!cmd->pending) {
2191 /* This will send the IDENTIFY command for nickname */
2192 silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2193 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2195 silc_client_command_getkey,
2196 silc_client_command_dup(cmd));
2200 SilcClientCommandReplyContext reply =
2201 (SilcClientCommandReplyContext)context2;
2204 /* If nickname was not found, then resolve the server. */
2205 silc_command_get_status(reply->payload, NULL, &error);
2206 if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2207 /* This sends the IDENTIFY command to resolve the server. */
2208 silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
2210 silc_client_command_reply_identify_i, 0,
2212 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2214 2, cmd->argv[1], cmd->argv_lens[1]);
2215 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
2217 silc_client_command_getkey,
2218 silc_client_command_dup(cmd));
2222 /* If server was not found, then we've resolved both nickname and
2223 server and did not find anybody. */
2224 if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2225 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2226 silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2227 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
2228 silc_get_status_message(error));
2229 COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2233 COMMAND_ERROR(error);
2238 idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2240 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2243 buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
2244 1, idp->data, idp->len);
2245 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2246 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2247 silc_buffer_free(buffer);
2248 silc_buffer_free(idp);
2250 /* Notify application */
2251 COMMAND(SILC_STATUS_OK);
2254 silc_free(nickname);
2255 silc_client_command_free(cmd);
2258 /* Register a new command indicated by the `command' to the SILC client.
2259 The `name' is optional command name. If provided the command may be
2260 searched using the silc_client_command_find by that name. The
2261 `command_function' is the function to be called when the command is
2262 executed, and the `command_reply_function' is the function to be
2263 called after the server has sent reply back to the command.
2265 The `ident' is optional identifier for the command. If non-zero
2266 the `command_reply_function' for the command type `command' will be
2267 called only if the command reply sent by server includes the
2268 command identifier `ident'. Application usually does not need it
2269 and set it to zero value. */
2271 bool silc_client_command_register(SilcClient client,
2272 SilcCommand command,
2274 SilcCommandCb command_function,
2275 SilcCommandCb command_reply_function,
2279 SilcClientCommand cmd;
2281 cmd = silc_calloc(1, sizeof(*cmd));
2283 cmd->command = command_function;
2284 cmd->reply = command_reply_function;
2285 cmd->name = name ? strdup(name) : NULL;
2286 cmd->max_args = max_args;
2289 silc_list_add(client->internal->commands, cmd);
2294 /* Unregister a command indicated by the `command' with command function
2295 `command_function' and command reply function `command_reply_function'.
2296 Returns TRUE if the command was found and unregistered. */
2298 bool silc_client_command_unregister(SilcClient client,
2299 SilcCommand command,
2300 SilcCommandCb command_function,
2301 SilcCommandCb command_reply_function,
2304 SilcClientCommand cmd;
2306 silc_list_start(client->internal->commands);
2307 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2308 if (cmd->cmd == command && cmd->command == command_function &&
2309 cmd->reply == command_reply_function && cmd->ident == ident) {
2310 silc_list_del(client->internal->commands, cmd);
2311 silc_free(cmd->name);
2320 /* Private range commands, specific to this implementation (and compatible
2321 with SILC Server). */
2323 /* CONNECT command. Connects the server to another server. */
2325 SILC_CLIENT_CMD_FUNC(connect)
2327 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2328 SilcClientConnection conn = cmd->conn;
2330 unsigned char port[4];
2334 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2335 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2339 if (cmd->argc < 2) {
2340 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2341 "Usage: /CONNECT <server> [<port>]");
2342 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2346 if (cmd->argc == 3) {
2347 tmp = atoi(cmd->argv[2]);
2348 SILC_PUT32_MSB(tmp, port);
2352 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
2354 strlen(cmd->argv[1]),
2357 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2359 strlen(cmd->argv[1]));
2360 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2361 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2362 silc_buffer_free(buffer);
2364 /* Notify application */
2365 COMMAND(SILC_STATUS_OK);
2368 silc_client_command_free(cmd);
2372 /* CLOSE command. Close server connection to the remote server */
2374 SILC_CLIENT_CMD_FUNC(close)
2376 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2377 SilcClientConnection conn = cmd->conn;
2379 unsigned char port[4];
2383 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2384 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2388 if (cmd->argc < 2) {
2389 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
2390 "Usage: /CLOSE <server> [<port>]");
2391 COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2395 if (cmd->argc == 3) {
2396 tmp = atoi(cmd->argv[2]);
2397 SILC_PUT32_MSB(tmp, port);
2401 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
2403 strlen(cmd->argv[1]),
2406 buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2408 strlen(cmd->argv[1]));
2409 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2410 0, NULL, NULL, buffer->data, buffer->len, TRUE);
2411 silc_buffer_free(buffer);
2413 /* Notify application */
2414 COMMAND(SILC_STATUS_OK);
2417 silc_client_command_free(cmd);
2420 /* SHUTDOWN command. Shutdowns the server. */
2422 SILC_CLIENT_CMD_FUNC(shutdown)
2424 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2427 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2428 COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2432 /* Send the command */
2433 silc_client_command_send(cmd->client, cmd->conn,
2434 SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2436 /* Notify application */
2437 COMMAND(SILC_STATUS_OK);
2440 silc_client_command_free(cmd);
2443 /* Register all default commands provided by the client library for the
2446 void silc_client_commands_register(SilcClient client)
2448 silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
2451 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2452 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2453 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2454 SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2455 SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2456 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2457 SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2458 SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2459 SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2460 SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2461 SILC_CLIENT_CMD(ping, PING, "PING", 2);
2462 SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2463 SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2464 SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2465 SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2466 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2467 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2468 SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2469 SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2470 SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2471 SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2472 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2473 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2474 SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2475 SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2477 SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2478 SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2479 SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2482 /* Unregister all commands. */
2484 void silc_client_commands_unregister(SilcClient client)
2486 SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2487 SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2488 SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2489 SILC_CLIENT_CMDU(nick, NICK, "NICK");
2490 SILC_CLIENT_CMDU(list, LIST, "LIST");
2491 SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2492 SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2493 SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2494 SILC_CLIENT_CMDU(kill, KILL, "KILL");
2495 SILC_CLIENT_CMDU(info, INFO, "INFO");
2496 SILC_CLIENT_CMDU(ping, PING, "PING");
2497 SILC_CLIENT_CMDU(oper, OPER, "OPER");
2498 SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2499 SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2500 SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2501 SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2502 SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2503 SILC_CLIENT_CMDU(kick, KICK, "KICK");
2504 SILC_CLIENT_CMDU(ban, BAN, "BAN");
2505 SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2506 SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2507 SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2508 SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2509 SILC_CLIENT_CMDU(users, USERS, "USERS");
2510 SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2512 SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2513 SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2514 SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");