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_command_exec(server, "JOIN", channel);
99 static void sig_connected(SILC_SERVER_REC *server)
101 if (IS_SILC_SERVER(server))
102 server->channels_join = (void *) silc_channels_join;
105 /* "server quit" signal from the core to indicate that QUIT command
108 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
110 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
111 silc_command_exec(server, "QUIT", msg);
115 * "event join". Joined to a channel.
118 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
119 SilcChannelEntry entry)
123 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
125 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
126 SILC_CHANNEL_REC *rec = tmp->data;
128 if (rec->entry == entry)
135 static void event_join(SILC_SERVER_REC *server, va_list va)
137 SILC_CHANNEL_REC *chanrec;
138 SILC_NICK_REC *nickrec;
139 SilcClientEntry client;
140 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 memset(userhost, 0, sizeof(userhost));
166 if (client->username)
167 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
168 client->username, client->hostname);
169 signal_emit("message join", 4, server, channel->channel_name,
171 client->username == NULL ? "" : userhost);
175 * "event leave". Left a channel.
178 static void event_leave(SILC_SERVER_REC *server, va_list va)
180 SILC_CHANNEL_REC *chanrec;
181 SILC_NICK_REC *nickrec;
182 SilcClientEntry client;
183 SilcChannelEntry channel;
186 client = va_arg(va, SilcClientEntry);
187 channel = va_arg(va, SilcChannelEntry);
189 memset(userhost, 0, sizeof(userhost));
190 if (client->username)
191 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
192 client->username, client->hostname);
193 signal_emit("message part", 5, server, channel->channel_name,
194 client->nickname, client->username ? userhost : "",
197 chanrec = silc_channel_find_entry(server, channel);
198 if (chanrec != NULL) {
199 nickrec = silc_nicklist_find(chanrec, client);
201 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
206 * "event signoff". Left the network.
209 static void event_signoff(SILC_SERVER_REC *server, va_list va)
211 SilcClientEntry client;
216 client = va_arg(va, SilcClientEntry);
217 message = va_arg(va, char *);
219 silc_server_free_ftp(server, client);
221 memset(userhost, 0, sizeof(userhost));
222 if (client->username)
223 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
224 client->username, client->hostname);
225 signal_emit("message quit", 4, server, client->nickname,
226 client->username ? userhost : "",
227 message ? message : "");
229 nicks = nicklist_get_same_unique(SERVER(server), client);
230 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
231 CHANNEL_REC *channel = tmp->data;
232 NICK_REC *nickrec = tmp->next->data;
234 nicklist_remove(channel, nickrec);
239 * "event topic". Changed topic.
242 static void event_topic(SILC_SERVER_REC *server, va_list va)
244 SILC_CHANNEL_REC *chanrec;
246 SilcClientEntry client;
247 SilcServerEntry server_entry;
248 SilcChannelEntry channel;
253 idtype = va_arg(va, int);
254 entry = va_arg(va, void *);
255 topic = va_arg(va, char *);
256 channel = va_arg(va, SilcChannelEntry);
258 chanrec = silc_channel_find_entry(server, channel);
259 if (chanrec != NULL) {
260 g_free_not_null(chanrec->topic);
261 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
262 signal_emit("channel topic changed", 1, chanrec);
265 if (idtype == SILC_ID_CLIENT) {
266 client = (SilcClientEntry)entry;
267 memset(userhost, 0, sizeof(userhost));
268 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
269 client->username, client->hostname);
270 signal_emit("message topic", 5, server, channel->channel_name,
271 topic, client->nickname, userhost);
272 } else if (idtype == SILC_ID_SERVER) {
273 server_entry = (SilcServerEntry)entry;
274 signal_emit("message topic", 5, server, channel->channel_name,
275 topic, server_entry->server_name,
276 server_entry->server_name);
278 channel = (SilcChannelEntry)entry;
279 signal_emit("message topic", 5, server, channel->channel_name,
280 topic, channel->channel_name, channel->channel_name);
285 * "event invite". Invited or modified invite list.
288 static void event_invite(SILC_SERVER_REC *server, va_list va)
290 SilcClientEntry client;
291 SilcChannelEntry channel;
295 channel = va_arg(va, SilcChannelEntry);
296 channel_name = va_arg(va, char *);
297 client = va_arg(va, SilcClientEntry);
299 memset(userhost, 0, sizeof(userhost));
300 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
301 client->username, client->hostname);
302 signal_emit("message invite", 4, server, channel ? channel->channel_name :
303 channel_name, client->nickname, userhost);
307 * "event nick". Changed nickname.
310 static void event_nick(SILC_SERVER_REC *server, va_list va)
312 SilcClientEntry oldclient, newclient;
315 oldclient = va_arg(va, SilcClientEntry);
316 newclient = va_arg(va, SilcClientEntry);
318 nicklist_rename_unique(SERVER(server),
319 oldclient, oldclient->nickname,
320 newclient, newclient->nickname);
322 memset(userhost, 0, sizeof(userhost));
323 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
324 newclient->username, newclient->hostname);
325 signal_emit("message nick", 4, server, newclient->nickname,
326 oldclient->nickname, userhost);
330 * "event cmode". Changed channel mode.
333 static void event_cmode(SILC_SERVER_REC *server, va_list va)
335 SILC_CHANNEL_REC *chanrec;
337 SilcClientEntry client;
338 SilcServerEntry server_entry;
339 SilcChannelEntry channel;
344 idtype = va_arg(va, int);
345 entry = va_arg(va, void *);
346 modei = va_arg(va, uint32);
347 (void)va_arg(va, char *);
348 (void)va_arg(va, char *);
349 channel = va_arg(va, SilcChannelEntry);
351 mode = silc_client_chmode(modei,
352 channel->channel_key->cipher->name,
353 silc_hmac_get_name(channel->hmac));
355 chanrec = silc_channel_find_entry(server, channel);
356 if (chanrec != NULL) {
357 g_free_not_null(chanrec->mode);
358 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
359 signal_emit("channel mode changed", 1, chanrec);
362 if (idtype == SILC_ID_CLIENT) {
363 client = (SilcClientEntry)entry;
364 printformat_module("fe-common/silc", server, channel->channel_name,
365 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
366 channel->channel_name, mode ? mode : "removed all",
369 server_entry = (SilcServerEntry)entry;
370 printformat_module("fe-common/silc", server, channel->channel_name,
371 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
372 channel->channel_name, mode ? mode : "removed all",
373 server_entry->server_name);
380 * "event cumode". Changed user's mode on channel.
383 static void event_cumode(SILC_SERVER_REC *server, va_list va)
385 SILC_CHANNEL_REC *chanrec;
386 SilcClientEntry client, destclient;
387 SilcChannelEntry channel;
391 client = va_arg(va, SilcClientEntry);
392 mode = va_arg(va, uint32);
393 destclient = va_arg(va, SilcClientEntry);
394 channel = va_arg(va, SilcChannelEntry);
396 modestr = silc_client_chumode(mode);
397 chanrec = silc_channel_find_entry(server, channel);
398 if (chanrec != NULL) {
401 if (destclient == server->conn->local_entry) {
403 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
406 nick = silc_nicklist_find(chanrec, destclient);
408 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
409 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
410 signal_emit("nick mode changed", 2, chanrec, nick);
414 printformat_module("fe-common/silc", server, channel->channel_name,
415 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
416 channel->channel_name, destclient->nickname,
417 modestr ? modestr : "removed all",
420 if (mode & SILC_CHANNEL_UMODE_CHANFO)
421 printformat_module("fe-common/silc",
422 server, channel->channel_name, MSGLEVEL_CRAP,
423 SILCTXT_CHANNEL_FOUNDER,
424 channel->channel_name, destclient->nickname);
430 * "event motd". Received MOTD.
433 static void event_motd(SILC_SERVER_REC *server, va_list va)
435 char *text = va_arg(va, char *);
437 if (!settings_get_bool("skip_motd"))
438 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
442 * "event channel_change". Channel ID has changed.
445 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
447 /* Nothing interesting to do */
451 * "event server_signoff". Server has quit the network.
454 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
456 SilcClientEntry *clients;
457 uint32 clients_count;
461 (void)va_arg(va, void *);
462 clients = va_arg(va, SilcClientEntry *);
463 clients_count = va_arg(va, uint32);
465 for (i = 0; i < clients_count; i++) {
468 memset(userhost, 0, sizeof(userhost));
469 if (clients[i]->username)
470 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
471 clients[i]->username, clients[i]->hostname);
472 signal_emit("message quit", 4, server, clients[i]->nickname,
473 clients[i]->username ? userhost : "",
476 silc_server_free_ftp(server, clients[i]);
478 nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
479 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
480 CHANNEL_REC *channel = tmp->data;
481 NICK_REC *nickrec = tmp->next->data;
482 nicklist_remove(channel, nickrec);
488 * "event kick". Someone was kicked from channel.
491 static void event_kick(SILC_SERVER_REC *server, va_list va)
493 SilcClientConnection conn = server->conn;
494 SilcClientEntry client_entry, kicker;
495 SilcChannelEntry channel_entry;
497 SILC_CHANNEL_REC *chanrec;
499 client_entry = va_arg(va, SilcClientEntry);
500 tmp = va_arg(va, char *);
501 kicker = va_arg(va, SilcClientEntry);
502 channel_entry = va_arg(va, SilcChannelEntry);
504 chanrec = silc_channel_find_entry(server, channel_entry);
506 if (client_entry == conn->local_entry) {
507 printformat_module("fe-common/silc", server, channel_entry->channel_name,
508 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
510 channel_entry->channel_name, tmp ? tmp : "");
512 chanrec->kicked = TRUE;
513 channel_destroy((CHANNEL_REC *)chanrec);
516 printformat_module("fe-common/silc", server, channel_entry->channel_name,
517 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
518 client_entry->nickname,
520 channel_entry->channel_name, tmp ? tmp : "");
523 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
525 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
531 * "event kill". Someone was killed from the network.
534 static void event_kill(SILC_SERVER_REC *server, va_list va)
536 SilcClientConnection conn = server->conn;
537 SilcClientEntry client_entry;
540 client_entry = va_arg(va, SilcClientEntry);
541 tmp = va_arg(va, char *);
543 if (client_entry == conn->local_entry) {
544 printformat_module("fe-common/silc", server, NULL,
545 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
548 GSList *nicks, *tmpn;
549 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
550 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
551 CHANNEL_REC *channel = tmpn->data;
552 NICK_REC *nickrec = tmpn->next->data;
553 nicklist_remove(channel, nickrec);
556 printformat_module("fe-common/silc", server, NULL,
557 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
558 client_entry->nickname,
563 /* PART (LEAVE) command. */
565 static void command_part(const char *data, SILC_SERVER_REC *server,
568 SILC_CHANNEL_REC *chanrec;
571 if (!IS_SILC_SERVER(server) || !server->connected)
572 cmd_return_error(CMDERR_NOT_CONNECTED);
574 if (!strcmp(data, "*") || *data == '\0') {
575 if (!IS_SILC_CHANNEL(item))
576 cmd_return_error(CMDERR_NOT_JOINED);
580 chanrec = silc_channel_find(server, data);
582 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
584 memset(userhost, 0, sizeof(userhost));
585 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
586 server->conn->local_entry->username,
587 server->conn->local_entry->hostname);
588 signal_emit("message part", 5, server, chanrec->name,
589 server->nick, userhost, "");
591 silc_command_exec(server, "LEAVE", chanrec->name);
594 channel_destroy(CHANNEL(chanrec));
597 /* ME local command. */
599 static void command_me(const char *data, SILC_SERVER_REC *server,
602 SILC_CHANNEL_REC *chanrec;
603 char *tmpcmd = "ME", *tmp;
605 unsigned char **argv;
606 uint32 *argv_lens, *argv_types;
609 if (!IS_SILC_SERVER(server) || !server->connected)
610 cmd_return_error(CMDERR_NOT_CONNECTED);
612 if (!IS_SILC_CHANNEL(item))
613 cmd_return_error(CMDERR_NOT_JOINED);
615 /* Now parse all arguments */
616 tmp = g_strconcat(tmpcmd, " ", data, NULL);
617 silc_parse_command_line(tmp, &argv, &argv_lens,
618 &argv_types, &argc, 2);
622 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
624 chanrec = silc_channel_find(server, item->name);
626 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
628 /* Send the action message */
629 silc_client_send_channel_message(silc_client, server->conn,
630 chanrec->entry, NULL,
631 SILC_MESSAGE_FLAG_ACTION,
632 argv[1], argv_lens[1], TRUE);
634 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
635 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
636 server->conn->local_entry->nickname, argv[1]);
638 for (i = 0; i < argc; i++)
640 silc_free(argv_lens);
641 silc_free(argv_types);
644 /* ACTION local command. Same as ME but takes the channel as mandatory
647 static void command_action(const char *data, SILC_SERVER_REC *server,
650 SILC_CHANNEL_REC *chanrec;
651 char *tmpcmd = "ME", *tmp;
653 unsigned char **argv;
654 uint32 *argv_lens, *argv_types;
657 if (!IS_SILC_SERVER(server) || !server->connected)
658 cmd_return_error(CMDERR_NOT_CONNECTED);
660 if (!IS_SILC_CHANNEL(item))
661 cmd_return_error(CMDERR_NOT_JOINED);
663 /* Now parse all arguments */
664 tmp = g_strconcat(tmpcmd, " ", data, NULL);
665 silc_parse_command_line(tmp, &argv, &argv_lens,
666 &argv_types, &argc, 3);
670 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
672 chanrec = silc_channel_find(server, argv[1]);
674 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
676 /* Send the action message */
677 silc_client_send_channel_message(silc_client, server->conn,
678 chanrec->entry, NULL,
679 SILC_MESSAGE_FLAG_ACTION,
680 argv[2], argv_lens[2], TRUE);
682 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
683 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
684 server->conn->local_entry->nickname, argv[2]);
686 for (i = 0; i < argc; i++)
688 silc_free(argv_lens);
689 silc_free(argv_types);
692 /* NOTICE local command. */
694 static void command_notice(const char *data, SILC_SERVER_REC *server,
697 SILC_CHANNEL_REC *chanrec;
698 char *tmpcmd = "ME", *tmp;
700 unsigned char **argv;
701 uint32 *argv_lens, *argv_types;
704 if (!IS_SILC_SERVER(server) || !server->connected)
705 cmd_return_error(CMDERR_NOT_CONNECTED);
707 if (!IS_SILC_CHANNEL(item))
708 cmd_return_error(CMDERR_NOT_JOINED);
710 /* Now parse all arguments */
711 tmp = g_strconcat(tmpcmd, " ", data, NULL);
712 silc_parse_command_line(tmp, &argv, &argv_lens,
713 &argv_types, &argc, 2);
717 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
719 chanrec = silc_channel_find(server, item->name);
721 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
723 /* Send the action message */
724 silc_client_send_channel_message(silc_client, server->conn,
725 chanrec->entry, NULL,
726 SILC_MESSAGE_FLAG_NOTICE,
727 argv[1], argv_lens[1], TRUE);
729 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
730 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
731 server->conn->local_entry->nickname, argv[1]);
733 for (i = 0; i < argc; i++)
735 silc_free(argv_lens);
736 silc_free(argv_types);
739 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
742 static void command_away(const char *data, SILC_SERVER_REC *server,
747 if (!IS_SILC_SERVER(server) || !server->connected)
748 cmd_return_error(CMDERR_NOT_CONNECTED);
751 /* Remove any possible away message */
752 silc_client_set_away_message(silc_client, server->conn, NULL);
755 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
758 /* Set the away message */
759 silc_client_set_away_message(silc_client, server->conn, (char *)data);
762 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
763 SILCTXT_SET_AWAY, data);
766 signal_emit("away mode changed", 1, server);
768 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
772 int type; /* 1 = msg, 2 = channel */
774 SILC_SERVER_REC *server;
777 /* Key agreement callback that is called after the key agreement protocol
778 has been performed. This is called also if error occured during the
779 key agreement protocol. The `key' is the allocated key material and
780 the caller is responsible of freeing it. The `key' is NULL if error
781 has occured. The application can freely use the `key' to whatever
782 purpose it needs. See lib/silcske/silcske.h for the definition of
783 the SilcSKEKeyMaterial structure. */
785 static void keyagr_completion(SilcClient client,
786 SilcClientConnection conn,
787 SilcClientEntry client_entry,
788 SilcKeyAgreementStatus status,
789 SilcSKEKeyMaterial *key,
792 KeyInternal i = (KeyInternal)context;
795 case SILC_KEY_AGREEMENT_OK:
796 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
797 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
800 /* Set the private key for this client */
801 silc_client_del_private_message_key(client, conn, client_entry);
802 silc_client_add_private_message_key_ske(client, conn, client_entry,
803 NULL, key, i->responder);
804 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
805 SILCTXT_KEY_AGREEMENT_PRIVMSG,
806 client_entry->nickname);
807 silc_ske_free_key_material(key);
812 case SILC_KEY_AGREEMENT_ERROR:
813 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
814 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
817 case SILC_KEY_AGREEMENT_FAILURE:
818 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
819 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
822 case SILC_KEY_AGREEMENT_TIMEOUT:
823 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
824 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
827 case SILC_KEY_AGREEMENT_ABORTED:
828 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
829 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
840 /* Local command KEY. This command is used to set and unset private
841 keys for channels, set and unset private keys for private messages
842 with remote clients and to send key agreement requests and
843 negotiate the key agreement protocol with remote client. The
844 key agreement is supported only to negotiate private message keys,
845 it currently cannot be used to negotiate private keys for channels,
846 as it is not convenient for that purpose. */
849 SILC_SERVER_REC *server;
855 /* Callback to be called after client information is resolved from the
858 static void silc_client_command_key_get_clients(SilcClient client,
859 SilcClientConnection conn,
860 SilcClientEntry *clients,
861 uint32 clients_count,
864 KeyGetClients internal = (KeyGetClients)context;
867 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
869 silc_free(internal->data);
870 silc_free(internal->nick);
875 signal_emit("command key", 3, internal->data, internal->server,
878 silc_free(internal->data);
879 silc_free(internal->nick);
883 static void command_key(const char *data, SILC_SERVER_REC *server,
886 SilcClientConnection conn;
887 SilcClientEntry *entrys, client_entry = NULL;
889 SilcChannelEntry channel_entry = NULL;
890 char *nickname = NULL, *tmp;
891 int command = 0, port = 0, type = 0;
892 char *hostname = NULL;
893 KeyInternal internal = NULL;
895 unsigned char **argv;
896 uint32 *argv_lens, *argv_types;
897 char *bindhost = NULL;
899 if (!server || !IS_SILC_SERVER(server) || !server->connected)
900 cmd_return_error(CMDERR_NOT_CONNECTED);
904 /* Now parse all arguments */
905 tmp = g_strconcat("KEY", " ", data, NULL);
906 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
910 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
913 if (!strcasecmp(argv[1], "msg"))
915 if (!strcasecmp(argv[1], "channel"))
919 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
922 if (argv[2][0] == '*') {
923 nickname = strdup("*");
925 /* Parse the typed nickname. */
926 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
927 printformat_module("fe-common/silc", server, NULL,
928 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
932 /* Find client entry */
933 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
934 argv[2], &entry_count);
936 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
937 inter->server = server;
938 inter->data = strdup(data);
939 inter->nick = strdup(nickname);
941 silc_client_get_clients(silc_client, conn, nickname, argv[2],
942 silc_client_command_key_get_clients, inter);
945 client_entry = entrys[0];
951 /* Get channel entry */
954 if (argv[2][0] == '*') {
955 if (!conn->current_channel) {
957 cmd_return_error(CMDERR_NOT_JOINED);
959 name = conn->current_channel->channel_name;
964 channel_entry = silc_client_get_channel(silc_client, conn, name);
965 if (!channel_entry) {
967 cmd_return_error(CMDERR_NOT_JOINED);
972 if (!strcasecmp(argv[3], "set")) {
976 if (type == 1 && client_entry) {
977 /* Set private message key */
979 silc_client_del_private_message_key(silc_client, conn, client_entry);
982 silc_client_add_private_message_key(silc_client, conn, client_entry,
986 TRUE : FALSE), FALSE);
988 silc_client_add_private_message_key(silc_client, conn, client_entry,
992 TRUE : FALSE), FALSE);
994 /* Send the key to the remote client so that it starts using it
996 silc_client_send_private_message_key(silc_client, conn,
998 } else if (type == 2) {
999 /* Set private channel key */
1000 char *cipher = NULL, *hmac = NULL;
1002 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
1003 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1004 SILCTXT_CH_PRIVATE_KEY_NOMODE,
1005 channel_entry->channel_name);
1014 if (!silc_client_add_channel_private_key(silc_client, conn,
1019 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1020 SILCTXT_CH_PRIVATE_KEY_ERROR,
1021 channel_entry->channel_name);
1025 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1026 SILCTXT_CH_PRIVATE_KEY_ADD,
1027 channel_entry->channel_name);
1035 if (!strcasecmp(argv[3], "unset")) {
1038 if (type == 1 && client_entry) {
1039 /* Unset private message key */
1040 silc_client_del_private_message_key(silc_client, conn, client_entry);
1041 } else if (type == 2) {
1042 /* Unset channel key(s) */
1043 SilcChannelPrivateKey *keys;
1048 silc_client_del_channel_private_keys(silc_client, conn,
1052 number = atoi(argv[4]);
1053 keys = silc_client_list_channel_private_keys(silc_client, conn,
1059 if (!number || number > keys_count) {
1060 silc_client_free_channel_private_keys(keys, keys_count);
1064 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1066 silc_client_free_channel_private_keys(keys, keys_count);
1074 if (!strcasecmp(argv[3], "list")) {
1078 SilcPrivateMessageKeys keys;
1083 keys = silc_client_list_private_message_keys(silc_client, conn,
1088 /* list the private message key(s) */
1089 if (nickname[0] == '*') {
1090 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1091 SILCTXT_PRIVATE_KEY_LIST);
1092 for (k = 0; k < keys_count; k++) {
1093 memset(buf, 0, sizeof(buf));
1094 strncat(buf, " ", 2);
1095 len = strlen(keys[k].client_entry->nickname);
1096 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1098 for (i = 0; i < 30 - len; i++)
1102 len = strlen(keys[k].cipher);
1103 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1105 for (i = 0; i < 14 - len; i++)
1110 strcat(buf, "<hidden>");
1112 strcat(buf, "*generated*");
1114 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1117 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1118 SILCTXT_PRIVATE_KEY_LIST_NICK,
1119 client_entry->nickname);
1120 for (k = 0; k < keys_count; k++) {
1121 if (keys[k].client_entry != client_entry)
1124 memset(buf, 0, sizeof(buf));
1125 strncat(buf, " ", 2);
1126 len = strlen(keys[k].client_entry->nickname);
1127 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1129 for (i = 0; i < 30 - len; i++)
1133 len = strlen(keys[k].cipher);
1134 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1136 for (i = 0; i < 14 - len; i++)
1141 strcat(buf, "<hidden>");
1143 strcat(buf, "*generated*");
1145 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1149 silc_client_free_private_message_keys(keys, keys_count);
1151 } else if (type == 2) {
1152 SilcChannelPrivateKey *keys;
1157 keys = silc_client_list_channel_private_keys(silc_client, conn,
1161 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1162 SILCTXT_CH_PRIVATE_KEY_LIST,
1163 channel_entry->channel_name);
1168 for (k = 0; k < keys_count; k++) {
1169 memset(buf, 0, sizeof(buf));
1170 strncat(buf, " ", 2);
1172 len = strlen(keys[k]->cipher->cipher->name);
1173 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1175 for (i = 0; i < 16 - len; i++)
1179 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1180 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1182 for (i = 0; i < 16 - len; i++)
1186 strcat(buf, "<hidden>");
1188 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1191 silc_client_free_channel_private_keys(keys, keys_count);
1197 /* Send command is used to send key agreement */
1198 if (!strcasecmp(argv[3], "agreement")) {
1204 port = atoi(argv[5]);
1206 internal = silc_calloc(1, sizeof(*internal));
1207 internal->type = type;
1208 internal->server = server;
1211 if (settings_get_bool("use_auto_addr")) {
1213 hostname = (char *)settings_get_str("auto_public_ip");
1215 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1218 if ((hostname) && (*hostname == '\0')) {
1222 bindhost = (char *)settings_get_str("auto_bind_ip");
1224 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1225 * public_ip is the same value as the bind_ip.
1227 if ((bindhost) && (*bindhost == '\0')) {
1228 bindhost = hostname;
1230 port = settings_get_int("auto_bind_port");
1232 } /* if use_auto_addr */
1236 /* Start command is used to start key agreement (after receiving the
1237 key_agreement client operation). */
1238 if (!strcasecmp(argv[3], "negotiate")) {
1244 port = atoi(argv[5]);
1246 internal = silc_calloc(1, sizeof(*internal));
1247 internal->type = type;
1248 internal->server = server;
1252 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1253 "Usage: /KEY msg|channel <nickname|channel> "
1254 "set|unset|agreement|negotiate [<arguments>]");
1258 if (command == 4 && client_entry) {
1259 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1260 SILCTXT_KEY_AGREEMENT, argv[2]);
1261 internal->responder = TRUE;
1262 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1263 bindhost, port, 120, keyagr_completion,
1266 silc_free(internal);
1270 if (command == 5 && client_entry && hostname) {
1271 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1272 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1273 internal->responder = FALSE;
1274 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1275 hostname, port, keyagr_completion,
1281 silc_free(nickname);
1284 /* Lists locally saved client and server public keys. */
1286 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1292 void silc_channels_init(void)
1294 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1295 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1296 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1298 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1299 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1300 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1301 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1302 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1303 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1304 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1305 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1306 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1307 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1308 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1309 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1310 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1312 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1313 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1314 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1315 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1316 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1317 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1318 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1320 silc_nicklist_init();
1323 void silc_channels_deinit(void)
1325 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1326 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1327 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1329 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1330 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1331 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1332 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1333 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1334 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1335 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1336 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1337 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1338 signal_remove("silc event channel_change",
1339 (SIGNAL_FUNC) event_channel_change);
1340 signal_remove("silc event server_signoff",
1341 (SIGNAL_FUNC) event_server_signoff);
1342 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1343 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1345 command_unbind("part", (SIGNAL_FUNC) command_part);
1346 command_unbind("me", (SIGNAL_FUNC) command_me);
1347 command_unbind("action", (SIGNAL_FUNC) command_action);
1348 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1349 command_unbind("away", (SIGNAL_FUNC) command_away);
1350 command_unbind("key", (SIGNAL_FUNC) command_key);
1351 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1353 silc_nicklist_deinit();