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 signal_emit("nick mode changed", 2, chanrec, nick);
356 printformat_module("fe-common/silc", server, channel->channel_name,
357 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
358 channel->channel_name, destclient->nickname,
359 modestr ? modestr : "removed all",
362 if (mode & SILC_CHANNEL_UMODE_CHANFO)
363 printformat_module("fe-common/silc",
364 server, channel->channel_name, MSGLEVEL_CRAP,
365 SILCTXT_CHANNEL_FOUNDER,
366 channel->channel_name, destclient->nickname);
372 * "event motd". Received MOTD.
375 static void event_motd(SILC_SERVER_REC *server, va_list va)
377 char *text = va_arg(va, char *);
379 if (!settings_get_bool("skip_motd"))
380 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
384 * "event channel_change". Channel ID has changed.
387 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
389 /* Nothing interesting to do */
393 * "event server_signoff". Server has quit the network.
396 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
398 SilcClientEntry *clients;
399 uint32 clients_count;
402 (void)va_arg(va, void *);
403 clients = va_arg(va, SilcClientEntry *);
404 clients_count = va_arg(va, uint32);
406 for (i = 0; i < clients_count; i++)
407 signal_emit("message quit", 4, server, clients[i]->nickname,
408 clients[i]->username ? clients[i]->username : "",
413 * "event kick". Someone was kicked from channel.
416 static void event_kick(SILC_SERVER_REC *server, va_list va)
418 SilcClientConnection conn = server->conn;
419 SilcClientEntry client_entry;
420 SilcChannelEntry channel_entry;
423 client_entry = va_arg(va, SilcClientEntry);
424 tmp = va_arg(va, char *);
425 channel_entry = va_arg(va, SilcChannelEntry);
427 if (client_entry == conn->local_entry) {
428 printformat_module("fe-common/silc", server, channel_entry->channel_name,
429 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_KICKED_YOU,
430 channel_entry->channel_name, tmp ? tmp : "");
432 printformat_module("fe-common/silc", server, channel_entry->channel_name,
433 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_KICKED,
434 client_entry->nickname,
435 channel_entry->channel_name, tmp ? tmp : "");
440 * "event kill". Someone was killed from the network.
443 static void event_kill(SILC_SERVER_REC *server, va_list va)
445 SilcClientConnection conn = server->conn;
446 SilcClientEntry client_entry;
447 SilcChannelEntry channel_entry;
450 client_entry = va_arg(va, SilcClientEntry);
451 tmp = va_arg(va, char *);
452 channel_entry = va_arg(va, SilcChannelEntry);
454 if (client_entry == conn->local_entry) {
455 printformat_module("fe-common/silc", server, channel_entry->channel_name,
456 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_KILLED_YOU,
457 channel_entry->channel_name, tmp ? tmp : "");
459 printformat_module("fe-common/silc", server, channel_entry->channel_name,
460 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_KILLED,
461 client_entry->nickname,
462 channel_entry->channel_name, tmp ? tmp : "");
466 /* PART (LEAVE) command. */
468 static void command_part(const char *data, SILC_SERVER_REC *server,
471 SILC_CHANNEL_REC *chanrec;
473 if (!IS_SILC_SERVER(server) || !server->connected)
474 cmd_return_error(CMDERR_NOT_CONNECTED);
477 if (!IS_SILC_CHANNEL(item))
478 cmd_return_error(CMDERR_NOT_JOINED);
482 chanrec = silc_channel_find(server, data);
484 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
486 signal_emit("message part", 5, server, chanrec->name,
487 server->nick, server->conn->local_entry->username, "");
489 silc_command_exec(server, "LEAVE", chanrec->name);
492 channel_destroy(CHANNEL(chanrec));
495 /* ME local command. */
497 static void command_me(const char *data, SILC_SERVER_REC *server,
500 SILC_CHANNEL_REC *chanrec;
501 char *tmpcmd = "ME", *tmp;
503 unsigned char **argv;
504 uint32 *argv_lens, *argv_types;
507 if (!IS_SILC_SERVER(server) || !server->connected)
508 cmd_return_error(CMDERR_NOT_CONNECTED);
510 if (!IS_SILC_CHANNEL(item))
511 cmd_return_error(CMDERR_NOT_JOINED);
513 /* Now parse all arguments */
514 tmp = g_strconcat(tmpcmd, " ", data, NULL);
515 silc_parse_command_line(tmp, &argv, &argv_lens,
516 &argv_types, &argc, 2);
520 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
522 chanrec = silc_channel_find(server, item->name);
524 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
526 /* Send the action message */
527 silc_client_send_channel_message(silc_client, server->conn,
528 chanrec->entry, NULL,
529 SILC_MESSAGE_FLAG_ACTION,
530 argv[1], argv_lens[1], TRUE);
532 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
533 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
534 server->conn->local_entry->nickname, argv[1]);
536 for (i = 0; i < argc; i++)
538 silc_free(argv_lens);
539 silc_free(argv_types);
542 /* ACTION local command. Same as ME but takes the channel as mandatory
545 static void command_action(const char *data, SILC_SERVER_REC *server,
548 SILC_CHANNEL_REC *chanrec;
549 char *tmpcmd = "ME", *tmp;
551 unsigned char **argv;
552 uint32 *argv_lens, *argv_types;
555 if (!IS_SILC_SERVER(server) || !server->connected)
556 cmd_return_error(CMDERR_NOT_CONNECTED);
558 if (!IS_SILC_CHANNEL(item))
559 cmd_return_error(CMDERR_NOT_JOINED);
561 /* Now parse all arguments */
562 tmp = g_strconcat(tmpcmd, " ", data, NULL);
563 silc_parse_command_line(tmp, &argv, &argv_lens,
564 &argv_types, &argc, 3);
568 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
570 chanrec = silc_channel_find(server, argv[1]);
572 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
574 /* Send the action message */
575 silc_client_send_channel_message(silc_client, server->conn,
576 chanrec->entry, NULL,
577 SILC_MESSAGE_FLAG_ACTION,
578 argv[2], argv_lens[2], TRUE);
580 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
581 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
582 server->conn->local_entry->nickname, argv[2]);
584 for (i = 0; i < argc; i++)
586 silc_free(argv_lens);
587 silc_free(argv_types);
590 /* NOTICE local command. */
592 static void command_notice(const char *data, SILC_SERVER_REC *server,
595 SILC_CHANNEL_REC *chanrec;
596 char *tmpcmd = "ME", *tmp;
598 unsigned char **argv;
599 uint32 *argv_lens, *argv_types;
602 if (!IS_SILC_SERVER(server) || !server->connected)
603 cmd_return_error(CMDERR_NOT_CONNECTED);
605 if (!IS_SILC_CHANNEL(item))
606 cmd_return_error(CMDERR_NOT_JOINED);
608 /* Now parse all arguments */
609 tmp = g_strconcat(tmpcmd, " ", data, NULL);
610 silc_parse_command_line(tmp, &argv, &argv_lens,
611 &argv_types, &argc, 2);
615 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
617 chanrec = silc_channel_find(server, item->name);
619 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
621 /* Send the action message */
622 silc_client_send_channel_message(silc_client, server->conn,
623 chanrec->entry, NULL,
624 SILC_MESSAGE_FLAG_NOTICE,
625 argv[1], argv_lens[1], TRUE);
627 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
628 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
629 server->conn->local_entry->nickname, argv[1]);
631 for (i = 0; i < argc; i++)
633 silc_free(argv_lens);
634 silc_free(argv_types);
637 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
640 static void command_away(const char *data, SILC_SERVER_REC *server,
645 if (!IS_SILC_SERVER(server) || !server->connected)
646 cmd_return_error(CMDERR_NOT_CONNECTED);
649 /* Remove any possible away message */
650 silc_client_set_away_message(silc_client, server->conn, NULL);
653 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
656 /* Set the away message */
657 silc_client_set_away_message(silc_client, server->conn, (char *)data);
660 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
661 SILCTXT_SET_AWAY, data);
664 signal_emit("away mode changed", 1, server);
666 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
670 int type; /* 1 = msg, 2 = channel */
671 SILC_SERVER_REC *server;
674 /* Key agreement callback that is called after the key agreement protocol
675 has been performed. This is called also if error occured during the
676 key agreement protocol. The `key' is the allocated key material and
677 the caller is responsible of freeing it. The `key' is NULL if error
678 has occured. The application can freely use the `key' to whatever
679 purpose it needs. See lib/silcske/silcske.h for the definition of
680 the SilcSKEKeyMaterial structure. */
682 static void keyagr_completion(SilcClient client,
683 SilcClientConnection conn,
684 SilcClientEntry client_entry,
685 SilcKeyAgreementStatus status,
686 SilcSKEKeyMaterial *key,
689 KeyInternal i = (KeyInternal)context;
692 case SILC_KEY_AGREEMENT_OK:
693 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
694 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
697 /* Set the private key for this client */
698 silc_client_del_private_message_key(client, conn, client_entry);
699 silc_client_add_private_message_key_ske(client, conn, client_entry,
701 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
702 SILCTXT_KEY_AGREEMENT_PRIVMSG,
703 client_entry->nickname);
704 silc_ske_free_key_material(key);
709 case SILC_KEY_AGREEMENT_ERROR:
710 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
711 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
714 case SILC_KEY_AGREEMENT_FAILURE:
715 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
716 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
719 case SILC_KEY_AGREEMENT_TIMEOUT:
720 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
721 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
732 /* Local command KEY. This command is used to set and unset private
733 keys for channels, set and unset private keys for private messages
734 with remote clients and to send key agreement requests and
735 negotiate the key agreement protocol with remote client. The
736 key agreement is supported only to negotiate private message keys,
737 it currently cannot be used to negotiate private keys for channels,
738 as it is not convenient for that purpose. */
741 SILC_SERVER_REC *server;
746 /* Callback to be called after client information is resolved from the
749 SILC_CLIENT_CMD_FUNC(key_get_clients)
751 KeyGetClients internal = (KeyGetClients)context;
752 signal_emit("command key", 3, internal->data, internal->server,
754 silc_free(internal->data);
758 static void command_key(const char *data, SILC_SERVER_REC *server,
761 SilcClientConnection conn = server->conn;
762 SilcClientEntry client_entry = NULL;
763 SilcChannelEntry channel_entry = NULL;
765 char *nickname = NULL, *serv = NULL, *tmp;
766 int command = 0, port = 0, type = 0;
767 char *hostname = NULL;
768 KeyInternal internal = NULL;
770 unsigned char **argv;
771 uint32 *argv_lens, *argv_types;
773 if (!IS_SILC_SERVER(server) || !server->connected)
774 cmd_return_error(CMDERR_NOT_CONNECTED);
776 /* Now parse all arguments */
777 tmp = g_strconcat("KEY", " ", data, NULL);
778 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
782 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
783 "set|unset|agreement|negotiate [<arguments>]");
788 if (!strcasecmp(argv[1], "msg"))
790 if (!strcasecmp(argv[1], "channel"))
794 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
795 "set|unset|agreement|negotiate [<arguments>]");
800 if (argv[2][0] == '*') {
803 /* Parse the typed nickname. */
804 if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) {
805 printformat_module("fe-common/silc", server, NULL,
806 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
810 /* Find client entry */
811 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
814 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
815 inter->server = server;
816 inter->data = strdup(data);
819 /* Client entry not found, it was requested thus mark this to be
821 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
823 NULL, silc_client_command_key_get_clients,
831 /* Get channel entry */
834 if (argv[2][0] == '*') {
835 if (!conn->current_channel) {
840 cmd_return_error(CMDERR_NOT_JOINED);
842 name = conn->current_channel->channel_name;
847 channel_entry = silc_client_get_channel(silc_client, conn, name);
848 if (!channel_entry) {
853 cmd_return_error(CMDERR_NOT_JOINED);
858 if (!strcasecmp(argv[3], "set")) {
862 if (type == 1 && client_entry) {
863 /* Set private message key */
865 silc_client_del_private_message_key(silc_client, conn, client_entry);
868 silc_client_add_private_message_key(silc_client, conn, client_entry,
874 silc_client_add_private_message_key(silc_client, conn, client_entry,
880 /* Send the key to the remote client so that it starts using it
882 silc_client_send_private_message_key(silc_client, conn,
884 } else if (type == 2) {
885 /* Set private channel key */
886 char *cipher = NULL, *hmac = NULL;
888 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
889 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
890 SILCTXT_CH_PRIVATE_KEY_NOMODE,
891 channel_entry->channel_name);
900 if (!silc_client_add_channel_private_key(silc_client, conn,
905 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
906 SILCTXT_CH_PRIVATE_KEY_ERROR,
907 channel_entry->channel_name);
911 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
912 SILCTXT_CH_PRIVATE_KEY_ADD,
913 channel_entry->channel_name);
921 if (!strcasecmp(argv[3], "unset")) {
924 if (type == 1 && client_entry) {
925 /* Unset private message key */
926 silc_client_del_private_message_key(silc_client, conn, client_entry);
927 } else if (type == 2) {
928 /* Unset channel key(s) */
929 SilcChannelPrivateKey *keys;
934 silc_client_del_channel_private_keys(silc_client, conn,
938 number = atoi(argv[4]);
939 keys = silc_client_list_channel_private_keys(silc_client, conn,
945 if (!number || number > keys_count) {
946 silc_client_free_channel_private_keys(keys, keys_count);
950 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
952 silc_client_free_channel_private_keys(keys, keys_count);
960 if (!strcasecmp(argv[3], "list")) {
964 SilcPrivateMessageKeys keys;
969 keys = silc_client_list_private_message_keys(silc_client, conn,
974 /* list the private message key(s) */
975 if (nickname[0] == '*') {
976 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
977 SILCTXT_PRIVATE_KEY_LIST);
978 for (k = 0; k < keys_count; k++) {
979 memset(buf, 0, sizeof(buf));
980 strncat(buf, " ", 2);
981 len = strlen(keys[k].client_entry->nickname);
982 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
984 for (i = 0; i < 30 - len; i++)
988 len = strlen(keys[k].cipher);
989 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
991 for (i = 0; i < 14 - len; i++)
996 strcat(buf, "<hidden>");
998 strcat(buf, "*generated*");
1000 silc_say(silc_client, conn, "%s", buf);
1003 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1004 SILCTXT_PRIVATE_KEY_LIST_NICK,
1005 client_entry->nickname);
1006 for (k = 0; k < keys_count; k++) {
1007 if (keys[k].client_entry != client_entry)
1010 memset(buf, 0, sizeof(buf));
1011 strncat(buf, " ", 2);
1012 len = strlen(keys[k].client_entry->nickname);
1013 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1015 for (i = 0; i < 30 - len; i++)
1019 len = strlen(keys[k].cipher);
1020 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1022 for (i = 0; i < 14 - len; i++)
1027 strcat(buf, "<hidden>");
1029 strcat(buf, "*generated*");
1031 silc_say(silc_client, conn, "%s", buf);
1035 silc_client_free_private_message_keys(keys, keys_count);
1036 } else if (type == 2) {
1037 SilcChannelPrivateKey *keys;
1042 keys = silc_client_list_channel_private_keys(silc_client, conn,
1048 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1049 SILCTXT_CH_PRIVATE_KEY_LIST,
1050 channel_entry->channel_name);
1051 for (k = 0; k < keys_count; k++) {
1052 memset(buf, 0, sizeof(buf));
1053 strncat(buf, " ", 2);
1055 len = strlen(keys[k]->cipher->cipher->name);
1056 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1058 for (i = 0; i < 16 - len; i++)
1062 len = strlen(keys[k]->hmac->hmac->name);
1063 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1065 for (i = 0; i < 16 - len; i++)
1069 strcat(buf, "<hidden>");
1071 silc_say(silc_client, conn, "%s", buf);
1074 silc_client_free_channel_private_keys(keys, keys_count);
1080 /* Send command is used to send key agreement */
1081 if (!strcasecmp(argv[3], "agreement")) {
1087 port = atoi(argv[5]);
1089 internal = silc_calloc(1, sizeof(*internal));
1090 internal->type = type;
1091 internal->server = server;
1094 /* Start command is used to start key agreement (after receiving the
1095 key_agreement client operation). */
1096 if (!strcasecmp(argv[3], "negotiate")) {
1102 port = atoi(argv[5]);
1104 internal = silc_calloc(1, sizeof(*internal));
1105 internal->type = type;
1106 internal->server = server;
1110 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
1111 "set|unset|agreement|negotiate [<arguments>]");
1115 if (command == 4 && client_entry) {
1116 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1117 SILCTXT_KEY_AGREEMENT, argv[2]);
1118 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1119 port, 120, keyagr_completion, internal);
1123 if (command == 5 && client_entry && hostname) {
1124 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1125 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1126 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1127 hostname, port, keyagr_completion,
1134 silc_free(nickname);
1139 void silc_channels_init(void)
1141 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1142 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1143 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1145 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1146 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1147 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1148 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1149 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1150 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1151 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1152 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1153 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1154 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1155 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1156 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1157 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1159 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1160 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1161 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1162 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1163 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1164 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1166 silc_nicklist_init();
1169 void silc_channels_deinit(void)
1171 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1172 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1173 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1175 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1176 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1177 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1178 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1179 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1180 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1181 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1182 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1183 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1184 signal_remove("silc event channel_change",
1185 (SIGNAL_FUNC) event_channel_change);
1186 signal_remove("silc event server_signoff",
1187 (SIGNAL_FUNC) event_server_signoff);
1188 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1189 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1191 command_unbind("part", (SIGNAL_FUNC) command_part);
1192 command_unbind("me", (SIGNAL_FUNC) command_me);
1193 command_unbind("action", (SIGNAL_FUNC) command_action);
1194 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1195 command_unbind("away", (SIGNAL_FUNC) command_away);
1196 command_unbind("key", (SIGNAL_FUNC) command_key);
1198 silc_nicklist_deinit();