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 */
692 SILC_SERVER_REC *server;
695 /* Key agreement callback that is called after the key agreement protocol
696 has been performed. This is called also if error occured during the
697 key agreement protocol. The `key' is the allocated key material and
698 the caller is responsible of freeing it. The `key' is NULL if error
699 has occured. The application can freely use the `key' to whatever
700 purpose it needs. See lib/silcske/silcske.h for the definition of
701 the SilcSKEKeyMaterial structure. */
703 static void keyagr_completion(SilcClient client,
704 SilcClientConnection conn,
705 SilcClientEntry client_entry,
706 SilcKeyAgreementStatus status,
707 SilcSKEKeyMaterial *key,
710 KeyInternal i = (KeyInternal)context;
713 case SILC_KEY_AGREEMENT_OK:
714 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
715 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
718 /* Set the private key for this client */
719 silc_client_del_private_message_key(client, conn, client_entry);
720 silc_client_add_private_message_key_ske(client, conn, client_entry,
721 NULL, key, i->responder);
722 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
723 SILCTXT_KEY_AGREEMENT_PRIVMSG,
724 client_entry->nickname);
725 silc_ske_free_key_material(key);
730 case SILC_KEY_AGREEMENT_ERROR:
731 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
732 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
735 case SILC_KEY_AGREEMENT_FAILURE:
736 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
737 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
740 case SILC_KEY_AGREEMENT_TIMEOUT:
741 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
742 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
753 /* Local command KEY. This command is used to set and unset private
754 keys for channels, set and unset private keys for private messages
755 with remote clients and to send key agreement requests and
756 negotiate the key agreement protocol with remote client. The
757 key agreement is supported only to negotiate private message keys,
758 it currently cannot be used to negotiate private keys for channels,
759 as it is not convenient for that purpose. */
762 SILC_SERVER_REC *server;
767 /* Callback to be called after client information is resolved from the
770 SILC_CLIENT_CMD_FUNC(key_get_clients)
772 KeyGetClients internal = (KeyGetClients)context;
773 signal_emit("command key", 3, internal->data, internal->server,
775 silc_free(internal->data);
779 static void command_key(const char *data, SILC_SERVER_REC *server,
782 SilcClientConnection conn = server->conn;
783 SilcClientEntry client_entry = NULL;
784 SilcChannelEntry channel_entry = NULL;
786 char *nickname = NULL, *serv = NULL, *tmp;
787 int command = 0, port = 0, type = 0;
788 char *hostname = NULL;
789 KeyInternal internal = NULL;
791 unsigned char **argv;
792 uint32 *argv_lens, *argv_types;
794 if (!IS_SILC_SERVER(server) || !server->connected)
795 cmd_return_error(CMDERR_NOT_CONNECTED);
797 /* Now parse all arguments */
798 tmp = g_strconcat("KEY", " ", data, NULL);
799 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
803 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
804 "set|unset|agreement|negotiate [<arguments>]");
809 if (!strcasecmp(argv[1], "msg"))
811 if (!strcasecmp(argv[1], "channel"))
815 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
816 "set|unset|agreement|negotiate [<arguments>]");
821 if (argv[2][0] == '*') {
824 /* Parse the typed nickname. */
825 if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) {
826 printformat_module("fe-common/silc", server, NULL,
827 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
831 /* Find client entry */
832 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
835 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
836 inter->server = server;
837 inter->data = strdup(data);
840 /* Client entry not found, it was requested thus mark this to be
842 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
844 NULL, silc_client_command_key_get_clients,
852 /* Get channel entry */
855 if (argv[2][0] == '*') {
856 if (!conn->current_channel) {
861 cmd_return_error(CMDERR_NOT_JOINED);
863 name = conn->current_channel->channel_name;
868 channel_entry = silc_client_get_channel(silc_client, conn, name);
869 if (!channel_entry) {
874 cmd_return_error(CMDERR_NOT_JOINED);
879 if (!strcasecmp(argv[3], "set")) {
883 if (type == 1 && client_entry) {
884 /* Set private message key */
886 silc_client_del_private_message_key(silc_client, conn, client_entry);
889 silc_client_add_private_message_key(silc_client, conn, client_entry,
893 TRUE : FALSE), FALSE);
895 silc_client_add_private_message_key(silc_client, conn, client_entry,
899 TRUE : FALSE), FALSE);
901 /* Send the key to the remote client so that it starts using it
903 silc_client_send_private_message_key(silc_client, conn,
905 } else if (type == 2) {
906 /* Set private channel key */
907 char *cipher = NULL, *hmac = NULL;
909 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
910 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
911 SILCTXT_CH_PRIVATE_KEY_NOMODE,
912 channel_entry->channel_name);
921 if (!silc_client_add_channel_private_key(silc_client, conn,
926 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
927 SILCTXT_CH_PRIVATE_KEY_ERROR,
928 channel_entry->channel_name);
932 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
933 SILCTXT_CH_PRIVATE_KEY_ADD,
934 channel_entry->channel_name);
942 if (!strcasecmp(argv[3], "unset")) {
945 if (type == 1 && client_entry) {
946 /* Unset private message key */
947 silc_client_del_private_message_key(silc_client, conn, client_entry);
948 } else if (type == 2) {
949 /* Unset channel key(s) */
950 SilcChannelPrivateKey *keys;
955 silc_client_del_channel_private_keys(silc_client, conn,
959 number = atoi(argv[4]);
960 keys = silc_client_list_channel_private_keys(silc_client, conn,
966 if (!number || number > keys_count) {
967 silc_client_free_channel_private_keys(keys, keys_count);
971 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
973 silc_client_free_channel_private_keys(keys, keys_count);
981 if (!strcasecmp(argv[3], "list")) {
985 SilcPrivateMessageKeys keys;
990 keys = silc_client_list_private_message_keys(silc_client, conn,
995 /* list the private message key(s) */
996 if (nickname[0] == '*') {
997 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
998 SILCTXT_PRIVATE_KEY_LIST);
999 for (k = 0; k < keys_count; k++) {
1000 memset(buf, 0, sizeof(buf));
1001 strncat(buf, " ", 2);
1002 len = strlen(keys[k].client_entry->nickname);
1003 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1005 for (i = 0; i < 30 - len; i++)
1009 len = strlen(keys[k].cipher);
1010 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1012 for (i = 0; i < 14 - len; i++)
1017 strcat(buf, "<hidden>");
1019 strcat(buf, "*generated*");
1021 silc_say(silc_client, conn, "%s", buf);
1024 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1025 SILCTXT_PRIVATE_KEY_LIST_NICK,
1026 client_entry->nickname);
1027 for (k = 0; k < keys_count; k++) {
1028 if (keys[k].client_entry != client_entry)
1031 memset(buf, 0, sizeof(buf));
1032 strncat(buf, " ", 2);
1033 len = strlen(keys[k].client_entry->nickname);
1034 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1036 for (i = 0; i < 30 - len; i++)
1040 len = strlen(keys[k].cipher);
1041 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1043 for (i = 0; i < 14 - len; i++)
1048 strcat(buf, "<hidden>");
1050 strcat(buf, "*generated*");
1052 silc_say(silc_client, conn, "%s", buf);
1056 silc_client_free_private_message_keys(keys, keys_count);
1057 } else if (type == 2) {
1058 SilcChannelPrivateKey *keys;
1063 keys = silc_client_list_channel_private_keys(silc_client, conn,
1069 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1070 SILCTXT_CH_PRIVATE_KEY_LIST,
1071 channel_entry->channel_name);
1072 for (k = 0; k < keys_count; k++) {
1073 memset(buf, 0, sizeof(buf));
1074 strncat(buf, " ", 2);
1076 len = strlen(keys[k]->cipher->cipher->name);
1077 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1079 for (i = 0; i < 16 - len; i++)
1083 len = strlen(keys[k]->hmac->hmac->name);
1084 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1086 for (i = 0; i < 16 - len; i++)
1090 strcat(buf, "<hidden>");
1092 silc_say(silc_client, conn, "%s", buf);
1095 silc_client_free_channel_private_keys(keys, keys_count);
1101 /* Send command is used to send key agreement */
1102 if (!strcasecmp(argv[3], "agreement")) {
1108 port = atoi(argv[5]);
1110 internal = silc_calloc(1, sizeof(*internal));
1111 internal->type = type;
1112 internal->server = server;
1115 /* Start command is used to start key agreement (after receiving the
1116 key_agreement client operation). */
1117 if (!strcasecmp(argv[3], "negotiate")) {
1123 port = atoi(argv[5]);
1125 internal = silc_calloc(1, sizeof(*internal));
1126 internal->type = type;
1127 internal->server = server;
1131 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
1132 "set|unset|agreement|negotiate [<arguments>]");
1136 if (command == 4 && client_entry) {
1137 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1138 SILCTXT_KEY_AGREEMENT, argv[2]);
1139 internal->responder = TRUE;
1140 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1141 port, 120, keyagr_completion, internal);
1143 silc_free(internal);
1147 if (command == 5 && client_entry && hostname) {
1148 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1149 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1150 internal->responder = FALSE;
1151 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1152 hostname, port, keyagr_completion,
1159 silc_free(nickname);
1164 void silc_channels_init(void)
1166 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1167 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1168 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1170 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1171 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1172 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1173 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1174 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1175 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1176 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1177 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1178 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1179 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1180 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1181 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1182 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1184 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1185 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1186 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1187 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1188 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1189 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1191 silc_nicklist_init();
1194 void silc_channels_deinit(void)
1196 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1197 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1198 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1200 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1201 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1202 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1203 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1204 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1205 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1206 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1207 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1208 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1209 signal_remove("silc event channel_change",
1210 (SIGNAL_FUNC) event_channel_change);
1211 signal_remove("silc event server_signoff",
1212 (SIGNAL_FUNC) event_server_signoff);
1213 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1214 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1216 command_unbind("part", (SIGNAL_FUNC) command_part);
1217 command_unbind("me", (SIGNAL_FUNC) command_me);
1218 command_unbind("action", (SIGNAL_FUNC) command_action);
1219 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1220 command_unbind("away", (SIGNAL_FUNC) command_away);
1221 command_unbind("key", (SIGNAL_FUNC) command_key);
1223 silc_nicklist_deinit();