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 memset(userhost, 0, sizeof(userhost));
166 if (client->username)
167 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
168 client->username, client->hostname);
169 signal_emit("message join", 4, server, channel->channel_name,
171 client->username == NULL ? "" : userhost);
175 * "event leave". Left a channel.
178 static void event_leave(SILC_SERVER_REC *server, va_list va)
180 SILC_CHANNEL_REC *chanrec;
181 SILC_NICK_REC *nickrec;
182 SilcClientEntry client;
183 SilcChannelEntry channel;
186 client = va_arg(va, SilcClientEntry);
187 channel = va_arg(va, SilcChannelEntry);
189 memset(userhost, 0, sizeof(userhost));
190 if (client->username)
191 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
192 client->username, client->hostname);
193 signal_emit("message part", 5, server, channel->channel_name,
194 client->nickname, client->username ? userhost : "",
197 chanrec = silc_channel_find_entry(server, channel);
198 if (chanrec != NULL) {
199 nickrec = silc_nicklist_find(chanrec, client);
201 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
206 * "event signoff". Left the network.
209 static void event_signoff(SILC_SERVER_REC *server, va_list va)
211 SilcClientEntry client;
216 client = va_arg(va, SilcClientEntry);
217 message = va_arg(va, char *);
219 memset(userhost, 0, sizeof(userhost));
220 if (client->username)
221 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
222 client->username, client->hostname);
223 signal_emit("message quit", 4, server, client->nickname,
224 client->username ? userhost : "",
225 message ? message : "");
227 nicks = nicklist_get_same_unique(SERVER(server), client);
228 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
229 CHANNEL_REC *channel = tmp->data;
230 NICK_REC *nickrec = tmp->next->data;
232 nicklist_remove(channel, nickrec);
237 * "event topic". Changed topic.
240 static void event_topic(SILC_SERVER_REC *server, va_list va)
242 SILC_CHANNEL_REC *chanrec;
243 SilcClientEntry client;
244 SilcChannelEntry channel;
248 client = va_arg(va, SilcClientEntry);
249 topic = va_arg(va, char *);
250 channel = va_arg(va, SilcChannelEntry);
252 chanrec = silc_channel_find_entry(server, channel);
253 if (chanrec != NULL) {
254 g_free_not_null(chanrec->topic);
255 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
256 signal_emit("channel topic changed", 1, chanrec);
259 memset(userhost, 0, sizeof(userhost));
260 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
261 client->username, client->hostname);
262 signal_emit("message topic", 5, server, channel->channel_name,
263 topic, client->nickname, userhost);
267 * "event invite". Invited or modified invite list.
270 static void event_invite(SILC_SERVER_REC *server, va_list va)
272 SilcClientEntry client;
273 SilcChannelEntry channel;
277 channel = va_arg(va, SilcChannelEntry);
278 channel_name = va_arg(va, char *);
279 client = va_arg(va, SilcClientEntry);
281 memset(userhost, 0, sizeof(userhost));
282 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
283 client->username, client->hostname);
284 signal_emit("message invite", 4, server, channel ? channel->channel_name :
285 channel_name, client->nickname, userhost);
289 * "event nick". Changed nickname.
292 static void event_nick(SILC_SERVER_REC *server, va_list va)
294 SilcClientEntry oldclient, newclient;
297 oldclient = va_arg(va, SilcClientEntry);
298 newclient = va_arg(va, SilcClientEntry);
300 nicklist_rename_unique(SERVER(server),
301 oldclient, oldclient->nickname,
302 newclient, newclient->nickname);
304 memset(userhost, 0, sizeof(userhost));
305 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
306 newclient->username, newclient->hostname);
307 signal_emit("message nick", 4, server, newclient->nickname,
308 oldclient->nickname, userhost);
312 * "event cmode". Changed channel mode.
315 static void event_cmode(SILC_SERVER_REC *server, va_list va)
317 SILC_CHANNEL_REC *chanrec;
319 SilcClientEntry client;
320 SilcServerEntry server_entry;
321 SilcChannelEntry channel;
326 idtype = va_arg(va, int);
327 entry = va_arg(va, void *);
328 modei = va_arg(va, uint32);
329 (void)va_arg(va, char *);
330 (void)va_arg(va, char *);
331 channel = va_arg(va, SilcChannelEntry);
333 mode = silc_client_chmode(modei,
334 channel->channel_key->cipher->name,
335 silc_hmac_get_name(channel->hmac));
337 chanrec = silc_channel_find_entry(server, channel);
338 if (chanrec != NULL) {
339 g_free_not_null(chanrec->mode);
340 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
341 signal_emit("channel mode changed", 1, chanrec);
344 if (idtype == SILC_ID_CLIENT) {
345 client = (SilcClientEntry)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",
351 server_entry = (SilcServerEntry)entry;
352 printformat_module("fe-common/silc", server, channel->channel_name,
353 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
354 channel->channel_name, mode ? mode : "removed all",
355 server_entry->server_name);
362 * "event cumode". Changed user's mode on channel.
365 static void event_cumode(SILC_SERVER_REC *server, va_list va)
367 SILC_CHANNEL_REC *chanrec;
368 SilcClientEntry client, destclient;
369 SilcChannelEntry channel;
373 client = va_arg(va, SilcClientEntry);
374 mode = va_arg(va, uint32);
375 destclient = va_arg(va, SilcClientEntry);
376 channel = va_arg(va, SilcChannelEntry);
378 modestr = silc_client_chumode(mode);
379 chanrec = silc_channel_find_entry(server, channel);
380 if (chanrec != NULL) {
383 if (destclient == server->conn->local_entry) {
385 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
388 nick = silc_nicklist_find(chanrec, destclient);
390 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
391 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
392 signal_emit("nick mode changed", 2, chanrec, nick);
396 printformat_module("fe-common/silc", server, channel->channel_name,
397 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
398 channel->channel_name, destclient->nickname,
399 modestr ? modestr : "removed all",
402 if (mode & SILC_CHANNEL_UMODE_CHANFO)
403 printformat_module("fe-common/silc",
404 server, channel->channel_name, MSGLEVEL_CRAP,
405 SILCTXT_CHANNEL_FOUNDER,
406 channel->channel_name, destclient->nickname);
412 * "event motd". Received MOTD.
415 static void event_motd(SILC_SERVER_REC *server, va_list va)
417 char *text = va_arg(va, char *);
419 if (!settings_get_bool("skip_motd"))
420 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
424 * "event channel_change". Channel ID has changed.
427 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
429 /* Nothing interesting to do */
433 * "event server_signoff". Server has quit the network.
436 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
438 SilcClientEntry *clients;
439 uint32 clients_count;
443 (void)va_arg(va, void *);
444 clients = va_arg(va, SilcClientEntry *);
445 clients_count = va_arg(va, uint32);
447 for (i = 0; i < clients_count; i++) {
448 memset(userhost, 0, sizeof(userhost));
449 if (clients[i]->username)
450 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
451 clients[i]->username, clients[i]->hostname);
452 signal_emit("message quit", 4, server, clients[i]->nickname,
453 clients[i]->username ? userhost : "",
459 * "event kick". Someone was kicked from channel.
462 static void event_kick(SILC_SERVER_REC *server, va_list va)
464 SilcClientConnection conn = server->conn;
465 SilcClientEntry client_entry;
466 SilcChannelEntry channel_entry;
468 SILC_CHANNEL_REC *chanrec;
470 client_entry = va_arg(va, SilcClientEntry);
471 tmp = va_arg(va, char *);
472 channel_entry = va_arg(va, SilcChannelEntry);
474 chanrec = silc_channel_find_entry(server, channel_entry);
476 if (client_entry == conn->local_entry) {
477 printformat_module("fe-common/silc", server, channel_entry->channel_name,
478 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
479 channel_entry->channel_name, tmp ? tmp : "");
481 chanrec->kicked = TRUE;
482 channel_destroy((CHANNEL_REC *)chanrec);
485 printformat_module("fe-common/silc", server, channel_entry->channel_name,
486 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
487 client_entry->nickname,
488 channel_entry->channel_name, tmp ? tmp : "");
491 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
493 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
499 * "event kill". Someone was killed from the network.
502 static void event_kill(SILC_SERVER_REC *server, va_list va)
504 SilcClientConnection conn = server->conn;
505 SilcClientEntry client_entry;
508 client_entry = va_arg(va, SilcClientEntry);
509 tmp = va_arg(va, char *);
511 if (client_entry == conn->local_entry) {
512 printformat_module("fe-common/silc", server, NULL,
513 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
516 GSList *nicks, *tmpn;
517 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
518 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
519 CHANNEL_REC *channel = tmpn->data;
520 NICK_REC *nickrec = tmpn->next->data;
521 nicklist_remove(channel, nickrec);
524 printformat_module("fe-common/silc", server, NULL,
525 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
526 client_entry->nickname,
531 /* PART (LEAVE) command. */
533 static void command_part(const char *data, SILC_SERVER_REC *server,
536 SILC_CHANNEL_REC *chanrec;
539 if (!IS_SILC_SERVER(server) || !server->connected)
540 cmd_return_error(CMDERR_NOT_CONNECTED);
542 if (!strcmp(data, "*") || *data == '\0') {
543 if (!IS_SILC_CHANNEL(item))
544 cmd_return_error(CMDERR_NOT_JOINED);
548 chanrec = silc_channel_find(server, data);
550 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
552 memset(userhost, 0, sizeof(userhost));
553 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
554 server->conn->local_entry->username,
555 server->conn->local_entry->hostname);
556 signal_emit("message part", 5, server, chanrec->name,
557 server->nick, userhost, "");
559 silc_command_exec(server, "LEAVE", chanrec->name);
562 channel_destroy(CHANNEL(chanrec));
565 /* ME local command. */
567 static void command_me(const char *data, SILC_SERVER_REC *server,
570 SILC_CHANNEL_REC *chanrec;
571 char *tmpcmd = "ME", *tmp;
573 unsigned char **argv;
574 uint32 *argv_lens, *argv_types;
577 if (!IS_SILC_SERVER(server) || !server->connected)
578 cmd_return_error(CMDERR_NOT_CONNECTED);
580 if (!IS_SILC_CHANNEL(item))
581 cmd_return_error(CMDERR_NOT_JOINED);
583 /* Now parse all arguments */
584 tmp = g_strconcat(tmpcmd, " ", data, NULL);
585 silc_parse_command_line(tmp, &argv, &argv_lens,
586 &argv_types, &argc, 2);
590 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
592 chanrec = silc_channel_find(server, item->name);
594 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
596 /* Send the action message */
597 silc_client_send_channel_message(silc_client, server->conn,
598 chanrec->entry, NULL,
599 SILC_MESSAGE_FLAG_ACTION,
600 argv[1], argv_lens[1], TRUE);
602 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
603 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
604 server->conn->local_entry->nickname, argv[1]);
606 for (i = 0; i < argc; i++)
608 silc_free(argv_lens);
609 silc_free(argv_types);
612 /* ACTION local command. Same as ME but takes the channel as mandatory
615 static void command_action(const char *data, SILC_SERVER_REC *server,
618 SILC_CHANNEL_REC *chanrec;
619 char *tmpcmd = "ME", *tmp;
621 unsigned char **argv;
622 uint32 *argv_lens, *argv_types;
625 if (!IS_SILC_SERVER(server) || !server->connected)
626 cmd_return_error(CMDERR_NOT_CONNECTED);
628 if (!IS_SILC_CHANNEL(item))
629 cmd_return_error(CMDERR_NOT_JOINED);
631 /* Now parse all arguments */
632 tmp = g_strconcat(tmpcmd, " ", data, NULL);
633 silc_parse_command_line(tmp, &argv, &argv_lens,
634 &argv_types, &argc, 3);
638 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
640 chanrec = silc_channel_find(server, argv[1]);
642 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
644 /* Send the action message */
645 silc_client_send_channel_message(silc_client, server->conn,
646 chanrec->entry, NULL,
647 SILC_MESSAGE_FLAG_ACTION,
648 argv[2], argv_lens[2], TRUE);
650 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
651 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
652 server->conn->local_entry->nickname, argv[2]);
654 for (i = 0; i < argc; i++)
656 silc_free(argv_lens);
657 silc_free(argv_types);
660 /* NOTICE local command. */
662 static void command_notice(const char *data, SILC_SERVER_REC *server,
665 SILC_CHANNEL_REC *chanrec;
666 char *tmpcmd = "ME", *tmp;
668 unsigned char **argv;
669 uint32 *argv_lens, *argv_types;
672 if (!IS_SILC_SERVER(server) || !server->connected)
673 cmd_return_error(CMDERR_NOT_CONNECTED);
675 if (!IS_SILC_CHANNEL(item))
676 cmd_return_error(CMDERR_NOT_JOINED);
678 /* Now parse all arguments */
679 tmp = g_strconcat(tmpcmd, " ", data, NULL);
680 silc_parse_command_line(tmp, &argv, &argv_lens,
681 &argv_types, &argc, 2);
685 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
687 chanrec = silc_channel_find(server, item->name);
689 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
691 /* Send the action message */
692 silc_client_send_channel_message(silc_client, server->conn,
693 chanrec->entry, NULL,
694 SILC_MESSAGE_FLAG_NOTICE,
695 argv[1], argv_lens[1], TRUE);
697 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
698 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
699 server->conn->local_entry->nickname, argv[1]);
701 for (i = 0; i < argc; i++)
703 silc_free(argv_lens);
704 silc_free(argv_types);
707 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
710 static void command_away(const char *data, SILC_SERVER_REC *server,
715 if (!IS_SILC_SERVER(server) || !server->connected)
716 cmd_return_error(CMDERR_NOT_CONNECTED);
719 /* Remove any possible away message */
720 silc_client_set_away_message(silc_client, server->conn, NULL);
723 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
726 /* Set the away message */
727 silc_client_set_away_message(silc_client, server->conn, (char *)data);
730 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
731 SILCTXT_SET_AWAY, data);
734 signal_emit("away mode changed", 1, server);
736 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
740 int type; /* 1 = msg, 2 = channel */
742 SILC_SERVER_REC *server;
745 /* Key agreement callback that is called after the key agreement protocol
746 has been performed. This is called also if error occured during the
747 key agreement protocol. The `key' is the allocated key material and
748 the caller is responsible of freeing it. The `key' is NULL if error
749 has occured. The application can freely use the `key' to whatever
750 purpose it needs. See lib/silcske/silcske.h for the definition of
751 the SilcSKEKeyMaterial structure. */
753 static void keyagr_completion(SilcClient client,
754 SilcClientConnection conn,
755 SilcClientEntry client_entry,
756 SilcKeyAgreementStatus status,
757 SilcSKEKeyMaterial *key,
760 KeyInternal i = (KeyInternal)context;
763 case SILC_KEY_AGREEMENT_OK:
764 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
765 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
768 /* Set the private key for this client */
769 silc_client_del_private_message_key(client, conn, client_entry);
770 silc_client_add_private_message_key_ske(client, conn, client_entry,
771 NULL, key, i->responder);
772 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
773 SILCTXT_KEY_AGREEMENT_PRIVMSG,
774 client_entry->nickname);
775 silc_ske_free_key_material(key);
780 case SILC_KEY_AGREEMENT_ERROR:
781 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
782 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
785 case SILC_KEY_AGREEMENT_FAILURE:
786 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
787 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
790 case SILC_KEY_AGREEMENT_TIMEOUT:
791 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES,
792 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
803 /* Local command KEY. This command is used to set and unset private
804 keys for channels, set and unset private keys for private messages
805 with remote clients and to send key agreement requests and
806 negotiate the key agreement protocol with remote client. The
807 key agreement is supported only to negotiate private message keys,
808 it currently cannot be used to negotiate private keys for channels,
809 as it is not convenient for that purpose. */
812 SILC_SERVER_REC *server;
817 /* Callback to be called after client information is resolved from the
820 SILC_CLIENT_CMD_FUNC(key_get_clients)
822 KeyGetClients internal = (KeyGetClients)context;
823 signal_emit("command key", 3, internal->data, internal->server,
825 silc_free(internal->data);
829 static void command_key(const char *data, SILC_SERVER_REC *server,
832 SilcClientConnection conn;
833 SilcClientEntry client_entry = NULL;
834 SilcChannelEntry channel_entry = NULL;
835 char *nickname = NULL, *tmp;
836 int command = 0, port = 0, type = 0;
837 char *hostname = NULL;
838 KeyInternal internal = NULL;
840 unsigned char **argv;
841 uint32 *argv_lens, *argv_types;
843 if (!server || !IS_SILC_SERVER(server) || !server->connected)
844 cmd_return_error(CMDERR_NOT_CONNECTED);
848 /* Now parse all arguments */
849 tmp = g_strconcat("KEY", " ", data, NULL);
850 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
854 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
855 "Usage: /KEY msg|channel <nickname|channel> "
856 "set|unset|agreement|negotiate [<arguments>]");
861 if (!strcasecmp(argv[1], "msg"))
863 if (!strcasecmp(argv[1], "channel"))
867 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
868 "Usage: /KEY msg|channel <nickname|channel> "
869 "set|unset|agreement|negotiate [<arguments>]");
874 if (argv[2][0] == '*') {
875 nickname = strdup("*");
877 /* Parse the typed nickname. */
878 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
879 printformat_module("fe-common/silc", server, NULL,
880 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
884 /* Find client entry */
885 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
888 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
889 inter->server = server;
890 inter->data = strdup(data);
893 /* Client entry not found, it was requested thus mark this to be
895 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
897 NULL, silc_client_command_key_get_clients,
905 /* Get channel entry */
908 if (argv[2][0] == '*') {
909 if (!conn->current_channel) {
911 cmd_return_error(CMDERR_NOT_JOINED);
913 name = conn->current_channel->channel_name;
918 channel_entry = silc_client_get_channel(silc_client, conn, name);
919 if (!channel_entry) {
921 cmd_return_error(CMDERR_NOT_JOINED);
926 if (!strcasecmp(argv[3], "set")) {
930 if (type == 1 && client_entry) {
931 /* Set private message key */
933 silc_client_del_private_message_key(silc_client, conn, client_entry);
936 silc_client_add_private_message_key(silc_client, conn, client_entry,
940 TRUE : FALSE), FALSE);
942 silc_client_add_private_message_key(silc_client, conn, client_entry,
946 TRUE : FALSE), FALSE);
948 /* Send the key to the remote client so that it starts using it
950 silc_client_send_private_message_key(silc_client, conn,
952 } else if (type == 2) {
953 /* Set private channel key */
954 char *cipher = NULL, *hmac = NULL;
956 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
957 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
958 SILCTXT_CH_PRIVATE_KEY_NOMODE,
959 channel_entry->channel_name);
968 if (!silc_client_add_channel_private_key(silc_client, conn,
973 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
974 SILCTXT_CH_PRIVATE_KEY_ERROR,
975 channel_entry->channel_name);
979 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
980 SILCTXT_CH_PRIVATE_KEY_ADD,
981 channel_entry->channel_name);
989 if (!strcasecmp(argv[3], "unset")) {
992 if (type == 1 && client_entry) {
993 /* Unset private message key */
994 silc_client_del_private_message_key(silc_client, conn, client_entry);
995 } else if (type == 2) {
996 /* Unset channel key(s) */
997 SilcChannelPrivateKey *keys;
1002 silc_client_del_channel_private_keys(silc_client, conn,
1006 number = atoi(argv[4]);
1007 keys = silc_client_list_channel_private_keys(silc_client, conn,
1013 if (!number || number > keys_count) {
1014 silc_client_free_channel_private_keys(keys, keys_count);
1018 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1020 silc_client_free_channel_private_keys(keys, keys_count);
1028 if (!strcasecmp(argv[3], "list")) {
1032 SilcPrivateMessageKeys keys;
1037 keys = silc_client_list_private_message_keys(silc_client, conn,
1042 /* list the private message key(s) */
1043 if (nickname[0] == '*') {
1044 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1045 SILCTXT_PRIVATE_KEY_LIST);
1046 for (k = 0; k < keys_count; k++) {
1047 memset(buf, 0, sizeof(buf));
1048 strncat(buf, " ", 2);
1049 len = strlen(keys[k].client_entry->nickname);
1050 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1052 for (i = 0; i < 30 - len; i++)
1056 len = strlen(keys[k].cipher);
1057 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1059 for (i = 0; i < 14 - len; i++)
1064 strcat(buf, "<hidden>");
1066 strcat(buf, "*generated*");
1068 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1071 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1072 SILCTXT_PRIVATE_KEY_LIST_NICK,
1073 client_entry->nickname);
1074 for (k = 0; k < keys_count; k++) {
1075 if (keys[k].client_entry != client_entry)
1078 memset(buf, 0, sizeof(buf));
1079 strncat(buf, " ", 2);
1080 len = strlen(keys[k].client_entry->nickname);
1081 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1083 for (i = 0; i < 30 - len; i++)
1087 len = strlen(keys[k].cipher);
1088 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1090 for (i = 0; i < 14 - len; i++)
1095 strcat(buf, "<hidden>");
1097 strcat(buf, "*generated*");
1099 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1103 silc_client_free_private_message_keys(keys, keys_count);
1105 } else if (type == 2) {
1106 SilcChannelPrivateKey *keys;
1111 keys = silc_client_list_channel_private_keys(silc_client, conn,
1115 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1116 SILCTXT_CH_PRIVATE_KEY_LIST,
1117 channel_entry->channel_name);
1122 for (k = 0; k < keys_count; k++) {
1123 memset(buf, 0, sizeof(buf));
1124 strncat(buf, " ", 2);
1126 len = strlen(keys[k]->cipher->cipher->name);
1127 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1129 for (i = 0; i < 16 - len; i++)
1133 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1134 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1136 for (i = 0; i < 16 - len; i++)
1140 strcat(buf, "<hidden>");
1142 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1145 silc_client_free_channel_private_keys(keys, keys_count);
1151 /* Send command is used to send key agreement */
1152 if (!strcasecmp(argv[3], "agreement")) {
1158 port = atoi(argv[5]);
1160 internal = silc_calloc(1, sizeof(*internal));
1161 internal->type = type;
1162 internal->server = server;
1165 /* Start command is used to start key agreement (after receiving the
1166 key_agreement client operation). */
1167 if (!strcasecmp(argv[3], "negotiate")) {
1173 port = atoi(argv[5]);
1175 internal = silc_calloc(1, sizeof(*internal));
1176 internal->type = type;
1177 internal->server = server;
1181 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1182 "Usage: /KEY msg|channel <nickname|channel> "
1183 "set|unset|agreement|negotiate [<arguments>]");
1187 if (command == 4 && client_entry) {
1188 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1189 SILCTXT_KEY_AGREEMENT, argv[2]);
1190 internal->responder = TRUE;
1191 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1192 port, 120, keyagr_completion, internal);
1194 silc_free(internal);
1198 if (command == 5 && client_entry && hostname) {
1199 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1200 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1201 internal->responder = FALSE;
1202 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1203 hostname, port, keyagr_completion,
1209 silc_free(nickname);
1212 /* Lists locally saved client and server public keys. */
1214 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1220 void silc_channels_init(void)
1222 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1223 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1224 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1226 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1227 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1228 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1229 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1230 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1231 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1232 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1233 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1234 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1235 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1236 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1237 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1238 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1240 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1241 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1242 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1243 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1244 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1245 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1246 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1248 silc_nicklist_init();
1251 void silc_channels_deinit(void)
1253 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1254 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1255 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1257 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1258 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1259 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1260 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1261 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1262 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1263 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1264 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1265 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1266 signal_remove("silc event channel_change",
1267 (SIGNAL_FUNC) event_channel_change);
1268 signal_remove("silc event server_signoff",
1269 (SIGNAL_FUNC) event_server_signoff);
1270 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1271 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1273 command_unbind("part", (SIGNAL_FUNC) command_part);
1274 command_unbind("me", (SIGNAL_FUNC) command_me);
1275 command_unbind("action", (SIGNAL_FUNC) command_action);
1276 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1277 command_unbind("away", (SIGNAL_FUNC) command_away);
1278 command_unbind("key", (SIGNAL_FUNC) command_key);
1279 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1281 silc_nicklist_deinit();