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 printformat_module("fe-common/silc", server, NULL,
472 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
473 client_entry->nickname,
478 /* PART (LEAVE) command. */
480 static void command_part(const char *data, SILC_SERVER_REC *server,
483 SILC_CHANNEL_REC *chanrec;
485 if (!IS_SILC_SERVER(server) || !server->connected)
486 cmd_return_error(CMDERR_NOT_CONNECTED);
488 if (!strcmp(data, "*") || *data == '\0') {
489 if (!IS_SILC_CHANNEL(item))
490 cmd_return_error(CMDERR_NOT_JOINED);
494 chanrec = silc_channel_find(server, data);
496 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
498 signal_emit("message part", 5, server, chanrec->name,
499 server->nick, server->conn->local_entry->username, "");
501 silc_command_exec(server, "LEAVE", chanrec->name);
504 channel_destroy(CHANNEL(chanrec));
507 /* ME local command. */
509 static void command_me(const char *data, SILC_SERVER_REC *server,
512 SILC_CHANNEL_REC *chanrec;
513 char *tmpcmd = "ME", *tmp;
515 unsigned char **argv;
516 uint32 *argv_lens, *argv_types;
519 if (!IS_SILC_SERVER(server) || !server->connected)
520 cmd_return_error(CMDERR_NOT_CONNECTED);
522 if (!IS_SILC_CHANNEL(item))
523 cmd_return_error(CMDERR_NOT_JOINED);
525 /* Now parse all arguments */
526 tmp = g_strconcat(tmpcmd, " ", data, NULL);
527 silc_parse_command_line(tmp, &argv, &argv_lens,
528 &argv_types, &argc, 2);
532 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
534 chanrec = silc_channel_find(server, item->name);
536 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
538 /* Send the action message */
539 silc_client_send_channel_message(silc_client, server->conn,
540 chanrec->entry, NULL,
541 SILC_MESSAGE_FLAG_ACTION,
542 argv[1], argv_lens[1], TRUE);
544 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
545 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
546 server->conn->local_entry->nickname, argv[1]);
548 for (i = 0; i < argc; i++)
550 silc_free(argv_lens);
551 silc_free(argv_types);
554 /* ACTION local command. Same as ME but takes the channel as mandatory
557 static void command_action(const char *data, SILC_SERVER_REC *server,
560 SILC_CHANNEL_REC *chanrec;
561 char *tmpcmd = "ME", *tmp;
563 unsigned char **argv;
564 uint32 *argv_lens, *argv_types;
567 if (!IS_SILC_SERVER(server) || !server->connected)
568 cmd_return_error(CMDERR_NOT_CONNECTED);
570 if (!IS_SILC_CHANNEL(item))
571 cmd_return_error(CMDERR_NOT_JOINED);
573 /* Now parse all arguments */
574 tmp = g_strconcat(tmpcmd, " ", data, NULL);
575 silc_parse_command_line(tmp, &argv, &argv_lens,
576 &argv_types, &argc, 3);
580 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
582 chanrec = silc_channel_find(server, argv[1]);
584 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
586 /* Send the action message */
587 silc_client_send_channel_message(silc_client, server->conn,
588 chanrec->entry, NULL,
589 SILC_MESSAGE_FLAG_ACTION,
590 argv[2], argv_lens[2], TRUE);
592 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
593 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
594 server->conn->local_entry->nickname, argv[2]);
596 for (i = 0; i < argc; i++)
598 silc_free(argv_lens);
599 silc_free(argv_types);
602 /* NOTICE local command. */
604 static void command_notice(const char *data, SILC_SERVER_REC *server,
607 SILC_CHANNEL_REC *chanrec;
608 char *tmpcmd = "ME", *tmp;
610 unsigned char **argv;
611 uint32 *argv_lens, *argv_types;
614 if (!IS_SILC_SERVER(server) || !server->connected)
615 cmd_return_error(CMDERR_NOT_CONNECTED);
617 if (!IS_SILC_CHANNEL(item))
618 cmd_return_error(CMDERR_NOT_JOINED);
620 /* Now parse all arguments */
621 tmp = g_strconcat(tmpcmd, " ", data, NULL);
622 silc_parse_command_line(tmp, &argv, &argv_lens,
623 &argv_types, &argc, 2);
627 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
629 chanrec = silc_channel_find(server, item->name);
631 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
633 /* Send the action message */
634 silc_client_send_channel_message(silc_client, server->conn,
635 chanrec->entry, NULL,
636 SILC_MESSAGE_FLAG_NOTICE,
637 argv[1], argv_lens[1], TRUE);
639 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
640 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
641 server->conn->local_entry->nickname, argv[1]);
643 for (i = 0; i < argc; i++)
645 silc_free(argv_lens);
646 silc_free(argv_types);
649 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
652 static void command_away(const char *data, SILC_SERVER_REC *server,
657 if (!IS_SILC_SERVER(server) || !server->connected)
658 cmd_return_error(CMDERR_NOT_CONNECTED);
661 /* Remove any possible away message */
662 silc_client_set_away_message(silc_client, server->conn, NULL);
665 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
668 /* Set the away message */
669 silc_client_set_away_message(silc_client, server->conn, (char *)data);
672 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
673 SILCTXT_SET_AWAY, data);
676 signal_emit("away mode changed", 1, server);
678 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
682 int type; /* 1 = msg, 2 = channel */
683 SILC_SERVER_REC *server;
686 /* Key agreement callback that is called after the key agreement protocol
687 has been performed. This is called also if error occured during the
688 key agreement protocol. The `key' is the allocated key material and
689 the caller is responsible of freeing it. The `key' is NULL if error
690 has occured. The application can freely use the `key' to whatever
691 purpose it needs. See lib/silcske/silcske.h for the definition of
692 the SilcSKEKeyMaterial structure. */
694 static void keyagr_completion(SilcClient client,
695 SilcClientConnection conn,
696 SilcClientEntry client_entry,
697 SilcKeyAgreementStatus status,
698 SilcSKEKeyMaterial *key,
701 KeyInternal i = (KeyInternal)context;
704 case SILC_KEY_AGREEMENT_OK:
705 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
706 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
709 /* Set the private key for this client */
710 silc_client_del_private_message_key(client, conn, client_entry);
711 silc_client_add_private_message_key_ske(client, conn, client_entry,
713 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
714 SILCTXT_KEY_AGREEMENT_PRIVMSG,
715 client_entry->nickname);
716 silc_ske_free_key_material(key);
721 case SILC_KEY_AGREEMENT_ERROR:
722 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
723 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
726 case SILC_KEY_AGREEMENT_FAILURE:
727 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
728 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
731 case SILC_KEY_AGREEMENT_TIMEOUT:
732 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
733 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
744 /* Local command KEY. This command is used to set and unset private
745 keys for channels, set and unset private keys for private messages
746 with remote clients and to send key agreement requests and
747 negotiate the key agreement protocol with remote client. The
748 key agreement is supported only to negotiate private message keys,
749 it currently cannot be used to negotiate private keys for channels,
750 as it is not convenient for that purpose. */
753 SILC_SERVER_REC *server;
758 /* Callback to be called after client information is resolved from the
761 SILC_CLIENT_CMD_FUNC(key_get_clients)
763 KeyGetClients internal = (KeyGetClients)context;
764 signal_emit("command key", 3, internal->data, internal->server,
766 silc_free(internal->data);
770 static void command_key(const char *data, SILC_SERVER_REC *server,
773 SilcClientConnection conn = server->conn;
774 SilcClientEntry client_entry = NULL;
775 SilcChannelEntry channel_entry = NULL;
777 char *nickname = NULL, *serv = NULL, *tmp;
778 int command = 0, port = 0, type = 0;
779 char *hostname = NULL;
780 KeyInternal internal = NULL;
782 unsigned char **argv;
783 uint32 *argv_lens, *argv_types;
785 if (!IS_SILC_SERVER(server) || !server->connected)
786 cmd_return_error(CMDERR_NOT_CONNECTED);
788 /* Now parse all arguments */
789 tmp = g_strconcat("KEY", " ", data, NULL);
790 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
794 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
795 "set|unset|agreement|negotiate [<arguments>]");
800 if (!strcasecmp(argv[1], "msg"))
802 if (!strcasecmp(argv[1], "channel"))
806 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
807 "set|unset|agreement|negotiate [<arguments>]");
812 if (argv[2][0] == '*') {
815 /* Parse the typed nickname. */
816 if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) {
817 printformat_module("fe-common/silc", server, NULL,
818 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
822 /* Find client entry */
823 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
826 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
827 inter->server = server;
828 inter->data = strdup(data);
831 /* Client entry not found, it was requested thus mark this to be
833 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
835 NULL, silc_client_command_key_get_clients,
843 /* Get channel entry */
846 if (argv[2][0] == '*') {
847 if (!conn->current_channel) {
852 cmd_return_error(CMDERR_NOT_JOINED);
854 name = conn->current_channel->channel_name;
859 channel_entry = silc_client_get_channel(silc_client, conn, name);
860 if (!channel_entry) {
865 cmd_return_error(CMDERR_NOT_JOINED);
870 if (!strcasecmp(argv[3], "set")) {
874 if (type == 1 && client_entry) {
875 /* Set private message key */
877 silc_client_del_private_message_key(silc_client, conn, client_entry);
880 silc_client_add_private_message_key(silc_client, conn, client_entry,
886 silc_client_add_private_message_key(silc_client, conn, client_entry,
892 /* Send the key to the remote client so that it starts using it
894 silc_client_send_private_message_key(silc_client, conn,
896 } else if (type == 2) {
897 /* Set private channel key */
898 char *cipher = NULL, *hmac = NULL;
900 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
901 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
902 SILCTXT_CH_PRIVATE_KEY_NOMODE,
903 channel_entry->channel_name);
912 if (!silc_client_add_channel_private_key(silc_client, conn,
917 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
918 SILCTXT_CH_PRIVATE_KEY_ERROR,
919 channel_entry->channel_name);
923 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
924 SILCTXT_CH_PRIVATE_KEY_ADD,
925 channel_entry->channel_name);
933 if (!strcasecmp(argv[3], "unset")) {
936 if (type == 1 && client_entry) {
937 /* Unset private message key */
938 silc_client_del_private_message_key(silc_client, conn, client_entry);
939 } else if (type == 2) {
940 /* Unset channel key(s) */
941 SilcChannelPrivateKey *keys;
946 silc_client_del_channel_private_keys(silc_client, conn,
950 number = atoi(argv[4]);
951 keys = silc_client_list_channel_private_keys(silc_client, conn,
957 if (!number || number > keys_count) {
958 silc_client_free_channel_private_keys(keys, keys_count);
962 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
964 silc_client_free_channel_private_keys(keys, keys_count);
972 if (!strcasecmp(argv[3], "list")) {
976 SilcPrivateMessageKeys keys;
981 keys = silc_client_list_private_message_keys(silc_client, conn,
986 /* list the private message key(s) */
987 if (nickname[0] == '*') {
988 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
989 SILCTXT_PRIVATE_KEY_LIST);
990 for (k = 0; k < keys_count; k++) {
991 memset(buf, 0, sizeof(buf));
992 strncat(buf, " ", 2);
993 len = strlen(keys[k].client_entry->nickname);
994 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
996 for (i = 0; i < 30 - len; i++)
1000 len = strlen(keys[k].cipher);
1001 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1003 for (i = 0; i < 14 - len; i++)
1008 strcat(buf, "<hidden>");
1010 strcat(buf, "*generated*");
1012 silc_say(silc_client, conn, "%s", buf);
1015 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1016 SILCTXT_PRIVATE_KEY_LIST_NICK,
1017 client_entry->nickname);
1018 for (k = 0; k < keys_count; k++) {
1019 if (keys[k].client_entry != client_entry)
1022 memset(buf, 0, sizeof(buf));
1023 strncat(buf, " ", 2);
1024 len = strlen(keys[k].client_entry->nickname);
1025 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1027 for (i = 0; i < 30 - len; i++)
1031 len = strlen(keys[k].cipher);
1032 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1034 for (i = 0; i < 14 - len; i++)
1039 strcat(buf, "<hidden>");
1041 strcat(buf, "*generated*");
1043 silc_say(silc_client, conn, "%s", buf);
1047 silc_client_free_private_message_keys(keys, keys_count);
1048 } else if (type == 2) {
1049 SilcChannelPrivateKey *keys;
1054 keys = silc_client_list_channel_private_keys(silc_client, conn,
1060 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1061 SILCTXT_CH_PRIVATE_KEY_LIST,
1062 channel_entry->channel_name);
1063 for (k = 0; k < keys_count; k++) {
1064 memset(buf, 0, sizeof(buf));
1065 strncat(buf, " ", 2);
1067 len = strlen(keys[k]->cipher->cipher->name);
1068 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1070 for (i = 0; i < 16 - len; i++)
1074 len = strlen(keys[k]->hmac->hmac->name);
1075 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1077 for (i = 0; i < 16 - len; i++)
1081 strcat(buf, "<hidden>");
1083 silc_say(silc_client, conn, "%s", buf);
1086 silc_client_free_channel_private_keys(keys, keys_count);
1092 /* Send command is used to send key agreement */
1093 if (!strcasecmp(argv[3], "agreement")) {
1099 port = atoi(argv[5]);
1101 internal = silc_calloc(1, sizeof(*internal));
1102 internal->type = type;
1103 internal->server = server;
1106 /* Start command is used to start key agreement (after receiving the
1107 key_agreement client operation). */
1108 if (!strcasecmp(argv[3], "negotiate")) {
1114 port = atoi(argv[5]);
1116 internal = silc_calloc(1, sizeof(*internal));
1117 internal->type = type;
1118 internal->server = server;
1122 silc_say(silc_client, conn, "Usage: /KEY msg|channel <nickname|channel> "
1123 "set|unset|agreement|negotiate [<arguments>]");
1127 if (command == 4 && client_entry) {
1128 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1129 SILCTXT_KEY_AGREEMENT, argv[2]);
1130 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1131 port, 120, keyagr_completion, internal);
1135 if (command == 5 && client_entry && hostname) {
1136 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1137 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1138 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1139 hostname, port, keyagr_completion,
1146 silc_free(nickname);
1151 void silc_channels_init(void)
1153 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1154 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1155 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1157 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1158 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1159 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1160 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1161 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1162 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1163 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1164 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1165 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1166 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1167 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1168 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1169 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1171 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1172 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1173 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1174 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1175 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1176 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1178 silc_nicklist_init();
1181 void silc_channels_deinit(void)
1183 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1184 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1185 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1187 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1188 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1189 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1190 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1191 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1192 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1193 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1194 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1195 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1196 signal_remove("silc event channel_change",
1197 (SIGNAL_FUNC) event_channel_change);
1198 signal_remove("silc event server_signoff",
1199 (SIGNAL_FUNC) event_server_signoff);
1200 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1201 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1203 command_unbind("part", (SIGNAL_FUNC) command_part);
1204 command_unbind("me", (SIGNAL_FUNC) command_me);
1205 command_unbind("action", (SIGNAL_FUNC) command_action);
1206 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1207 command_unbind("away", (SIGNAL_FUNC) command_away);
1208 command_unbind("key", (SIGNAL_FUNC) command_key);
1210 silc_nicklist_deinit();