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 silc_server_free_ftp(server, client);
221 memset(userhost, 0, sizeof(userhost));
222 if (client->username)
223 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
224 client->username, client->hostname);
225 signal_emit("message quit", 4, server, client->nickname,
226 client->username ? userhost : "",
227 message ? message : "");
229 nicks = nicklist_get_same_unique(SERVER(server), client);
230 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
231 CHANNEL_REC *channel = tmp->data;
232 NICK_REC *nickrec = tmp->next->data;
234 nicklist_remove(channel, nickrec);
239 * "event topic". Changed topic.
242 static void event_topic(SILC_SERVER_REC *server, va_list va)
244 SILC_CHANNEL_REC *chanrec;
245 SilcClientEntry client;
246 SilcChannelEntry channel;
250 client = va_arg(va, SilcClientEntry);
251 topic = va_arg(va, char *);
252 channel = va_arg(va, SilcChannelEntry);
254 silc_server_free_ftp(server, client);
256 chanrec = silc_channel_find_entry(server, channel);
257 if (chanrec != NULL) {
258 g_free_not_null(chanrec->topic);
259 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
260 signal_emit("channel topic changed", 1, chanrec);
263 memset(userhost, 0, sizeof(userhost));
264 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
265 client->username, client->hostname);
266 signal_emit("message topic", 5, server, channel->channel_name,
267 topic, client->nickname, userhost);
271 * "event invite". Invited or modified invite list.
274 static void event_invite(SILC_SERVER_REC *server, va_list va)
276 SilcClientEntry client;
277 SilcChannelEntry channel;
281 channel = va_arg(va, SilcChannelEntry);
282 channel_name = va_arg(va, char *);
283 client = va_arg(va, SilcClientEntry);
285 memset(userhost, 0, sizeof(userhost));
286 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
287 client->username, client->hostname);
288 signal_emit("message invite", 4, server, channel ? channel->channel_name :
289 channel_name, client->nickname, userhost);
293 * "event nick". Changed nickname.
296 static void event_nick(SILC_SERVER_REC *server, va_list va)
298 SilcClientEntry oldclient, newclient;
301 oldclient = va_arg(va, SilcClientEntry);
302 newclient = va_arg(va, SilcClientEntry);
304 nicklist_rename_unique(SERVER(server),
305 oldclient, oldclient->nickname,
306 newclient, newclient->nickname);
308 memset(userhost, 0, sizeof(userhost));
309 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
310 newclient->username, newclient->hostname);
311 signal_emit("message nick", 4, server, newclient->nickname,
312 oldclient->nickname, userhost);
316 * "event cmode". Changed channel mode.
319 static void event_cmode(SILC_SERVER_REC *server, va_list va)
321 SILC_CHANNEL_REC *chanrec;
323 SilcClientEntry client;
324 SilcServerEntry server_entry;
325 SilcChannelEntry channel;
330 idtype = va_arg(va, int);
331 entry = va_arg(va, void *);
332 modei = va_arg(va, uint32);
333 (void)va_arg(va, char *);
334 (void)va_arg(va, char *);
335 channel = va_arg(va, SilcChannelEntry);
337 mode = silc_client_chmode(modei,
338 channel->channel_key->cipher->name,
339 silc_hmac_get_name(channel->hmac));
341 chanrec = silc_channel_find_entry(server, channel);
342 if (chanrec != NULL) {
343 g_free_not_null(chanrec->mode);
344 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
345 signal_emit("channel mode changed", 1, chanrec);
348 if (idtype == SILC_ID_CLIENT) {
349 client = (SilcClientEntry)entry;
350 printformat_module("fe-common/silc", server, channel->channel_name,
351 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
352 channel->channel_name, mode ? mode : "removed all",
355 server_entry = (SilcServerEntry)entry;
356 printformat_module("fe-common/silc", server, channel->channel_name,
357 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
358 channel->channel_name, mode ? mode : "removed all",
359 server_entry->server_name);
366 * "event cumode". Changed user's mode on channel.
369 static void event_cumode(SILC_SERVER_REC *server, va_list va)
371 SILC_CHANNEL_REC *chanrec;
372 SilcClientEntry client, destclient;
373 SilcChannelEntry channel;
377 client = va_arg(va, SilcClientEntry);
378 mode = va_arg(va, uint32);
379 destclient = va_arg(va, SilcClientEntry);
380 channel = va_arg(va, SilcChannelEntry);
382 modestr = silc_client_chumode(mode);
383 chanrec = silc_channel_find_entry(server, channel);
384 if (chanrec != NULL) {
387 if (destclient == server->conn->local_entry) {
389 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
392 nick = silc_nicklist_find(chanrec, destclient);
394 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
395 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
396 signal_emit("nick mode changed", 2, chanrec, nick);
400 printformat_module("fe-common/silc", server, channel->channel_name,
401 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
402 channel->channel_name, destclient->nickname,
403 modestr ? modestr : "removed all",
406 if (mode & SILC_CHANNEL_UMODE_CHANFO)
407 printformat_module("fe-common/silc",
408 server, channel->channel_name, MSGLEVEL_CRAP,
409 SILCTXT_CHANNEL_FOUNDER,
410 channel->channel_name, destclient->nickname);
416 * "event motd". Received MOTD.
419 static void event_motd(SILC_SERVER_REC *server, va_list va)
421 char *text = va_arg(va, char *);
423 if (!settings_get_bool("skip_motd"))
424 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
428 * "event channel_change". Channel ID has changed.
431 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
433 /* Nothing interesting to do */
437 * "event server_signoff". Server has quit the network.
440 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
442 SilcClientEntry *clients;
443 uint32 clients_count;
447 (void)va_arg(va, void *);
448 clients = va_arg(va, SilcClientEntry *);
449 clients_count = va_arg(va, uint32);
451 for (i = 0; i < clients_count; i++) {
454 memset(userhost, 0, sizeof(userhost));
455 if (clients[i]->username)
456 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
457 clients[i]->username, clients[i]->hostname);
458 signal_emit("message quit", 4, server, clients[i]->nickname,
459 clients[i]->username ? userhost : "",
462 nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
463 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
464 CHANNEL_REC *channel = tmp->data;
465 NICK_REC *nickrec = tmp->next->data;
466 nicklist_remove(channel, nickrec);
472 * "event kick". Someone was kicked from channel.
475 static void event_kick(SILC_SERVER_REC *server, va_list va)
477 SilcClientConnection conn = server->conn;
478 SilcClientEntry client_entry, kicker;
479 SilcChannelEntry channel_entry;
481 SILC_CHANNEL_REC *chanrec;
483 client_entry = va_arg(va, SilcClientEntry);
484 tmp = va_arg(va, char *);
485 kicker = va_arg(va, SilcClientEntry);
486 channel_entry = va_arg(va, SilcChannelEntry);
488 chanrec = silc_channel_find_entry(server, channel_entry);
490 if (client_entry == conn->local_entry) {
491 printformat_module("fe-common/silc", server, channel_entry->channel_name,
492 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
494 channel_entry->channel_name, tmp ? tmp : "");
496 chanrec->kicked = TRUE;
497 channel_destroy((CHANNEL_REC *)chanrec);
500 printformat_module("fe-common/silc", server, channel_entry->channel_name,
501 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
502 client_entry->nickname,
504 channel_entry->channel_name, tmp ? tmp : "");
507 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
509 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
515 * "event kill". Someone was killed from the network.
518 static void event_kill(SILC_SERVER_REC *server, va_list va)
520 SilcClientConnection conn = server->conn;
521 SilcClientEntry client_entry;
524 client_entry = va_arg(va, SilcClientEntry);
525 tmp = va_arg(va, char *);
527 if (client_entry == conn->local_entry) {
528 printformat_module("fe-common/silc", server, NULL,
529 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
532 GSList *nicks, *tmpn;
533 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
534 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
535 CHANNEL_REC *channel = tmpn->data;
536 NICK_REC *nickrec = tmpn->next->data;
537 nicklist_remove(channel, nickrec);
540 printformat_module("fe-common/silc", server, NULL,
541 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
542 client_entry->nickname,
547 /* PART (LEAVE) command. */
549 static void command_part(const char *data, SILC_SERVER_REC *server,
552 SILC_CHANNEL_REC *chanrec;
555 if (!IS_SILC_SERVER(server) || !server->connected)
556 cmd_return_error(CMDERR_NOT_CONNECTED);
558 if (!strcmp(data, "*") || *data == '\0') {
559 if (!IS_SILC_CHANNEL(item))
560 cmd_return_error(CMDERR_NOT_JOINED);
564 chanrec = silc_channel_find(server, data);
566 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
568 memset(userhost, 0, sizeof(userhost));
569 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
570 server->conn->local_entry->username,
571 server->conn->local_entry->hostname);
572 signal_emit("message part", 5, server, chanrec->name,
573 server->nick, userhost, "");
575 silc_command_exec(server, "LEAVE", chanrec->name);
578 channel_destroy(CHANNEL(chanrec));
581 /* ME local command. */
583 static void command_me(const char *data, SILC_SERVER_REC *server,
586 SILC_CHANNEL_REC *chanrec;
587 char *tmpcmd = "ME", *tmp;
589 unsigned char **argv;
590 uint32 *argv_lens, *argv_types;
593 if (!IS_SILC_SERVER(server) || !server->connected)
594 cmd_return_error(CMDERR_NOT_CONNECTED);
596 if (!IS_SILC_CHANNEL(item))
597 cmd_return_error(CMDERR_NOT_JOINED);
599 /* Now parse all arguments */
600 tmp = g_strconcat(tmpcmd, " ", data, NULL);
601 silc_parse_command_line(tmp, &argv, &argv_lens,
602 &argv_types, &argc, 2);
606 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
608 chanrec = silc_channel_find(server, item->name);
610 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
612 /* Send the action message */
613 silc_client_send_channel_message(silc_client, server->conn,
614 chanrec->entry, NULL,
615 SILC_MESSAGE_FLAG_ACTION,
616 argv[1], argv_lens[1], TRUE);
618 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
619 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
620 server->conn->local_entry->nickname, argv[1]);
622 for (i = 0; i < argc; i++)
624 silc_free(argv_lens);
625 silc_free(argv_types);
628 /* ACTION local command. Same as ME but takes the channel as mandatory
631 static void command_action(const char *data, SILC_SERVER_REC *server,
634 SILC_CHANNEL_REC *chanrec;
635 char *tmpcmd = "ME", *tmp;
637 unsigned char **argv;
638 uint32 *argv_lens, *argv_types;
641 if (!IS_SILC_SERVER(server) || !server->connected)
642 cmd_return_error(CMDERR_NOT_CONNECTED);
644 if (!IS_SILC_CHANNEL(item))
645 cmd_return_error(CMDERR_NOT_JOINED);
647 /* Now parse all arguments */
648 tmp = g_strconcat(tmpcmd, " ", data, NULL);
649 silc_parse_command_line(tmp, &argv, &argv_lens,
650 &argv_types, &argc, 3);
654 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
656 chanrec = silc_channel_find(server, argv[1]);
658 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
660 /* Send the action message */
661 silc_client_send_channel_message(silc_client, server->conn,
662 chanrec->entry, NULL,
663 SILC_MESSAGE_FLAG_ACTION,
664 argv[2], argv_lens[2], TRUE);
666 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
667 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
668 server->conn->local_entry->nickname, argv[2]);
670 for (i = 0; i < argc; i++)
672 silc_free(argv_lens);
673 silc_free(argv_types);
676 /* NOTICE local command. */
678 static void command_notice(const char *data, SILC_SERVER_REC *server,
681 SILC_CHANNEL_REC *chanrec;
682 char *tmpcmd = "ME", *tmp;
684 unsigned char **argv;
685 uint32 *argv_lens, *argv_types;
688 if (!IS_SILC_SERVER(server) || !server->connected)
689 cmd_return_error(CMDERR_NOT_CONNECTED);
691 if (!IS_SILC_CHANNEL(item))
692 cmd_return_error(CMDERR_NOT_JOINED);
694 /* Now parse all arguments */
695 tmp = g_strconcat(tmpcmd, " ", data, NULL);
696 silc_parse_command_line(tmp, &argv, &argv_lens,
697 &argv_types, &argc, 2);
701 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
703 chanrec = silc_channel_find(server, item->name);
705 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
707 /* Send the action message */
708 silc_client_send_channel_message(silc_client, server->conn,
709 chanrec->entry, NULL,
710 SILC_MESSAGE_FLAG_NOTICE,
711 argv[1], argv_lens[1], TRUE);
713 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
714 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
715 server->conn->local_entry->nickname, argv[1]);
717 for (i = 0; i < argc; i++)
719 silc_free(argv_lens);
720 silc_free(argv_types);
723 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
726 static void command_away(const char *data, SILC_SERVER_REC *server,
731 if (!IS_SILC_SERVER(server) || !server->connected)
732 cmd_return_error(CMDERR_NOT_CONNECTED);
735 /* Remove any possible away message */
736 silc_client_set_away_message(silc_client, server->conn, NULL);
739 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
742 /* Set the away message */
743 silc_client_set_away_message(silc_client, server->conn, (char *)data);
746 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
747 SILCTXT_SET_AWAY, data);
750 signal_emit("away mode changed", 1, server);
752 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
756 int type; /* 1 = msg, 2 = channel */
758 SILC_SERVER_REC *server;
761 /* Key agreement callback that is called after the key agreement protocol
762 has been performed. This is called also if error occured during the
763 key agreement protocol. The `key' is the allocated key material and
764 the caller is responsible of freeing it. The `key' is NULL if error
765 has occured. The application can freely use the `key' to whatever
766 purpose it needs. See lib/silcske/silcske.h for the definition of
767 the SilcSKEKeyMaterial structure. */
769 static void keyagr_completion(SilcClient client,
770 SilcClientConnection conn,
771 SilcClientEntry client_entry,
772 SilcKeyAgreementStatus status,
773 SilcSKEKeyMaterial *key,
776 KeyInternal i = (KeyInternal)context;
779 case SILC_KEY_AGREEMENT_OK:
780 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
781 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
784 /* Set the private key for this client */
785 silc_client_del_private_message_key(client, conn, client_entry);
786 silc_client_add_private_message_key_ske(client, conn, client_entry,
787 NULL, key, i->responder);
788 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
789 SILCTXT_KEY_AGREEMENT_PRIVMSG,
790 client_entry->nickname);
791 silc_ske_free_key_material(key);
796 case SILC_KEY_AGREEMENT_ERROR:
797 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
798 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
801 case SILC_KEY_AGREEMENT_FAILURE:
802 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
803 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
806 case SILC_KEY_AGREEMENT_TIMEOUT:
807 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
808 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
811 case SILC_KEY_AGREEMENT_ABORTED:
812 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
813 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
824 /* Local command KEY. This command is used to set and unset private
825 keys for channels, set and unset private keys for private messages
826 with remote clients and to send key agreement requests and
827 negotiate the key agreement protocol with remote client. The
828 key agreement is supported only to negotiate private message keys,
829 it currently cannot be used to negotiate private keys for channels,
830 as it is not convenient for that purpose. */
833 SILC_SERVER_REC *server;
839 /* Callback to be called after client information is resolved from the
842 static void silc_client_command_key_get_clients(SilcClient client,
843 SilcClientConnection conn,
844 SilcClientEntry *clients,
845 uint32 clients_count,
848 KeyGetClients internal = (KeyGetClients)context;
851 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
853 silc_free(internal->data);
854 silc_free(internal->nick);
859 signal_emit("command key", 3, internal->data, internal->server,
862 silc_free(internal->data);
863 silc_free(internal->nick);
867 static void command_key(const char *data, SILC_SERVER_REC *server,
870 SilcClientConnection conn;
871 SilcClientEntry *entrys, client_entry = NULL;
873 SilcChannelEntry channel_entry = NULL;
874 char *nickname = NULL, *tmp;
875 int command = 0, port = 0, type = 0;
876 char *hostname = NULL;
877 KeyInternal internal = NULL;
879 unsigned char **argv;
880 uint32 *argv_lens, *argv_types;
881 char *bindhost = NULL;
883 if (!server || !IS_SILC_SERVER(server) || !server->connected)
884 cmd_return_error(CMDERR_NOT_CONNECTED);
888 /* Now parse all arguments */
889 tmp = g_strconcat("KEY", " ", data, NULL);
890 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
894 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
897 if (!strcasecmp(argv[1], "msg"))
899 if (!strcasecmp(argv[1], "channel"))
903 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
906 if (argv[2][0] == '*') {
907 nickname = strdup("*");
909 /* Parse the typed nickname. */
910 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
911 printformat_module("fe-common/silc", server, NULL,
912 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
916 /* Find client entry */
917 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
918 argv[2], &entry_count);
920 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
921 inter->server = server;
922 inter->data = strdup(data);
923 inter->nick = strdup(nickname);
925 silc_client_get_clients(silc_client, conn, nickname, argv[2],
926 silc_client_command_key_get_clients, inter);
929 client_entry = entrys[0];
935 /* Get channel entry */
938 if (argv[2][0] == '*') {
939 if (!conn->current_channel) {
941 cmd_return_error(CMDERR_NOT_JOINED);
943 name = conn->current_channel->channel_name;
948 channel_entry = silc_client_get_channel(silc_client, conn, name);
949 if (!channel_entry) {
951 cmd_return_error(CMDERR_NOT_JOINED);
956 if (!strcasecmp(argv[3], "set")) {
960 if (type == 1 && client_entry) {
961 /* Set private message key */
963 silc_client_del_private_message_key(silc_client, conn, client_entry);
966 silc_client_add_private_message_key(silc_client, conn, client_entry,
970 TRUE : FALSE), FALSE);
972 silc_client_add_private_message_key(silc_client, conn, client_entry,
976 TRUE : FALSE), FALSE);
978 /* Send the key to the remote client so that it starts using it
980 silc_client_send_private_message_key(silc_client, conn,
982 } else if (type == 2) {
983 /* Set private channel key */
984 char *cipher = NULL, *hmac = NULL;
986 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
987 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
988 SILCTXT_CH_PRIVATE_KEY_NOMODE,
989 channel_entry->channel_name);
998 if (!silc_client_add_channel_private_key(silc_client, conn,
1003 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1004 SILCTXT_CH_PRIVATE_KEY_ERROR,
1005 channel_entry->channel_name);
1009 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1010 SILCTXT_CH_PRIVATE_KEY_ADD,
1011 channel_entry->channel_name);
1019 if (!strcasecmp(argv[3], "unset")) {
1022 if (type == 1 && client_entry) {
1023 /* Unset private message key */
1024 silc_client_del_private_message_key(silc_client, conn, client_entry);
1025 } else if (type == 2) {
1026 /* Unset channel key(s) */
1027 SilcChannelPrivateKey *keys;
1032 silc_client_del_channel_private_keys(silc_client, conn,
1036 number = atoi(argv[4]);
1037 keys = silc_client_list_channel_private_keys(silc_client, conn,
1043 if (!number || number > keys_count) {
1044 silc_client_free_channel_private_keys(keys, keys_count);
1048 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1050 silc_client_free_channel_private_keys(keys, keys_count);
1058 if (!strcasecmp(argv[3], "list")) {
1062 SilcPrivateMessageKeys keys;
1067 keys = silc_client_list_private_message_keys(silc_client, conn,
1072 /* list the private message key(s) */
1073 if (nickname[0] == '*') {
1074 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1075 SILCTXT_PRIVATE_KEY_LIST);
1076 for (k = 0; k < keys_count; k++) {
1077 memset(buf, 0, sizeof(buf));
1078 strncat(buf, " ", 2);
1079 len = strlen(keys[k].client_entry->nickname);
1080 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1082 for (i = 0; i < 30 - len; i++)
1086 len = strlen(keys[k].cipher);
1087 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1089 for (i = 0; i < 14 - len; i++)
1094 strcat(buf, "<hidden>");
1096 strcat(buf, "*generated*");
1098 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1101 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1102 SILCTXT_PRIVATE_KEY_LIST_NICK,
1103 client_entry->nickname);
1104 for (k = 0; k < keys_count; k++) {
1105 if (keys[k].client_entry != client_entry)
1108 memset(buf, 0, sizeof(buf));
1109 strncat(buf, " ", 2);
1110 len = strlen(keys[k].client_entry->nickname);
1111 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1113 for (i = 0; i < 30 - len; i++)
1117 len = strlen(keys[k].cipher);
1118 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1120 for (i = 0; i < 14 - len; i++)
1125 strcat(buf, "<hidden>");
1127 strcat(buf, "*generated*");
1129 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1133 silc_client_free_private_message_keys(keys, keys_count);
1135 } else if (type == 2) {
1136 SilcChannelPrivateKey *keys;
1141 keys = silc_client_list_channel_private_keys(silc_client, conn,
1145 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1146 SILCTXT_CH_PRIVATE_KEY_LIST,
1147 channel_entry->channel_name);
1152 for (k = 0; k < keys_count; k++) {
1153 memset(buf, 0, sizeof(buf));
1154 strncat(buf, " ", 2);
1156 len = strlen(keys[k]->cipher->cipher->name);
1157 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1159 for (i = 0; i < 16 - len; i++)
1163 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1164 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1166 for (i = 0; i < 16 - len; i++)
1170 strcat(buf, "<hidden>");
1172 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1175 silc_client_free_channel_private_keys(keys, keys_count);
1181 /* Send command is used to send key agreement */
1182 if (!strcasecmp(argv[3], "agreement")) {
1188 port = atoi(argv[5]);
1190 internal = silc_calloc(1, sizeof(*internal));
1191 internal->type = type;
1192 internal->server = server;
1195 if (settings_get_bool("use_auto_addr")) {
1197 hostname = (char *)settings_get_str("auto_public_ip");
1199 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1202 if ((hostname) && (*hostname == '\0')) {
1206 bindhost = (char *)settings_get_str("auto_bind_ip");
1208 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1209 * public_ip is the same value as the bind_ip.
1211 if ((bindhost) && (*bindhost == '\0')) {
1212 bindhost = hostname;
1214 port = settings_get_int("auto_bind_port");
1216 } /* if use_auto_addr */
1220 /* Start command is used to start key agreement (after receiving the
1221 key_agreement client operation). */
1222 if (!strcasecmp(argv[3], "negotiate")) {
1228 port = atoi(argv[5]);
1230 internal = silc_calloc(1, sizeof(*internal));
1231 internal->type = type;
1232 internal->server = server;
1236 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1237 "Usage: /KEY msg|channel <nickname|channel> "
1238 "set|unset|agreement|negotiate [<arguments>]");
1242 if (command == 4 && client_entry) {
1243 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1244 SILCTXT_KEY_AGREEMENT, argv[2]);
1245 internal->responder = TRUE;
1246 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1247 bindhost, port, 120, keyagr_completion,
1250 silc_free(internal);
1254 if (command == 5 && client_entry && hostname) {
1255 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1256 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1257 internal->responder = FALSE;
1258 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1259 hostname, port, keyagr_completion,
1265 silc_free(nickname);
1268 /* Lists locally saved client and server public keys. */
1270 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1276 void silc_channels_init(void)
1278 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1279 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1280 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1282 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1283 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1284 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1285 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1286 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1287 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1288 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1289 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1290 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1291 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1292 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1293 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1294 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1296 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1297 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1298 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1299 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1300 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1301 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1302 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1304 silc_nicklist_init();
1307 void silc_channels_deinit(void)
1309 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1310 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1311 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1313 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1314 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1315 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1316 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1317 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1318 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1319 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1320 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1321 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1322 signal_remove("silc event channel_change",
1323 (SIGNAL_FUNC) event_channel_change);
1324 signal_remove("silc event server_signoff",
1325 (SIGNAL_FUNC) event_server_signoff);
1326 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1327 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1329 command_unbind("part", (SIGNAL_FUNC) command_part);
1330 command_unbind("me", (SIGNAL_FUNC) command_me);
1331 command_unbind("action", (SIGNAL_FUNC) command_action);
1332 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1333 command_unbind("away", (SIGNAL_FUNC) command_away);
1334 command_unbind("key", (SIGNAL_FUNC) command_key);
1335 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1337 silc_nicklist_deinit();