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 chu = silc_client_on_channel(channel, client);
156 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
160 memset(userhost, 0, sizeof(userhost));
161 if (client->username)
162 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
163 client->username, client->hostname);
164 signal_emit("message join", 4, server, channel->channel_name,
166 client->username == NULL ? "" : userhost);
170 * "event leave". Left a channel.
173 static void event_leave(SILC_SERVER_REC *server, va_list va)
175 SILC_CHANNEL_REC *chanrec;
176 SILC_NICK_REC *nickrec;
177 SilcClientEntry client;
178 SilcChannelEntry channel;
181 client = va_arg(va, SilcClientEntry);
182 channel = va_arg(va, SilcChannelEntry);
184 memset(userhost, 0, sizeof(userhost));
185 if (client->username)
186 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
187 client->username, client->hostname);
188 signal_emit("message part", 5, server, channel->channel_name,
189 client->nickname, client->username ? userhost : "",
192 chanrec = silc_channel_find_entry(server, channel);
193 if (chanrec != NULL) {
194 nickrec = silc_nicklist_find(chanrec, client);
196 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
201 * "event signoff". Left the network.
204 static void event_signoff(SILC_SERVER_REC *server, va_list va)
206 SilcClientEntry client;
211 client = va_arg(va, SilcClientEntry);
212 message = va_arg(va, char *);
214 silc_server_free_ftp(server, client);
216 memset(userhost, 0, sizeof(userhost));
217 if (client->username)
218 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
219 client->username, client->hostname);
220 signal_emit("message quit", 4, server, client->nickname,
221 client->username ? userhost : "",
222 message ? message : "");
224 nicks = nicklist_get_same_unique(SERVER(server), client);
225 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
226 CHANNEL_REC *channel = tmp->data;
227 NICK_REC *nickrec = tmp->next->data;
229 nicklist_remove(channel, nickrec);
234 * "event topic". Changed topic.
237 static void event_topic(SILC_SERVER_REC *server, va_list va)
239 SILC_CHANNEL_REC *chanrec;
241 SilcClientEntry client;
242 SilcServerEntry server_entry;
243 SilcChannelEntry channel;
248 idtype = va_arg(va, SilcIdType);
249 entry = va_arg(va, void *);
250 topic = va_arg(va, char *);
251 channel = va_arg(va, SilcChannelEntry);
253 chanrec = silc_channel_find_entry(server, channel);
254 if (chanrec != NULL) {
255 g_free_not_null(chanrec->topic);
256 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
257 signal_emit("channel topic changed", 1, chanrec);
260 if (idtype == SILC_ID_CLIENT) {
261 client = (SilcClientEntry)entry;
262 memset(userhost, 0, sizeof(userhost));
263 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
264 client->username, client->hostname);
265 signal_emit("message topic", 5, server, channel->channel_name,
266 topic, client->nickname, userhost);
267 } else if (idtype == SILC_ID_SERVER) {
268 server_entry = (SilcServerEntry)entry;
269 signal_emit("message topic", 5, server, channel->channel_name,
270 topic, server_entry->server_name,
271 server_entry->server_name);
273 channel = (SilcChannelEntry)entry;
274 signal_emit("message topic", 5, server, channel->channel_name,
275 topic, channel->channel_name, channel->channel_name);
280 * "event invite". Invited or modified invite list.
283 static void event_invite(SILC_SERVER_REC *server, va_list va)
285 SilcClientEntry client;
286 SilcChannelEntry channel;
290 channel = va_arg(va, SilcChannelEntry);
291 channel_name = va_arg(va, char *);
292 client = va_arg(va, SilcClientEntry);
294 memset(userhost, 0, sizeof(userhost));
295 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
296 client->username, client->hostname);
297 signal_emit("message invite", 4, server, channel ? channel->channel_name :
298 channel_name, client->nickname, userhost);
302 * "event nick". Changed nickname.
305 static void event_nick(SILC_SERVER_REC *server, va_list va)
307 SilcClientEntry oldclient, newclient;
310 oldclient = va_arg(va, SilcClientEntry);
311 newclient = va_arg(va, SilcClientEntry);
313 nicklist_rename_unique(SERVER(server),
314 oldclient, oldclient->nickname,
315 newclient, newclient->nickname);
317 memset(userhost, 0, sizeof(userhost));
318 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
319 newclient->username, newclient->hostname);
320 signal_emit("message nick", 4, server, newclient->nickname,
321 oldclient->nickname, userhost);
325 * "event cmode". Changed channel mode.
328 static void event_cmode(SILC_SERVER_REC *server, va_list va)
330 SILC_CHANNEL_REC *chanrec;
332 SilcClientEntry client;
333 SilcServerEntry server_entry;
334 SilcChannelEntry channel;
339 idtype = va_arg(va, int);
340 entry = va_arg(va, void *);
341 modei = va_arg(va, uint32);
342 (void)va_arg(va, char *);
343 (void)va_arg(va, char *);
344 channel = va_arg(va, SilcChannelEntry);
346 mode = silc_client_chmode(modei,
347 channel->channel_key ?
348 channel->channel_key->cipher->name : "",
350 silc_hmac_get_name(channel->hmac) : "");
352 chanrec = silc_channel_find_entry(server, channel);
353 if (chanrec != NULL) {
354 g_free_not_null(chanrec->mode);
355 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
356 signal_emit("channel mode changed", 1, chanrec);
359 if (idtype == SILC_ID_CLIENT) {
360 client = (SilcClientEntry)entry;
361 printformat_module("fe-common/silc", server, channel->channel_name,
362 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
363 channel->channel_name, mode ? mode : "removed all",
366 server_entry = (SilcServerEntry)entry;
367 printformat_module("fe-common/silc", server, channel->channel_name,
368 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
369 channel->channel_name, mode ? mode : "removed all",
370 server_entry->server_name);
377 * "event cumode". Changed user's mode on channel.
380 static void event_cumode(SILC_SERVER_REC *server, va_list va)
382 SILC_CHANNEL_REC *chanrec;
383 SilcClientEntry client, destclient;
384 SilcChannelEntry channel;
388 client = va_arg(va, SilcClientEntry);
389 mode = va_arg(va, uint32);
390 destclient = va_arg(va, SilcClientEntry);
391 channel = va_arg(va, SilcChannelEntry);
393 modestr = silc_client_chumode(mode);
394 chanrec = silc_channel_find_entry(server, channel);
395 if (chanrec != NULL) {
398 if (destclient == server->conn->local_entry) {
400 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
403 nick = silc_nicklist_find(chanrec, destclient);
405 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
406 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
407 signal_emit("nick mode changed", 2, chanrec, nick);
411 printformat_module("fe-common/silc", server, channel->channel_name,
412 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
413 channel->channel_name, destclient->nickname,
414 modestr ? modestr : "removed all",
417 if (mode & SILC_CHANNEL_UMODE_CHANFO)
418 printformat_module("fe-common/silc",
419 server, channel->channel_name, MSGLEVEL_CRAP,
420 SILCTXT_CHANNEL_FOUNDER,
421 channel->channel_name, destclient->nickname);
427 * "event motd". Received MOTD.
430 static void event_motd(SILC_SERVER_REC *server, va_list va)
432 char *text = va_arg(va, char *);
434 if (!settings_get_bool("skip_motd"))
435 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
439 * "event channel_change". Channel ID has changed.
442 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
444 /* Nothing interesting to do */
448 * "event server_signoff". Server has quit the network.
451 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
453 SilcClientEntry *clients;
454 uint32 clients_count;
458 (void)va_arg(va, void *);
459 clients = va_arg(va, SilcClientEntry *);
460 clients_count = va_arg(va, uint32);
462 for (i = 0; i < clients_count; i++) {
465 memset(userhost, 0, sizeof(userhost));
466 if (clients[i]->username)
467 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
468 clients[i]->username, clients[i]->hostname);
469 signal_emit("message quit", 4, server, clients[i]->nickname,
470 clients[i]->username ? userhost : "",
473 silc_server_free_ftp(server, clients[i]);
475 nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
476 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
477 CHANNEL_REC *channel = tmp->data;
478 NICK_REC *nickrec = tmp->next->data;
479 nicklist_remove(channel, nickrec);
485 * "event kick". Someone was kicked from channel.
488 static void event_kick(SILC_SERVER_REC *server, va_list va)
490 SilcClientConnection conn = server->conn;
491 SilcClientEntry client_entry, kicker;
492 SilcChannelEntry channel_entry;
494 SILC_CHANNEL_REC *chanrec;
496 client_entry = va_arg(va, SilcClientEntry);
497 tmp = va_arg(va, char *);
498 kicker = va_arg(va, SilcClientEntry);
499 channel_entry = va_arg(va, SilcChannelEntry);
501 chanrec = silc_channel_find_entry(server, channel_entry);
503 if (client_entry == conn->local_entry) {
504 printformat_module("fe-common/silc", server, channel_entry->channel_name,
505 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
507 channel_entry->channel_name, tmp ? tmp : "");
509 chanrec->kicked = TRUE;
510 channel_destroy((CHANNEL_REC *)chanrec);
513 printformat_module("fe-common/silc", server, channel_entry->channel_name,
514 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
515 client_entry->nickname,
517 channel_entry->channel_name, tmp ? tmp : "");
520 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
522 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
528 * "event kill". Someone was killed from the network.
531 static void event_kill(SILC_SERVER_REC *server, va_list va)
533 SilcClientConnection conn = server->conn;
534 SilcClientEntry client_entry;
537 client_entry = va_arg(va, SilcClientEntry);
538 tmp = va_arg(va, char *);
540 if (client_entry == conn->local_entry) {
541 printformat_module("fe-common/silc", server, NULL,
542 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
545 GSList *nicks, *tmpn;
546 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
547 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
548 CHANNEL_REC *channel = tmpn->data;
549 NICK_REC *nickrec = tmpn->next->data;
550 nicklist_remove(channel, nickrec);
553 printformat_module("fe-common/silc", server, NULL,
554 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
555 client_entry->nickname,
560 /* PART (LEAVE) command. */
562 static void command_part(const char *data, SILC_SERVER_REC *server,
565 SILC_CHANNEL_REC *chanrec;
568 if (!IS_SILC_SERVER(server) || !server->connected)
569 cmd_return_error(CMDERR_NOT_CONNECTED);
571 if (!strcmp(data, "*") || *data == '\0') {
572 if (!IS_SILC_CHANNEL(item))
573 cmd_return_error(CMDERR_NOT_JOINED);
577 chanrec = silc_channel_find(server, data);
579 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
581 memset(userhost, 0, sizeof(userhost));
582 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
583 server->conn->local_entry->username,
584 server->conn->local_entry->hostname);
585 signal_emit("message part", 5, server, chanrec->name,
586 server->nick, userhost, "");
588 silc_command_exec(server, "LEAVE", chanrec->name);
591 channel_destroy(CHANNEL(chanrec));
594 /* ME local command. */
596 static void command_me(const char *data, SILC_SERVER_REC *server,
599 SILC_CHANNEL_REC *chanrec;
600 char *tmpcmd = "ME", *tmp;
602 unsigned char **argv;
603 uint32 *argv_lens, *argv_types;
606 if (!IS_SILC_SERVER(server) || !server->connected)
607 cmd_return_error(CMDERR_NOT_CONNECTED);
609 if (!IS_SILC_CHANNEL(item))
610 cmd_return_error(CMDERR_NOT_JOINED);
612 /* Now parse all arguments */
613 tmp = g_strconcat(tmpcmd, " ", data, NULL);
614 silc_parse_command_line(tmp, &argv, &argv_lens,
615 &argv_types, &argc, 2);
619 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
621 chanrec = silc_channel_find(server, item->name);
623 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
625 /* Send the action message */
626 silc_client_send_channel_message(silc_client, server->conn,
627 chanrec->entry, NULL,
628 SILC_MESSAGE_FLAG_ACTION,
629 argv[1], argv_lens[1], TRUE);
631 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
632 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
633 server->conn->local_entry->nickname, argv[1]);
635 for (i = 0; i < argc; i++)
637 silc_free(argv_lens);
638 silc_free(argv_types);
641 /* ACTION local command. Same as ME but takes the channel as mandatory
644 static void command_action(const char *data, SILC_SERVER_REC *server,
647 SILC_CHANNEL_REC *chanrec;
648 char *tmpcmd = "ME", *tmp;
650 unsigned char **argv;
651 uint32 *argv_lens, *argv_types;
654 if (!IS_SILC_SERVER(server) || !server->connected)
655 cmd_return_error(CMDERR_NOT_CONNECTED);
657 if (!IS_SILC_CHANNEL(item))
658 cmd_return_error(CMDERR_NOT_JOINED);
660 /* Now parse all arguments */
661 tmp = g_strconcat(tmpcmd, " ", data, NULL);
662 silc_parse_command_line(tmp, &argv, &argv_lens,
663 &argv_types, &argc, 3);
667 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
669 chanrec = silc_channel_find(server, argv[1]);
671 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
673 /* Send the action message */
674 silc_client_send_channel_message(silc_client, server->conn,
675 chanrec->entry, NULL,
676 SILC_MESSAGE_FLAG_ACTION,
677 argv[2], argv_lens[2], TRUE);
679 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
680 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
681 server->conn->local_entry->nickname, argv[2]);
683 for (i = 0; i < argc; i++)
685 silc_free(argv_lens);
686 silc_free(argv_types);
689 /* NOTICE local command. */
691 static void command_notice(const char *data, SILC_SERVER_REC *server,
694 SILC_CHANNEL_REC *chanrec;
695 char *tmpcmd = "ME", *tmp;
697 unsigned char **argv;
698 uint32 *argv_lens, *argv_types;
701 if (!IS_SILC_SERVER(server) || !server->connected)
702 cmd_return_error(CMDERR_NOT_CONNECTED);
704 if (!IS_SILC_CHANNEL(item))
705 cmd_return_error(CMDERR_NOT_JOINED);
707 /* Now parse all arguments */
708 tmp = g_strconcat(tmpcmd, " ", data, NULL);
709 silc_parse_command_line(tmp, &argv, &argv_lens,
710 &argv_types, &argc, 2);
714 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
716 chanrec = silc_channel_find(server, item->name);
718 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
720 /* Send the action message */
721 silc_client_send_channel_message(silc_client, server->conn,
722 chanrec->entry, NULL,
723 SILC_MESSAGE_FLAG_NOTICE,
724 argv[1], argv_lens[1], TRUE);
726 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
727 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
728 server->conn->local_entry->nickname, argv[1]);
730 for (i = 0; i < argc; i++)
732 silc_free(argv_lens);
733 silc_free(argv_types);
736 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
739 static void command_away(const char *data, SILC_SERVER_REC *server,
744 if (!IS_SILC_SERVER(server) || !server->connected)
745 cmd_return_error(CMDERR_NOT_CONNECTED);
748 /* Remove any possible away message */
749 silc_client_set_away_message(silc_client, server->conn, NULL);
752 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
755 /* Set the away message */
756 silc_client_set_away_message(silc_client, server->conn, (char *)data);
759 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
760 SILCTXT_SET_AWAY, data);
763 signal_emit("away mode changed", 1, server);
765 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
769 int type; /* 1 = msg, 2 = channel */
771 SILC_SERVER_REC *server;
774 /* Key agreement callback that is called after the key agreement protocol
775 has been performed. This is called also if error occured during the
776 key agreement protocol. The `key' is the allocated key material and
777 the caller is responsible of freeing it. The `key' is NULL if error
778 has occured. The application can freely use the `key' to whatever
779 purpose it needs. See lib/silcske/silcske.h for the definition of
780 the SilcSKEKeyMaterial structure. */
782 static void keyagr_completion(SilcClient client,
783 SilcClientConnection conn,
784 SilcClientEntry client_entry,
785 SilcKeyAgreementStatus status,
786 SilcSKEKeyMaterial *key,
789 KeyInternal i = (KeyInternal)context;
792 case SILC_KEY_AGREEMENT_OK:
793 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
794 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
797 /* Set the private key for this client */
798 silc_client_del_private_message_key(client, conn, client_entry);
799 silc_client_add_private_message_key_ske(client, conn, client_entry,
800 NULL, key, i->responder);
801 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
802 SILCTXT_KEY_AGREEMENT_PRIVMSG,
803 client_entry->nickname);
804 silc_ske_free_key_material(key);
809 case SILC_KEY_AGREEMENT_ERROR:
810 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
811 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
814 case SILC_KEY_AGREEMENT_FAILURE:
815 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
816 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
819 case SILC_KEY_AGREEMENT_TIMEOUT:
820 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
821 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
824 case SILC_KEY_AGREEMENT_ABORTED:
825 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
826 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
837 /* Local command KEY. This command is used to set and unset private
838 keys for channels, set and unset private keys for private messages
839 with remote clients and to send key agreement requests and
840 negotiate the key agreement protocol with remote client. The
841 key agreement is supported only to negotiate private message keys,
842 it currently cannot be used to negotiate private keys for channels,
843 as it is not convenient for that purpose. */
846 SILC_SERVER_REC *server;
852 /* Callback to be called after client information is resolved from the
855 static void silc_client_command_key_get_clients(SilcClient client,
856 SilcClientConnection conn,
857 SilcClientEntry *clients,
858 uint32 clients_count,
861 KeyGetClients internal = (KeyGetClients)context;
864 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
866 silc_free(internal->data);
867 silc_free(internal->nick);
872 signal_emit("command key", 3, internal->data, internal->server,
875 silc_free(internal->data);
876 silc_free(internal->nick);
880 static void command_key(const char *data, SILC_SERVER_REC *server,
883 SilcClientConnection conn;
884 SilcClientEntry *entrys, client_entry = NULL;
886 SilcChannelEntry channel_entry = NULL;
887 char *nickname = NULL, *tmp;
888 int command = 0, port = 0, type = 0;
889 char *hostname = NULL;
890 KeyInternal internal = NULL;
892 unsigned char **argv;
893 uint32 *argv_lens, *argv_types;
894 char *bindhost = NULL;
896 if (!server || !IS_SILC_SERVER(server) || !server->connected)
897 cmd_return_error(CMDERR_NOT_CONNECTED);
901 /* Now parse all arguments */
902 tmp = g_strconcat("KEY", " ", data, NULL);
903 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
907 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
910 if (!strcasecmp(argv[1], "msg"))
912 if (!strcasecmp(argv[1], "channel"))
916 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
919 if (argv[2][0] == '*') {
920 nickname = strdup("*");
922 /* Parse the typed nickname. */
923 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
924 printformat_module("fe-common/silc", server, NULL,
925 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
929 /* Find client entry */
930 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
931 argv[2], &entry_count);
933 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
934 inter->server = server;
935 inter->data = strdup(data);
936 inter->nick = strdup(nickname);
938 silc_client_get_clients(silc_client, conn, nickname, argv[2],
939 silc_client_command_key_get_clients, inter);
942 client_entry = entrys[0];
948 /* Get channel entry */
951 if (argv[2][0] == '*') {
952 if (!conn->current_channel) {
954 cmd_return_error(CMDERR_NOT_JOINED);
956 name = conn->current_channel->channel_name;
961 channel_entry = silc_client_get_channel(silc_client, conn, name);
962 if (!channel_entry) {
964 cmd_return_error(CMDERR_NOT_JOINED);
969 if (!strcasecmp(argv[3], "set")) {
973 if (type == 1 && client_entry) {
974 /* Set private message key */
976 silc_client_del_private_message_key(silc_client, conn, client_entry);
979 silc_client_add_private_message_key(silc_client, conn, client_entry,
983 TRUE : FALSE), FALSE);
985 silc_client_add_private_message_key(silc_client, conn, client_entry,
989 TRUE : FALSE), FALSE);
991 /* Send the key to the remote client so that it starts using it
993 silc_client_send_private_message_key(silc_client, conn,
995 } else if (type == 2) {
996 /* Set private channel key */
997 char *cipher = NULL, *hmac = NULL;
999 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
1000 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1001 SILCTXT_CH_PRIVATE_KEY_NOMODE,
1002 channel_entry->channel_name);
1011 if (!silc_client_add_channel_private_key(silc_client, conn,
1016 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1017 SILCTXT_CH_PRIVATE_KEY_ERROR,
1018 channel_entry->channel_name);
1022 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1023 SILCTXT_CH_PRIVATE_KEY_ADD,
1024 channel_entry->channel_name);
1032 if (!strcasecmp(argv[3], "unset")) {
1035 if (type == 1 && client_entry) {
1036 /* Unset private message key */
1037 silc_client_del_private_message_key(silc_client, conn, client_entry);
1038 } else if (type == 2) {
1039 /* Unset channel key(s) */
1040 SilcChannelPrivateKey *keys;
1045 silc_client_del_channel_private_keys(silc_client, conn,
1049 number = atoi(argv[4]);
1050 keys = silc_client_list_channel_private_keys(silc_client, conn,
1056 if (!number || number > keys_count) {
1057 silc_client_free_channel_private_keys(keys, keys_count);
1061 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1063 silc_client_free_channel_private_keys(keys, keys_count);
1071 if (!strcasecmp(argv[3], "list")) {
1075 SilcPrivateMessageKeys keys;
1080 keys = silc_client_list_private_message_keys(silc_client, conn,
1085 /* list the private message key(s) */
1086 if (nickname[0] == '*') {
1087 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1088 SILCTXT_PRIVATE_KEY_LIST);
1089 for (k = 0; k < keys_count; k++) {
1090 memset(buf, 0, sizeof(buf));
1091 strncat(buf, " ", 2);
1092 len = strlen(keys[k].client_entry->nickname);
1093 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1095 for (i = 0; i < 30 - len; i++)
1099 len = strlen(keys[k].cipher);
1100 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1102 for (i = 0; i < 14 - len; i++)
1107 strcat(buf, "<hidden>");
1109 strcat(buf, "*generated*");
1111 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1114 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1115 SILCTXT_PRIVATE_KEY_LIST_NICK,
1116 client_entry->nickname);
1117 for (k = 0; k < keys_count; k++) {
1118 if (keys[k].client_entry != client_entry)
1121 memset(buf, 0, sizeof(buf));
1122 strncat(buf, " ", 2);
1123 len = strlen(keys[k].client_entry->nickname);
1124 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1126 for (i = 0; i < 30 - len; i++)
1130 len = strlen(keys[k].cipher);
1131 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1133 for (i = 0; i < 14 - len; i++)
1138 strcat(buf, "<hidden>");
1140 strcat(buf, "*generated*");
1142 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1146 silc_client_free_private_message_keys(keys, keys_count);
1148 } else if (type == 2) {
1149 SilcChannelPrivateKey *keys;
1154 keys = silc_client_list_channel_private_keys(silc_client, conn,
1158 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1159 SILCTXT_CH_PRIVATE_KEY_LIST,
1160 channel_entry->channel_name);
1165 for (k = 0; k < keys_count; k++) {
1166 memset(buf, 0, sizeof(buf));
1167 strncat(buf, " ", 2);
1169 len = strlen(keys[k]->cipher->cipher->name);
1170 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1172 for (i = 0; i < 16 - len; i++)
1176 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1177 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1179 for (i = 0; i < 16 - len; i++)
1183 strcat(buf, "<hidden>");
1185 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1188 silc_client_free_channel_private_keys(keys, keys_count);
1194 /* Send command is used to send key agreement */
1195 if (!strcasecmp(argv[3], "agreement")) {
1201 port = atoi(argv[5]);
1203 internal = silc_calloc(1, sizeof(*internal));
1204 internal->type = type;
1205 internal->server = server;
1208 if (settings_get_bool("use_auto_addr")) {
1210 hostname = (char *)settings_get_str("auto_public_ip");
1212 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1215 if ((hostname) && (*hostname == '\0')) {
1219 bindhost = (char *)settings_get_str("auto_bind_ip");
1221 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1222 * public_ip is the same value as the bind_ip.
1224 if ((bindhost) && (*bindhost == '\0')) {
1225 bindhost = hostname;
1227 port = settings_get_int("auto_bind_port");
1229 } /* if use_auto_addr */
1233 /* Start command is used to start key agreement (after receiving the
1234 key_agreement client operation). */
1235 if (!strcasecmp(argv[3], "negotiate")) {
1241 port = atoi(argv[5]);
1243 internal = silc_calloc(1, sizeof(*internal));
1244 internal->type = type;
1245 internal->server = server;
1249 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1250 "Usage: /KEY msg|channel <nickname|channel> "
1251 "set|unset|agreement|negotiate [<arguments>]");
1255 if (command == 4 && client_entry) {
1256 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1257 SILCTXT_KEY_AGREEMENT, argv[2]);
1258 internal->responder = TRUE;
1259 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1260 bindhost, port, 120, keyagr_completion,
1263 silc_free(internal);
1267 if (command == 5 && client_entry && hostname) {
1268 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1269 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1270 internal->responder = FALSE;
1271 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1272 hostname, port, keyagr_completion,
1278 silc_free(nickname);
1281 /* Lists locally saved client and server public keys. */
1283 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1289 void silc_channels_init(void)
1291 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1292 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1293 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1295 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1296 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1297 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1298 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1299 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1300 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1301 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1302 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1303 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1304 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1305 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1306 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1307 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1309 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1310 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1311 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1312 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1313 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1314 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1315 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1317 silc_nicklist_init();
1320 void silc_channels_deinit(void)
1322 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1323 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1324 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1326 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1327 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1328 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1329 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1330 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1331 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1332 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1333 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1334 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1335 signal_remove("silc event channel_change",
1336 (SIGNAL_FUNC) event_channel_change);
1337 signal_remove("silc event server_signoff",
1338 (SIGNAL_FUNC) event_server_signoff);
1339 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1340 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1342 command_unbind("part", (SIGNAL_FUNC) command_part);
1343 command_unbind("me", (SIGNAL_FUNC) command_me);
1344 command_unbind("action", (SIGNAL_FUNC) command_action);
1345 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1346 command_unbind("away", (SIGNAL_FUNC) command_away);
1347 command_unbind("key", (SIGNAL_FUNC) command_key);
1348 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1350 silc_nicklist_deinit();