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;
479 SilcChannelEntry channel_entry;
481 SILC_CHANNEL_REC *chanrec;
483 client_entry = va_arg(va, SilcClientEntry);
484 tmp = va_arg(va, char *);
485 channel_entry = va_arg(va, SilcChannelEntry);
487 chanrec = silc_channel_find_entry(server, channel_entry);
489 if (client_entry == conn->local_entry) {
490 printformat_module("fe-common/silc", server, channel_entry->channel_name,
491 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
492 channel_entry->channel_name, tmp ? tmp : "");
494 chanrec->kicked = TRUE;
495 channel_destroy((CHANNEL_REC *)chanrec);
498 printformat_module("fe-common/silc", server, channel_entry->channel_name,
499 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
500 client_entry->nickname,
501 channel_entry->channel_name, tmp ? tmp : "");
504 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
506 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
512 * "event kill". Someone was killed from the network.
515 static void event_kill(SILC_SERVER_REC *server, va_list va)
517 SilcClientConnection conn = server->conn;
518 SilcClientEntry client_entry;
521 client_entry = va_arg(va, SilcClientEntry);
522 tmp = va_arg(va, char *);
524 if (client_entry == conn->local_entry) {
525 printformat_module("fe-common/silc", server, NULL,
526 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
529 GSList *nicks, *tmpn;
530 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
531 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
532 CHANNEL_REC *channel = tmpn->data;
533 NICK_REC *nickrec = tmpn->next->data;
534 nicklist_remove(channel, nickrec);
537 printformat_module("fe-common/silc", server, NULL,
538 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
539 client_entry->nickname,
544 /* PART (LEAVE) command. */
546 static void command_part(const char *data, SILC_SERVER_REC *server,
549 SILC_CHANNEL_REC *chanrec;
552 if (!IS_SILC_SERVER(server) || !server->connected)
553 cmd_return_error(CMDERR_NOT_CONNECTED);
555 if (!strcmp(data, "*") || *data == '\0') {
556 if (!IS_SILC_CHANNEL(item))
557 cmd_return_error(CMDERR_NOT_JOINED);
561 chanrec = silc_channel_find(server, data);
563 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
565 memset(userhost, 0, sizeof(userhost));
566 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
567 server->conn->local_entry->username,
568 server->conn->local_entry->hostname);
569 signal_emit("message part", 5, server, chanrec->name,
570 server->nick, userhost, "");
572 silc_command_exec(server, "LEAVE", chanrec->name);
575 channel_destroy(CHANNEL(chanrec));
578 /* ME local command. */
580 static void command_me(const char *data, SILC_SERVER_REC *server,
583 SILC_CHANNEL_REC *chanrec;
584 char *tmpcmd = "ME", *tmp;
586 unsigned char **argv;
587 uint32 *argv_lens, *argv_types;
590 if (!IS_SILC_SERVER(server) || !server->connected)
591 cmd_return_error(CMDERR_NOT_CONNECTED);
593 if (!IS_SILC_CHANNEL(item))
594 cmd_return_error(CMDERR_NOT_JOINED);
596 /* Now parse all arguments */
597 tmp = g_strconcat(tmpcmd, " ", data, NULL);
598 silc_parse_command_line(tmp, &argv, &argv_lens,
599 &argv_types, &argc, 2);
603 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
605 chanrec = silc_channel_find(server, item->name);
607 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
609 /* Send the action message */
610 silc_client_send_channel_message(silc_client, server->conn,
611 chanrec->entry, NULL,
612 SILC_MESSAGE_FLAG_ACTION,
613 argv[1], argv_lens[1], TRUE);
615 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
616 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
617 server->conn->local_entry->nickname, argv[1]);
619 for (i = 0; i < argc; i++)
621 silc_free(argv_lens);
622 silc_free(argv_types);
625 /* ACTION local command. Same as ME but takes the channel as mandatory
628 static void command_action(const char *data, SILC_SERVER_REC *server,
631 SILC_CHANNEL_REC *chanrec;
632 char *tmpcmd = "ME", *tmp;
634 unsigned char **argv;
635 uint32 *argv_lens, *argv_types;
638 if (!IS_SILC_SERVER(server) || !server->connected)
639 cmd_return_error(CMDERR_NOT_CONNECTED);
641 if (!IS_SILC_CHANNEL(item))
642 cmd_return_error(CMDERR_NOT_JOINED);
644 /* Now parse all arguments */
645 tmp = g_strconcat(tmpcmd, " ", data, NULL);
646 silc_parse_command_line(tmp, &argv, &argv_lens,
647 &argv_types, &argc, 3);
651 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
653 chanrec = silc_channel_find(server, argv[1]);
655 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
657 /* Send the action message */
658 silc_client_send_channel_message(silc_client, server->conn,
659 chanrec->entry, NULL,
660 SILC_MESSAGE_FLAG_ACTION,
661 argv[2], argv_lens[2], TRUE);
663 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
664 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
665 server->conn->local_entry->nickname, argv[2]);
667 for (i = 0; i < argc; i++)
669 silc_free(argv_lens);
670 silc_free(argv_types);
673 /* NOTICE local command. */
675 static void command_notice(const char *data, SILC_SERVER_REC *server,
678 SILC_CHANNEL_REC *chanrec;
679 char *tmpcmd = "ME", *tmp;
681 unsigned char **argv;
682 uint32 *argv_lens, *argv_types;
685 if (!IS_SILC_SERVER(server) || !server->connected)
686 cmd_return_error(CMDERR_NOT_CONNECTED);
688 if (!IS_SILC_CHANNEL(item))
689 cmd_return_error(CMDERR_NOT_JOINED);
691 /* Now parse all arguments */
692 tmp = g_strconcat(tmpcmd, " ", data, NULL);
693 silc_parse_command_line(tmp, &argv, &argv_lens,
694 &argv_types, &argc, 2);
698 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
700 chanrec = silc_channel_find(server, item->name);
702 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
704 /* Send the action message */
705 silc_client_send_channel_message(silc_client, server->conn,
706 chanrec->entry, NULL,
707 SILC_MESSAGE_FLAG_NOTICE,
708 argv[1], argv_lens[1], TRUE);
710 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
711 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
712 server->conn->local_entry->nickname, argv[1]);
714 for (i = 0; i < argc; i++)
716 silc_free(argv_lens);
717 silc_free(argv_types);
720 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
723 static void command_away(const char *data, SILC_SERVER_REC *server,
728 if (!IS_SILC_SERVER(server) || !server->connected)
729 cmd_return_error(CMDERR_NOT_CONNECTED);
732 /* Remove any possible away message */
733 silc_client_set_away_message(silc_client, server->conn, NULL);
736 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
739 /* Set the away message */
740 silc_client_set_away_message(silc_client, server->conn, (char *)data);
743 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
744 SILCTXT_SET_AWAY, data);
747 signal_emit("away mode changed", 1, server);
749 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
753 int type; /* 1 = msg, 2 = channel */
755 SILC_SERVER_REC *server;
758 /* Key agreement callback that is called after the key agreement protocol
759 has been performed. This is called also if error occured during the
760 key agreement protocol. The `key' is the allocated key material and
761 the caller is responsible of freeing it. The `key' is NULL if error
762 has occured. The application can freely use the `key' to whatever
763 purpose it needs. See lib/silcske/silcske.h for the definition of
764 the SilcSKEKeyMaterial structure. */
766 static void keyagr_completion(SilcClient client,
767 SilcClientConnection conn,
768 SilcClientEntry client_entry,
769 SilcKeyAgreementStatus status,
770 SilcSKEKeyMaterial *key,
773 KeyInternal i = (KeyInternal)context;
776 case SILC_KEY_AGREEMENT_OK:
777 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
778 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
781 /* Set the private key for this client */
782 silc_client_del_private_message_key(client, conn, client_entry);
783 silc_client_add_private_message_key_ske(client, conn, client_entry,
784 NULL, key, i->responder);
785 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
786 SILCTXT_KEY_AGREEMENT_PRIVMSG,
787 client_entry->nickname);
788 silc_ske_free_key_material(key);
793 case SILC_KEY_AGREEMENT_ERROR:
794 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
795 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
798 case SILC_KEY_AGREEMENT_FAILURE:
799 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
800 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
803 case SILC_KEY_AGREEMENT_TIMEOUT:
804 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
805 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
816 /* Local command KEY. This command is used to set and unset private
817 keys for channels, set and unset private keys for private messages
818 with remote clients and to send key agreement requests and
819 negotiate the key agreement protocol with remote client. The
820 key agreement is supported only to negotiate private message keys,
821 it currently cannot be used to negotiate private keys for channels,
822 as it is not convenient for that purpose. */
825 SILC_SERVER_REC *server;
831 /* Callback to be called after client information is resolved from the
834 static void silc_client_command_key_get_clients(SilcClient client,
835 SilcClientConnection conn,
836 SilcClientEntry *clients,
837 uint32 clients_count,
840 KeyGetClients internal = (KeyGetClients)context;
843 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
845 silc_free(internal->data);
846 silc_free(internal->nick);
851 signal_emit("command key", 3, internal->data, internal->server,
854 silc_free(internal->data);
855 silc_free(internal->nick);
859 static void command_key(const char *data, SILC_SERVER_REC *server,
862 SilcClientConnection conn;
863 SilcClientEntry *entrys, client_entry = NULL;
865 SilcChannelEntry channel_entry = NULL;
866 char *nickname = NULL, *tmp;
867 int command = 0, port = 0, type = 0;
868 char *hostname = NULL;
869 KeyInternal internal = NULL;
871 unsigned char **argv;
872 uint32 *argv_lens, *argv_types;
873 char *bindhost = NULL;
875 if (!server || !IS_SILC_SERVER(server) || !server->connected)
876 cmd_return_error(CMDERR_NOT_CONNECTED);
880 /* Now parse all arguments */
881 tmp = g_strconcat("KEY", " ", data, NULL);
882 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
886 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
889 if (!strcasecmp(argv[1], "msg"))
891 if (!strcasecmp(argv[1], "channel"))
895 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
898 if (argv[2][0] == '*') {
899 nickname = strdup("*");
901 /* Parse the typed nickname. */
902 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
903 printformat_module("fe-common/silc", server, NULL,
904 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
908 /* Find client entry */
909 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
910 argv[2], &entry_count);
912 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
913 inter->server = server;
914 inter->data = strdup(data);
915 inter->nick = strdup(nickname);
917 silc_client_get_clients(silc_client, conn, nickname, argv[2],
918 silc_client_command_key_get_clients, inter);
921 client_entry = entrys[0];
927 /* Get channel entry */
930 if (argv[2][0] == '*') {
931 if (!conn->current_channel) {
933 cmd_return_error(CMDERR_NOT_JOINED);
935 name = conn->current_channel->channel_name;
940 channel_entry = silc_client_get_channel(silc_client, conn, name);
941 if (!channel_entry) {
943 cmd_return_error(CMDERR_NOT_JOINED);
948 if (!strcasecmp(argv[3], "set")) {
952 if (type == 1 && client_entry) {
953 /* Set private message key */
955 silc_client_del_private_message_key(silc_client, conn, client_entry);
958 silc_client_add_private_message_key(silc_client, conn, client_entry,
962 TRUE : FALSE), FALSE);
964 silc_client_add_private_message_key(silc_client, conn, client_entry,
968 TRUE : FALSE), FALSE);
970 /* Send the key to the remote client so that it starts using it
972 silc_client_send_private_message_key(silc_client, conn,
974 } else if (type == 2) {
975 /* Set private channel key */
976 char *cipher = NULL, *hmac = NULL;
978 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
979 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
980 SILCTXT_CH_PRIVATE_KEY_NOMODE,
981 channel_entry->channel_name);
990 if (!silc_client_add_channel_private_key(silc_client, conn,
995 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
996 SILCTXT_CH_PRIVATE_KEY_ERROR,
997 channel_entry->channel_name);
1001 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1002 SILCTXT_CH_PRIVATE_KEY_ADD,
1003 channel_entry->channel_name);
1011 if (!strcasecmp(argv[3], "unset")) {
1014 if (type == 1 && client_entry) {
1015 /* Unset private message key */
1016 silc_client_del_private_message_key(silc_client, conn, client_entry);
1017 } else if (type == 2) {
1018 /* Unset channel key(s) */
1019 SilcChannelPrivateKey *keys;
1024 silc_client_del_channel_private_keys(silc_client, conn,
1028 number = atoi(argv[4]);
1029 keys = silc_client_list_channel_private_keys(silc_client, conn,
1035 if (!number || number > keys_count) {
1036 silc_client_free_channel_private_keys(keys, keys_count);
1040 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1042 silc_client_free_channel_private_keys(keys, keys_count);
1050 if (!strcasecmp(argv[3], "list")) {
1054 SilcPrivateMessageKeys keys;
1059 keys = silc_client_list_private_message_keys(silc_client, conn,
1064 /* list the private message key(s) */
1065 if (nickname[0] == '*') {
1066 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1067 SILCTXT_PRIVATE_KEY_LIST);
1068 for (k = 0; k < keys_count; k++) {
1069 memset(buf, 0, sizeof(buf));
1070 strncat(buf, " ", 2);
1071 len = strlen(keys[k].client_entry->nickname);
1072 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1074 for (i = 0; i < 30 - len; i++)
1078 len = strlen(keys[k].cipher);
1079 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1081 for (i = 0; i < 14 - len; i++)
1086 strcat(buf, "<hidden>");
1088 strcat(buf, "*generated*");
1090 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1093 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1094 SILCTXT_PRIVATE_KEY_LIST_NICK,
1095 client_entry->nickname);
1096 for (k = 0; k < keys_count; k++) {
1097 if (keys[k].client_entry != client_entry)
1100 memset(buf, 0, sizeof(buf));
1101 strncat(buf, " ", 2);
1102 len = strlen(keys[k].client_entry->nickname);
1103 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1105 for (i = 0; i < 30 - len; i++)
1109 len = strlen(keys[k].cipher);
1110 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1112 for (i = 0; i < 14 - len; i++)
1117 strcat(buf, "<hidden>");
1119 strcat(buf, "*generated*");
1121 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1125 silc_client_free_private_message_keys(keys, keys_count);
1127 } else if (type == 2) {
1128 SilcChannelPrivateKey *keys;
1133 keys = silc_client_list_channel_private_keys(silc_client, conn,
1137 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1138 SILCTXT_CH_PRIVATE_KEY_LIST,
1139 channel_entry->channel_name);
1144 for (k = 0; k < keys_count; k++) {
1145 memset(buf, 0, sizeof(buf));
1146 strncat(buf, " ", 2);
1148 len = strlen(keys[k]->cipher->cipher->name);
1149 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1151 for (i = 0; i < 16 - len; i++)
1155 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1156 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1158 for (i = 0; i < 16 - len; i++)
1162 strcat(buf, "<hidden>");
1164 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1167 silc_client_free_channel_private_keys(keys, keys_count);
1173 /* Send command is used to send key agreement */
1174 if (!strcasecmp(argv[3], "agreement")) {
1180 port = atoi(argv[5]);
1182 internal = silc_calloc(1, sizeof(*internal));
1183 internal->type = type;
1184 internal->server = server;
1187 if (settings_get_bool("use_auto_addr")) {
1189 hostname = (char *)settings_get_str("auto_public_ip");
1191 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1194 if ((hostname) && (*hostname == '\0')) {
1198 bindhost = (char *)settings_get_str("auto_bind_ip");
1200 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1201 * public_ip is the same value as the bind_ip.
1203 if ((bindhost) && (*bindhost == '\0')) {
1204 bindhost = hostname;
1206 port = settings_get_int("auto_bind_port");
1208 } /* if use_auto_addr */
1212 /* Start command is used to start key agreement (after receiving the
1213 key_agreement client operation). */
1214 if (!strcasecmp(argv[3], "negotiate")) {
1220 port = atoi(argv[5]);
1222 internal = silc_calloc(1, sizeof(*internal));
1223 internal->type = type;
1224 internal->server = server;
1228 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1229 "Usage: /KEY msg|channel <nickname|channel> "
1230 "set|unset|agreement|negotiate [<arguments>]");
1234 if (command == 4 && client_entry) {
1235 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1236 SILCTXT_KEY_AGREEMENT, argv[2]);
1237 internal->responder = TRUE;
1238 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1239 bindhost, port, 120, keyagr_completion,
1242 silc_free(internal);
1246 if (command == 5 && client_entry && hostname) {
1247 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1248 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1249 internal->responder = FALSE;
1250 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1251 hostname, port, keyagr_completion,
1257 silc_free(nickname);
1260 /* Lists locally saved client and server public keys. */
1262 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1268 void silc_channels_init(void)
1270 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1271 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1272 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1274 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1275 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1276 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1277 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1278 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1279 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1280 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1281 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1282 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1283 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1284 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1285 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1286 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1288 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1289 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1290 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1291 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1292 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1293 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1294 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1296 silc_nicklist_init();
1299 void silc_channels_deinit(void)
1301 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1302 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1303 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1305 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1306 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1307 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1308 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1309 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1310 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1311 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1312 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1313 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1314 signal_remove("silc event channel_change",
1315 (SIGNAL_FUNC) event_channel_change);
1316 signal_remove("silc event server_signoff",
1317 (SIGNAL_FUNC) event_server_signoff);
1318 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1319 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1321 command_unbind("part", (SIGNAL_FUNC) command_part);
1322 command_unbind("me", (SIGNAL_FUNC) command_me);
1323 command_unbind("action", (SIGNAL_FUNC) command_action);
1324 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1325 command_unbind("away", (SIGNAL_FUNC) command_away);
1326 command_unbind("key", (SIGNAL_FUNC) command_key);
1327 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1329 silc_nicklist_deinit();