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)
79 SILC_CHANNEL_REC *chanrec;
81 list = g_strsplit(channels, ",", -1);
82 for (tmp = list; *tmp != NULL; tmp++) {
83 chanrec = silc_channel_find(server, *tmp);
87 silc_command_exec(server, "JOIN", *tmp);
93 static void sig_connected(SILC_SERVER_REC *server)
95 if (IS_SILC_SERVER(server))
96 server->channels_join = (void *) silc_channels_join;
99 /* "server quit" signal from the core to indicate that QUIT command
102 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
104 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
105 silc_command_exec(server, "QUIT", msg);
109 * "event join". Joined to a channel.
112 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
113 SilcChannelEntry entry)
117 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
119 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
120 SILC_CHANNEL_REC *rec = tmp->data;
122 if (rec->entry == entry)
129 static void event_join(SILC_SERVER_REC *server, va_list va)
131 SILC_CHANNEL_REC *chanrec;
132 SILC_NICK_REC *nickrec;
133 SilcClientEntry client;
134 SilcChannelEntry channel;
137 client = va_arg(va, SilcClientEntry);
138 channel = va_arg(va, SilcChannelEntry);
140 if (client == server->conn->local_entry) {
141 /* You joined to channel */
142 chanrec = silc_channel_find(server, channel->channel_name);
143 if (chanrec != NULL && !chanrec->joined)
144 chanrec->entry = channel;
146 chanrec = silc_channel_find_entry(server, channel);
147 if (chanrec != NULL) {
148 SilcChannelUser chu = silc_client_on_channel(channel, client);
150 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
154 memset(userhost, 0, sizeof(userhost));
155 if (client->username)
156 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
157 client->username, client->hostname);
158 signal_emit("message join", 4, server, channel->channel_name,
160 client->username == NULL ? "" : userhost);
164 * "event leave". Left a channel.
167 static void event_leave(SILC_SERVER_REC *server, va_list va)
169 SILC_CHANNEL_REC *chanrec;
170 SILC_NICK_REC *nickrec;
171 SilcClientEntry client;
172 SilcChannelEntry channel;
175 client = va_arg(va, SilcClientEntry);
176 channel = va_arg(va, SilcChannelEntry);
178 memset(userhost, 0, sizeof(userhost));
179 if (client->username)
180 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
181 client->username, client->hostname);
182 signal_emit("message part", 5, server, channel->channel_name,
183 client->nickname, client->username ? userhost : "",
186 chanrec = silc_channel_find_entry(server, channel);
187 if (chanrec != NULL) {
188 nickrec = silc_nicklist_find(chanrec, client);
190 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
195 * "event signoff". Left the network.
198 static void event_signoff(SILC_SERVER_REC *server, va_list va)
200 SilcClientEntry client;
205 client = va_arg(va, SilcClientEntry);
206 message = va_arg(va, char *);
208 silc_server_free_ftp(server, client);
210 memset(userhost, 0, sizeof(userhost));
211 if (client->username)
212 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
213 client->username, client->hostname);
214 signal_emit("message quit", 4, server, client->nickname,
215 client->username ? userhost : "",
216 message ? message : "");
218 nicks = nicklist_get_same_unique(SERVER(server), client);
219 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
220 CHANNEL_REC *channel = tmp->data;
221 NICK_REC *nickrec = tmp->next->data;
223 nicklist_remove(channel, nickrec);
228 * "event topic". Changed topic.
231 static void event_topic(SILC_SERVER_REC *server, va_list va)
233 SILC_CHANNEL_REC *chanrec;
235 SilcClientEntry client;
236 SilcServerEntry server_entry;
237 SilcChannelEntry channel;
242 idtype = va_arg(va, int);
243 entry = va_arg(va, void *);
244 topic = va_arg(va, char *);
245 channel = va_arg(va, SilcChannelEntry);
247 chanrec = silc_channel_find_entry(server, channel);
248 if (chanrec != NULL) {
249 g_free_not_null(chanrec->topic);
250 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
251 signal_emit("channel topic changed", 1, chanrec);
254 if (idtype == SILC_ID_CLIENT) {
255 client = (SilcClientEntry)entry;
256 memset(userhost, 0, sizeof(userhost));
257 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
258 client->username, client->hostname);
259 signal_emit("message topic", 5, server, channel->channel_name,
260 topic, client->nickname, userhost);
261 } else if (idtype == SILC_ID_SERVER) {
262 server_entry = (SilcServerEntry)entry;
263 signal_emit("message topic", 5, server, channel->channel_name,
264 topic, server_entry->server_name,
265 server_entry->server_name);
267 channel = (SilcChannelEntry)entry;
268 signal_emit("message topic", 5, server, channel->channel_name,
269 topic, channel->channel_name, channel->channel_name);
274 * "event invite". Invited or modified invite list.
277 static void event_invite(SILC_SERVER_REC *server, va_list va)
279 SilcClientEntry client;
280 SilcChannelEntry channel;
284 channel = va_arg(va, SilcChannelEntry);
285 channel_name = va_arg(va, char *);
286 client = va_arg(va, SilcClientEntry);
288 memset(userhost, 0, sizeof(userhost));
289 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
290 client->username, client->hostname);
291 signal_emit("message invite", 4, server, channel ? channel->channel_name :
292 channel_name, client->nickname, userhost);
296 * "event nick". Changed nickname.
299 static void event_nick(SILC_SERVER_REC *server, va_list va)
301 SilcClientEntry oldclient, newclient;
304 oldclient = va_arg(va, SilcClientEntry);
305 newclient = va_arg(va, SilcClientEntry);
307 nicklist_rename_unique(SERVER(server),
308 oldclient, oldclient->nickname,
309 newclient, newclient->nickname);
311 memset(userhost, 0, sizeof(userhost));
312 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
313 newclient->username, newclient->hostname);
314 signal_emit("message nick", 4, server, newclient->nickname,
315 oldclient->nickname, userhost);
319 * "event cmode". Changed channel mode.
322 static void event_cmode(SILC_SERVER_REC *server, va_list va)
324 SILC_CHANNEL_REC *chanrec;
326 SilcClientEntry client;
327 SilcServerEntry server_entry;
328 SilcChannelEntry channel;
333 idtype = va_arg(va, int);
334 entry = va_arg(va, void *);
335 modei = va_arg(va, uint32);
336 (void)va_arg(va, char *);
337 (void)va_arg(va, char *);
338 channel = va_arg(va, SilcChannelEntry);
340 mode = silc_client_chmode(modei,
341 channel->channel_key ?
342 channel->channel_key->cipher->name : "",
344 silc_hmac_get_name(channel->hmac) : "");
346 chanrec = silc_channel_find_entry(server, channel);
347 if (chanrec != NULL) {
348 g_free_not_null(chanrec->mode);
349 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
350 signal_emit("channel mode changed", 1, chanrec);
353 if (idtype == SILC_ID_CLIENT) {
354 client = (SilcClientEntry)entry;
355 printformat_module("fe-common/silc", server, channel->channel_name,
356 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
357 channel->channel_name, mode ? mode : "removed all",
360 server_entry = (SilcServerEntry)entry;
361 printformat_module("fe-common/silc", server, channel->channel_name,
362 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
363 channel->channel_name, mode ? mode : "removed all",
364 server_entry->server_name);
371 * "event cumode". Changed user's mode on channel.
374 static void event_cumode(SILC_SERVER_REC *server, va_list va)
376 SILC_CHANNEL_REC *chanrec;
377 SilcClientEntry client, destclient;
378 SilcChannelEntry channel;
382 client = va_arg(va, SilcClientEntry);
383 mode = va_arg(va, uint32);
384 destclient = va_arg(va, SilcClientEntry);
385 channel = va_arg(va, SilcChannelEntry);
387 modestr = silc_client_chumode(mode);
388 chanrec = silc_channel_find_entry(server, channel);
389 if (chanrec != NULL) {
392 if (destclient == server->conn->local_entry) {
394 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
397 nick = silc_nicklist_find(chanrec, destclient);
399 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
400 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
401 signal_emit("nick mode changed", 2, chanrec, nick);
405 printformat_module("fe-common/silc", server, channel->channel_name,
406 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
407 channel->channel_name, destclient->nickname,
408 modestr ? modestr : "removed all",
411 if (mode & SILC_CHANNEL_UMODE_CHANFO)
412 printformat_module("fe-common/silc",
413 server, channel->channel_name, MSGLEVEL_CRAP,
414 SILCTXT_CHANNEL_FOUNDER,
415 channel->channel_name, destclient->nickname);
421 * "event motd". Received MOTD.
424 static void event_motd(SILC_SERVER_REC *server, va_list va)
426 char *text = va_arg(va, char *);
428 if (!settings_get_bool("skip_motd"))
429 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
433 * "event channel_change". Channel ID has changed.
436 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
438 /* Nothing interesting to do */
442 * "event server_signoff". Server has quit the network.
445 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
447 SilcClientEntry *clients;
448 uint32 clients_count;
452 (void)va_arg(va, void *);
453 clients = va_arg(va, SilcClientEntry *);
454 clients_count = va_arg(va, uint32);
456 for (i = 0; i < clients_count; i++) {
459 memset(userhost, 0, sizeof(userhost));
460 if (clients[i]->username)
461 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
462 clients[i]->username, clients[i]->hostname);
463 signal_emit("message quit", 4, server, clients[i]->nickname,
464 clients[i]->username ? userhost : "",
467 silc_server_free_ftp(server, clients[i]);
469 nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
470 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
471 CHANNEL_REC *channel = tmp->data;
472 NICK_REC *nickrec = tmp->next->data;
473 nicklist_remove(channel, nickrec);
479 * "event kick". Someone was kicked from channel.
482 static void event_kick(SILC_SERVER_REC *server, va_list va)
484 SilcClientConnection conn = server->conn;
485 SilcClientEntry client_entry, kicker;
486 SilcChannelEntry channel_entry;
488 SILC_CHANNEL_REC *chanrec;
490 client_entry = va_arg(va, SilcClientEntry);
491 tmp = va_arg(va, char *);
492 kicker = va_arg(va, SilcClientEntry);
493 channel_entry = va_arg(va, SilcChannelEntry);
495 chanrec = silc_channel_find_entry(server, channel_entry);
497 if (client_entry == conn->local_entry) {
498 printformat_module("fe-common/silc", server, channel_entry->channel_name,
499 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
501 channel_entry->channel_name, tmp ? tmp : "");
503 chanrec->kicked = TRUE;
504 channel_destroy((CHANNEL_REC *)chanrec);
507 printformat_module("fe-common/silc", server, channel_entry->channel_name,
508 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
509 client_entry->nickname,
511 channel_entry->channel_name, tmp ? tmp : "");
514 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
516 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
522 * "event kill". Someone was killed from the network.
525 static void event_kill(SILC_SERVER_REC *server, va_list va)
527 SilcClientConnection conn = server->conn;
528 SilcClientEntry client_entry;
531 client_entry = va_arg(va, SilcClientEntry);
532 tmp = va_arg(va, char *);
534 if (client_entry == conn->local_entry) {
535 printformat_module("fe-common/silc", server, NULL,
536 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
539 GSList *nicks, *tmpn;
540 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
541 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
542 CHANNEL_REC *channel = tmpn->data;
543 NICK_REC *nickrec = tmpn->next->data;
544 nicklist_remove(channel, nickrec);
547 printformat_module("fe-common/silc", server, NULL,
548 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
549 client_entry->nickname,
554 /* PART (LEAVE) command. */
556 static void command_part(const char *data, SILC_SERVER_REC *server,
559 SILC_CHANNEL_REC *chanrec;
562 if (!IS_SILC_SERVER(server) || !server->connected)
563 cmd_return_error(CMDERR_NOT_CONNECTED);
565 if (!strcmp(data, "*") || *data == '\0') {
566 if (!IS_SILC_CHANNEL(item))
567 cmd_return_error(CMDERR_NOT_JOINED);
571 chanrec = silc_channel_find(server, data);
573 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
575 memset(userhost, 0, sizeof(userhost));
576 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
577 server->conn->local_entry->username,
578 server->conn->local_entry->hostname);
579 signal_emit("message part", 5, server, chanrec->name,
580 server->nick, userhost, "");
582 silc_command_exec(server, "LEAVE", chanrec->name);
585 channel_destroy(CHANNEL(chanrec));
588 /* ME local command. */
590 static void command_me(const char *data, SILC_SERVER_REC *server,
593 SILC_CHANNEL_REC *chanrec;
594 char *tmpcmd = "ME", *tmp;
596 unsigned char **argv;
597 uint32 *argv_lens, *argv_types;
600 if (!IS_SILC_SERVER(server) || !server->connected)
601 cmd_return_error(CMDERR_NOT_CONNECTED);
603 if (!IS_SILC_CHANNEL(item))
604 cmd_return_error(CMDERR_NOT_JOINED);
606 /* Now parse all arguments */
607 tmp = g_strconcat(tmpcmd, " ", data, NULL);
608 silc_parse_command_line(tmp, &argv, &argv_lens,
609 &argv_types, &argc, 2);
613 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
615 chanrec = silc_channel_find(server, item->name);
617 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
619 /* Send the action message */
620 silc_client_send_channel_message(silc_client, server->conn,
621 chanrec->entry, NULL,
622 SILC_MESSAGE_FLAG_ACTION,
623 argv[1], argv_lens[1], TRUE);
625 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
626 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
627 server->conn->local_entry->nickname, argv[1]);
629 for (i = 0; i < argc; i++)
631 silc_free(argv_lens);
632 silc_free(argv_types);
635 /* ACTION local command. Same as ME but takes the channel as mandatory
638 static void command_action(const char *data, SILC_SERVER_REC *server,
641 SILC_CHANNEL_REC *chanrec;
642 char *tmpcmd = "ME", *tmp;
644 unsigned char **argv;
645 uint32 *argv_lens, *argv_types;
648 if (!IS_SILC_SERVER(server) || !server->connected)
649 cmd_return_error(CMDERR_NOT_CONNECTED);
651 if (!IS_SILC_CHANNEL(item))
652 cmd_return_error(CMDERR_NOT_JOINED);
654 /* Now parse all arguments */
655 tmp = g_strconcat(tmpcmd, " ", data, NULL);
656 silc_parse_command_line(tmp, &argv, &argv_lens,
657 &argv_types, &argc, 3);
661 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
663 chanrec = silc_channel_find(server, argv[1]);
665 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
667 /* Send the action message */
668 silc_client_send_channel_message(silc_client, server->conn,
669 chanrec->entry, NULL,
670 SILC_MESSAGE_FLAG_ACTION,
671 argv[2], argv_lens[2], TRUE);
673 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
674 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
675 server->conn->local_entry->nickname, argv[2]);
677 for (i = 0; i < argc; i++)
679 silc_free(argv_lens);
680 silc_free(argv_types);
683 /* NOTICE local command. */
685 static void command_notice(const char *data, SILC_SERVER_REC *server,
688 SILC_CHANNEL_REC *chanrec;
689 char *tmpcmd = "ME", *tmp;
691 unsigned char **argv;
692 uint32 *argv_lens, *argv_types;
695 if (!IS_SILC_SERVER(server) || !server->connected)
696 cmd_return_error(CMDERR_NOT_CONNECTED);
698 if (!IS_SILC_CHANNEL(item))
699 cmd_return_error(CMDERR_NOT_JOINED);
701 /* Now parse all arguments */
702 tmp = g_strconcat(tmpcmd, " ", data, NULL);
703 silc_parse_command_line(tmp, &argv, &argv_lens,
704 &argv_types, &argc, 2);
708 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
710 chanrec = silc_channel_find(server, item->name);
712 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
714 /* Send the action message */
715 silc_client_send_channel_message(silc_client, server->conn,
716 chanrec->entry, NULL,
717 SILC_MESSAGE_FLAG_NOTICE,
718 argv[1], argv_lens[1], TRUE);
720 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
721 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
722 server->conn->local_entry->nickname, argv[1]);
724 for (i = 0; i < argc; i++)
726 silc_free(argv_lens);
727 silc_free(argv_types);
730 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
733 static void command_away(const char *data, SILC_SERVER_REC *server,
738 if (!IS_SILC_SERVER(server) || !server->connected)
739 cmd_return_error(CMDERR_NOT_CONNECTED);
742 /* Remove any possible away message */
743 silc_client_set_away_message(silc_client, server->conn, NULL);
746 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
749 /* Set the away message */
750 silc_client_set_away_message(silc_client, server->conn, (char *)data);
753 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
754 SILCTXT_SET_AWAY, data);
757 signal_emit("away mode changed", 1, server);
759 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
763 int type; /* 1 = msg, 2 = channel */
765 SILC_SERVER_REC *server;
768 /* Key agreement callback that is called after the key agreement protocol
769 has been performed. This is called also if error occured during the
770 key agreement protocol. The `key' is the allocated key material and
771 the caller is responsible of freeing it. The `key' is NULL if error
772 has occured. The application can freely use the `key' to whatever
773 purpose it needs. See lib/silcske/silcske.h for the definition of
774 the SilcSKEKeyMaterial structure. */
776 static void keyagr_completion(SilcClient client,
777 SilcClientConnection conn,
778 SilcClientEntry client_entry,
779 SilcKeyAgreementStatus status,
780 SilcSKEKeyMaterial *key,
783 KeyInternal i = (KeyInternal)context;
786 case SILC_KEY_AGREEMENT_OK:
787 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
788 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
791 /* Set the private key for this client */
792 silc_client_del_private_message_key(client, conn, client_entry);
793 silc_client_add_private_message_key_ske(client, conn, client_entry,
794 NULL, key, i->responder);
795 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
796 SILCTXT_KEY_AGREEMENT_PRIVMSG,
797 client_entry->nickname);
798 silc_ske_free_key_material(key);
803 case SILC_KEY_AGREEMENT_ERROR:
804 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
805 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
808 case SILC_KEY_AGREEMENT_FAILURE:
809 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
810 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
813 case SILC_KEY_AGREEMENT_TIMEOUT:
814 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
815 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
818 case SILC_KEY_AGREEMENT_ABORTED:
819 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
820 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
831 /* Local command KEY. This command is used to set and unset private
832 keys for channels, set and unset private keys for private messages
833 with remote clients and to send key agreement requests and
834 negotiate the key agreement protocol with remote client. The
835 key agreement is supported only to negotiate private message keys,
836 it currently cannot be used to negotiate private keys for channels,
837 as it is not convenient for that purpose. */
840 SILC_SERVER_REC *server;
846 /* Callback to be called after client information is resolved from the
849 static void silc_client_command_key_get_clients(SilcClient client,
850 SilcClientConnection conn,
851 SilcClientEntry *clients,
852 uint32 clients_count,
855 KeyGetClients internal = (KeyGetClients)context;
858 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
860 silc_free(internal->data);
861 silc_free(internal->nick);
866 signal_emit("command key", 3, internal->data, internal->server,
869 silc_free(internal->data);
870 silc_free(internal->nick);
874 static void command_key(const char *data, SILC_SERVER_REC *server,
877 SilcClientConnection conn;
878 SilcClientEntry *entrys, client_entry = NULL;
880 SilcChannelEntry channel_entry = NULL;
881 char *nickname = NULL, *tmp;
882 int command = 0, port = 0, type = 0;
883 char *hostname = NULL;
884 KeyInternal internal = NULL;
886 unsigned char **argv;
887 uint32 *argv_lens, *argv_types;
888 char *bindhost = NULL;
890 if (!server || !IS_SILC_SERVER(server) || !server->connected)
891 cmd_return_error(CMDERR_NOT_CONNECTED);
895 /* Now parse all arguments */
896 tmp = g_strconcat("KEY", " ", data, NULL);
897 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
901 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
904 if (!strcasecmp(argv[1], "msg"))
906 if (!strcasecmp(argv[1], "channel"))
910 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
913 if (argv[2][0] == '*') {
914 nickname = strdup("*");
916 /* Parse the typed nickname. */
917 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
918 printformat_module("fe-common/silc", server, NULL,
919 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
923 /* Find client entry */
924 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
925 argv[2], &entry_count);
927 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
928 inter->server = server;
929 inter->data = strdup(data);
930 inter->nick = strdup(nickname);
932 silc_client_get_clients(silc_client, conn, nickname, argv[2],
933 silc_client_command_key_get_clients, inter);
936 client_entry = entrys[0];
942 /* Get channel entry */
945 if (argv[2][0] == '*') {
946 if (!conn->current_channel) {
948 cmd_return_error(CMDERR_NOT_JOINED);
950 name = conn->current_channel->channel_name;
955 channel_entry = silc_client_get_channel(silc_client, conn, name);
956 if (!channel_entry) {
958 cmd_return_error(CMDERR_NOT_JOINED);
963 if (!strcasecmp(argv[3], "set")) {
967 if (type == 1 && client_entry) {
968 /* Set private message key */
970 silc_client_del_private_message_key(silc_client, conn, client_entry);
973 silc_client_add_private_message_key(silc_client, conn, client_entry,
977 TRUE : FALSE), FALSE);
979 silc_client_add_private_message_key(silc_client, conn, client_entry,
983 TRUE : FALSE), FALSE);
985 /* Send the key to the remote client so that it starts using it
987 silc_client_send_private_message_key(silc_client, conn,
989 } else if (type == 2) {
990 /* Set private channel key */
991 char *cipher = NULL, *hmac = NULL;
993 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
994 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
995 SILCTXT_CH_PRIVATE_KEY_NOMODE,
996 channel_entry->channel_name);
1005 if (!silc_client_add_channel_private_key(silc_client, conn,
1010 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1011 SILCTXT_CH_PRIVATE_KEY_ERROR,
1012 channel_entry->channel_name);
1016 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1017 SILCTXT_CH_PRIVATE_KEY_ADD,
1018 channel_entry->channel_name);
1026 if (!strcasecmp(argv[3], "unset")) {
1029 if (type == 1 && client_entry) {
1030 /* Unset private message key */
1031 silc_client_del_private_message_key(silc_client, conn, client_entry);
1032 } else if (type == 2) {
1033 /* Unset channel key(s) */
1034 SilcChannelPrivateKey *keys;
1039 silc_client_del_channel_private_keys(silc_client, conn,
1043 number = atoi(argv[4]);
1044 keys = silc_client_list_channel_private_keys(silc_client, conn,
1050 if (!number || number > keys_count) {
1051 silc_client_free_channel_private_keys(keys, keys_count);
1055 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1057 silc_client_free_channel_private_keys(keys, keys_count);
1065 if (!strcasecmp(argv[3], "list")) {
1069 SilcPrivateMessageKeys keys;
1074 keys = silc_client_list_private_message_keys(silc_client, conn,
1079 /* list the private message key(s) */
1080 if (nickname[0] == '*') {
1081 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1082 SILCTXT_PRIVATE_KEY_LIST);
1083 for (k = 0; k < keys_count; k++) {
1084 memset(buf, 0, sizeof(buf));
1085 strncat(buf, " ", 2);
1086 len = strlen(keys[k].client_entry->nickname);
1087 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1089 for (i = 0; i < 30 - len; i++)
1093 len = strlen(keys[k].cipher);
1094 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1096 for (i = 0; i < 14 - len; i++)
1101 strcat(buf, "<hidden>");
1103 strcat(buf, "*generated*");
1105 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1108 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1109 SILCTXT_PRIVATE_KEY_LIST_NICK,
1110 client_entry->nickname);
1111 for (k = 0; k < keys_count; k++) {
1112 if (keys[k].client_entry != client_entry)
1115 memset(buf, 0, sizeof(buf));
1116 strncat(buf, " ", 2);
1117 len = strlen(keys[k].client_entry->nickname);
1118 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1120 for (i = 0; i < 30 - len; i++)
1124 len = strlen(keys[k].cipher);
1125 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1127 for (i = 0; i < 14 - len; i++)
1132 strcat(buf, "<hidden>");
1134 strcat(buf, "*generated*");
1136 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1140 silc_client_free_private_message_keys(keys, keys_count);
1142 } else if (type == 2) {
1143 SilcChannelPrivateKey *keys;
1148 keys = silc_client_list_channel_private_keys(silc_client, conn,
1152 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1153 SILCTXT_CH_PRIVATE_KEY_LIST,
1154 channel_entry->channel_name);
1159 for (k = 0; k < keys_count; k++) {
1160 memset(buf, 0, sizeof(buf));
1161 strncat(buf, " ", 2);
1163 len = strlen(keys[k]->cipher->cipher->name);
1164 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1166 for (i = 0; i < 16 - len; i++)
1170 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1171 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1173 for (i = 0; i < 16 - len; i++)
1177 strcat(buf, "<hidden>");
1179 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1182 silc_client_free_channel_private_keys(keys, keys_count);
1188 /* Send command is used to send key agreement */
1189 if (!strcasecmp(argv[3], "agreement")) {
1195 port = atoi(argv[5]);
1197 internal = silc_calloc(1, sizeof(*internal));
1198 internal->type = type;
1199 internal->server = server;
1202 if (settings_get_bool("use_auto_addr")) {
1204 hostname = (char *)settings_get_str("auto_public_ip");
1206 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1209 if ((hostname) && (*hostname == '\0')) {
1213 bindhost = (char *)settings_get_str("auto_bind_ip");
1215 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1216 * public_ip is the same value as the bind_ip.
1218 if ((bindhost) && (*bindhost == '\0')) {
1219 bindhost = hostname;
1221 port = settings_get_int("auto_bind_port");
1223 } /* if use_auto_addr */
1227 /* Start command is used to start key agreement (after receiving the
1228 key_agreement client operation). */
1229 if (!strcasecmp(argv[3], "negotiate")) {
1235 port = atoi(argv[5]);
1237 internal = silc_calloc(1, sizeof(*internal));
1238 internal->type = type;
1239 internal->server = server;
1243 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1244 "Usage: /KEY msg|channel <nickname|channel> "
1245 "set|unset|agreement|negotiate [<arguments>]");
1249 if (command == 4 && client_entry) {
1250 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1251 SILCTXT_KEY_AGREEMENT, argv[2]);
1252 internal->responder = TRUE;
1253 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1254 bindhost, port, 120, keyagr_completion,
1257 silc_free(internal);
1261 if (command == 5 && client_entry && hostname) {
1262 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1263 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1264 internal->responder = FALSE;
1265 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1266 hostname, port, keyagr_completion,
1272 silc_free(nickname);
1275 /* Lists locally saved client and server public keys. */
1277 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1283 void silc_channels_init(void)
1285 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1286 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1287 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1289 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1290 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1291 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1292 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1293 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1294 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1295 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1296 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1297 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1298 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1299 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1300 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1301 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1303 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1304 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1305 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1306 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1307 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1308 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1309 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1311 silc_nicklist_init();
1314 void silc_channels_deinit(void)
1316 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1317 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1318 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1320 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1321 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1322 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1323 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1324 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1325 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1326 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1327 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1328 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1329 signal_remove("silc event channel_change",
1330 (SIGNAL_FUNC) event_channel_change);
1331 signal_remove("silc event server_signoff",
1332 (SIGNAL_FUNC) event_server_signoff);
1333 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1334 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1336 command_unbind("part", (SIGNAL_FUNC) command_part);
1337 command_unbind("me", (SIGNAL_FUNC) command_me);
1338 command_unbind("action", (SIGNAL_FUNC) command_action);
1339 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1340 command_unbind("away", (SIGNAL_FUNC) command_away);
1341 command_unbind("key", (SIGNAL_FUNC) command_key);
1342 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1344 silc_nicklist_deinit();