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;
821 /* Callback to be called after client information is resolved from the
824 SILC_CLIENT_CMD_FUNC(key_get_clients)
826 KeyGetClients internal = (KeyGetClients)context;
827 signal_emit("command key", 3, internal->data, internal->server,
829 silc_free(internal->data);
833 static void command_key(const char *data, SILC_SERVER_REC *server,
836 SilcClientConnection conn;
837 SilcClientEntry client_entry = NULL;
838 SilcChannelEntry channel_entry = NULL;
839 char *nickname = NULL, *tmp;
840 int command = 0, port = 0, type = 0;
841 char *hostname = NULL;
842 KeyInternal internal = NULL;
844 unsigned char **argv;
845 uint32 *argv_lens, *argv_types;
847 if (!server || !IS_SILC_SERVER(server) || !server->connected)
848 cmd_return_error(CMDERR_NOT_CONNECTED);
852 /* Now parse all arguments */
853 tmp = g_strconcat("KEY", " ", data, NULL);
854 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
858 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
861 if (!strcasecmp(argv[1], "msg"))
863 if (!strcasecmp(argv[1], "channel"))
867 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
870 if (argv[2][0] == '*') {
871 nickname = strdup("*");
873 /* Parse the typed nickname. */
874 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
875 printformat_module("fe-common/silc", server, NULL,
876 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
880 /* Find client entry */
881 client_entry = silc_idlist_get_client(silc_client, conn, nickname,
884 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
885 inter->server = server;
886 inter->data = strdup(data);
889 /* Client entry not found, it was requested thus mark this to be
891 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
893 NULL, silc_client_command_key_get_clients,
901 /* Get channel entry */
904 if (argv[2][0] == '*') {
905 if (!conn->current_channel) {
907 cmd_return_error(CMDERR_NOT_JOINED);
909 name = conn->current_channel->channel_name;
914 channel_entry = silc_client_get_channel(silc_client, conn, name);
915 if (!channel_entry) {
917 cmd_return_error(CMDERR_NOT_JOINED);
922 if (!strcasecmp(argv[3], "set")) {
926 if (type == 1 && client_entry) {
927 /* Set private message key */
929 silc_client_del_private_message_key(silc_client, conn, client_entry);
932 silc_client_add_private_message_key(silc_client, conn, client_entry,
936 TRUE : FALSE), FALSE);
938 silc_client_add_private_message_key(silc_client, conn, client_entry,
942 TRUE : FALSE), FALSE);
944 /* Send the key to the remote client so that it starts using it
946 silc_client_send_private_message_key(silc_client, conn,
948 } else if (type == 2) {
949 /* Set private channel key */
950 char *cipher = NULL, *hmac = NULL;
952 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
953 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
954 SILCTXT_CH_PRIVATE_KEY_NOMODE,
955 channel_entry->channel_name);
964 if (!silc_client_add_channel_private_key(silc_client, conn,
969 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
970 SILCTXT_CH_PRIVATE_KEY_ERROR,
971 channel_entry->channel_name);
975 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
976 SILCTXT_CH_PRIVATE_KEY_ADD,
977 channel_entry->channel_name);
985 if (!strcasecmp(argv[3], "unset")) {
988 if (type == 1 && client_entry) {
989 /* Unset private message key */
990 silc_client_del_private_message_key(silc_client, conn, client_entry);
991 } else if (type == 2) {
992 /* Unset channel key(s) */
993 SilcChannelPrivateKey *keys;
998 silc_client_del_channel_private_keys(silc_client, conn,
1002 number = atoi(argv[4]);
1003 keys = silc_client_list_channel_private_keys(silc_client, conn,
1009 if (!number || number > keys_count) {
1010 silc_client_free_channel_private_keys(keys, keys_count);
1014 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1016 silc_client_free_channel_private_keys(keys, keys_count);
1024 if (!strcasecmp(argv[3], "list")) {
1028 SilcPrivateMessageKeys keys;
1033 keys = silc_client_list_private_message_keys(silc_client, conn,
1038 /* list the private message key(s) */
1039 if (nickname[0] == '*') {
1040 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1041 SILCTXT_PRIVATE_KEY_LIST);
1042 for (k = 0; k < keys_count; k++) {
1043 memset(buf, 0, sizeof(buf));
1044 strncat(buf, " ", 2);
1045 len = strlen(keys[k].client_entry->nickname);
1046 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1048 for (i = 0; i < 30 - len; i++)
1052 len = strlen(keys[k].cipher);
1053 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1055 for (i = 0; i < 14 - len; i++)
1060 strcat(buf, "<hidden>");
1062 strcat(buf, "*generated*");
1064 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1067 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1068 SILCTXT_PRIVATE_KEY_LIST_NICK,
1069 client_entry->nickname);
1070 for (k = 0; k < keys_count; k++) {
1071 if (keys[k].client_entry != client_entry)
1074 memset(buf, 0, sizeof(buf));
1075 strncat(buf, " ", 2);
1076 len = strlen(keys[k].client_entry->nickname);
1077 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1079 for (i = 0; i < 30 - len; i++)
1083 len = strlen(keys[k].cipher);
1084 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1086 for (i = 0; i < 14 - len; i++)
1091 strcat(buf, "<hidden>");
1093 strcat(buf, "*generated*");
1095 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1099 silc_client_free_private_message_keys(keys, keys_count);
1101 } else if (type == 2) {
1102 SilcChannelPrivateKey *keys;
1107 keys = silc_client_list_channel_private_keys(silc_client, conn,
1111 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1112 SILCTXT_CH_PRIVATE_KEY_LIST,
1113 channel_entry->channel_name);
1118 for (k = 0; k < keys_count; k++) {
1119 memset(buf, 0, sizeof(buf));
1120 strncat(buf, " ", 2);
1122 len = strlen(keys[k]->cipher->cipher->name);
1123 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1125 for (i = 0; i < 16 - len; i++)
1129 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1130 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1132 for (i = 0; i < 16 - len; i++)
1136 strcat(buf, "<hidden>");
1138 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1141 silc_client_free_channel_private_keys(keys, keys_count);
1147 /* Send command is used to send key agreement */
1148 if (!strcasecmp(argv[3], "agreement")) {
1154 port = atoi(argv[5]);
1156 internal = silc_calloc(1, sizeof(*internal));
1157 internal->type = type;
1158 internal->server = server;
1161 /* Start command is used to start key agreement (after receiving the
1162 key_agreement client operation). */
1163 if (!strcasecmp(argv[3], "negotiate")) {
1169 port = atoi(argv[5]);
1171 internal = silc_calloc(1, sizeof(*internal));
1172 internal->type = type;
1173 internal->server = server;
1177 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1178 "Usage: /KEY msg|channel <nickname|channel> "
1179 "set|unset|agreement|negotiate [<arguments>]");
1183 if (command == 4 && client_entry) {
1184 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1185 SILCTXT_KEY_AGREEMENT, argv[2]);
1186 internal->responder = TRUE;
1187 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1188 port, 120, keyagr_completion, internal);
1190 silc_free(internal);
1194 if (command == 5 && client_entry && hostname) {
1195 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1196 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1197 internal->responder = FALSE;
1198 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1199 hostname, port, keyagr_completion,
1205 silc_free(nickname);
1208 /* Lists locally saved client and server public keys. */
1210 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1216 void silc_channels_init(void)
1218 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1219 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1220 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1222 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1223 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1224 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1225 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1226 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1227 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1228 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1229 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1230 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1231 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1232 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1233 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1234 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1236 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1237 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1238 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1239 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1240 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1241 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1242 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1244 silc_nicklist_init();
1247 void silc_channels_deinit(void)
1249 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1250 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1251 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1253 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1254 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1255 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1256 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1257 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1258 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1259 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1260 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1261 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1262 signal_remove("silc event channel_change",
1263 (SIGNAL_FUNC) event_channel_change);
1264 signal_remove("silc event server_signoff",
1265 (SIGNAL_FUNC) event_server_signoff);
1266 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1267 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1269 command_unbind("part", (SIGNAL_FUNC) command_part);
1270 command_unbind("me", (SIGNAL_FUNC) command_me);
1271 command_unbind("action", (SIGNAL_FUNC) command_action);
1272 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1273 command_unbind("away", (SIGNAL_FUNC) command_away);
1274 command_unbind("key", (SIGNAL_FUNC) command_key);
1275 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1277 silc_nicklist_deinit();