2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001 Timo Sirainen
5 Pekka Riikonen <priikone@poseidon.pspt.fi>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
35 #include "channels-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "silc-nicklist.h"
41 #include "window-item-def.h"
43 #include "fe-common/core/printtext.h"
44 #include "fe-common/silc/module-formats.h"
46 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
47 const char *name, int automatic)
49 SILC_CHANNEL_REC *rec;
51 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
52 g_return_val_if_fail(name != NULL, NULL);
54 rec = g_new0(SILC_CHANNEL_REC, 1);
55 rec->chat_type = SILC_PROTOCOL;
56 rec->name = g_strdup(name);
59 channel_init((CHANNEL_REC *) rec, automatic);
63 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
65 if (!IS_SILC_CHANNEL(channel))
68 if (channel->server != NULL && !channel->left && !channel->kicked) {
69 /* destroying channel record without actually
70 having left the channel yet */
71 silc_command_exec(channel->server, "PART", channel->name);
75 static void silc_channels_join(SILC_SERVER_REC *server,
76 const char *channels, int automatic)
78 char **list, **tmp, *channel;
79 SILC_CHANNEL_REC *chanrec;
81 list = g_strsplit(channels, ",", -1);
82 for (tmp = list; *tmp != NULL; tmp++) {
83 channel = **tmp == '#' ? g_strdup(*tmp) :
84 g_strconcat("#", *tmp, NULL);
86 chanrec = silc_channel_find(server, channel);
92 silc_channel_create(server, channel, FALSE);
93 silc_command_exec(server, "JOIN", channel);
100 static void sig_connected(SILC_SERVER_REC *server)
102 if (IS_SILC_SERVER(server))
103 server->channels_join = (void *) silc_channels_join;
106 /* "server quit" signal from the core to indicate that QUIT command
109 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
111 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
112 silc_command_exec(server, "QUIT", msg);
116 * "event join". Joined to a channel.
119 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
120 SilcChannelEntry entry)
124 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
126 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
127 SILC_CHANNEL_REC *rec = tmp->data;
129 if (rec->entry == entry)
136 static void event_join(SILC_SERVER_REC *server, va_list va)
138 SILC_CHANNEL_REC *chanrec;
139 SILC_NICK_REC *nickrec;
140 SilcClientEntry client;
141 SilcChannelEntry channel;
143 client = va_arg(va, SilcClientEntry);
144 channel = va_arg(va, SilcChannelEntry);
146 if (client == server->conn->local_entry) {
147 /* You joined to channel */
148 chanrec = silc_channel_find(server, channel->channel_name);
149 if (chanrec != NULL && !chanrec->joined)
150 chanrec->entry = channel;
152 chanrec = silc_channel_find_entry(server, channel);
153 if (chanrec != NULL) {
154 SilcChannelUser user;
156 silc_list_start(chanrec->entry->clients);
157 while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
158 if (user->client == client) {
159 nickrec = silc_nicklist_insert(chanrec, user, TRUE);
165 signal_emit("message join", 4, server, channel->channel_name,
167 client->username == NULL ? "" : client->username);
171 * "event leave". Left a channel.
174 static void event_leave(SILC_SERVER_REC *server, va_list va)
176 SILC_CHANNEL_REC *chanrec;
177 SILC_NICK_REC *nickrec;
178 SilcClientEntry client;
179 SilcChannelEntry channel;
181 client = va_arg(va, SilcClientEntry);
182 channel = va_arg(va, SilcChannelEntry);
184 signal_emit("message part", 5, server, channel->channel_name,
185 client->nickname, client->username ? client->username : "",
188 chanrec = silc_channel_find_entry(server, channel);
189 if (chanrec != NULL) {
190 nickrec = silc_nicklist_find(chanrec, client);
192 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
197 * "event signoff". Left the network.
200 static void event_signoff(SILC_SERVER_REC *server, va_list va)
202 SilcClientEntry client;
206 client = va_arg(va, SilcClientEntry);
207 message = va_arg(va, char *);
209 signal_emit("message quit", 4, server, client->nickname,
210 client->username ? client->username : "",
211 message ? message : "");
213 nicks = nicklist_get_same_unique(SERVER(server), client);
214 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
215 CHANNEL_REC *channel = tmp->data;
216 NICK_REC *nickrec = tmp->next->data;
218 nicklist_remove(channel, nickrec);
223 * "event topic". Changed topic.
226 static void event_topic(SILC_SERVER_REC *server, va_list va)
228 SILC_CHANNEL_REC *chanrec;
229 SilcClientEntry client;
230 SilcChannelEntry channel;
233 client = va_arg(va, SilcClientEntry);
234 topic = va_arg(va, char *);
235 channel = va_arg(va, SilcChannelEntry);
237 chanrec = silc_channel_find_entry(server, channel);
238 if (chanrec != NULL) {
239 g_free_not_null(chanrec->topic);
240 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
241 signal_emit("channel topic changed", 1, chanrec);
244 signal_emit("message topic", 5, server, channel->channel_name,
245 topic, client->nickname, client->username);
249 * "event invite". Invited or modified invite list.
252 static void event_invite(SILC_SERVER_REC *server, va_list va)
254 SilcClientEntry client;
255 SilcChannelEntry channel;
258 channel = va_arg(va, SilcChannelEntry);
259 channel_name = va_arg(va, char *);
260 client = va_arg(va, SilcClientEntry);
262 signal_emit("message invite", 4, server, channel ? channel->channel_name :
263 channel_name, client->nickname, client->username);
267 * "event nick". Changed nickname.
270 static void event_nick(SILC_SERVER_REC *server, va_list va)
272 SilcClientEntry oldclient, newclient;
274 oldclient = va_arg(va, SilcClientEntry);
275 newclient = va_arg(va, SilcClientEntry);
277 nicklist_rename_unique(SERVER(server),
278 oldclient, oldclient->nickname,
279 newclient, newclient->nickname);
281 signal_emit("message nick", 4, server, newclient->nickname,
282 oldclient->nickname, newclient->username);
286 * "event cmode". Changed channel mode.
289 static void event_cmode(SILC_SERVER_REC *server, va_list va)
291 SILC_CHANNEL_REC *chanrec;
292 SilcClientEntry client;
293 SilcChannelEntry channel;
297 client = va_arg(va, SilcClientEntry);
298 modei = va_arg(va, uint32);
299 (void)va_arg(va, char *);
300 (void)va_arg(va, char *);
301 channel = va_arg(va, SilcChannelEntry);
303 mode = silc_client_chmode(modei,
304 channel->channel_key->cipher->name,
305 channel->hmac->hmac->name);
307 chanrec = silc_channel_find_entry(server, channel);
308 if (chanrec != NULL) {
309 g_free_not_null(chanrec->mode);
310 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
311 signal_emit("channel mode changed", 1, chanrec);
314 printformat_module("fe-common/silc", server, channel->channel_name,
315 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
316 channel->channel_name, mode ? mode : "removed all",
323 * "event cumode". Changed user's mode on channel.
326 static void event_cumode(SILC_SERVER_REC *server, va_list va)
328 SILC_CHANNEL_REC *chanrec;
329 SilcClientEntry client, destclient;
330 SilcChannelEntry channel;
334 client = va_arg(va, SilcClientEntry);
335 mode = va_arg(va, uint32);
336 destclient = va_arg(va, SilcClientEntry);
337 channel = va_arg(va, SilcChannelEntry);
339 modestr = silc_client_chumode(mode);
340 chanrec = silc_channel_find_entry(server, channel);
341 if (chanrec != NULL) {
344 if (destclient == server->conn->local_entry) {
346 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
349 nick = silc_nicklist_find(chanrec, destclient);
351 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
352 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
353 signal_emit("nick mode changed", 2, chanrec, nick);
357 printformat_module("fe-common/silc", server, channel->channel_name,
358 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
359 channel->channel_name, destclient->nickname,
360 modestr ? modestr : "removed all",
363 if (mode & SILC_CHANNEL_UMODE_CHANFO)
364 printformat_module("fe-common/silc",
365 server, channel->channel_name, MSGLEVEL_CRAP,
366 SILCTXT_CHANNEL_FOUNDER,
367 channel->channel_name, destclient->nickname);
373 * "event motd". Received MOTD.
376 static void event_motd(SILC_SERVER_REC *server, va_list va)
378 char *text = va_arg(va, char *);
380 if (!settings_get_bool("skip_motd"))
381 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
385 * "event channel_change". Channel ID has changed.
388 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
390 /* Nothing interesting to do */
394 * "event server_signoff". Server has quit the network.
397 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
399 SilcClientEntry *clients;
400 uint32 clients_count;
403 (void)va_arg(va, void *);
404 clients = va_arg(va, SilcClientEntry *);
405 clients_count = va_arg(va, uint32);
407 for (i = 0; i < clients_count; i++)
408 signal_emit("message quit", 4, server, clients[i]->nickname,
409 clients[i]->username ? clients[i]->username : "",
414 * "event kick". Someone was kicked from channel.
417 static void event_kick(SILC_SERVER_REC *server, va_list va)
419 SilcClientConnection conn = server->conn;
420 SilcClientEntry client_entry;
421 SilcChannelEntry channel_entry;
423 SILC_CHANNEL_REC *chanrec;
425 client_entry = va_arg(va, SilcClientEntry);
426 tmp = va_arg(va, char *);
427 channel_entry = va_arg(va, SilcChannelEntry);
429 chanrec = silc_channel_find_entry(server, channel_entry);
431 if (client_entry == conn->local_entry) {
432 printformat_module("fe-common/silc", server, channel_entry->channel_name,
433 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
434 channel_entry->channel_name, tmp ? tmp : "");
436 chanrec->kicked = TRUE;
437 channel_destroy((CHANNEL_REC *)chanrec);
440 printformat_module("fe-common/silc", server, channel_entry->channel_name,
441 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
442 client_entry->nickname,
443 channel_entry->channel_name, tmp ? tmp : "");
446 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
448 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
454 * "event kill". Someone was killed from the network.
457 static void event_kill(SILC_SERVER_REC *server, va_list va)
459 SilcClientConnection conn = server->conn;
460 SilcClientEntry client_entry;
463 client_entry = va_arg(va, SilcClientEntry);
464 tmp = va_arg(va, char *);
466 if (client_entry == conn->local_entry) {
467 printformat_module("fe-common/silc", server, NULL,
468 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
471 GSList *nicks, *tmpn;
472 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
473 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
474 CHANNEL_REC *channel = tmpn->data;
475 NICK_REC *nickrec = tmpn->next->data;
476 nicklist_remove(channel, nickrec);
479 printformat_module("fe-common/silc", server, NULL,
480 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
481 client_entry->nickname,
486 /* PART (LEAVE) command. */
488 static void command_part(const char *data, SILC_SERVER_REC *server,
491 SILC_CHANNEL_REC *chanrec;
493 if (!IS_SILC_SERVER(server) || !server->connected)
494 cmd_return_error(CMDERR_NOT_CONNECTED);
496 if (!strcmp(data, "*") || *data == '\0') {
497 if (!IS_SILC_CHANNEL(item))
498 cmd_return_error(CMDERR_NOT_JOINED);
502 chanrec = silc_channel_find(server, data);
504 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
506 signal_emit("message part", 5, server, chanrec->name,
507 server->nick, server->conn->local_entry->username, "");
509 silc_command_exec(server, "LEAVE", chanrec->name);
512 channel_destroy(CHANNEL(chanrec));
515 /* ME local command. */
517 static void command_me(const char *data, SILC_SERVER_REC *server,
520 SILC_CHANNEL_REC *chanrec;
521 char *tmpcmd = "ME", *tmp;
523 unsigned char **argv;
524 uint32 *argv_lens, *argv_types;
527 if (!IS_SILC_SERVER(server) || !server->connected)
528 cmd_return_error(CMDERR_NOT_CONNECTED);
530 if (!IS_SILC_CHANNEL(item))
531 cmd_return_error(CMDERR_NOT_JOINED);
533 /* Now parse all arguments */
534 tmp = g_strconcat(tmpcmd, " ", data, NULL);
535 silc_parse_command_line(tmp, &argv, &argv_lens,
536 &argv_types, &argc, 2);
540 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
542 chanrec = silc_channel_find(server, item->name);
544 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
546 /* Send the action message */
547 silc_client_send_channel_message(silc_client, server->conn,
548 chanrec->entry, NULL,
549 SILC_MESSAGE_FLAG_ACTION,
550 argv[1], argv_lens[1], TRUE);
552 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
553 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
554 server->conn->local_entry->nickname, argv[1]);
556 for (i = 0; i < argc; i++)
558 silc_free(argv_lens);
559 silc_free(argv_types);
562 /* ACTION local command. Same as ME but takes the channel as mandatory
565 static void command_action(const char *data, SILC_SERVER_REC *server,
568 SILC_CHANNEL_REC *chanrec;
569 char *tmpcmd = "ME", *tmp;
571 unsigned char **argv;
572 uint32 *argv_lens, *argv_types;
575 if (!IS_SILC_SERVER(server) || !server->connected)
576 cmd_return_error(CMDERR_NOT_CONNECTED);
578 if (!IS_SILC_CHANNEL(item))
579 cmd_return_error(CMDERR_NOT_JOINED);
581 /* Now parse all arguments */
582 tmp = g_strconcat(tmpcmd, " ", data, NULL);
583 silc_parse_command_line(tmp, &argv, &argv_lens,
584 &argv_types, &argc, 3);
588 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
590 chanrec = silc_channel_find(server, argv[1]);
592 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
594 /* Send the action message */
595 silc_client_send_channel_message(silc_client, server->conn,
596 chanrec->entry, NULL,
597 SILC_MESSAGE_FLAG_ACTION,
598 argv[2], argv_lens[2], TRUE);
600 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
601 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
602 server->conn->local_entry->nickname, argv[2]);
604 for (i = 0; i < argc; i++)
606 silc_free(argv_lens);
607 silc_free(argv_types);
610 /* NOTICE local command. */
612 static void command_notice(const char *data, SILC_SERVER_REC *server,
615 SILC_CHANNEL_REC *chanrec;
616 char *tmpcmd = "ME", *tmp;
618 unsigned char **argv;
619 uint32 *argv_lens, *argv_types;
622 if (!IS_SILC_SERVER(server) || !server->connected)
623 cmd_return_error(CMDERR_NOT_CONNECTED);
625 if (!IS_SILC_CHANNEL(item))
626 cmd_return_error(CMDERR_NOT_JOINED);
628 /* Now parse all arguments */
629 tmp = g_strconcat(tmpcmd, " ", data, NULL);
630 silc_parse_command_line(tmp, &argv, &argv_lens,
631 &argv_types, &argc, 2);
635 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
637 chanrec = silc_channel_find(server, item->name);
639 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
641 /* Send the action message */
642 silc_client_send_channel_message(silc_client, server->conn,
643 chanrec->entry, NULL,
644 SILC_MESSAGE_FLAG_NOTICE,
645 argv[1], argv_lens[1], TRUE);
647 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
648 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
649 server->conn->local_entry->nickname, argv[1]);
651 for (i = 0; i < argc; i++)
653 silc_free(argv_lens);
654 silc_free(argv_types);
657 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
660 static void command_away(const char *data, SILC_SERVER_REC *server,
665 if (!IS_SILC_SERVER(server) || !server->connected)
666 cmd_return_error(CMDERR_NOT_CONNECTED);
669 /* Remove any possible away message */
670 silc_client_set_away_message(silc_client, server->conn, NULL);
673 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
676 /* Set the away message */
677 silc_client_set_away_message(silc_client, server->conn, (char *)data);
680 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
681 SILCTXT_SET_AWAY, data);
684 signal_emit("away mode changed", 1, server);
686 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
690 int type; /* 1 = msg, 2 = channel */
691 SILC_SERVER_REC *server;
694 /* Key agreement callback that is called after the key agreement protocol
695 has been performed. This is called also if error occured during the
696 key agreement protocol. The `key' is the allocated key material and
697 the caller is responsible of freeing it. The `key' is NULL if error
698 has occured. The application can freely use the `key' to whatever
699 purpose it needs. See lib/silcske/silcske.h for the definition of
700 the SilcSKEKeyMaterial structure. */
702 static void keyagr_completion(SilcClient client,
703 SilcClientConnection conn,
704 SilcClientEntry client_entry,
705 SilcKeyAgreementStatus status,
706 SilcSKEKeyMaterial *key,
709 KeyInternal i = (KeyInternal)context;
712 case SILC_KEY_AGREEMENT_OK:
713 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
714 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
717 /* Set the private key for this client */
718 silc_client_del_private_message_key(client, conn, client_entry);
719 silc_client_add_private_message_key_ske(client, conn, client_entry,
721 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
722 SILCTXT_KEY_AGREEMENT_PRIVMSG,
723 client_entry->nickname);
724 silc_ske_free_key_material(key);
729 case SILC_KEY_AGREEMENT_ERROR:
730 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
731 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
734 case SILC_KEY_AGREEMENT_FAILURE:
735 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
736 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
739 case SILC_KEY_AGREEMENT_TIMEOUT:
740 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
741 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
752 /* Local command KEY. This command is used to set and unset private
753 keys for channels, set and unset private keys for private messages
754 with remote clients and to send key agreement requests and
755 negotiate the key agreement protocol with remote client. The
756 key agreement is supported only to negotiate private message keys,
757 it currently cannot be used to negotiate private keys for channels,
758 as it is not convenient for that purpose. */
761 SILC_SERVER_REC *server;
766 /* Callback to be called after client information is resolved from the
769 SILC_CLIENT_CMD_FUNC(key_get_clients)
771 KeyGetClients internal = (KeyGetClients)context;
772 signal_emit("command key", 3, internal->data, internal->server,
774 silc_free(internal->data);
778 static void command_key(const char *data, SILC_SERVER_REC *server,
781 SilcClientConnection conn = server->conn;
782 SilcClientEntry client_entry = NULL;
783 SilcChannelEntry channel_entry = NULL;
785 char *nickname = NULL, *serv = NULL, *tmp;
786 int command = 0, port = 0, type = 0;
787 char *hostname = NULL;
788 KeyInternal internal = NULL;
790 unsigned char **argv;
791 uint32 *argv_lens, *argv_types;
793 if (!IS_SILC_SERVER(server) || !server->connected)
794 cmd_return_error(CMDERR_NOT_CONNECTED);
796 /* Now parse all arguments */
797 tmp = g_strconcat("KEY", " ", data, NULL);
798 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
802 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
803 "set|unset|agreement|negotiate [<arguments>]");
808 if (!strcasecmp(argv[1], "msg"))
810 if (!strcasecmp(argv[1], "channel"))
814 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
815 "set|unset|agreement|negotiate [<arguments>]");
820 if (argv[2][0] == '*') {
823 /* Parse the typed nickname. */
824 if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) {
825 printformat_module("fe-common/silc", server, NULL,
826 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
830 /* Find client entry */
831 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
834 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
835 inter->server = server;
836 inter->data = strdup(data);
839 /* Client entry not found, it was requested thus mark this to be
841 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
843 NULL, silc_client_command_key_get_clients,
851 /* Get channel entry */
854 if (argv[2][0] == '*') {
855 if (!conn->current_channel) {
860 cmd_return_error(CMDERR_NOT_JOINED);
862 name = conn->current_channel->channel_name;
867 channel_entry = silc_client_get_channel(silc_client, conn, name);
868 if (!channel_entry) {
873 cmd_return_error(CMDERR_NOT_JOINED);
878 if (!strcasecmp(argv[3], "set")) {
882 if (type == 1 && client_entry) {
883 /* Set private message key */
885 silc_client_del_private_message_key(silc_client, conn, client_entry);
888 silc_client_add_private_message_key(silc_client, conn, client_entry,
894 silc_client_add_private_message_key(silc_client, conn, client_entry,
900 /* Send the key to the remote client so that it starts using it
902 silc_client_send_private_message_key(silc_client, conn,
904 } else if (type == 2) {
905 /* Set private channel key */
906 char *cipher = NULL, *hmac = NULL;
908 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
909 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
910 SILCTXT_CH_PRIVATE_KEY_NOMODE,
911 channel_entry->channel_name);
920 if (!silc_client_add_channel_private_key(silc_client, conn,
925 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
926 SILCTXT_CH_PRIVATE_KEY_ERROR,
927 channel_entry->channel_name);
931 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
932 SILCTXT_CH_PRIVATE_KEY_ADD,
933 channel_entry->channel_name);
941 if (!strcasecmp(argv[3], "unset")) {
944 if (type == 1 && client_entry) {
945 /* Unset private message key */
946 silc_client_del_private_message_key(silc_client, conn, client_entry);
947 } else if (type == 2) {
948 /* Unset channel key(s) */
949 SilcChannelPrivateKey *keys;
954 silc_client_del_channel_private_keys(silc_client, conn,
958 number = atoi(argv[4]);
959 keys = silc_client_list_channel_private_keys(silc_client, conn,
965 if (!number || number > keys_count) {
966 silc_client_free_channel_private_keys(keys, keys_count);
970 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
972 silc_client_free_channel_private_keys(keys, keys_count);
980 if (!strcasecmp(argv[3], "list")) {
984 SilcPrivateMessageKeys keys;
989 keys = silc_client_list_private_message_keys(silc_client, conn,
994 /* list the private message key(s) */
995 if (nickname[0] == '*') {
996 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
997 SILCTXT_PRIVATE_KEY_LIST);
998 for (k = 0; k < keys_count; k++) {
999 memset(buf, 0, sizeof(buf));
1000 strncat(buf, " ", 2);
1001 len = strlen(keys[k].client_entry->nickname);
1002 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1004 for (i = 0; i < 30 - len; i++)
1008 len = strlen(keys[k].cipher);
1009 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1011 for (i = 0; i < 14 - len; i++)
1016 strcat(buf, "<hidden>");
1018 strcat(buf, "*generated*");
1020 silc_say(silc_client, conn, "%s", buf);
1023 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1024 SILCTXT_PRIVATE_KEY_LIST_NICK,
1025 client_entry->nickname);
1026 for (k = 0; k < keys_count; k++) {
1027 if (keys[k].client_entry != client_entry)
1030 memset(buf, 0, sizeof(buf));
1031 strncat(buf, " ", 2);
1032 len = strlen(keys[k].client_entry->nickname);
1033 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1035 for (i = 0; i < 30 - len; i++)
1039 len = strlen(keys[k].cipher);
1040 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1042 for (i = 0; i < 14 - len; i++)
1047 strcat(buf, "<hidden>");
1049 strcat(buf, "*generated*");
1051 silc_say(silc_client, conn, "%s", buf);
1055 silc_client_free_private_message_keys(keys, keys_count);
1056 } else if (type == 2) {
1057 SilcChannelPrivateKey *keys;
1062 keys = silc_client_list_channel_private_keys(silc_client, conn,
1068 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1069 SILCTXT_CH_PRIVATE_KEY_LIST,
1070 channel_entry->channel_name);
1071 for (k = 0; k < keys_count; k++) {
1072 memset(buf, 0, sizeof(buf));
1073 strncat(buf, " ", 2);
1075 len = strlen(keys[k]->cipher->cipher->name);
1076 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1078 for (i = 0; i < 16 - len; i++)
1082 len = strlen(keys[k]->hmac->hmac->name);
1083 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1085 for (i = 0; i < 16 - len; i++)
1089 strcat(buf, "<hidden>");
1091 silc_say(silc_client, conn, "%s", buf);
1094 silc_client_free_channel_private_keys(keys, keys_count);
1100 /* Send command is used to send key agreement */
1101 if (!strcasecmp(argv[3], "agreement")) {
1107 port = atoi(argv[5]);
1109 internal = silc_calloc(1, sizeof(*internal));
1110 internal->type = type;
1111 internal->server = server;
1114 /* Start command is used to start key agreement (after receiving the
1115 key_agreement client operation). */
1116 if (!strcasecmp(argv[3], "negotiate")) {
1122 port = atoi(argv[5]);
1124 internal = silc_calloc(1, sizeof(*internal));
1125 internal->type = type;
1126 internal->server = server;
1130 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
1131 "set|unset|agreement|negotiate [<arguments>]");
1135 if (command == 4 && client_entry) {
1136 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1137 SILCTXT_KEY_AGREEMENT, argv[2]);
1138 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1139 port, 120, keyagr_completion, internal);
1143 if (command == 5 && client_entry && hostname) {
1144 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1145 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1146 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1147 hostname, port, keyagr_completion,
1154 silc_free(nickname);
1159 void silc_channels_init(void)
1161 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1162 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1163 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1165 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1166 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1167 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1168 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1169 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1170 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1171 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1172 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1173 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1174 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1175 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1176 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1177 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1179 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1180 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1181 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1182 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1183 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1184 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1186 silc_nicklist_init();
1189 void silc_channels_deinit(void)
1191 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1192 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1193 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1195 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1196 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1197 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1198 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1199 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1200 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1201 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1202 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1203 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1204 signal_remove("silc event channel_change",
1205 (SIGNAL_FUNC) event_channel_change);
1206 signal_remove("silc event server_signoff",
1207 (SIGNAL_FUNC) event_server_signoff);
1208 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1209 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1211 command_unbind("part", (SIGNAL_FUNC) command_part);
1212 command_unbind("me", (SIGNAL_FUNC) command_me);
1213 command_unbind("action", (SIGNAL_FUNC) command_action);
1214 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1215 command_unbind("away", (SIGNAL_FUNC) command_away);
1216 command_unbind("key", (SIGNAL_FUNC) command_key);
1218 silc_nicklist_deinit();