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;
142 client = va_arg(va, SilcClientEntry);
143 channel = va_arg(va, SilcChannelEntry);
145 if (client == server->conn->local_entry) {
146 /* You joined to channel */
147 chanrec = silc_channel_find(server, channel->channel_name);
148 if (chanrec != NULL && !chanrec->joined)
149 chanrec->entry = channel;
151 chanrec = silc_channel_find_entry(server, channel);
152 if (chanrec != NULL) {
153 SilcChannelUser user;
155 silc_list_start(chanrec->entry->clients);
156 while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
157 if (user->client == client) {
158 nickrec = silc_nicklist_insert(chanrec, user, TRUE);
164 signal_emit("message join", 4, server, channel->channel_name,
166 client->username == NULL ? "" : client->username);
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;
180 client = va_arg(va, SilcClientEntry);
181 channel = va_arg(va, SilcChannelEntry);
183 signal_emit("message part", 5, server, channel->channel_name,
184 client->nickname, client->username ? client->username : "",
187 chanrec = silc_channel_find_entry(server, channel);
188 if (chanrec != NULL) {
189 nickrec = silc_nicklist_find(chanrec, client);
191 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
196 * "event signoff". Left the network.
199 static void event_signoff(SILC_SERVER_REC *server, va_list va)
201 SilcClientEntry client;
205 client = va_arg(va, SilcClientEntry);
206 message = va_arg(va, char *);
208 signal_emit("message quit", 4, server, client->nickname,
209 client->username ? client->username : "",
210 message ? message : "");
212 nicks = nicklist_get_same_unique(SERVER(server), client);
213 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
214 CHANNEL_REC *channel = tmp->data;
215 NICK_REC *nickrec = tmp->next->data;
217 nicklist_remove(channel, nickrec);
222 * "event topic". Changed topic.
225 static void event_topic(SILC_SERVER_REC *server, va_list va)
227 SILC_CHANNEL_REC *chanrec;
228 SilcClientEntry client;
229 SilcChannelEntry channel;
232 client = va_arg(va, SilcClientEntry);
233 topic = va_arg(va, char *);
234 channel = va_arg(va, SilcChannelEntry);
236 chanrec = silc_channel_find_entry(server, channel);
237 if (chanrec != NULL) {
238 g_free_not_null(chanrec->topic);
239 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
240 signal_emit("channel topic changed", 1, chanrec);
243 signal_emit("message topic", 5, server, channel->channel_name,
244 topic, client->nickname, client->username);
248 * "event invite". Invited or modified invite list.
251 static void event_invite(SILC_SERVER_REC *server, va_list va)
253 SilcClientEntry client;
254 SilcChannelEntry channel;
257 channel = va_arg(va, SilcChannelEntry);
258 channel_name = va_arg(va, char *);
259 client = va_arg(va, SilcClientEntry);
261 signal_emit("message invite", 4, server, channel ? channel->channel_name :
262 channel_name, client->nickname, client->username);
266 * "event nick". Changed nickname.
269 static void event_nick(SILC_SERVER_REC *server, va_list va)
271 SilcClientEntry oldclient, newclient;
273 oldclient = va_arg(va, SilcClientEntry);
274 newclient = va_arg(va, SilcClientEntry);
276 nicklist_rename_unique(SERVER(server),
277 oldclient, oldclient->nickname,
278 newclient, newclient->nickname);
280 signal_emit("message nick", 4, server, newclient->nickname,
281 oldclient->nickname, newclient->username);
285 * "event cmode". Changed channel mode.
288 static void event_cmode(SILC_SERVER_REC *server, va_list va)
290 SILC_CHANNEL_REC *chanrec;
292 SilcClientEntry client;
293 SilcServerEntry server_entry;
294 SilcChannelEntry channel;
299 idtype = va_arg(va, int);
300 entry = va_arg(va, void *);
301 modei = va_arg(va, uint32);
302 (void)va_arg(va, char *);
303 (void)va_arg(va, char *);
304 channel = va_arg(va, SilcChannelEntry);
306 mode = silc_client_chmode(modei,
307 channel->channel_key->cipher->name,
308 channel->hmac->hmac->name);
310 chanrec = silc_channel_find_entry(server, channel);
311 if (chanrec != NULL) {
312 g_free_not_null(chanrec->mode);
313 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
314 signal_emit("channel mode changed", 1, chanrec);
317 if (idtype == SILC_ID_CLIENT) {
318 client = (SilcClientEntry)entry;
319 printformat_module("fe-common/silc", server, channel->channel_name,
320 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
321 channel->channel_name, mode ? mode : "removed all",
324 server_entry = (SilcServerEntry)entry;
325 printformat_module("fe-common/silc", server, channel->channel_name,
326 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
327 channel->channel_name, mode ? mode : "removed all",
328 server_entry->server_name);
335 * "event cumode". Changed user's mode on channel.
338 static void event_cumode(SILC_SERVER_REC *server, va_list va)
340 SILC_CHANNEL_REC *chanrec;
341 SilcClientEntry client, destclient;
342 SilcChannelEntry channel;
346 client = va_arg(va, SilcClientEntry);
347 mode = va_arg(va, uint32);
348 destclient = va_arg(va, SilcClientEntry);
349 channel = va_arg(va, SilcChannelEntry);
351 modestr = silc_client_chumode(mode);
352 chanrec = silc_channel_find_entry(server, channel);
353 if (chanrec != NULL) {
356 if (destclient == server->conn->local_entry) {
358 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
361 nick = silc_nicklist_find(chanrec, destclient);
363 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
364 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
365 signal_emit("nick mode changed", 2, chanrec, nick);
369 printformat_module("fe-common/silc", server, channel->channel_name,
370 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
371 channel->channel_name, destclient->nickname,
372 modestr ? modestr : "removed all",
375 if (mode & SILC_CHANNEL_UMODE_CHANFO)
376 printformat_module("fe-common/silc",
377 server, channel->channel_name, MSGLEVEL_CRAP,
378 SILCTXT_CHANNEL_FOUNDER,
379 channel->channel_name, destclient->nickname);
385 * "event motd". Received MOTD.
388 static void event_motd(SILC_SERVER_REC *server, va_list va)
390 char *text = va_arg(va, char *);
392 if (!settings_get_bool("skip_motd"))
393 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
397 * "event channel_change". Channel ID has changed.
400 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
402 /* Nothing interesting to do */
406 * "event server_signoff". Server has quit the network.
409 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
411 SilcClientEntry *clients;
412 uint32 clients_count;
415 (void)va_arg(va, void *);
416 clients = va_arg(va, SilcClientEntry *);
417 clients_count = va_arg(va, uint32);
419 for (i = 0; i < clients_count; i++)
420 signal_emit("message quit", 4, server, clients[i]->nickname,
421 clients[i]->username ? clients[i]->username : "",
426 * "event kick". Someone was kicked from channel.
429 static void event_kick(SILC_SERVER_REC *server, va_list va)
431 SilcClientConnection conn = server->conn;
432 SilcClientEntry client_entry;
433 SilcChannelEntry channel_entry;
435 SILC_CHANNEL_REC *chanrec;
437 client_entry = va_arg(va, SilcClientEntry);
438 tmp = va_arg(va, char *);
439 channel_entry = va_arg(va, SilcChannelEntry);
441 chanrec = silc_channel_find_entry(server, channel_entry);
443 if (client_entry == conn->local_entry) {
444 printformat_module("fe-common/silc", server, channel_entry->channel_name,
445 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
446 channel_entry->channel_name, tmp ? tmp : "");
448 chanrec->kicked = TRUE;
449 channel_destroy((CHANNEL_REC *)chanrec);
452 printformat_module("fe-common/silc", server, channel_entry->channel_name,
453 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
454 client_entry->nickname,
455 channel_entry->channel_name, tmp ? tmp : "");
458 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
460 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
466 * "event kill". Someone was killed from the network.
469 static void event_kill(SILC_SERVER_REC *server, va_list va)
471 SilcClientConnection conn = server->conn;
472 SilcClientEntry client_entry;
475 client_entry = va_arg(va, SilcClientEntry);
476 tmp = va_arg(va, char *);
478 if (client_entry == conn->local_entry) {
479 printformat_module("fe-common/silc", server, NULL,
480 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
483 GSList *nicks, *tmpn;
484 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
485 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
486 CHANNEL_REC *channel = tmpn->data;
487 NICK_REC *nickrec = tmpn->next->data;
488 nicklist_remove(channel, nickrec);
491 printformat_module("fe-common/silc", server, NULL,
492 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
493 client_entry->nickname,
498 /* PART (LEAVE) command. */
500 static void command_part(const char *data, SILC_SERVER_REC *server,
503 SILC_CHANNEL_REC *chanrec;
505 if (!IS_SILC_SERVER(server) || !server->connected)
506 cmd_return_error(CMDERR_NOT_CONNECTED);
508 if (!strcmp(data, "*") || *data == '\0') {
509 if (!IS_SILC_CHANNEL(item))
510 cmd_return_error(CMDERR_NOT_JOINED);
514 chanrec = silc_channel_find(server, data);
516 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
518 signal_emit("message part", 5, server, chanrec->name,
519 server->nick, server->conn->local_entry->username, "");
521 silc_command_exec(server, "LEAVE", chanrec->name);
524 channel_destroy(CHANNEL(chanrec));
527 /* ME local command. */
529 static void command_me(const char *data, SILC_SERVER_REC *server,
532 SILC_CHANNEL_REC *chanrec;
533 char *tmpcmd = "ME", *tmp;
535 unsigned char **argv;
536 uint32 *argv_lens, *argv_types;
539 if (!IS_SILC_SERVER(server) || !server->connected)
540 cmd_return_error(CMDERR_NOT_CONNECTED);
542 if (!IS_SILC_CHANNEL(item))
543 cmd_return_error(CMDERR_NOT_JOINED);
545 /* Now parse all arguments */
546 tmp = g_strconcat(tmpcmd, " ", data, NULL);
547 silc_parse_command_line(tmp, &argv, &argv_lens,
548 &argv_types, &argc, 2);
552 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
554 chanrec = silc_channel_find(server, item->name);
556 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
558 /* Send the action message */
559 silc_client_send_channel_message(silc_client, server->conn,
560 chanrec->entry, NULL,
561 SILC_MESSAGE_FLAG_ACTION,
562 argv[1], argv_lens[1], TRUE);
564 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
565 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
566 server->conn->local_entry->nickname, argv[1]);
568 for (i = 0; i < argc; i++)
570 silc_free(argv_lens);
571 silc_free(argv_types);
574 /* ACTION local command. Same as ME but takes the channel as mandatory
577 static void command_action(const char *data, SILC_SERVER_REC *server,
580 SILC_CHANNEL_REC *chanrec;
581 char *tmpcmd = "ME", *tmp;
583 unsigned char **argv;
584 uint32 *argv_lens, *argv_types;
587 if (!IS_SILC_SERVER(server) || !server->connected)
588 cmd_return_error(CMDERR_NOT_CONNECTED);
590 if (!IS_SILC_CHANNEL(item))
591 cmd_return_error(CMDERR_NOT_JOINED);
593 /* Now parse all arguments */
594 tmp = g_strconcat(tmpcmd, " ", data, NULL);
595 silc_parse_command_line(tmp, &argv, &argv_lens,
596 &argv_types, &argc, 3);
600 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
602 chanrec = silc_channel_find(server, argv[1]);
604 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
606 /* Send the action message */
607 silc_client_send_channel_message(silc_client, server->conn,
608 chanrec->entry, NULL,
609 SILC_MESSAGE_FLAG_ACTION,
610 argv[2], argv_lens[2], TRUE);
612 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
613 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
614 server->conn->local_entry->nickname, argv[2]);
616 for (i = 0; i < argc; i++)
618 silc_free(argv_lens);
619 silc_free(argv_types);
622 /* NOTICE local command. */
624 static void command_notice(const char *data, SILC_SERVER_REC *server,
627 SILC_CHANNEL_REC *chanrec;
628 char *tmpcmd = "ME", *tmp;
630 unsigned char **argv;
631 uint32 *argv_lens, *argv_types;
634 if (!IS_SILC_SERVER(server) || !server->connected)
635 cmd_return_error(CMDERR_NOT_CONNECTED);
637 if (!IS_SILC_CHANNEL(item))
638 cmd_return_error(CMDERR_NOT_JOINED);
640 /* Now parse all arguments */
641 tmp = g_strconcat(tmpcmd, " ", data, NULL);
642 silc_parse_command_line(tmp, &argv, &argv_lens,
643 &argv_types, &argc, 2);
647 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
649 chanrec = silc_channel_find(server, item->name);
651 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
653 /* Send the action message */
654 silc_client_send_channel_message(silc_client, server->conn,
655 chanrec->entry, NULL,
656 SILC_MESSAGE_FLAG_NOTICE,
657 argv[1], argv_lens[1], TRUE);
659 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
660 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
661 server->conn->local_entry->nickname, argv[1]);
663 for (i = 0; i < argc; i++)
665 silc_free(argv_lens);
666 silc_free(argv_types);
669 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
672 static void command_away(const char *data, SILC_SERVER_REC *server,
677 if (!IS_SILC_SERVER(server) || !server->connected)
678 cmd_return_error(CMDERR_NOT_CONNECTED);
681 /* Remove any possible away message */
682 silc_client_set_away_message(silc_client, server->conn, NULL);
685 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
688 /* Set the away message */
689 silc_client_set_away_message(silc_client, server->conn, (char *)data);
692 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
693 SILCTXT_SET_AWAY, data);
696 signal_emit("away mode changed", 1, server);
698 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
702 int type; /* 1 = msg, 2 = channel */
704 SILC_SERVER_REC *server;
707 /* Key agreement callback that is called after the key agreement protocol
708 has been performed. This is called also if error occured during the
709 key agreement protocol. The `key' is the allocated key material and
710 the caller is responsible of freeing it. The `key' is NULL if error
711 has occured. The application can freely use the `key' to whatever
712 purpose it needs. See lib/silcske/silcske.h for the definition of
713 the SilcSKEKeyMaterial structure. */
715 static void keyagr_completion(SilcClient client,
716 SilcClientConnection conn,
717 SilcClientEntry client_entry,
718 SilcKeyAgreementStatus status,
719 SilcSKEKeyMaterial *key,
722 KeyInternal i = (KeyInternal)context;
725 case SILC_KEY_AGREEMENT_OK:
726 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
727 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
730 /* Set the private key for this client */
731 silc_client_del_private_message_key(client, conn, client_entry);
732 silc_client_add_private_message_key_ske(client, conn, client_entry,
733 NULL, key, i->responder);
734 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
735 SILCTXT_KEY_AGREEMENT_PRIVMSG,
736 client_entry->nickname);
737 silc_ske_free_key_material(key);
742 case SILC_KEY_AGREEMENT_ERROR:
743 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
744 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
747 case SILC_KEY_AGREEMENT_FAILURE:
748 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
749 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
752 case SILC_KEY_AGREEMENT_TIMEOUT:
753 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
754 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
765 /* Local command KEY. This command is used to set and unset private
766 keys for channels, set and unset private keys for private messages
767 with remote clients and to send key agreement requests and
768 negotiate the key agreement protocol with remote client. The
769 key agreement is supported only to negotiate private message keys,
770 it currently cannot be used to negotiate private keys for channels,
771 as it is not convenient for that purpose. */
774 SILC_SERVER_REC *server;
779 /* Callback to be called after client information is resolved from the
782 SILC_CLIENT_CMD_FUNC(key_get_clients)
784 KeyGetClients internal = (KeyGetClients)context;
785 signal_emit("command key", 3, internal->data, internal->server,
787 silc_free(internal->data);
791 static void command_key(const char *data, SILC_SERVER_REC *server,
794 SilcClientConnection conn = server->conn;
795 SilcClientEntry client_entry = NULL;
796 SilcChannelEntry channel_entry = NULL;
798 char *nickname = NULL, *serv = NULL, *tmp;
799 int command = 0, port = 0, type = 0;
800 char *hostname = NULL;
801 KeyInternal internal = NULL;
803 unsigned char **argv;
804 uint32 *argv_lens, *argv_types;
806 if (!IS_SILC_SERVER(server) || !server->connected)
807 cmd_return_error(CMDERR_NOT_CONNECTED);
809 /* Now parse all arguments */
810 tmp = g_strconcat("KEY", " ", data, NULL);
811 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
815 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
816 "Usage: /KEY msg|channel <nickname|channel> "
817 "set|unset|agreement|negotiate [<arguments>]");
822 if (!strcasecmp(argv[1], "msg"))
824 if (!strcasecmp(argv[1], "channel"))
828 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
829 "Usage: /KEY msg|channel <nickname|channel> "
830 "set|unset|agreement|negotiate [<arguments>]");
835 if (argv[2][0] == '*') {
838 /* Parse the typed nickname. */
839 if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) {
840 printformat_module("fe-common/silc", server, NULL,
841 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
845 /* Find client entry */
846 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
849 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
850 inter->server = server;
851 inter->data = strdup(data);
854 /* Client entry not found, it was requested thus mark this to be
856 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
858 NULL, silc_client_command_key_get_clients,
866 /* Get channel entry */
869 if (argv[2][0] == '*') {
870 if (!conn->current_channel) {
875 cmd_return_error(CMDERR_NOT_JOINED);
877 name = conn->current_channel->channel_name;
882 channel_entry = silc_client_get_channel(silc_client, conn, name);
883 if (!channel_entry) {
888 cmd_return_error(CMDERR_NOT_JOINED);
893 if (!strcasecmp(argv[3], "set")) {
897 if (type == 1 && client_entry) {
898 /* Set private message key */
900 silc_client_del_private_message_key(silc_client, conn, client_entry);
903 silc_client_add_private_message_key(silc_client, conn, client_entry,
907 TRUE : FALSE), FALSE);
909 silc_client_add_private_message_key(silc_client, conn, client_entry,
913 TRUE : FALSE), FALSE);
915 /* Send the key to the remote client so that it starts using it
917 silc_client_send_private_message_key(silc_client, conn,
919 } else if (type == 2) {
920 /* Set private channel key */
921 char *cipher = NULL, *hmac = NULL;
923 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
924 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
925 SILCTXT_CH_PRIVATE_KEY_NOMODE,
926 channel_entry->channel_name);
935 if (!silc_client_add_channel_private_key(silc_client, conn,
940 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
941 SILCTXT_CH_PRIVATE_KEY_ERROR,
942 channel_entry->channel_name);
946 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
947 SILCTXT_CH_PRIVATE_KEY_ADD,
948 channel_entry->channel_name);
956 if (!strcasecmp(argv[3], "unset")) {
959 if (type == 1 && client_entry) {
960 /* Unset private message key */
961 silc_client_del_private_message_key(silc_client, conn, client_entry);
962 } else if (type == 2) {
963 /* Unset channel key(s) */
964 SilcChannelPrivateKey *keys;
969 silc_client_del_channel_private_keys(silc_client, conn,
973 number = atoi(argv[4]);
974 keys = silc_client_list_channel_private_keys(silc_client, conn,
980 if (!number || number > keys_count) {
981 silc_client_free_channel_private_keys(keys, keys_count);
985 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
987 silc_client_free_channel_private_keys(keys, keys_count);
995 if (!strcasecmp(argv[3], "list")) {
999 SilcPrivateMessageKeys keys;
1004 keys = silc_client_list_private_message_keys(silc_client, conn,
1009 /* list the private message key(s) */
1010 if (nickname[0] == '*') {
1011 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1012 SILCTXT_PRIVATE_KEY_LIST);
1013 for (k = 0; k < keys_count; k++) {
1014 memset(buf, 0, sizeof(buf));
1015 strncat(buf, " ", 2);
1016 len = strlen(keys[k].client_entry->nickname);
1017 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1019 for (i = 0; i < 30 - len; i++)
1023 len = strlen(keys[k].cipher);
1024 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1026 for (i = 0; i < 14 - len; i++)
1031 strcat(buf, "<hidden>");
1033 strcat(buf, "*generated*");
1035 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1038 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1039 SILCTXT_PRIVATE_KEY_LIST_NICK,
1040 client_entry->nickname);
1041 for (k = 0; k < keys_count; k++) {
1042 if (keys[k].client_entry != client_entry)
1045 memset(buf, 0, sizeof(buf));
1046 strncat(buf, " ", 2);
1047 len = strlen(keys[k].client_entry->nickname);
1048 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1050 for (i = 0; i < 30 - len; i++)
1054 len = strlen(keys[k].cipher);
1055 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1057 for (i = 0; i < 14 - len; i++)
1062 strcat(buf, "<hidden>");
1064 strcat(buf, "*generated*");
1066 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1070 silc_client_free_private_message_keys(keys, keys_count);
1071 } else if (type == 2) {
1072 SilcChannelPrivateKey *keys;
1077 keys = silc_client_list_channel_private_keys(silc_client, conn,
1083 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1084 SILCTXT_CH_PRIVATE_KEY_LIST,
1085 channel_entry->channel_name);
1086 for (k = 0; k < keys_count; k++) {
1087 memset(buf, 0, sizeof(buf));
1088 strncat(buf, " ", 2);
1090 len = strlen(keys[k]->cipher->cipher->name);
1091 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1093 for (i = 0; i < 16 - len; i++)
1097 len = strlen(keys[k]->hmac->hmac->name);
1098 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1100 for (i = 0; i < 16 - len; i++)
1104 strcat(buf, "<hidden>");
1106 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1109 silc_client_free_channel_private_keys(keys, keys_count);
1115 /* Send command is used to send key agreement */
1116 if (!strcasecmp(argv[3], "agreement")) {
1122 port = atoi(argv[5]);
1124 internal = silc_calloc(1, sizeof(*internal));
1125 internal->type = type;
1126 internal->server = server;
1129 /* Start command is used to start key agreement (after receiving the
1130 key_agreement client operation). */
1131 if (!strcasecmp(argv[3], "negotiate")) {
1137 port = atoi(argv[5]);
1139 internal = silc_calloc(1, sizeof(*internal));
1140 internal->type = type;
1141 internal->server = server;
1145 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1146 "Usage: /KEY msg|channel <nickname|channel> "
1147 "set|unset|agreement|negotiate [<arguments>]");
1151 if (command == 4 && client_entry) {
1152 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1153 SILCTXT_KEY_AGREEMENT, argv[2]);
1154 internal->responder = TRUE;
1155 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1156 port, 120, keyagr_completion, internal);
1158 silc_free(internal);
1162 if (command == 5 && client_entry && hostname) {
1163 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1164 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1165 internal->responder = FALSE;
1166 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1167 hostname, port, keyagr_completion,
1174 silc_free(nickname);
1179 /* Lists locally saved client and server public keys. */
1181 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1187 void silc_channels_init(void)
1189 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1190 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1191 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1193 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1194 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1195 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1196 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1197 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1198 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1199 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1200 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1201 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1202 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1203 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1204 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1205 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1207 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1208 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1209 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1210 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1211 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1212 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1213 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1215 silc_nicklist_init();
1218 void silc_channels_deinit(void)
1220 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1221 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1222 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1224 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1225 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1226 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1227 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1228 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1229 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1230 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1231 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1232 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1233 signal_remove("silc event channel_change",
1234 (SIGNAL_FUNC) event_channel_change);
1235 signal_remove("silc event server_signoff",
1236 (SIGNAL_FUNC) event_server_signoff);
1237 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1238 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1240 command_unbind("part", (SIGNAL_FUNC) command_part);
1241 command_unbind("me", (SIGNAL_FUNC) command_me);
1242 command_unbind("action", (SIGNAL_FUNC) command_action);
1243 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1244 command_unbind("away", (SIGNAL_FUNC) command_away);
1245 command_unbind("key", (SIGNAL_FUNC) command_key);
1246 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1248 silc_nicklist_deinit();