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;
797 char *nickname = NULL, *tmp;
798 int command = 0, port = 0, type = 0;
799 char *hostname = NULL;
800 KeyInternal internal = NULL;
802 unsigned char **argv;
803 uint32 *argv_lens, *argv_types;
805 if (!IS_SILC_SERVER(server) || !server->connected)
806 cmd_return_error(CMDERR_NOT_CONNECTED);
808 /* Now parse all arguments */
809 tmp = g_strconcat("KEY", " ", data, NULL);
810 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
814 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
815 "Usage: /KEY msg|channel <nickname|channel> "
816 "set|unset|agreement|negotiate [<arguments>]");
821 if (!strcasecmp(argv[1], "msg"))
823 if (!strcasecmp(argv[1], "channel"))
827 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
828 "Usage: /KEY msg|channel <nickname|channel> "
829 "set|unset|agreement|negotiate [<arguments>]");
834 if (argv[2][0] == '*') {
837 /* Parse the typed nickname. */
838 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
839 printformat_module("fe-common/silc", server, NULL,
840 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
844 /* Find client entry */
845 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
848 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
849 inter->server = server;
850 inter->data = strdup(data);
853 /* Client entry not found, it was requested thus mark this to be
855 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
857 NULL, silc_client_command_key_get_clients,
865 /* Get channel entry */
868 if (argv[2][0] == '*') {
869 if (!conn->current_channel) {
871 cmd_return_error(CMDERR_NOT_JOINED);
873 name = conn->current_channel->channel_name;
878 channel_entry = silc_client_get_channel(silc_client, conn, name);
879 if (!channel_entry) {
881 cmd_return_error(CMDERR_NOT_JOINED);
886 if (!strcasecmp(argv[3], "set")) {
890 if (type == 1 && client_entry) {
891 /* Set private message key */
893 silc_client_del_private_message_key(silc_client, conn, client_entry);
896 silc_client_add_private_message_key(silc_client, conn, client_entry,
900 TRUE : FALSE), FALSE);
902 silc_client_add_private_message_key(silc_client, conn, client_entry,
906 TRUE : FALSE), FALSE);
908 /* Send the key to the remote client so that it starts using it
910 silc_client_send_private_message_key(silc_client, conn,
912 } else if (type == 2) {
913 /* Set private channel key */
914 char *cipher = NULL, *hmac = NULL;
916 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
917 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
918 SILCTXT_CH_PRIVATE_KEY_NOMODE,
919 channel_entry->channel_name);
928 if (!silc_client_add_channel_private_key(silc_client, conn,
933 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
934 SILCTXT_CH_PRIVATE_KEY_ERROR,
935 channel_entry->channel_name);
939 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
940 SILCTXT_CH_PRIVATE_KEY_ADD,
941 channel_entry->channel_name);
949 if (!strcasecmp(argv[3], "unset")) {
952 if (type == 1 && client_entry) {
953 /* Unset private message key */
954 silc_client_del_private_message_key(silc_client, conn, client_entry);
955 } else if (type == 2) {
956 /* Unset channel key(s) */
957 SilcChannelPrivateKey *keys;
962 silc_client_del_channel_private_keys(silc_client, conn,
966 number = atoi(argv[4]);
967 keys = silc_client_list_channel_private_keys(silc_client, conn,
973 if (!number || number > keys_count) {
974 silc_client_free_channel_private_keys(keys, keys_count);
978 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
980 silc_client_free_channel_private_keys(keys, keys_count);
988 if (!strcasecmp(argv[3], "list")) {
992 SilcPrivateMessageKeys keys;
997 keys = silc_client_list_private_message_keys(silc_client, conn,
1002 /* list the private message key(s) */
1003 if (nickname[0] == '*') {
1004 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1005 SILCTXT_PRIVATE_KEY_LIST);
1006 for (k = 0; k < keys_count; k++) {
1007 memset(buf, 0, sizeof(buf));
1008 strncat(buf, " ", 2);
1009 len = strlen(keys[k].client_entry->nickname);
1010 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1012 for (i = 0; i < 30 - len; i++)
1016 len = strlen(keys[k].cipher);
1017 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1019 for (i = 0; i < 14 - len; i++)
1024 strcat(buf, "<hidden>");
1026 strcat(buf, "*generated*");
1028 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1031 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1032 SILCTXT_PRIVATE_KEY_LIST_NICK,
1033 client_entry->nickname);
1034 for (k = 0; k < keys_count; k++) {
1035 if (keys[k].client_entry != client_entry)
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);
1063 silc_client_free_private_message_keys(keys, keys_count);
1064 } else if (type == 2) {
1065 SilcChannelPrivateKey *keys;
1070 keys = silc_client_list_channel_private_keys(silc_client, conn,
1076 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1077 SILCTXT_CH_PRIVATE_KEY_LIST,
1078 channel_entry->channel_name);
1079 for (k = 0; k < keys_count; k++) {
1080 memset(buf, 0, sizeof(buf));
1081 strncat(buf, " ", 2);
1083 len = strlen(keys[k]->cipher->cipher->name);
1084 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1086 for (i = 0; i < 16 - len; i++)
1090 len = strlen(keys[k]->hmac->hmac->name);
1091 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1093 for (i = 0; i < 16 - len; i++)
1097 strcat(buf, "<hidden>");
1099 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1102 silc_client_free_channel_private_keys(keys, keys_count);
1108 /* Send command is used to send key agreement */
1109 if (!strcasecmp(argv[3], "agreement")) {
1115 port = atoi(argv[5]);
1117 internal = silc_calloc(1, sizeof(*internal));
1118 internal->type = type;
1119 internal->server = server;
1122 /* Start command is used to start key agreement (after receiving the
1123 key_agreement client operation). */
1124 if (!strcasecmp(argv[3], "negotiate")) {
1130 port = atoi(argv[5]);
1132 internal = silc_calloc(1, sizeof(*internal));
1133 internal->type = type;
1134 internal->server = server;
1138 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1139 "Usage: /KEY msg|channel <nickname|channel> "
1140 "set|unset|agreement|negotiate [<arguments>]");
1144 if (command == 4 && client_entry) {
1145 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1146 SILCTXT_KEY_AGREEMENT, argv[2]);
1147 internal->responder = TRUE;
1148 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1149 port, 120, keyagr_completion, internal);
1151 silc_free(internal);
1155 if (command == 5 && client_entry && hostname) {
1156 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1157 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1158 internal->responder = FALSE;
1159 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1160 hostname, port, keyagr_completion,
1166 silc_free(nickname);
1169 /* Lists locally saved client and server public keys. */
1171 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1177 void silc_channels_init(void)
1179 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1180 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1181 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1183 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1184 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1185 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1186 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1187 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1188 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1189 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1190 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1191 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1192 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1193 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1194 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1195 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1197 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1198 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1199 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1200 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1201 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1202 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1203 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1205 silc_nicklist_init();
1208 void silc_channels_deinit(void)
1210 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1211 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1212 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1214 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1215 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1216 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1217 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1218 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1219 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1220 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1221 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1222 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1223 signal_remove("silc event channel_change",
1224 (SIGNAL_FUNC) event_channel_change);
1225 signal_remove("silc event server_signoff",
1226 (SIGNAL_FUNC) event_server_signoff);
1227 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1228 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1230 command_unbind("part", (SIGNAL_FUNC) command_part);
1231 command_unbind("me", (SIGNAL_FUNC) command_me);
1232 command_unbind("action", (SIGNAL_FUNC) command_action);
1233 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1234 command_unbind("away", (SIGNAL_FUNC) command_away);
1235 command_unbind("key", (SIGNAL_FUNC) command_key);
1236 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1238 silc_nicklist_deinit();