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, int);
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->cipher->name,
348 silc_hmac_get_name(channel->hmac));
350 chanrec = silc_channel_find_entry(server, channel);
351 if (chanrec != NULL) {
352 g_free_not_null(chanrec->mode);
353 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
354 signal_emit("channel mode changed", 1, chanrec);
357 if (idtype == SILC_ID_CLIENT) {
358 client = (SilcClientEntry)entry;
359 printformat_module("fe-common/silc", server, channel->channel_name,
360 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
361 channel->channel_name, mode ? mode : "removed all",
364 server_entry = (SilcServerEntry)entry;
365 printformat_module("fe-common/silc", server, channel->channel_name,
366 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
367 channel->channel_name, mode ? mode : "removed all",
368 server_entry->server_name);
375 * "event cumode". Changed user's mode on channel.
378 static void event_cumode(SILC_SERVER_REC *server, va_list va)
380 SILC_CHANNEL_REC *chanrec;
381 SilcClientEntry client, destclient;
382 SilcChannelEntry channel;
386 client = va_arg(va, SilcClientEntry);
387 mode = va_arg(va, uint32);
388 destclient = va_arg(va, SilcClientEntry);
389 channel = va_arg(va, SilcChannelEntry);
391 modestr = silc_client_chumode(mode);
392 chanrec = silc_channel_find_entry(server, channel);
393 if (chanrec != NULL) {
396 if (destclient == server->conn->local_entry) {
398 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
401 nick = silc_nicklist_find(chanrec, destclient);
403 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
404 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
405 signal_emit("nick mode changed", 2, chanrec, nick);
409 printformat_module("fe-common/silc", server, channel->channel_name,
410 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
411 channel->channel_name, destclient->nickname,
412 modestr ? modestr : "removed all",
415 if (mode & SILC_CHANNEL_UMODE_CHANFO)
416 printformat_module("fe-common/silc",
417 server, channel->channel_name, MSGLEVEL_CRAP,
418 SILCTXT_CHANNEL_FOUNDER,
419 channel->channel_name, destclient->nickname);
425 * "event motd". Received MOTD.
428 static void event_motd(SILC_SERVER_REC *server, va_list va)
430 char *text = va_arg(va, char *);
432 if (!settings_get_bool("skip_motd"))
433 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
437 * "event channel_change". Channel ID has changed.
440 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
442 /* Nothing interesting to do */
446 * "event server_signoff". Server has quit the network.
449 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
451 SilcClientEntry *clients;
452 uint32 clients_count;
456 (void)va_arg(va, void *);
457 clients = va_arg(va, SilcClientEntry *);
458 clients_count = va_arg(va, uint32);
460 for (i = 0; i < clients_count; i++) {
463 memset(userhost, 0, sizeof(userhost));
464 if (clients[i]->username)
465 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
466 clients[i]->username, clients[i]->hostname);
467 signal_emit("message quit", 4, server, clients[i]->nickname,
468 clients[i]->username ? userhost : "",
471 silc_server_free_ftp(server, clients[i]);
473 nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
474 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
475 CHANNEL_REC *channel = tmp->data;
476 NICK_REC *nickrec = tmp->next->data;
477 nicklist_remove(channel, nickrec);
483 * "event kick". Someone was kicked from channel.
486 static void event_kick(SILC_SERVER_REC *server, va_list va)
488 SilcClientConnection conn = server->conn;
489 SilcClientEntry client_entry, kicker;
490 SilcChannelEntry channel_entry;
492 SILC_CHANNEL_REC *chanrec;
494 client_entry = va_arg(va, SilcClientEntry);
495 tmp = va_arg(va, char *);
496 kicker = va_arg(va, SilcClientEntry);
497 channel_entry = va_arg(va, SilcChannelEntry);
499 chanrec = silc_channel_find_entry(server, channel_entry);
501 if (client_entry == conn->local_entry) {
502 printformat_module("fe-common/silc", server, channel_entry->channel_name,
503 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
505 channel_entry->channel_name, tmp ? tmp : "");
507 chanrec->kicked = TRUE;
508 channel_destroy((CHANNEL_REC *)chanrec);
511 printformat_module("fe-common/silc", server, channel_entry->channel_name,
512 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
513 client_entry->nickname,
515 channel_entry->channel_name, tmp ? tmp : "");
518 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
520 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
526 * "event kill". Someone was killed from the network.
529 static void event_kill(SILC_SERVER_REC *server, va_list va)
531 SilcClientConnection conn = server->conn;
532 SilcClientEntry client_entry;
535 client_entry = va_arg(va, SilcClientEntry);
536 tmp = va_arg(va, char *);
538 if (client_entry == conn->local_entry) {
539 printformat_module("fe-common/silc", server, NULL,
540 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
543 GSList *nicks, *tmpn;
544 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
545 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
546 CHANNEL_REC *channel = tmpn->data;
547 NICK_REC *nickrec = tmpn->next->data;
548 nicklist_remove(channel, nickrec);
551 printformat_module("fe-common/silc", server, NULL,
552 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
553 client_entry->nickname,
558 /* PART (LEAVE) command. */
560 static void command_part(const char *data, SILC_SERVER_REC *server,
563 SILC_CHANNEL_REC *chanrec;
566 if (!IS_SILC_SERVER(server) || !server->connected)
567 cmd_return_error(CMDERR_NOT_CONNECTED);
569 if (!strcmp(data, "*") || *data == '\0') {
570 if (!IS_SILC_CHANNEL(item))
571 cmd_return_error(CMDERR_NOT_JOINED);
575 chanrec = silc_channel_find(server, data);
577 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
579 memset(userhost, 0, sizeof(userhost));
580 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
581 server->conn->local_entry->username,
582 server->conn->local_entry->hostname);
583 signal_emit("message part", 5, server, chanrec->name,
584 server->nick, userhost, "");
586 silc_command_exec(server, "LEAVE", chanrec->name);
589 channel_destroy(CHANNEL(chanrec));
592 /* ME local command. */
594 static void command_me(const char *data, SILC_SERVER_REC *server,
597 SILC_CHANNEL_REC *chanrec;
598 char *tmpcmd = "ME", *tmp;
600 unsigned char **argv;
601 uint32 *argv_lens, *argv_types;
604 if (!IS_SILC_SERVER(server) || !server->connected)
605 cmd_return_error(CMDERR_NOT_CONNECTED);
607 if (!IS_SILC_CHANNEL(item))
608 cmd_return_error(CMDERR_NOT_JOINED);
610 /* Now parse all arguments */
611 tmp = g_strconcat(tmpcmd, " ", data, NULL);
612 silc_parse_command_line(tmp, &argv, &argv_lens,
613 &argv_types, &argc, 2);
617 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
619 chanrec = silc_channel_find(server, item->name);
621 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
623 /* Send the action message */
624 silc_client_send_channel_message(silc_client, server->conn,
625 chanrec->entry, NULL,
626 SILC_MESSAGE_FLAG_ACTION,
627 argv[1], argv_lens[1], TRUE);
629 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
630 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
631 server->conn->local_entry->nickname, argv[1]);
633 for (i = 0; i < argc; i++)
635 silc_free(argv_lens);
636 silc_free(argv_types);
639 /* ACTION local command. Same as ME but takes the channel as mandatory
642 static void command_action(const char *data, SILC_SERVER_REC *server,
645 SILC_CHANNEL_REC *chanrec;
646 char *tmpcmd = "ME", *tmp;
648 unsigned char **argv;
649 uint32 *argv_lens, *argv_types;
652 if (!IS_SILC_SERVER(server) || !server->connected)
653 cmd_return_error(CMDERR_NOT_CONNECTED);
655 if (!IS_SILC_CHANNEL(item))
656 cmd_return_error(CMDERR_NOT_JOINED);
658 /* Now parse all arguments */
659 tmp = g_strconcat(tmpcmd, " ", data, NULL);
660 silc_parse_command_line(tmp, &argv, &argv_lens,
661 &argv_types, &argc, 3);
665 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
667 chanrec = silc_channel_find(server, argv[1]);
669 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
671 /* Send the action message */
672 silc_client_send_channel_message(silc_client, server->conn,
673 chanrec->entry, NULL,
674 SILC_MESSAGE_FLAG_ACTION,
675 argv[2], argv_lens[2], TRUE);
677 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
678 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
679 server->conn->local_entry->nickname, argv[2]);
681 for (i = 0; i < argc; i++)
683 silc_free(argv_lens);
684 silc_free(argv_types);
687 /* NOTICE local command. */
689 static void command_notice(const char *data, SILC_SERVER_REC *server,
692 SILC_CHANNEL_REC *chanrec;
693 char *tmpcmd = "ME", *tmp;
695 unsigned char **argv;
696 uint32 *argv_lens, *argv_types;
699 if (!IS_SILC_SERVER(server) || !server->connected)
700 cmd_return_error(CMDERR_NOT_CONNECTED);
702 if (!IS_SILC_CHANNEL(item))
703 cmd_return_error(CMDERR_NOT_JOINED);
705 /* Now parse all arguments */
706 tmp = g_strconcat(tmpcmd, " ", data, NULL);
707 silc_parse_command_line(tmp, &argv, &argv_lens,
708 &argv_types, &argc, 2);
712 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
714 chanrec = silc_channel_find(server, item->name);
716 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
718 /* Send the action message */
719 silc_client_send_channel_message(silc_client, server->conn,
720 chanrec->entry, NULL,
721 SILC_MESSAGE_FLAG_NOTICE,
722 argv[1], argv_lens[1], TRUE);
724 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
725 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
726 server->conn->local_entry->nickname, argv[1]);
728 for (i = 0; i < argc; i++)
730 silc_free(argv_lens);
731 silc_free(argv_types);
734 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
737 static void command_away(const char *data, SILC_SERVER_REC *server,
742 if (!IS_SILC_SERVER(server) || !server->connected)
743 cmd_return_error(CMDERR_NOT_CONNECTED);
746 /* Remove any possible away message */
747 silc_client_set_away_message(silc_client, server->conn, NULL);
750 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
753 /* Set the away message */
754 silc_client_set_away_message(silc_client, server->conn, (char *)data);
757 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
758 SILCTXT_SET_AWAY, data);
761 signal_emit("away mode changed", 1, server);
763 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
767 int type; /* 1 = msg, 2 = channel */
769 SILC_SERVER_REC *server;
772 /* Key agreement callback that is called after the key agreement protocol
773 has been performed. This is called also if error occured during the
774 key agreement protocol. The `key' is the allocated key material and
775 the caller is responsible of freeing it. The `key' is NULL if error
776 has occured. The application can freely use the `key' to whatever
777 purpose it needs. See lib/silcske/silcske.h for the definition of
778 the SilcSKEKeyMaterial structure. */
780 static void keyagr_completion(SilcClient client,
781 SilcClientConnection conn,
782 SilcClientEntry client_entry,
783 SilcKeyAgreementStatus status,
784 SilcSKEKeyMaterial *key,
787 KeyInternal i = (KeyInternal)context;
790 case SILC_KEY_AGREEMENT_OK:
791 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
792 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
795 /* Set the private key for this client */
796 silc_client_del_private_message_key(client, conn, client_entry);
797 silc_client_add_private_message_key_ske(client, conn, client_entry,
798 NULL, key, i->responder);
799 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
800 SILCTXT_KEY_AGREEMENT_PRIVMSG,
801 client_entry->nickname);
802 silc_ske_free_key_material(key);
807 case SILC_KEY_AGREEMENT_ERROR:
808 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
809 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
812 case SILC_KEY_AGREEMENT_FAILURE:
813 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
814 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
817 case SILC_KEY_AGREEMENT_TIMEOUT:
818 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
819 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
822 case SILC_KEY_AGREEMENT_ABORTED:
823 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
824 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
835 /* Local command KEY. This command is used to set and unset private
836 keys for channels, set and unset private keys for private messages
837 with remote clients and to send key agreement requests and
838 negotiate the key agreement protocol with remote client. The
839 key agreement is supported only to negotiate private message keys,
840 it currently cannot be used to negotiate private keys for channels,
841 as it is not convenient for that purpose. */
844 SILC_SERVER_REC *server;
850 /* Callback to be called after client information is resolved from the
853 static void silc_client_command_key_get_clients(SilcClient client,
854 SilcClientConnection conn,
855 SilcClientEntry *clients,
856 uint32 clients_count,
859 KeyGetClients internal = (KeyGetClients)context;
862 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
864 silc_free(internal->data);
865 silc_free(internal->nick);
870 signal_emit("command key", 3, internal->data, internal->server,
873 silc_free(internal->data);
874 silc_free(internal->nick);
878 static void command_key(const char *data, SILC_SERVER_REC *server,
881 SilcClientConnection conn;
882 SilcClientEntry *entrys, client_entry = NULL;
884 SilcChannelEntry channel_entry = NULL;
885 char *nickname = NULL, *tmp;
886 int command = 0, port = 0, type = 0;
887 char *hostname = NULL;
888 KeyInternal internal = NULL;
890 unsigned char **argv;
891 uint32 *argv_lens, *argv_types;
892 char *bindhost = NULL;
894 if (!server || !IS_SILC_SERVER(server) || !server->connected)
895 cmd_return_error(CMDERR_NOT_CONNECTED);
899 /* Now parse all arguments */
900 tmp = g_strconcat("KEY", " ", data, NULL);
901 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
905 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
908 if (!strcasecmp(argv[1], "msg"))
910 if (!strcasecmp(argv[1], "channel"))
914 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
917 if (argv[2][0] == '*') {
918 nickname = strdup("*");
920 /* Parse the typed nickname. */
921 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
922 printformat_module("fe-common/silc", server, NULL,
923 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
927 /* Find client entry */
928 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
929 argv[2], &entry_count);
931 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
932 inter->server = server;
933 inter->data = strdup(data);
934 inter->nick = strdup(nickname);
936 silc_client_get_clients(silc_client, conn, nickname, argv[2],
937 silc_client_command_key_get_clients, inter);
940 client_entry = entrys[0];
946 /* Get channel entry */
949 if (argv[2][0] == '*') {
950 if (!conn->current_channel) {
952 cmd_return_error(CMDERR_NOT_JOINED);
954 name = conn->current_channel->channel_name;
959 channel_entry = silc_client_get_channel(silc_client, conn, name);
960 if (!channel_entry) {
962 cmd_return_error(CMDERR_NOT_JOINED);
967 if (!strcasecmp(argv[3], "set")) {
971 if (type == 1 && client_entry) {
972 /* Set private message key */
974 silc_client_del_private_message_key(silc_client, conn, client_entry);
977 silc_client_add_private_message_key(silc_client, conn, client_entry,
981 TRUE : FALSE), FALSE);
983 silc_client_add_private_message_key(silc_client, conn, client_entry,
987 TRUE : FALSE), FALSE);
989 /* Send the key to the remote client so that it starts using it
991 silc_client_send_private_message_key(silc_client, conn,
993 } else if (type == 2) {
994 /* Set private channel key */
995 char *cipher = NULL, *hmac = NULL;
997 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
998 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
999 SILCTXT_CH_PRIVATE_KEY_NOMODE,
1000 channel_entry->channel_name);
1009 if (!silc_client_add_channel_private_key(silc_client, conn,
1014 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1015 SILCTXT_CH_PRIVATE_KEY_ERROR,
1016 channel_entry->channel_name);
1020 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1021 SILCTXT_CH_PRIVATE_KEY_ADD,
1022 channel_entry->channel_name);
1030 if (!strcasecmp(argv[3], "unset")) {
1033 if (type == 1 && client_entry) {
1034 /* Unset private message key */
1035 silc_client_del_private_message_key(silc_client, conn, client_entry);
1036 } else if (type == 2) {
1037 /* Unset channel key(s) */
1038 SilcChannelPrivateKey *keys;
1043 silc_client_del_channel_private_keys(silc_client, conn,
1047 number = atoi(argv[4]);
1048 keys = silc_client_list_channel_private_keys(silc_client, conn,
1054 if (!number || number > keys_count) {
1055 silc_client_free_channel_private_keys(keys, keys_count);
1059 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1061 silc_client_free_channel_private_keys(keys, keys_count);
1069 if (!strcasecmp(argv[3], "list")) {
1073 SilcPrivateMessageKeys keys;
1078 keys = silc_client_list_private_message_keys(silc_client, conn,
1083 /* list the private message key(s) */
1084 if (nickname[0] == '*') {
1085 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1086 SILCTXT_PRIVATE_KEY_LIST);
1087 for (k = 0; k < keys_count; k++) {
1088 memset(buf, 0, sizeof(buf));
1089 strncat(buf, " ", 2);
1090 len = strlen(keys[k].client_entry->nickname);
1091 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1093 for (i = 0; i < 30 - len; i++)
1097 len = strlen(keys[k].cipher);
1098 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1100 for (i = 0; i < 14 - len; i++)
1105 strcat(buf, "<hidden>");
1107 strcat(buf, "*generated*");
1109 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1112 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1113 SILCTXT_PRIVATE_KEY_LIST_NICK,
1114 client_entry->nickname);
1115 for (k = 0; k < keys_count; k++) {
1116 if (keys[k].client_entry != client_entry)
1119 memset(buf, 0, sizeof(buf));
1120 strncat(buf, " ", 2);
1121 len = strlen(keys[k].client_entry->nickname);
1122 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1124 for (i = 0; i < 30 - len; i++)
1128 len = strlen(keys[k].cipher);
1129 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1131 for (i = 0; i < 14 - len; i++)
1136 strcat(buf, "<hidden>");
1138 strcat(buf, "*generated*");
1140 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1144 silc_client_free_private_message_keys(keys, keys_count);
1146 } else if (type == 2) {
1147 SilcChannelPrivateKey *keys;
1152 keys = silc_client_list_channel_private_keys(silc_client, conn,
1156 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1157 SILCTXT_CH_PRIVATE_KEY_LIST,
1158 channel_entry->channel_name);
1163 for (k = 0; k < keys_count; k++) {
1164 memset(buf, 0, sizeof(buf));
1165 strncat(buf, " ", 2);
1167 len = strlen(keys[k]->cipher->cipher->name);
1168 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1170 for (i = 0; i < 16 - len; i++)
1174 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1175 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1177 for (i = 0; i < 16 - len; i++)
1181 strcat(buf, "<hidden>");
1183 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1186 silc_client_free_channel_private_keys(keys, keys_count);
1192 /* Send command is used to send key agreement */
1193 if (!strcasecmp(argv[3], "agreement")) {
1199 port = atoi(argv[5]);
1201 internal = silc_calloc(1, sizeof(*internal));
1202 internal->type = type;
1203 internal->server = server;
1206 if (settings_get_bool("use_auto_addr")) {
1208 hostname = (char *)settings_get_str("auto_public_ip");
1210 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1213 if ((hostname) && (*hostname == '\0')) {
1217 bindhost = (char *)settings_get_str("auto_bind_ip");
1219 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1220 * public_ip is the same value as the bind_ip.
1222 if ((bindhost) && (*bindhost == '\0')) {
1223 bindhost = hostname;
1225 port = settings_get_int("auto_bind_port");
1227 } /* if use_auto_addr */
1231 /* Start command is used to start key agreement (after receiving the
1232 key_agreement client operation). */
1233 if (!strcasecmp(argv[3], "negotiate")) {
1239 port = atoi(argv[5]);
1241 internal = silc_calloc(1, sizeof(*internal));
1242 internal->type = type;
1243 internal->server = server;
1247 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1248 "Usage: /KEY msg|channel <nickname|channel> "
1249 "set|unset|agreement|negotiate [<arguments>]");
1253 if (command == 4 && client_entry) {
1254 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1255 SILCTXT_KEY_AGREEMENT, argv[2]);
1256 internal->responder = TRUE;
1257 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1258 bindhost, port, 120, keyagr_completion,
1261 silc_free(internal);
1265 if (command == 5 && client_entry && hostname) {
1266 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1267 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1268 internal->responder = FALSE;
1269 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1270 hostname, port, keyagr_completion,
1276 silc_free(nickname);
1279 /* Lists locally saved client and server public keys. */
1281 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1287 void silc_channels_init(void)
1289 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1290 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1291 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1293 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1294 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1295 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1296 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1297 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1298 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1299 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1300 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1301 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1302 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1303 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1304 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1305 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1307 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1308 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1309 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1310 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1311 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1312 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1313 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1315 silc_nicklist_init();
1318 void silc_channels_deinit(void)
1320 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1321 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1322 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1324 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1325 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1326 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1327 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1328 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1329 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1330 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1331 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1332 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1333 signal_remove("silc event channel_change",
1334 (SIGNAL_FUNC) event_channel_change);
1335 signal_remove("silc event server_signoff",
1336 (SIGNAL_FUNC) event_server_signoff);
1337 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1338 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1340 command_unbind("part", (SIGNAL_FUNC) command_part);
1341 command_unbind("me", (SIGNAL_FUNC) command_me);
1342 command_unbind("action", (SIGNAL_FUNC) command_action);
1343 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1344 command_unbind("away", (SIGNAL_FUNC) command_away);
1345 command_unbind("key", (SIGNAL_FUNC) command_key);
1346 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1348 silc_nicklist_deinit();