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;
865 if (!server || !IS_SILC_SERVER(server) || !server->connected)
866 cmd_return_error(CMDERR_NOT_CONNECTED);
870 /* Now parse all arguments */
871 tmp = g_strconcat("KEY", " ", data, NULL);
872 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
876 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
879 if (!strcasecmp(argv[1], "msg"))
881 if (!strcasecmp(argv[1], "channel"))
885 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
888 if (argv[2][0] == '*') {
889 nickname = strdup("*");
891 /* Parse the typed nickname. */
892 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
893 printformat_module("fe-common/silc", server, NULL,
894 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
898 /* Find client entry */
899 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
900 argv[2], &entry_count);
902 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
903 inter->server = server;
904 inter->data = strdup(data);
905 inter->nick = strdup(nickname);
907 silc_client_get_clients(silc_client, conn, nickname, argv[2],
908 silc_client_command_key_get_clients, inter);
911 client_entry = entrys[0];
917 /* Get channel entry */
920 if (argv[2][0] == '*') {
921 if (!conn->current_channel) {
923 cmd_return_error(CMDERR_NOT_JOINED);
925 name = conn->current_channel->channel_name;
930 channel_entry = silc_client_get_channel(silc_client, conn, name);
931 if (!channel_entry) {
933 cmd_return_error(CMDERR_NOT_JOINED);
938 if (!strcasecmp(argv[3], "set")) {
942 if (type == 1 && client_entry) {
943 /* Set private message key */
945 silc_client_del_private_message_key(silc_client, conn, client_entry);
948 silc_client_add_private_message_key(silc_client, conn, client_entry,
952 TRUE : FALSE), FALSE);
954 silc_client_add_private_message_key(silc_client, conn, client_entry,
958 TRUE : FALSE), FALSE);
960 /* Send the key to the remote client so that it starts using it
962 silc_client_send_private_message_key(silc_client, conn,
964 } else if (type == 2) {
965 /* Set private channel key */
966 char *cipher = NULL, *hmac = NULL;
968 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
969 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
970 SILCTXT_CH_PRIVATE_KEY_NOMODE,
971 channel_entry->channel_name);
980 if (!silc_client_add_channel_private_key(silc_client, conn,
985 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
986 SILCTXT_CH_PRIVATE_KEY_ERROR,
987 channel_entry->channel_name);
991 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
992 SILCTXT_CH_PRIVATE_KEY_ADD,
993 channel_entry->channel_name);
1001 if (!strcasecmp(argv[3], "unset")) {
1004 if (type == 1 && client_entry) {
1005 /* Unset private message key */
1006 silc_client_del_private_message_key(silc_client, conn, client_entry);
1007 } else if (type == 2) {
1008 /* Unset channel key(s) */
1009 SilcChannelPrivateKey *keys;
1014 silc_client_del_channel_private_keys(silc_client, conn,
1018 number = atoi(argv[4]);
1019 keys = silc_client_list_channel_private_keys(silc_client, conn,
1025 if (!number || number > keys_count) {
1026 silc_client_free_channel_private_keys(keys, keys_count);
1030 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1032 silc_client_free_channel_private_keys(keys, keys_count);
1040 if (!strcasecmp(argv[3], "list")) {
1044 SilcPrivateMessageKeys keys;
1049 keys = silc_client_list_private_message_keys(silc_client, conn,
1054 /* list the private message key(s) */
1055 if (nickname[0] == '*') {
1056 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1057 SILCTXT_PRIVATE_KEY_LIST);
1058 for (k = 0; k < keys_count; k++) {
1059 memset(buf, 0, sizeof(buf));
1060 strncat(buf, " ", 2);
1061 len = strlen(keys[k].client_entry->nickname);
1062 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1064 for (i = 0; i < 30 - len; i++)
1068 len = strlen(keys[k].cipher);
1069 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1071 for (i = 0; i < 14 - len; i++)
1076 strcat(buf, "<hidden>");
1078 strcat(buf, "*generated*");
1080 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1083 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1084 SILCTXT_PRIVATE_KEY_LIST_NICK,
1085 client_entry->nickname);
1086 for (k = 0; k < keys_count; k++) {
1087 if (keys[k].client_entry != client_entry)
1090 memset(buf, 0, sizeof(buf));
1091 strncat(buf, " ", 2);
1092 len = strlen(keys[k].client_entry->nickname);
1093 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1095 for (i = 0; i < 30 - len; i++)
1099 len = strlen(keys[k].cipher);
1100 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1102 for (i = 0; i < 14 - len; i++)
1107 strcat(buf, "<hidden>");
1109 strcat(buf, "*generated*");
1111 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1115 silc_client_free_private_message_keys(keys, keys_count);
1117 } else if (type == 2) {
1118 SilcChannelPrivateKey *keys;
1123 keys = silc_client_list_channel_private_keys(silc_client, conn,
1127 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1128 SILCTXT_CH_PRIVATE_KEY_LIST,
1129 channel_entry->channel_name);
1134 for (k = 0; k < keys_count; k++) {
1135 memset(buf, 0, sizeof(buf));
1136 strncat(buf, " ", 2);
1138 len = strlen(keys[k]->cipher->cipher->name);
1139 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1141 for (i = 0; i < 16 - len; i++)
1145 len = strlen(silc_hmac_get_name(keys[k]->hmac));
1146 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1148 for (i = 0; i < 16 - len; i++)
1152 strcat(buf, "<hidden>");
1154 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1157 silc_client_free_channel_private_keys(keys, keys_count);
1163 /* Send command is used to send key agreement */
1164 if (!strcasecmp(argv[3], "agreement")) {
1170 port = atoi(argv[5]);
1172 internal = silc_calloc(1, sizeof(*internal));
1173 internal->type = type;
1174 internal->server = server;
1177 /* Start command is used to start key agreement (after receiving the
1178 key_agreement client operation). */
1179 if (!strcasecmp(argv[3], "negotiate")) {
1185 port = atoi(argv[5]);
1187 internal = silc_calloc(1, sizeof(*internal));
1188 internal->type = type;
1189 internal->server = server;
1193 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1194 "Usage: /KEY msg|channel <nickname|channel> "
1195 "set|unset|agreement|negotiate [<arguments>]");
1199 if (command == 4 && client_entry) {
1200 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1201 SILCTXT_KEY_AGREEMENT, argv[2]);
1202 internal->responder = TRUE;
1203 silc_client_send_key_agreement(silc_client, conn, client_entry, hostname,
1204 port, 120, keyagr_completion, internal);
1206 silc_free(internal);
1210 if (command == 5 && client_entry && hostname) {
1211 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1212 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1213 internal->responder = FALSE;
1214 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1215 hostname, port, keyagr_completion,
1221 silc_free(nickname);
1224 /* Lists locally saved client and server public keys. */
1226 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1232 void silc_channels_init(void)
1234 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1235 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1236 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1238 signal_add("silc event join", (SIGNAL_FUNC) event_join);
1239 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1240 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1241 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1242 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1243 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1244 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1245 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1246 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1247 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1248 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1249 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1250 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1252 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1253 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1254 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1255 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1256 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1257 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1258 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1260 silc_nicklist_init();
1263 void silc_channels_deinit(void)
1265 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1266 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1267 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1269 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1270 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1271 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1272 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1273 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1274 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1275 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1276 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1277 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1278 signal_remove("silc event channel_change",
1279 (SIGNAL_FUNC) event_channel_change);
1280 signal_remove("silc event server_signoff",
1281 (SIGNAL_FUNC) event_server_signoff);
1282 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1283 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1285 command_unbind("part", (SIGNAL_FUNC) command_part);
1286 command_unbind("me", (SIGNAL_FUNC) command_me);
1287 command_unbind("action", (SIGNAL_FUNC) command_action);
1288 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1289 command_unbind("away", (SIGNAL_FUNC) command_away);
1290 command_unbind("key", (SIGNAL_FUNC) command_key);
1291 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1293 silc_nicklist_deinit();