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++) {
452 memset(userhost, 0, sizeof(userhost));
453 if (clients[i]->username)
454 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
455 clients[i]->username, clients[i]->hostname);
456 signal_emit("message quit", 4, server, clients[i]->nickname,
457 clients[i]->username ? userhost : "",
463 * "event kick". Someone was kicked from channel.
466 static void event_kick(SILC_SERVER_REC *server, va_list va)
468 SilcClientConnection conn = server->conn;
469 SilcClientEntry client_entry;
470 SilcChannelEntry channel_entry;
472 SILC_CHANNEL_REC *chanrec;
474 client_entry = va_arg(va, SilcClientEntry);
475 tmp = va_arg(va, char *);
476 channel_entry = va_arg(va, SilcChannelEntry);
478 chanrec = silc_channel_find_entry(server, channel_entry);
480 if (client_entry == conn->local_entry) {
481 printformat_module("fe-common/silc", server, channel_entry->channel_name,
482 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
483 channel_entry->channel_name, tmp ? tmp : "");
485 chanrec->kicked = TRUE;
486 channel_destroy((CHANNEL_REC *)chanrec);
489 printformat_module("fe-common/silc", server, channel_entry->channel_name,
490 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
491 client_entry->nickname,
492 channel_entry->channel_name, tmp ? tmp : "");
495 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
497 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
503 * "event kill". Someone was killed from the network.
506 static void event_kill(SILC_SERVER_REC *server, va_list va)
508 SilcClientConnection conn = server->conn;
509 SilcClientEntry client_entry;
512 client_entry = va_arg(va, SilcClientEntry);
513 tmp = va_arg(va, char *);
515 if (client_entry == conn->local_entry) {
516 printformat_module("fe-common/silc", server, NULL,
517 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
520 GSList *nicks, *tmpn;
521 nicks = nicklist_get_same_unique(SERVER(server), client_entry);
522 for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
523 CHANNEL_REC *channel = tmpn->data;
524 NICK_REC *nickrec = tmpn->next->data;
525 nicklist_remove(channel, nickrec);
528 printformat_module("fe-common/silc", server, NULL,
529 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
530 client_entry->nickname,
535 /* PART (LEAVE) command. */
537 static void command_part(const char *data, SILC_SERVER_REC *server,
540 SILC_CHANNEL_REC *chanrec;
543 if (!IS_SILC_SERVER(server) || !server->connected)
544 cmd_return_error(CMDERR_NOT_CONNECTED);
546 if (!strcmp(data, "*") || *data == '\0') {
547 if (!IS_SILC_CHANNEL(item))
548 cmd_return_error(CMDERR_NOT_JOINED);
552 chanrec = silc_channel_find(server, data);
554 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
556 memset(userhost, 0, sizeof(userhost));
557 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
558 server->conn->local_entry->username,
559 server->conn->local_entry->hostname);
560 signal_emit("message part", 5, server, chanrec->name,
561 server->nick, userhost, "");
563 silc_command_exec(server, "LEAVE", chanrec->name);
566 channel_destroy(CHANNEL(chanrec));
569 /* ME local command. */
571 static void command_me(const char *data, SILC_SERVER_REC *server,
574 SILC_CHANNEL_REC *chanrec;
575 char *tmpcmd = "ME", *tmp;
577 unsigned char **argv;
578 uint32 *argv_lens, *argv_types;
581 if (!IS_SILC_SERVER(server) || !server->connected)
582 cmd_return_error(CMDERR_NOT_CONNECTED);
584 if (!IS_SILC_CHANNEL(item))
585 cmd_return_error(CMDERR_NOT_JOINED);
587 /* Now parse all arguments */
588 tmp = g_strconcat(tmpcmd, " ", data, NULL);
589 silc_parse_command_line(tmp, &argv, &argv_lens,
590 &argv_types, &argc, 2);
594 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
596 chanrec = silc_channel_find(server, item->name);
598 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
600 /* Send the action message */
601 silc_client_send_channel_message(silc_client, server->conn,
602 chanrec->entry, NULL,
603 SILC_MESSAGE_FLAG_ACTION,
604 argv[1], argv_lens[1], TRUE);
606 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
607 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
608 server->conn->local_entry->nickname, argv[1]);
610 for (i = 0; i < argc; i++)
612 silc_free(argv_lens);
613 silc_free(argv_types);
616 /* ACTION local command. Same as ME but takes the channel as mandatory
619 static void command_action(const char *data, SILC_SERVER_REC *server,
622 SILC_CHANNEL_REC *chanrec;
623 char *tmpcmd = "ME", *tmp;
625 unsigned char **argv;
626 uint32 *argv_lens, *argv_types;
629 if (!IS_SILC_SERVER(server) || !server->connected)
630 cmd_return_error(CMDERR_NOT_CONNECTED);
632 if (!IS_SILC_CHANNEL(item))
633 cmd_return_error(CMDERR_NOT_JOINED);
635 /* Now parse all arguments */
636 tmp = g_strconcat(tmpcmd, " ", data, NULL);
637 silc_parse_command_line(tmp, &argv, &argv_lens,
638 &argv_types, &argc, 3);
642 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
644 chanrec = silc_channel_find(server, argv[1]);
646 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
648 /* Send the action message */
649 silc_client_send_channel_message(silc_client, server->conn,
650 chanrec->entry, NULL,
651 SILC_MESSAGE_FLAG_ACTION,
652 argv[2], argv_lens[2], TRUE);
654 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
655 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
656 server->conn->local_entry->nickname, argv[2]);
658 for (i = 0; i < argc; i++)
660 silc_free(argv_lens);
661 silc_free(argv_types);
664 /* NOTICE local command. */
666 static void command_notice(const char *data, SILC_SERVER_REC *server,
669 SILC_CHANNEL_REC *chanrec;
670 char *tmpcmd = "ME", *tmp;
672 unsigned char **argv;
673 uint32 *argv_lens, *argv_types;
676 if (!IS_SILC_SERVER(server) || !server->connected)
677 cmd_return_error(CMDERR_NOT_CONNECTED);
679 if (!IS_SILC_CHANNEL(item))
680 cmd_return_error(CMDERR_NOT_JOINED);
682 /* Now parse all arguments */
683 tmp = g_strconcat(tmpcmd, " ", data, NULL);
684 silc_parse_command_line(tmp, &argv, &argv_lens,
685 &argv_types, &argc, 2);
689 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
691 chanrec = silc_channel_find(server, item->name);
693 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
695 /* Send the action message */
696 silc_client_send_channel_message(silc_client, server->conn,
697 chanrec->entry, NULL,
698 SILC_MESSAGE_FLAG_NOTICE,
699 argv[1], argv_lens[1], TRUE);
701 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
702 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
703 server->conn->local_entry->nickname, argv[1]);
705 for (i = 0; i < argc; i++)
707 silc_free(argv_lens);
708 silc_free(argv_types);
711 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
714 static void command_away(const char *data, SILC_SERVER_REC *server,
719 if (!IS_SILC_SERVER(server) || !server->connected)
720 cmd_return_error(CMDERR_NOT_CONNECTED);
723 /* Remove any possible away message */
724 silc_client_set_away_message(silc_client, server->conn, NULL);
727 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
730 /* Set the away message */
731 silc_client_set_away_message(silc_client, server->conn, (char *)data);
734 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
735 SILCTXT_SET_AWAY, data);
738 signal_emit("away mode changed", 1, server);
740 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
744 int type; /* 1 = msg, 2 = channel */
746 SILC_SERVER_REC *server;
749 /* Key agreement callback that is called after the key agreement protocol
750 has been performed. This is called also if error occured during the
751 key agreement protocol. The `key' is the allocated key material and
752 the caller is responsible of freeing it. The `key' is NULL if error
753 has occured. The application can freely use the `key' to whatever
754 purpose it needs. See lib/silcske/silcske.h for the definition of
755 the SilcSKEKeyMaterial structure. */
757 static void keyagr_completion(SilcClient client,
758 SilcClientConnection conn,
759 SilcClientEntry client_entry,
760 SilcKeyAgreementStatus status,
761 SilcSKEKeyMaterial *key,
764 KeyInternal i = (KeyInternal)context;
767 case SILC_KEY_AGREEMENT_OK:
768 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
769 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
772 /* Set the private key for this client */
773 silc_client_del_private_message_key(client, conn, client_entry);
774 silc_client_add_private_message_key_ske(client, conn, client_entry,
775 NULL, key, i->responder);
776 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
777 SILCTXT_KEY_AGREEMENT_PRIVMSG,
778 client_entry->nickname);
779 silc_ske_free_key_material(key);
784 case SILC_KEY_AGREEMENT_ERROR:
785 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
786 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
789 case SILC_KEY_AGREEMENT_FAILURE:
790 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
791 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
794 case SILC_KEY_AGREEMENT_TIMEOUT:
795 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
796 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
807 /* Local command KEY. This command is used to set and unset private
808 keys for channels, set and unset private keys for private messages
809 with remote clients and to send key agreement requests and
810 negotiate the key agreement protocol with remote client. The
811 key agreement is supported only to negotiate private message keys,
812 it currently cannot be used to negotiate private keys for channels,
813 as it is not convenient for that purpose. */
816 SILC_SERVER_REC *server;
822 /* Callback to be called after client information is resolved from the
825 static void silc_client_command_key_get_clients(SilcClient client,
826 SilcClientConnection conn,
827 SilcClientEntry *clients,
828 uint32 clients_count,
831 KeyGetClients internal = (KeyGetClients)context;
834 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
836 silc_free(internal->data);
837 silc_free(internal->nick);
842 signal_emit("command key", 3, internal->data, internal->server,
845 silc_free(internal->data);
846 silc_free(internal->nick);
850 static void command_key(const char *data, SILC_SERVER_REC *server,
853 SilcClientConnection conn;
854 SilcClientEntry *entrys, client_entry = NULL;
856 SilcChannelEntry channel_entry = NULL;
857 char *nickname = NULL, *tmp;
858 int command = 0, port = 0, type = 0;
859 char *hostname = NULL;
860 KeyInternal internal = NULL;
862 unsigned char **argv;
863 uint32 *argv_lens, *argv_types;
864 char *bindhost = NULL;
866 if (!server || !IS_SILC_SERVER(server) || !server->connected)
867 cmd_return_error(CMDERR_NOT_CONNECTED);
871 /* Now parse all arguments */
872 tmp = g_strconcat("KEY", " ", data, NULL);
873 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
877 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
880 if (!strcasecmp(argv[1], "msg"))
882 if (!strcasecmp(argv[1], "channel"))
886 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
889 if (argv[2][0] == '*') {
890 nickname = strdup("*");
892 /* Parse the typed nickname. */
893 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
894 printformat_module("fe-common/silc", server, NULL,
895 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
899 /* Find client entry */
900 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
901 argv[2], &entry_count);
903 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
904 inter->server = server;
905 inter->data = strdup(data);
906 inter->nick = strdup(nickname);
908 silc_client_get_clients(silc_client, conn, nickname, argv[2],
909 silc_client_command_key_get_clients, inter);
912 client_entry = entrys[0];
918 /* Get channel entry */
921 if (argv[2][0] == '*') {
922 if (!conn->current_channel) {
924 cmd_return_error(CMDERR_NOT_JOINED);
926 name = conn->current_channel->channel_name;
931 channel_entry = silc_client_get_channel(silc_client, conn, name);
932 if (!channel_entry) {
934 cmd_return_error(CMDERR_NOT_JOINED);
939 if (!strcasecmp(argv[3], "set")) {
943 if (type == 1 && client_entry) {
944 /* Set private message key */
946 silc_client_del_private_message_key(silc_client, conn, client_entry);
949 silc_client_add_private_message_key(silc_client, conn, client_entry,
953 TRUE : FALSE), FALSE);
955 silc_client_add_private_message_key(silc_client, conn, client_entry,
959 TRUE : FALSE), FALSE);
961 /* Send the key to the remote client so that it starts using it
963 silc_client_send_private_message_key(silc_client, conn,
965 } else if (type == 2) {
966 /* Set private channel key */
967 char *cipher = NULL, *hmac = NULL;
969 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
970 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
971 SILCTXT_CH_PRIVATE_KEY_NOMODE,
972 channel_entry->channel_name);
981 if (!silc_client_add_channel_private_key(silc_client, conn,
986 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
987 SILCTXT_CH_PRIVATE_KEY_ERROR,
988 channel_entry->channel_name);
992 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
993 SILCTXT_CH_PRIVATE_KEY_ADD,
994 channel_entry->channel_name);
1002 if (!strcasecmp(argv[3], "unset")) {
1005 if (type == 1 && client_entry) {
1006 /* Unset private message key */
1007 silc_client_del_private_message_key(silc_client, conn, client_entry);
1008 } else if (type == 2) {
1009 /* Unset channel key(s) */
1010 SilcChannelPrivateKey *keys;
1015 silc_client_del_channel_private_keys(silc_client, conn,
1019 number = atoi(argv[4]);
1020 keys = silc_client_list_channel_private_keys(silc_client, conn,
1026 if (!number || number > keys_count) {
1027 silc_client_free_channel_private_keys(keys, keys_count);
1031 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1033 silc_client_free_channel_private_keys(keys, keys_count);
1041 if (!strcasecmp(argv[3], "list")) {
1045 SilcPrivateMessageKeys keys;
1050 keys = silc_client_list_private_message_keys(silc_client, conn,
1055 /* list the private message key(s) */
1056 if (nickname[0] == '*') {
1057 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1058 SILCTXT_PRIVATE_KEY_LIST);
1059 for (k = 0; k < keys_count; k++) {
1060 memset(buf, 0, sizeof(buf));
1061 strncat(buf, " ", 2);
1062 len = strlen(keys[k].client_entry->nickname);
1063 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1065 for (i = 0; i < 30 - len; i++)
1069 len = strlen(keys[k].cipher);
1070 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1072 for (i = 0; i < 14 - len; i++)
1077 strcat(buf, "<hidden>");
1079 strcat(buf, "*generated*");
1081 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1084 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1085 SILCTXT_PRIVATE_KEY_LIST_NICK,
1086 client_entry->nickname);
1087 for (k = 0; k < keys_count; k++) {
1088 if (keys[k].client_entry != client_entry)
1091 memset(buf, 0, sizeof(buf));
1092 strncat(buf, " ", 2);
1093 len = strlen(keys[k].client_entry->nickname);
1094 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1096 for (i = 0; i < 30 - len; i++)
1100 len = strlen(keys[k].cipher);
1101 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1103 for (i = 0; i < 14 - len; i++)
1108 strcat(buf, "<hidden>");
1110 strcat(buf, "*generated*");
1112 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1116 silc_client_free_private_message_keys(keys, keys_count);
1118 } else if (type == 2) {
1119 SilcChannelPrivateKey *keys;
1124 keys = silc_client_list_channel_private_keys(silc_client, conn,
1128 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1129 SILCTXT_CH_PRIVATE_KEY_LIST,
1130 channel_entry->channel_name);
1135 for (k = 0; k < keys_count; k++) {
1136 memset(buf, 0, sizeof(buf));
1137 strncat(buf, " ", 2);
1139 len = strlen(keys[k]->cipher->cipher->name);
1140 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1142 for (i = 0; i < 16 - len; i++)
1146 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1147 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1149 for (i = 0; i < 16 - len; i++)
1153 strcat(buf, "<hidden>");
1155 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1158 silc_client_free_channel_private_keys(keys, keys_count);
1164 /* Send command is used to send key agreement */
1165 if (!strcasecmp(argv[3], "agreement")) {
1171 port = atoi(argv[5]);
1173 internal = silc_calloc(1, sizeof(*internal));
1174 internal->type = type;
1175 internal->server = server;
1178 if (settings_get_bool("use_auto_addr")) {
1180 hostname = (char *)settings_get_str("auto_public_ip");
1182 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1185 if ((hostname) && (*hostname == '\0')) {
1189 bindhost = (char *)settings_get_str("auto_bind_ip");
1191 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1192 * public_ip is the same value as the bind_ip.
1194 if ((bindhost) && (*bindhost == '\0')) {
1195 bindhost = hostname;
1197 port = settings_get_int("auto_bind_port");
1199 } /* if use_auto_addr */
1203 /* Start command is used to start key agreement (after receiving the
1204 key_agreement client operation). */
1205 if (!strcasecmp(argv[3], "negotiate")) {
1211 port = atoi(argv[5]);
1213 internal = silc_calloc(1, sizeof(*internal));
1214 internal->type = type;
1215 internal->server = server;
1219 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1220 "Usage: /KEY msg|channel <nickname|channel> "
1221 "set|unset|agreement|negotiate [<arguments>]");
1225 if (command == 4 && client_entry) {
1226 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1227 SILCTXT_KEY_AGREEMENT, argv[2]);
1228 internal->responder = TRUE;
1229 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1230 bindhost, port, 120, keyagr_completion,
1233 silc_free(internal);
1237 if (command == 5 && client_entry && hostname) {
1238 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1239 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1240 internal->responder = FALSE;
1241 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1242 hostname, port, keyagr_completion,
1248 silc_free(nickname);
1251 /* Lists locally saved client and server public keys. */
1253 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1259 void silc_channels_init(void)
1261 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1262 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1263 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1265 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1266 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1267 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1268 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1269 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1270 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1271 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1272 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1273 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1274 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1275 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1276 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1277 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1279 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1280 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1281 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1282 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1283 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1284 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1285 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1287 silc_nicklist_init();
1290 void silc_channels_deinit(void)
1292 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1293 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1294 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1296 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1297 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1298 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1299 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1300 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1301 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1302 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1303 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1304 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1305 signal_remove("silc event channel_change",
1306 (SIGNAL_FUNC) event_channel_change);
1307 signal_remove("silc event server_signoff",
1308 (SIGNAL_FUNC) event_server_signoff);
1309 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1310 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1312 command_unbind("part", (SIGNAL_FUNC) command_part);
1313 command_unbind("me", (SIGNAL_FUNC) command_me);
1314 command_unbind("action", (SIGNAL_FUNC) command_action);
1315 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1316 command_unbind("away", (SIGNAL_FUNC) command_away);
1317 command_unbind("key", (SIGNAL_FUNC) command_key);
1318 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1320 silc_nicklist_deinit();