2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001 Timo Sirainen
5 Pekka Riikonen <priikone@poseidon.pspt.fi>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
35 #include "channels-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "silc-nicklist.h"
41 #include "window-item-def.h"
43 #include "fe-common/core/printtext.h"
44 #include "fe-common/silc/module-formats.h"
46 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
47 const char *name, int automatic)
49 SILC_CHANNEL_REC *rec;
51 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
52 g_return_val_if_fail(name != NULL, NULL);
54 rec = g_new0(SILC_CHANNEL_REC, 1);
55 rec->chat_type = SILC_PROTOCOL;
56 rec->name = g_strdup(name);
59 channel_init((CHANNEL_REC *) rec, automatic);
63 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
65 if (!IS_SILC_CHANNEL(channel))
68 if (channel->server != NULL && !channel->left && !channel->kicked) {
69 /* destroying channel record without actually
70 having left the channel yet */
71 silc_command_exec(channel->server, "PART", channel->name);
75 static void silc_channels_join(SILC_SERVER_REC *server,
76 const char *channels, int automatic)
78 char **list, **tmp, *channel;
79 SILC_CHANNEL_REC *chanrec;
81 list = g_strsplit(channels, ",", -1);
82 for (tmp = list; *tmp != NULL; tmp++) {
83 channel = **tmp == '#' ? g_strdup(*tmp) :
84 g_strconcat("#", *tmp, NULL);
86 chanrec = silc_channel_find(server, channel);
92 silc_command_exec(server, "JOIN", channel);
99 static void sig_connected(SILC_SERVER_REC *server)
101 if (IS_SILC_SERVER(server))
102 server->channels_join = (void *) silc_channels_join;
105 /* "server quit" signal from the core to indicate that QUIT command
108 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
110 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
111 silc_command_exec(server, "QUIT", msg);
115 * "event join". Joined to a channel.
118 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
119 SilcChannelEntry entry)
123 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
125 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
126 SILC_CHANNEL_REC *rec = tmp->data;
128 if (rec->entry == entry)
135 static void event_join(SILC_SERVER_REC *server, va_list va)
137 SILC_CHANNEL_REC *chanrec;
138 SILC_NICK_REC *nickrec;
139 SilcClientEntry client;
140 SilcChannelEntry channel;
143 client = va_arg(va, SilcClientEntry);
144 channel = va_arg(va, SilcChannelEntry);
146 if (client == server->conn->local_entry) {
147 /* You joined to channel */
148 chanrec = silc_channel_find(server, channel->channel_name);
149 if (chanrec != NULL && !chanrec->joined)
150 chanrec->entry = channel;
152 chanrec = silc_channel_find_entry(server, channel);
153 if (chanrec != NULL) {
154 SilcChannelUser user;
156 silc_list_start(chanrec->entry->clients);
157 while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
158 if (user->client == client) {
159 nickrec = silc_nicklist_insert(chanrec, user, TRUE);
165 if (client->username)
166 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
167 client->username, client->hostname);
168 signal_emit("message join", 4, server, channel->channel_name,
170 client->username == NULL ? "" : userhost);
174 * "event leave". Left a channel.
177 static void event_leave(SILC_SERVER_REC *server, va_list va)
179 SILC_CHANNEL_REC *chanrec;
180 SILC_NICK_REC *nickrec;
181 SilcClientEntry client;
182 SilcChannelEntry channel;
185 client = va_arg(va, SilcClientEntry);
186 channel = va_arg(va, SilcChannelEntry);
188 if (client->username)
189 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
190 client->username, client->hostname);
191 signal_emit("message part", 5, server, channel->channel_name,
192 client->nickname, client->username ? userhost : "",
195 chanrec = silc_channel_find_entry(server, channel);
196 if (chanrec != NULL) {
197 nickrec = silc_nicklist_find(chanrec, client);
199 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
204 * "event signoff". Left the network.
207 static void event_signoff(SILC_SERVER_REC *server, va_list va)
209 SilcClientEntry client;
214 client = va_arg(va, SilcClientEntry);
215 message = va_arg(va, char *);
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;
240 SilcClientEntry client;
241 SilcChannelEntry channel;
245 client = va_arg(va, SilcClientEntry);
246 topic = va_arg(va, char *);
247 channel = va_arg(va, SilcChannelEntry);
249 chanrec = silc_channel_find_entry(server, channel);
250 if (chanrec != NULL) {
251 g_free_not_null(chanrec->topic);
252 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
253 signal_emit("channel topic changed", 1, chanrec);
256 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
257 client->username, client->hostname);
258 signal_emit("message topic", 5, server, channel->channel_name,
259 topic, client->nickname, userhost);
263 * "event invite". Invited or modified invite list.
266 static void event_invite(SILC_SERVER_REC *server, va_list va)
268 SilcClientEntry client;
269 SilcChannelEntry channel;
273 channel = va_arg(va, SilcChannelEntry);
274 channel_name = va_arg(va, char *);
275 client = va_arg(va, SilcClientEntry);
277 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
278 client->username, client->hostname);
279 signal_emit("message invite", 4, server, channel ? channel->channel_name :
280 channel_name, client->nickname, userhost);
284 * "event nick". Changed nickname.
287 static void event_nick(SILC_SERVER_REC *server, va_list va)
289 SilcClientEntry oldclient, newclient;
292 oldclient = va_arg(va, SilcClientEntry);
293 newclient = va_arg(va, SilcClientEntry);
295 nicklist_rename_unique(SERVER(server),
296 oldclient, oldclient->nickname,
297 newclient, newclient->nickname);
299 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
300 newclient->username, newclient->hostname);
301 signal_emit("message nick", 4, server, newclient->nickname,
302 oldclient->nickname, userhost);
306 * "event cmode". Changed channel mode.
309 static void event_cmode(SILC_SERVER_REC *server, va_list va)
311 SILC_CHANNEL_REC *chanrec;
313 SilcClientEntry client;
314 SilcServerEntry server_entry;
315 SilcChannelEntry channel;
320 idtype = va_arg(va, int);
321 entry = va_arg(va, void *);
322 modei = va_arg(va, uint32);
323 (void)va_arg(va, char *);
324 (void)va_arg(va, char *);
325 channel = va_arg(va, SilcChannelEntry);
327 mode = silc_client_chmode(modei,
328 channel->channel_key->cipher->name,
329 channel->hmac->hmac->name);
331 chanrec = silc_channel_find_entry(server, channel);
332 if (chanrec != NULL) {
333 g_free_not_null(chanrec->mode);
334 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
335 signal_emit("channel mode changed", 1, chanrec);
338 if (idtype == SILC_ID_CLIENT) {
339 client = (SilcClientEntry)entry;
340 printformat_module("fe-common/silc", server, channel->channel_name,
341 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
342 channel->channel_name, mode ? mode : "removed all",
345 server_entry = (SilcServerEntry)entry;
346 printformat_module("fe-common/silc", server, channel->channel_name,
347 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
348 channel->channel_name, mode ? mode : "removed all",
349 server_entry->server_name);
356 * "event cumode". Changed user's mode on channel.
359 static void event_cumode(SILC_SERVER_REC *server, va_list va)
361 SILC_CHANNEL_REC *chanrec;
362 SilcClientEntry client, destclient;
363 SilcChannelEntry channel;
367 client = va_arg(va, SilcClientEntry);
368 mode = va_arg(va, uint32);
369 destclient = va_arg(va, SilcClientEntry);
370 channel = va_arg(va, SilcChannelEntry);
372 modestr = silc_client_chumode(mode);
373 chanrec = silc_channel_find_entry(server, channel);
374 if (chanrec != NULL) {
377 if (destclient == server->conn->local_entry) {
379 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
382 nick = silc_nicklist_find(chanrec, destclient);
384 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
385 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
386 signal_emit("nick mode changed", 2, chanrec, nick);
390 printformat_module("fe-common/silc", server, channel->channel_name,
391 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
392 channel->channel_name, destclient->nickname,
393 modestr ? modestr : "removed all",
396 if (mode & SILC_CHANNEL_UMODE_CHANFO)
397 printformat_module("fe-common/silc",
398 server, channel->channel_name, MSGLEVEL_CRAP,
399 SILCTXT_CHANNEL_FOUNDER,
400 channel->channel_name, destclient->nickname);
406 * "event motd". Received MOTD.
409 static void event_motd(SILC_SERVER_REC *server, va_list va)
411 char *text = va_arg(va, char *);
413 if (!settings_get_bool("skip_motd"))
414 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
418 * "event channel_change". Channel ID has changed.
421 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
423 /* Nothing interesting to do */
427 * "event server_signoff". Server has quit the network.
430 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
432 SilcClientEntry *clients;
433 uint32 clients_count;
437 (void)va_arg(va, void *);
438 clients = va_arg(va, SilcClientEntry *);
439 clients_count = va_arg(va, uint32);
441 for (i = 0; i < clients_count; i++) {
442 memset(userhost, 0, sizeof(userhost));
443 if (clients[i]->username)
444 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
445 clients[i]->username, clients[i]->hostname);
446 signal_emit("message quit", 4, server, clients[i]->nickname,
447 clients[i]->username ? userhost : "",
453 * "event kick". Someone was kicked from channel.
456 static void event_kick(SILC_SERVER_REC *server, va_list va)
458 SilcClientConnection conn = server->conn;
459 SilcClientEntry client_entry;
460 SilcChannelEntry channel_entry;
462 SILC_CHANNEL_REC *chanrec;
464 client_entry = va_arg(va, SilcClientEntry);
465 tmp = va_arg(va, char *);
466 channel_entry = va_arg(va, SilcChannelEntry);
468 chanrec = silc_channel_find_entry(server, channel_entry);
470 if (client_entry == conn->local_entry) {
471 printformat_module("fe-common/silc", server, channel_entry->channel_name,
472 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
473 channel_entry->channel_name, tmp ? tmp : "");
475 chanrec->kicked = TRUE;
476 channel_destroy((CHANNEL_REC *)chanrec);
479 printformat_module("fe-common/silc", server, channel_entry->channel_name,
480 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
481 client_entry->nickname,
482 channel_entry->channel_name, tmp ? tmp : "");
485 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
487 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
493 * "event kill". Someone was killed from the network.
496 static void event_kill(SILC_SERVER_REC *server, va_list va)
498 SilcClientConnection conn = server->conn;
499 SilcClientEntry client_entry;
502 client_entry = va_arg(va, SilcClientEntry);
503 tmp = va_arg(va, char *);
505 if (client_entry == conn->local_entry) {
506 printformat_module("fe-common/silc", server, NULL,
507 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
510 GSList *nicks, *tmpn;
511 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
512 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
513 CHANNEL_REC *channel = tmpn->data;
514 NICK_REC *nickrec = tmpn->next->data;
515 nicklist_remove(channel, nickrec);
518 printformat_module("fe-common/silc", server, NULL,
519 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
520 client_entry->nickname,
525 /* PART (LEAVE) command. */
527 static void command_part(const char *data, SILC_SERVER_REC *server,
530 SILC_CHANNEL_REC *chanrec;
533 if (!IS_SILC_SERVER(server) || !server->connected)
534 cmd_return_error(CMDERR_NOT_CONNECTED);
536 if (!strcmp(data, "*") || *data == '\0') {
537 if (!IS_SILC_CHANNEL(item))
538 cmd_return_error(CMDERR_NOT_JOINED);
542 chanrec = silc_channel_find(server, data);
544 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
546 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
547 server->conn->local_entry->username,
548 server->conn->local_entry->hostname);
549 signal_emit("message part", 5, server, chanrec->name,
550 server->nick, userhost, "");
552 silc_command_exec(server, "LEAVE", chanrec->name);
555 channel_destroy(CHANNEL(chanrec));
558 /* ME local command. */
560 static void command_me(const char *data, SILC_SERVER_REC *server,
563 SILC_CHANNEL_REC *chanrec;
564 char *tmpcmd = "ME", *tmp;
566 unsigned char **argv;
567 uint32 *argv_lens, *argv_types;
570 if (!IS_SILC_SERVER(server) || !server->connected)
571 cmd_return_error(CMDERR_NOT_CONNECTED);
573 if (!IS_SILC_CHANNEL(item))
574 cmd_return_error(CMDERR_NOT_JOINED);
576 /* Now parse all arguments */
577 tmp = g_strconcat(tmpcmd, " ", data, NULL);
578 silc_parse_command_line(tmp, &argv, &argv_lens,
579 &argv_types, &argc, 2);
583 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
585 chanrec = silc_channel_find(server, item->name);
587 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
589 /* Send the action message */
590 silc_client_send_channel_message(silc_client, server->conn,
591 chanrec->entry, NULL,
592 SILC_MESSAGE_FLAG_ACTION,
593 argv[1], argv_lens[1], TRUE);
595 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
596 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
597 server->conn->local_entry->nickname, argv[1]);
599 for (i = 0; i < argc; i++)
601 silc_free(argv_lens);
602 silc_free(argv_types);
605 /* ACTION local command. Same as ME but takes the channel as mandatory
608 static void command_action(const char *data, SILC_SERVER_REC *server,
611 SILC_CHANNEL_REC *chanrec;
612 char *tmpcmd = "ME", *tmp;
614 unsigned char **argv;
615 uint32 *argv_lens, *argv_types;
618 if (!IS_SILC_SERVER(server) || !server->connected)
619 cmd_return_error(CMDERR_NOT_CONNECTED);
621 if (!IS_SILC_CHANNEL(item))
622 cmd_return_error(CMDERR_NOT_JOINED);
624 /* Now parse all arguments */
625 tmp = g_strconcat(tmpcmd, " ", data, NULL);
626 silc_parse_command_line(tmp, &argv, &argv_lens,
627 &argv_types, &argc, 3);
631 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
633 chanrec = silc_channel_find(server, argv[1]);
635 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
637 /* Send the action message */
638 silc_client_send_channel_message(silc_client, server->conn,
639 chanrec->entry, NULL,
640 SILC_MESSAGE_FLAG_ACTION,
641 argv[2], argv_lens[2], TRUE);
643 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
644 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
645 server->conn->local_entry->nickname, argv[2]);
647 for (i = 0; i < argc; i++)
649 silc_free(argv_lens);
650 silc_free(argv_types);
653 /* NOTICE local command. */
655 static void command_notice(const char *data, SILC_SERVER_REC *server,
658 SILC_CHANNEL_REC *chanrec;
659 char *tmpcmd = "ME", *tmp;
661 unsigned char **argv;
662 uint32 *argv_lens, *argv_types;
665 if (!IS_SILC_SERVER(server) || !server->connected)
666 cmd_return_error(CMDERR_NOT_CONNECTED);
668 if (!IS_SILC_CHANNEL(item))
669 cmd_return_error(CMDERR_NOT_JOINED);
671 /* Now parse all arguments */
672 tmp = g_strconcat(tmpcmd, " ", data, NULL);
673 silc_parse_command_line(tmp, &argv, &argv_lens,
674 &argv_types, &argc, 2);
678 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
680 chanrec = silc_channel_find(server, item->name);
682 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
684 /* Send the action message */
685 silc_client_send_channel_message(silc_client, server->conn,
686 chanrec->entry, NULL,
687 SILC_MESSAGE_FLAG_NOTICE,
688 argv[1], argv_lens[1], TRUE);
690 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
691 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
692 server->conn->local_entry->nickname, argv[1]);
694 for (i = 0; i < argc; i++)
696 silc_free(argv_lens);
697 silc_free(argv_types);
700 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
703 static void command_away(const char *data, SILC_SERVER_REC *server,
708 if (!IS_SILC_SERVER(server) || !server->connected)
709 cmd_return_error(CMDERR_NOT_CONNECTED);
712 /* Remove any possible away message */
713 silc_client_set_away_message(silc_client, server->conn, NULL);
716 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
719 /* Set the away message */
720 silc_client_set_away_message(silc_client, server->conn, (char *)data);
723 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
724 SILCTXT_SET_AWAY, data);
727 signal_emit("away mode changed", 1, server);
729 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
733 int type; /* 1 = msg, 2 = channel */
735 SILC_SERVER_REC *server;
738 /* Key agreement callback that is called after the key agreement protocol
739 has been performed. This is called also if error occured during the
740 key agreement protocol. The `key' is the allocated key material and
741 the caller is responsible of freeing it. The `key' is NULL if error
742 has occured. The application can freely use the `key' to whatever
743 purpose it needs. See lib/silcske/silcske.h for the definition of
744 the SilcSKEKeyMaterial structure. */
746 static void keyagr_completion(SilcClient client,
747 SilcClientConnection conn,
748 SilcClientEntry client_entry,
749 SilcKeyAgreementStatus status,
750 SilcSKEKeyMaterial *key,
753 KeyInternal i = (KeyInternal)context;
756 case SILC_KEY_AGREEMENT_OK:
757 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
758 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
761 /* Set the private key for this client */
762 silc_client_del_private_message_key(client, conn, client_entry);
763 silc_client_add_private_message_key_ske(client, conn, client_entry,
764 NULL, key, i->responder);
765 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
766 SILCTXT_KEY_AGREEMENT_PRIVMSG,
767 client_entry->nickname);
768 silc_ske_free_key_material(key);
773 case SILC_KEY_AGREEMENT_ERROR:
774 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
775 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
778 case SILC_KEY_AGREEMENT_FAILURE:
779 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
780 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
783 case SILC_KEY_AGREEMENT_TIMEOUT:
784 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
785 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
796 /* Local command KEY. This command is used to set and unset private
797 keys for channels, set and unset private keys for private messages
798 with remote clients and to send key agreement requests and
799 negotiate the key agreement protocol with remote client. The
800 key agreement is supported only to negotiate private message keys,
801 it currently cannot be used to negotiate private keys for channels,
802 as it is not convenient for that purpose. */
805 SILC_SERVER_REC *server;
810 /* Callback to be called after client information is resolved from the
813 SILC_CLIENT_CMD_FUNC(key_get_clients)
815 KeyGetClients internal = (KeyGetClients)context;
816 signal_emit("command key", 3, internal->data, internal->server,
818 silc_free(internal->data);
822 static void command_key(const char *data, SILC_SERVER_REC *server,
825 SilcClientConnection conn = server->conn;
826 SilcClientEntry client_entry = NULL;
827 SilcChannelEntry channel_entry = NULL;
828 char *nickname = NULL, *tmp;
829 int command = 0, port = 0, type = 0;
830 char *hostname = NULL;
831 KeyInternal internal = NULL;
833 unsigned char **argv;
834 uint32 *argv_lens, *argv_types;
836 if (!IS_SILC_SERVER(server) || !server->connected)
837 cmd_return_error(CMDERR_NOT_CONNECTED);
839 /* Now parse all arguments */
840 tmp = g_strconcat("KEY", " ", data, NULL);
841 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
845 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
846 "Usage: /KEY msg|channel <nickname|channel> "
847 "set|unset|agreement|negotiate [<arguments>]");
852 if (!strcasecmp(argv[1], "msg"))
854 if (!strcasecmp(argv[1], "channel"))
858 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
859 "Usage: /KEY msg|channel <nickname|channel> "
860 "set|unset|agreement|negotiate [<arguments>]");
865 if (argv[2][0] == '*') {
868 /* Parse the typed nickname. */
869 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
870 printformat_module("fe-common/silc", server, NULL,
871 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
875 /* Find client entry */
876 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
879 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
880 inter->server = server;
881 inter->data = strdup(data);
884 /* Client entry not found, it was requested thus mark this to be
886 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
888 NULL, silc_client_command_key_get_clients,
896 /* Get channel entry */
899 if (argv[2][0] == '*') {
900 if (!conn->current_channel) {
902 cmd_return_error(CMDERR_NOT_JOINED);
904 name = conn->current_channel->channel_name;
909 channel_entry = silc_client_get_channel(silc_client, conn, name);
910 if (!channel_entry) {
912 cmd_return_error(CMDERR_NOT_JOINED);
917 if (!strcasecmp(argv[3], "set")) {
921 if (type == 1 && client_entry) {
922 /* Set private message key */
924 silc_client_del_private_message_key(silc_client, conn, client_entry);
927 silc_client_add_private_message_key(silc_client, conn, client_entry,
931 TRUE : FALSE), FALSE);
933 silc_client_add_private_message_key(silc_client, conn, client_entry,
937 TRUE : FALSE), FALSE);
939 /* Send the key to the remote client so that it starts using it
941 silc_client_send_private_message_key(silc_client, conn,
943 } else if (type == 2) {
944 /* Set private channel key */
945 char *cipher = NULL, *hmac = NULL;
947 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
948 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
949 SILCTXT_CH_PRIVATE_KEY_NOMODE,
950 channel_entry->channel_name);
959 if (!silc_client_add_channel_private_key(silc_client, conn,
964 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
965 SILCTXT_CH_PRIVATE_KEY_ERROR,
966 channel_entry->channel_name);
970 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
971 SILCTXT_CH_PRIVATE_KEY_ADD,
972 channel_entry->channel_name);
980 if (!strcasecmp(argv[3], "unset")) {
983 if (type == 1 && client_entry) {
984 /* Unset private message key */
985 silc_client_del_private_message_key(silc_client, conn, client_entry);
986 } else if (type == 2) {
987 /* Unset channel key(s) */
988 SilcChannelPrivateKey *keys;
993 silc_client_del_channel_private_keys(silc_client, conn,
997 number = atoi(argv[4]);
998 keys = silc_client_list_channel_private_keys(silc_client, conn,
1004 if (!number || number > keys_count) {
1005 silc_client_free_channel_private_keys(keys, keys_count);
1009 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1011 silc_client_free_channel_private_keys(keys, keys_count);
1019 if (!strcasecmp(argv[3], "list")) {
1023 SilcPrivateMessageKeys keys;
1028 keys = silc_client_list_private_message_keys(silc_client, conn,
1033 /* list the private message key(s) */
1034 if (nickname[0] == '*') {
1035 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1036 SILCTXT_PRIVATE_KEY_LIST);
1037 for (k = 0; k < keys_count; k++) {
1038 memset(buf, 0, sizeof(buf));
1039 strncat(buf, " ", 2);
1040 len = strlen(keys[k].client_entry->nickname);
1041 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1043 for (i = 0; i < 30 - len; i++)
1047 len = strlen(keys[k].cipher);
1048 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1050 for (i = 0; i < 14 - len; i++)
1055 strcat(buf, "<hidden>");
1057 strcat(buf, "*generated*");
1059 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1062 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1063 SILCTXT_PRIVATE_KEY_LIST_NICK,
1064 client_entry->nickname);
1065 for (k = 0; k < keys_count; k++) {
1066 if (keys[k].client_entry != client_entry)
1069 memset(buf, 0, sizeof(buf));
1070 strncat(buf, " ", 2);
1071 len = strlen(keys[k].client_entry->nickname);
1072 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1074 for (i = 0; i < 30 - len; i++)
1078 len = strlen(keys[k].cipher);
1079 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1081 for (i = 0; i < 14 - len; i++)
1086 strcat(buf, "<hidden>");
1088 strcat(buf, "*generated*");
1090 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1094 silc_client_free_private_message_keys(keys, keys_count);
1095 } else if (type == 2) {
1096 SilcChannelPrivateKey *keys;
1101 keys = silc_client_list_channel_private_keys(silc_client, conn,
1107 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1108 SILCTXT_CH_PRIVATE_KEY_LIST,
1109 channel_entry->channel_name);
1110 for (k = 0; k < keys_count; k++) {
1111 memset(buf, 0, sizeof(buf));
1112 strncat(buf, " ", 2);
1114 len = strlen(keys[k]->cipher->cipher->name);
1115 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1117 for (i = 0; i < 16 - len; i++)
1121 len = strlen(keys[k]->hmac->hmac->name);
1122 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1124 for (i = 0; i < 16 - len; i++)
1128 strcat(buf, "<hidden>");
1130 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1133 silc_client_free_channel_private_keys(keys, keys_count);
1139 /* Send command is used to send key agreement */
1140 if (!strcasecmp(argv[3], "agreement")) {
1146 port = atoi(argv[5]);
1148 internal = silc_calloc(1, sizeof(*internal));
1149 internal->type = type;
1150 internal->server = server;
1153 /* Start command is used to start key agreement (after receiving the
1154 key_agreement client operation). */
1155 if (!strcasecmp(argv[3], "negotiate")) {
1161 port = atoi(argv[5]);
1163 internal = silc_calloc(1, sizeof(*internal));
1164 internal->type = type;
1165 internal->server = server;
1169 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1170 "Usage: /KEY msg|channel <nickname|channel> "
1171 "set|unset|agreement|negotiate [<arguments>]");
1175 if (command == 4 && client_entry) {
1176 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1177 SILCTXT_KEY_AGREEMENT, argv[2]);
1178 internal->responder = TRUE;
1179 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1180 port, 120, keyagr_completion, internal);
1182 silc_free(internal);
1186 if (command == 5 && client_entry && hostname) {
1187 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1188 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1189 internal->responder = FALSE;
1190 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1191 hostname, port, keyagr_completion,
1197 silc_free(nickname);
1200 /* Lists locally saved client and server public keys. */
1202 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1208 void silc_channels_init(void)
1210 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1211 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1212 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1214 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1215 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1216 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1217 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1218 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1219 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1220 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1221 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1222 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1223 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1224 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1225 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1226 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1228 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1229 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1230 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1231 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1232 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1233 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1234 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1236 silc_nicklist_init();
1239 void silc_channels_deinit(void)
1241 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1242 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1243 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1245 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1246 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1247 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1248 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1249 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1250 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1251 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1252 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1253 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1254 signal_remove("silc event channel_change",
1255 (SIGNAL_FUNC) event_channel_change);
1256 signal_remove("silc event server_signoff",
1257 (SIGNAL_FUNC) event_server_signoff);
1258 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1259 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1261 command_unbind("part", (SIGNAL_FUNC) command_part);
1262 command_unbind("me", (SIGNAL_FUNC) command_me);
1263 command_unbind("action", (SIGNAL_FUNC) command_action);
1264 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1265 command_unbind("away", (SIGNAL_FUNC) command_away);
1266 command_unbind("key", (SIGNAL_FUNC) command_key);
1267 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1269 silc_nicklist_deinit();