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, SILC_CLIENT_MESSAGE_INFO,
804 "Usage: /KEY msg|channel <nickname|channel> "
805 "set|unset|agreement|negotiate [<arguments>]");
810 if (!strcasecmp(argv[1], "msg"))
812 if (!strcasecmp(argv[1], "channel"))
816 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
817 "Usage: /KEY msg|channel <nickname|channel> "
818 "set|unset|agreement|negotiate [<arguments>]");
823 if (argv[2][0] == '*') {
826 /* Parse the typed nickname. */
827 if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) {
828 printformat_module("fe-common/silc", server, NULL,
829 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
833 /* Find client entry */
834 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
837 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
838 inter->server = server;
839 inter->data = strdup(data);
842 /* Client entry not found, it was requested thus mark this to be
844 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
846 NULL, silc_client_command_key_get_clients,
854 /* Get channel entry */
857 if (argv[2][0] == '*') {
858 if (!conn->current_channel) {
863 cmd_return_error(CMDERR_NOT_JOINED);
865 name = conn->current_channel->channel_name;
870 channel_entry = silc_client_get_channel(silc_client, conn, name);
871 if (!channel_entry) {
876 cmd_return_error(CMDERR_NOT_JOINED);
881 if (!strcasecmp(argv[3], "set")) {
885 if (type == 1 && client_entry) {
886 /* Set private message key */
888 silc_client_del_private_message_key(silc_client, conn, client_entry);
891 silc_client_add_private_message_key(silc_client, conn, client_entry,
895 TRUE : FALSE), FALSE);
897 silc_client_add_private_message_key(silc_client, conn, client_entry,
901 TRUE : FALSE), FALSE);
903 /* Send the key to the remote client so that it starts using it
905 silc_client_send_private_message_key(silc_client, conn,
907 } else if (type == 2) {
908 /* Set private channel key */
909 char *cipher = NULL, *hmac = NULL;
911 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
912 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
913 SILCTXT_CH_PRIVATE_KEY_NOMODE,
914 channel_entry->channel_name);
923 if (!silc_client_add_channel_private_key(silc_client, conn,
928 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
929 SILCTXT_CH_PRIVATE_KEY_ERROR,
930 channel_entry->channel_name);
934 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
935 SILCTXT_CH_PRIVATE_KEY_ADD,
936 channel_entry->channel_name);
944 if (!strcasecmp(argv[3], "unset")) {
947 if (type == 1 && client_entry) {
948 /* Unset private message key */
949 silc_client_del_private_message_key(silc_client, conn, client_entry);
950 } else if (type == 2) {
951 /* Unset channel key(s) */
952 SilcChannelPrivateKey *keys;
957 silc_client_del_channel_private_keys(silc_client, conn,
961 number = atoi(argv[4]);
962 keys = silc_client_list_channel_private_keys(silc_client, conn,
968 if (!number || number > keys_count) {
969 silc_client_free_channel_private_keys(keys, keys_count);
973 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
975 silc_client_free_channel_private_keys(keys, keys_count);
983 if (!strcasecmp(argv[3], "list")) {
987 SilcPrivateMessageKeys keys;
992 keys = silc_client_list_private_message_keys(silc_client, conn,
997 /* list the private message key(s) */
998 if (nickname[0] == '*') {
999 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1000 SILCTXT_PRIVATE_KEY_LIST);
1001 for (k = 0; k < keys_count; k++) {
1002 memset(buf, 0, sizeof(buf));
1003 strncat(buf, " ", 2);
1004 len = strlen(keys[k].client_entry->nickname);
1005 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1007 for (i = 0; i < 30 - len; i++)
1011 len = strlen(keys[k].cipher);
1012 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1014 for (i = 0; i < 14 - len; i++)
1019 strcat(buf, "<hidden>");
1021 strcat(buf, "*generated*");
1023 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1026 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1027 SILCTXT_PRIVATE_KEY_LIST_NICK,
1028 client_entry->nickname);
1029 for (k = 0; k < keys_count; k++) {
1030 if (keys[k].client_entry != client_entry)
1033 memset(buf, 0, sizeof(buf));
1034 strncat(buf, " ", 2);
1035 len = strlen(keys[k].client_entry->nickname);
1036 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1038 for (i = 0; i < 30 - len; i++)
1042 len = strlen(keys[k].cipher);
1043 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1045 for (i = 0; i < 14 - len; i++)
1050 strcat(buf, "<hidden>");
1052 strcat(buf, "*generated*");
1054 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1058 silc_client_free_private_message_keys(keys, keys_count);
1059 } else if (type == 2) {
1060 SilcChannelPrivateKey *keys;
1065 keys = silc_client_list_channel_private_keys(silc_client, conn,
1071 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1072 SILCTXT_CH_PRIVATE_KEY_LIST,
1073 channel_entry->channel_name);
1074 for (k = 0; k < keys_count; k++) {
1075 memset(buf, 0, sizeof(buf));
1076 strncat(buf, " ", 2);
1078 len = strlen(keys[k]->cipher->cipher->name);
1079 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1081 for (i = 0; i < 16 - len; i++)
1085 len = strlen(keys[k]->hmac->hmac->name);
1086 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1088 for (i = 0; i < 16 - len; i++)
1092 strcat(buf, "<hidden>");
1094 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1097 silc_client_free_channel_private_keys(keys, keys_count);
1103 /* Send command is used to send key agreement */
1104 if (!strcasecmp(argv[3], "agreement")) {
1110 port = atoi(argv[5]);
1112 internal = silc_calloc(1, sizeof(*internal));
1113 internal->type = type;
1114 internal->server = server;
1117 /* Start command is used to start key agreement (after receiving the
1118 key_agreement client operation). */
1119 if (!strcasecmp(argv[3], "negotiate")) {
1125 port = atoi(argv[5]);
1127 internal = silc_calloc(1, sizeof(*internal));
1128 internal->type = type;
1129 internal->server = server;
1133 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1134 "Usage: /KEY msg|channel <nickname|channel> "
1135 "set|unset|agreement|negotiate [<arguments>]");
1139 if (command == 4 && client_entry) {
1140 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1141 SILCTXT_KEY_AGREEMENT, argv[2]);
1142 internal->responder = TRUE;
1143 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1144 port, 120, keyagr_completion, internal);
1146 silc_free(internal);
1150 if (command == 5 && client_entry && hostname) {
1151 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1152 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1153 internal->responder = FALSE;
1154 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1155 hostname, port, keyagr_completion,
1162 silc_free(nickname);
1167 void silc_channels_init(void)
1169 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1170 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1171 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1173 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1174 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1175 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1176 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1177 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1178 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1179 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1180 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1181 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1182 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1183 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1184 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1185 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1187 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1188 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1189 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1190 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1191 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1192 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1194 silc_nicklist_init();
1197 void silc_channels_deinit(void)
1199 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1200 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1201 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1203 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1204 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1205 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1206 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1207 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1208 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1209 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1210 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1211 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1212 signal_remove("silc event channel_change",
1213 (SIGNAL_FUNC) event_channel_change);
1214 signal_remove("silc event server_signoff",
1215 (SIGNAL_FUNC) event_server_signoff);
1216 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1217 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1219 command_unbind("part", (SIGNAL_FUNC) command_part);
1220 command_unbind("me", (SIGNAL_FUNC) command_me);
1221 command_unbind("action", (SIGNAL_FUNC) command_action);
1222 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1223 command_unbind("away", (SIGNAL_FUNC) command_away);
1224 command_unbind("key", (SIGNAL_FUNC) command_key);
1226 silc_nicklist_deinit();