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 channel->hmac->hmac->name);
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 = server->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 (!IS_SILC_SERVER(server) || !server->connected)
844 cmd_return_error(CMDERR_NOT_CONNECTED);
846 /* Now parse all arguments */
847 tmp = g_strconcat("KEY", " ", data, NULL);
848 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
852 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
853 "Usage: /KEY msg|channel <nickname|channel> "
854 "set|unset|agreement|negotiate [<arguments>]");
859 if (!strcasecmp(argv[1], "msg"))
861 if (!strcasecmp(argv[1], "channel"))
865 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
866 "Usage: /KEY msg|channel <nickname|channel> "
867 "set|unset|agreement|negotiate [<arguments>]");
872 if (argv[2][0] == '*') {
875 /* Parse the typed nickname. */
876 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
877 printformat_module("fe-common/silc", server, NULL,
878 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
882 /* Find client entry */
883 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
886 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
887 inter->server = server;
888 inter->data = strdup(data);
891 /* Client entry not found, it was requested thus mark this to be
893 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
895 NULL, silc_client_command_key_get_clients,
903 /* Get channel entry */
906 if (argv[2][0] == '*') {
907 if (!conn->current_channel) {
909 cmd_return_error(CMDERR_NOT_JOINED);
911 name = conn->current_channel->channel_name;
916 channel_entry = silc_client_get_channel(silc_client, conn, name);
917 if (!channel_entry) {
919 cmd_return_error(CMDERR_NOT_JOINED);
924 if (!strcasecmp(argv[3], "set")) {
928 if (type == 1 && client_entry) {
929 /* Set private message key */
931 silc_client_del_private_message_key(silc_client, conn, client_entry);
934 silc_client_add_private_message_key(silc_client, conn, client_entry,
938 TRUE : FALSE), FALSE);
940 silc_client_add_private_message_key(silc_client, conn, client_entry,
944 TRUE : FALSE), FALSE);
946 /* Send the key to the remote client so that it starts using it
948 silc_client_send_private_message_key(silc_client, conn,
950 } else if (type == 2) {
951 /* Set private channel key */
952 char *cipher = NULL, *hmac = NULL;
954 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
955 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
956 SILCTXT_CH_PRIVATE_KEY_NOMODE,
957 channel_entry->channel_name);
966 if (!silc_client_add_channel_private_key(silc_client, conn,
971 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
972 SILCTXT_CH_PRIVATE_KEY_ERROR,
973 channel_entry->channel_name);
977 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
978 SILCTXT_CH_PRIVATE_KEY_ADD,
979 channel_entry->channel_name);
987 if (!strcasecmp(argv[3], "unset")) {
990 if (type == 1 && client_entry) {
991 /* Unset private message key */
992 silc_client_del_private_message_key(silc_client, conn, client_entry);
993 } else if (type == 2) {
994 /* Unset channel key(s) */
995 SilcChannelPrivateKey *keys;
1000 silc_client_del_channel_private_keys(silc_client, conn,
1004 number = atoi(argv[4]);
1005 keys = silc_client_list_channel_private_keys(silc_client, conn,
1011 if (!number || number > keys_count) {
1012 silc_client_free_channel_private_keys(keys, keys_count);
1016 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1018 silc_client_free_channel_private_keys(keys, keys_count);
1026 if (!strcasecmp(argv[3], "list")) {
1030 SilcPrivateMessageKeys keys;
1035 keys = silc_client_list_private_message_keys(silc_client, conn,
1040 /* list the private message key(s) */
1041 if (nickname[0] == '*') {
1042 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1043 SILCTXT_PRIVATE_KEY_LIST);
1044 for (k = 0; k < keys_count; k++) {
1045 memset(buf, 0, sizeof(buf));
1046 strncat(buf, " ", 2);
1047 len = strlen(keys[k].client_entry->nickname);
1048 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1050 for (i = 0; i < 30 - len; i++)
1054 len = strlen(keys[k].cipher);
1055 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1057 for (i = 0; i < 14 - len; i++)
1062 strcat(buf, "<hidden>");
1064 strcat(buf, "*generated*");
1066 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1069 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1070 SILCTXT_PRIVATE_KEY_LIST_NICK,
1071 client_entry->nickname);
1072 for (k = 0; k < keys_count; k++) {
1073 if (keys[k].client_entry != client_entry)
1076 memset(buf, 0, sizeof(buf));
1077 strncat(buf, " ", 2);
1078 len = strlen(keys[k].client_entry->nickname);
1079 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1081 for (i = 0; i < 30 - len; i++)
1085 len = strlen(keys[k].cipher);
1086 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1088 for (i = 0; i < 14 - len; i++)
1093 strcat(buf, "<hidden>");
1095 strcat(buf, "*generated*");
1097 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1101 silc_client_free_private_message_keys(keys, keys_count);
1102 } else if (type == 2) {
1103 SilcChannelPrivateKey *keys;
1108 keys = silc_client_list_channel_private_keys(silc_client, conn,
1114 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1115 SILCTXT_CH_PRIVATE_KEY_LIST,
1116 channel_entry->channel_name);
1117 for (k = 0; k < keys_count; k++) {
1118 memset(buf, 0, sizeof(buf));
1119 strncat(buf, " ", 2);
1121 len = strlen(keys[k]->cipher->cipher->name);
1122 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1124 for (i = 0; i < 16 - len; i++)
1128 len = strlen(keys[k]->hmac->hmac->name);
1129 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
1131 for (i = 0; i < 16 - len; i++)
1135 strcat(buf, "<hidden>");
1137 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1140 silc_client_free_channel_private_keys(keys, keys_count);
1146 /* Send command is used to send key agreement */
1147 if (!strcasecmp(argv[3], "agreement")) {
1153 port = atoi(argv[5]);
1155 internal = silc_calloc(1, sizeof(*internal));
1156 internal->type = type;
1157 internal->server = server;
1160 /* Start command is used to start key agreement (after receiving the
1161 key_agreement client operation). */
1162 if (!strcasecmp(argv[3], "negotiate")) {
1168 port = atoi(argv[5]);
1170 internal = silc_calloc(1, sizeof(*internal));
1171 internal->type = type;
1172 internal->server = server;
1176 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1177 "Usage: /KEY msg|channel <nickname|channel> "
1178 "set|unset|agreement|negotiate [<arguments>]");
1182 if (command == 4 && client_entry) {
1183 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1184 SILCTXT_KEY_AGREEMENT, argv[2]);
1185 internal->responder = TRUE;
1186 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1187 port, 120, keyagr_completion, internal);
1189 silc_free(internal);
1193 if (command == 5 && client_entry && hostname) {
1194 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES,
1195 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1196 internal->responder = FALSE;
1197 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1198 hostname, port, keyagr_completion,
1204 silc_free(nickname);
1207 /* Lists locally saved client and server public keys. */
1209 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1215 void silc_channels_init(void)
1217 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1218 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1219 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1221 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1222 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1223 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1224 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1225 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1226 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1227 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1228 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1229 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1230 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1231 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1232 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1233 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1235 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1236 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1237 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1238 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1239 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1240 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1241 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1243 silc_nicklist_init();
1246 void silc_channels_deinit(void)
1248 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1249 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1250 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1252 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1253 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1254 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1255 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1256 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1257 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1258 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1259 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1260 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1261 signal_remove("silc event channel_change",
1262 (SIGNAL_FUNC) event_channel_change);
1263 signal_remove("silc event server_signoff",
1264 (SIGNAL_FUNC) event_server_signoff);
1265 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1266 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1268 command_unbind("part", (SIGNAL_FUNC) command_part);
1269 command_unbind("me", (SIGNAL_FUNC) command_me);
1270 command_unbind("action", (SIGNAL_FUNC) command_action);
1271 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1272 command_unbind("away", (SIGNAL_FUNC) command_away);
1273 command_unbind("key", (SIGNAL_FUNC) command_key);
1274 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1276 silc_nicklist_deinit();