5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
42 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
43 const char *name, SilcSocketType conn_type,
44 unsigned char *pk, uint32 pk_len,
45 SilcSKEPKType pk_type,
46 SilcVerifyPublicKey completion, void *context);
48 void silc_say(SilcClient client, SilcClientConnection conn,
49 SilcClientMessageType type, char *msg, ...)
51 SILC_SERVER_REC *server;
55 server = conn == NULL ? NULL : conn->context;
58 str = g_strdup_vprintf(msg, va);
59 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
64 void silc_say_error(char *msg, ...)
70 str = g_strdup_vprintf(msg, va);
71 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
77 /* Message for a channel. The `sender' is the nickname of the sender
78 received in the packet. The `channel_name' is the name of the channel. */
80 void silc_channel_message(SilcClient client, SilcClientConnection conn,
81 SilcClientEntry sender, SilcChannelEntry channel,
82 SilcMessageFlags flags, char *msg)
84 SILC_SERVER_REC *server;
86 SILC_CHANNEL_REC *chanrec;
88 SILC_LOG_DEBUG(("Start"));
90 server = conn == NULL ? NULL : conn->context;
91 chanrec = silc_channel_find_entry(server, channel);
95 nick = silc_nicklist_find(chanrec, sender);
97 /* We didn't find client but it clearly exists, add it. It must be
98 found on the channel->clients list. */
101 silc_list_start(channel->clients);
102 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
103 if (chu->client == sender) {
104 nick = silc_nicklist_insert(chanrec, chu, FALSE);
110 if (flags & SILC_MESSAGE_FLAG_ACTION)
111 printformat_module("fe-common/silc", server, channel->channel_name,
112 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
113 nick == NULL ? "[<unknown>]" : nick->nick, msg);
114 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
115 printformat_module("fe-common/silc", server, channel->channel_name,
116 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
117 nick == NULL ? "[<unknown>]" : nick->nick, msg);
119 signal_emit("message public", 6, server, msg,
120 nick == NULL ? "[<unknown>]" : nick->nick,
121 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
122 chanrec->name, nick);
125 /* Private message to the client. The `sender' is the nickname of the
126 sender received in the packet. */
128 void silc_private_message(SilcClient client, SilcClientConnection conn,
129 SilcClientEntry sender, SilcMessageFlags flags,
132 SILC_SERVER_REC *server;
135 SILC_LOG_DEBUG(("Start"));
137 server = conn == NULL ? NULL : conn->context;
138 memset(userhost, 0, sizeof(userhost));
139 if (sender->username)
140 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
141 sender->username, sender->hostname);
142 signal_emit("message private", 4, server, msg,
143 sender->nickname ? sender->nickname : "[<unknown>]",
144 sender->username ? userhost : NULL);
147 /* Notify message to the client. The notify arguments are sent in the
148 same order as servers sends them. The arguments are same as received
149 from the server except for ID's. If ID is received application receives
150 the corresponding entry to the ID. For example, if Client ID is received
151 application receives SilcClientEntry. Also, if the notify type is
152 for channel the channel entry is sent to application (even if server
153 does not send it). */
160 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
161 static NOTIFY_REC notifies[] = {
162 { SILC_NOTIFY_TYPE_NONE, NULL },
163 { SILC_NOTIFY_TYPE_INVITE, "invite" },
164 { SILC_NOTIFY_TYPE_JOIN, "join" },
165 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
166 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
167 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
168 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
169 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
170 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
171 { SILC_NOTIFY_TYPE_MOTD, "motd" },
172 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
173 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
174 { SILC_NOTIFY_TYPE_KICKED, "kick" },
175 { SILC_NOTIFY_TYPE_KILLED, "kill" },
176 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
177 { SILC_NOTIFY_TYPE_BAN, "ban" },
180 void silc_notify(SilcClient client, SilcClientConnection conn,
181 SilcNotifyType type, ...)
183 SILC_SERVER_REC *server;
186 SILC_LOG_DEBUG(("Start"));
188 server = conn == NULL ? NULL : conn->context;
191 if (type == SILC_NOTIFY_TYPE_NONE) {
192 /* Some generic notice from server */
193 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
194 } else if (type < MAX_NOTIFY) {
195 /* Send signal about the notify event */
197 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
198 signal_emit(signal, 2, server, va);
201 printformat_module("fe-common/silc", server, NULL,
202 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
208 /* Called to indicate that connection was either successfully established
209 or connecting failed. This is also the first time application receives
210 the SilcClientConnection object which it should save somewhere. */
212 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
214 SILC_SERVER_REC *server = conn->context;
216 if (!server && !success) {
217 silc_client_close_connection(client, NULL, conn);
222 server->connected = TRUE;
223 signal_emit("event connected", 1, server);
225 server->connection_lost = TRUE;
226 server->conn->context = NULL;
227 server_disconnect(SERVER(server));
231 /* Called to indicate that connection was disconnected to the server. */
233 void silc_disconnect(SilcClient client, SilcClientConnection conn)
235 SILC_SERVER_REC *server = conn->context;
237 SILC_LOG_DEBUG(("Start"));
240 nicklist_rename_unique(SERVER(server),
241 server->conn->local_entry, server->nick,
242 server->conn->local_entry,
243 silc_client->username);
244 silc_change_nick(server, silc_client->username);
247 server->conn->context = NULL;
249 server->connection_lost = TRUE;
250 server_disconnect(SERVER(server));
253 /* Command handler. This function is called always in the command function.
254 If error occurs it will be called as well. `conn' is the associated
255 client connection. `cmd_context' is the command context that was
256 originally sent to the command. `success' is FALSE if error occured
257 during command. `command' is the command being processed. It must be
258 noted that this is not reply from server. This is merely called just
259 after application has called the command. Just to tell application
260 that the command really was processed. */
262 void silc_command(SilcClient client, SilcClientConnection conn,
263 SilcClientCommandContext cmd_context, int success,
266 SILC_SERVER_REC *server = conn->context;
268 SILC_LOG_DEBUG(("Start"));
274 case SILC_COMMAND_INVITE:
275 printformat_module("fe-common/silc", server, NULL,
276 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
277 cmd_context->argv[2],
278 (cmd_context->argv[1][0] == '*' ?
279 (char *)conn->current_channel->channel_name :
280 (char *)cmd_context->argv[1]));
287 /* Client info resolving callback when JOIN command reply is received.
288 This will cache all users on the channel. */
290 static void silc_client_join_get_users(SilcClient client,
291 SilcClientConnection conn,
292 SilcClientEntry *clients,
293 uint32 clients_count,
296 SilcChannelEntry channel = (SilcChannelEntry)context;
298 SILC_SERVER_REC *server = conn->context;
299 SILC_CHANNEL_REC *chanrec;
300 SilcClientEntry founder = NULL;
306 chanrec = silc_channel_find(server, channel->channel_name);
310 silc_list_start(channel->clients);
311 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
312 if (!chu->client->nickname)
314 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
315 founder = chu->client;
316 silc_nicklist_insert(chanrec, chu, FALSE);
319 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
320 nicklist_set_own(CHANNEL(chanrec), ownnick);
321 signal_emit("channel joined", 1, chanrec);
324 printformat_module("fe-common/silc", server, channel->channel_name,
325 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
326 channel->channel_name, chanrec->topic);
328 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
331 if (founder == conn->local_entry)
332 printformat_module("fe-common/silc",
333 server, channel->channel_name, MSGLEVEL_CRAP,
334 SILCTXT_CHANNEL_FOUNDER_YOU,
335 channel->channel_name);
337 printformat_module("fe-common/silc",
338 server, channel->channel_name, MSGLEVEL_CRAP,
339 SILCTXT_CHANNEL_FOUNDER,
340 channel->channel_name, founder->nickname);
346 SilcClientConnection conn;
352 void silc_getkey_cb(bool success, void *context)
354 GetkeyContext getkey = (GetkeyContext)context;
355 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
356 char *name = (getkey->id_type == SILC_ID_CLIENT ?
357 ((SilcClientEntry)getkey->entry)->nickname :
358 ((SilcServerEntry)getkey->entry)->server_name);
361 printformat_module("fe-common/silc", NULL, NULL,
362 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
364 printformat_module("fe-common/silc", NULL, NULL,
365 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
368 silc_free(getkey->fingerprint);
372 /* Command reply handler. This function is called always in the command reply
373 function. If error occurs it will be called as well. Normal scenario
374 is that it will be called after the received command data has been parsed
375 and processed. The function is used to pass the received command data to
378 `conn' is the associated client connection. `cmd_payload' is the command
379 payload data received from server and it can be ignored. It is provided
380 if the application would like to re-parse the received command data,
381 however, it must be noted that the data is parsed already by the library
382 thus the payload can be ignored. `success' is FALSE if error occured.
383 In this case arguments are not sent to the application. `command' is the
384 command reply being processed. The function has variable argument list
385 and each command defines the number and type of arguments it passes to the
386 application (on error they are not sent). */
389 silc_command_reply(SilcClient client, SilcClientConnection conn,
390 SilcCommandPayload cmd_payload, int success,
391 SilcCommand command, SilcCommandStatus status, ...)
394 SILC_SERVER_REC *server = conn->context;
395 SILC_CHANNEL_REC *chanrec;
398 va_start(vp, status);
400 SILC_LOG_DEBUG(("Start"));
403 case SILC_COMMAND_WHOIS:
405 char buf[1024], *nickname, *username, *realname, *nick;
406 unsigned char *fingerprint;
409 SilcClientEntry client_entry;
411 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
412 /* Print the unknown nick for user */
414 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
417 silc_say_error("%s: %s", tmp,
418 silc_client_command_status_message(status));
420 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
421 /* Try to find the entry for the unknown client ID, since we
422 might have, and print the nickname of it for user. */
425 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
428 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
430 client_entry = silc_client_get_client_by_id(client, conn,
432 if (client_entry && client_entry->nickname)
433 silc_say_error("%s: %s", client_entry->nickname,
434 silc_client_command_status_message(status));
435 silc_free(client_id);
444 client_entry = va_arg(vp, SilcClientEntry);
445 nickname = va_arg(vp, char *);
446 username = va_arg(vp, char *);
447 realname = va_arg(vp, char *);
448 channels = va_arg(vp, SilcBuffer);
449 mode = va_arg(vp, uint32);
450 idle = va_arg(vp, uint32);
451 fingerprint = va_arg(vp, unsigned char *);
453 silc_parse_userfqdn(nickname, &nick, NULL);
454 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
455 SILCTXT_WHOIS_USERINFO, nickname,
456 client_entry->username, client_entry->hostname,
457 nick, client_entry->nickname);
458 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
459 SILCTXT_WHOIS_REALNAME, realname);
463 SilcDList list = silc_channel_payload_parse_list(channels->data,
466 SilcChannelPayload entry;
467 memset(buf, 0, sizeof(buf));
468 silc_dlist_start(list);
469 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
470 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
472 char *name = silc_channel_get_name(entry, &name_len);
475 strncat(buf, m, strlen(m));
476 strncat(buf, name, name_len);
477 strncat(buf, " ", 1);
481 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
482 SILCTXT_WHOIS_CHANNELS, buf);
483 silc_channel_payload_list_free(list);
488 memset(buf, 0, sizeof(buf));
490 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
491 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
492 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
494 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
495 "SILC Operator " : "[Unknown mode] ");
497 if (mode & SILC_UMODE_GONE)
500 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
501 SILCTXT_WHOIS_MODES, buf);
504 if (idle && nickname) {
505 memset(buf, 0, sizeof(buf));
506 snprintf(buf, sizeof(buf) - 1, "%lu %s",
507 idle > 60 ? (idle / 60) : idle,
508 idle > 60 ? "minutes" : "seconds");
510 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
511 SILCTXT_WHOIS_IDLE, buf);
515 fingerprint = silc_fingerprint(fingerprint, 20);
516 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
517 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
518 silc_free(fingerprint);
523 case SILC_COMMAND_IDENTIFY:
525 SilcClientEntry client_entry;
527 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
528 /* Print the unknown nick for user */
530 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
533 silc_say_error("%s: %s", tmp,
534 silc_client_command_status_message(status));
536 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
537 /* Try to find the entry for the unknown client ID, since we
538 might have, and print the nickname of it for user. */
541 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
544 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
546 client_entry = silc_client_get_client_by_id(client, conn,
548 if (client_entry && client_entry->nickname)
549 silc_say_error("%s: %s", client_entry->nickname,
550 silc_client_command_status_message(status));
551 silc_free(client_id);
560 case SILC_COMMAND_WHOWAS:
562 char *nickname, *username, *realname;
564 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
565 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
567 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
570 silc_say_error("%s: %s", tmp,
571 silc_client_command_status_message(status));
578 (void)va_arg(vp, SilcClientEntry);
579 nickname = va_arg(vp, char *);
580 username = va_arg(vp, char *);
581 realname = va_arg(vp, char *);
583 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
584 SILCTXT_WHOWAS_USERINFO, nickname, username,
585 realname ? realname : "");
589 case SILC_COMMAND_INVITE:
591 SilcChannelEntry channel;
593 SilcArgumentPayload args;
599 channel = va_arg(vp, SilcChannelEntry);
600 invite_list = va_arg(vp, char *);
602 args = silc_command_get_args(cmd_payload);
604 argc = silc_argument_get_arg_num(args);
607 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
608 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
611 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
612 SILCTXT_CHANNEL_NO_INVITE_LIST,
613 channel->channel_name);
617 case SILC_COMMAND_JOIN:
619 char *channel, *mode, *topic;
621 SilcChannelEntry channel_entry;
622 SilcBuffer client_id_list;
628 channel = va_arg(vp, char *);
629 channel_entry = va_arg(vp, SilcChannelEntry);
630 modei = va_arg(vp, uint32);
631 (void)va_arg(vp, uint32);
632 (void)va_arg(vp, unsigned char *);
633 (void)va_arg(vp, unsigned char *);
634 (void)va_arg(vp, unsigned char *);
635 topic = va_arg(vp, char *);
636 (void)va_arg(vp, unsigned char *);
637 list_count = va_arg(vp, uint32);
638 client_id_list = va_arg(vp, SilcBuffer);
640 chanrec = silc_channel_find(server, channel);
642 chanrec = silc_channel_create(server, channel, TRUE);
645 g_free_not_null(chanrec->topic);
646 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
647 signal_emit("channel topic changed", 1, chanrec);
650 mode = silc_client_chmode(modei,
651 channel_entry->channel_key ?
652 channel_entry->channel_key->cipher->name : "",
653 channel_entry->hmac ?
654 silc_hmac_get_name(channel_entry->hmac) : "");
655 g_free_not_null(chanrec->mode);
656 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
657 signal_emit("channel mode changed", 1, chanrec);
659 /* Resolve the client information */
660 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
661 silc_client_join_get_users,
666 case SILC_COMMAND_NICK:
668 SilcClientEntry client = va_arg(vp, SilcClientEntry);
674 old = g_strdup(server->nick);
675 server_change_nick(SERVER(server), client->nickname);
676 nicklist_rename_unique(SERVER(server),
677 server->conn->local_entry, server->nick,
678 client, client->nickname);
680 signal_emit("message own_nick", 4, server, server->nick, old, "");
685 case SILC_COMMAND_LIST:
694 (void)va_arg(vp, SilcChannelEntry);
695 name = va_arg(vp, char *);
696 topic = va_arg(vp, char *);
697 usercount = va_arg(vp, int);
699 if (status == SILC_STATUS_LIST_START ||
700 status == SILC_STATUS_OK)
701 printformat_module("fe-common/silc", server, NULL,
702 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
705 snprintf(users, sizeof(users) - 1, "N/A");
707 snprintf(users, sizeof(users) - 1, "%d", usercount);
708 printformat_module("fe-common/silc", server, NULL,
709 MSGLEVEL_CRAP, SILCTXT_LIST,
710 name, users, topic ? topic : "");
714 case SILC_COMMAND_UMODE:
721 mode = va_arg(vp, uint32);
723 if (mode & SILC_UMODE_SERVER_OPERATOR &&
724 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
725 printformat_module("fe-common/silc", server, NULL,
726 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
728 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
729 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
730 printformat_module("fe-common/silc", server, NULL,
731 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
733 server->umode = mode;
737 case SILC_COMMAND_OPER:
741 printformat_module("fe-common/silc", server, NULL,
742 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
745 case SILC_COMMAND_SILCOPER:
749 printformat_module("fe-common/silc", server, NULL,
750 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
753 case SILC_COMMAND_USERS:
755 SilcChannelEntry channel;
761 channel = va_arg(vp, SilcChannelEntry);
763 printformat_module("fe-common/silc", server, channel->channel_name,
764 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
765 channel->channel_name);
767 silc_list_start(channel->clients);
768 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
769 SilcClientEntry e = chu->client;
775 memset(stat, 0, sizeof(stat));
776 mode = silc_client_chumode_char(chu->mode);
777 if (e->mode & SILC_UMODE_GONE)
784 printformat_module("fe-common/silc", server, channel->channel_name,
785 MSGLEVEL_CRAP, SILCTXT_USERS,
787 e->username ? e->username : "",
788 e->hostname ? e->hostname : "",
789 e->realname ? e->realname : "");
796 case SILC_COMMAND_BAN:
798 SilcChannelEntry channel;
804 channel = va_arg(vp, SilcChannelEntry);
805 ban_list = va_arg(vp, char *);
808 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
809 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
812 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
813 SILCTXT_CHANNEL_NO_BAN_LIST,
814 channel->channel_name);
818 case SILC_COMMAND_GETKEY:
822 SilcPublicKey public_key;
825 GetkeyContext getkey;
831 id_type = va_arg(vp, uint32);
832 entry = va_arg(vp, void *);
833 public_key = va_arg(vp, SilcPublicKey);
836 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
838 getkey = silc_calloc(1, sizeof(*getkey));
839 getkey->entry = entry;
840 getkey->id_type = id_type;
841 getkey->client = client;
843 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
845 name = (id_type == SILC_ID_CLIENT ?
846 ((SilcClientEntry)entry)->nickname :
847 ((SilcServerEntry)entry)->server_name);
849 silc_verify_public_key_internal(client, conn, name,
850 (id_type == SILC_ID_CLIENT ?
851 SILC_SOCKET_TYPE_CLIENT :
852 SILC_SOCKET_TYPE_SERVER),
853 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
854 silc_getkey_cb, getkey);
857 printformat_module("fe-common/silc", server, NULL,
858 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
863 case SILC_COMMAND_INFO:
865 SilcServerEntry server_entry;
872 server_entry = va_arg(vp, SilcServerEntry);
873 server_name = va_arg(vp, char *);
874 server_info = va_arg(vp, char *);
876 if (server_name && server_info )
878 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
879 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
884 case SILC_COMMAND_TOPIC:
886 SilcChannelEntry channel;
892 channel = va_arg(vp, SilcChannelEntry);
893 topic = va_arg(vp, char *);
896 chanrec = silc_channel_find_entry(server, channel);
898 g_free_not_null(chanrec->topic);
899 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
900 signal_emit("channel topic changed", 1, chanrec);
902 printformat_module("fe-common/silc", server, channel->channel_name,
903 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
904 channel->channel_name, topic);
906 printformat_module("fe-common/silc", server, channel->channel_name,
907 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
908 channel->channel_name);
920 SilcClientConnection conn;
926 SilcSKEPKType pk_type;
927 SilcVerifyPublicKey completion;
931 static void verify_public_key_completion(const char *line, void *context)
933 PublicKeyVerify verify = (PublicKeyVerify)context;
935 if (line[0] == 'Y' || line[0] == 'y') {
936 /* Call the completion */
937 if (verify->completion)
938 verify->completion(TRUE, verify->context);
940 /* Save the key for future checking */
941 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
942 verify->pk_len, SILC_PKCS_FILE_PEM);
944 /* Call the completion */
945 if (verify->completion)
946 verify->completion(FALSE, verify->context);
948 printformat_module("fe-common/silc", NULL, NULL,
949 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
950 verify->entity_name ? verify->entity_name :
954 silc_free(verify->filename);
955 silc_free(verify->entity);
956 silc_free(verify->entity_name);
957 silc_free(verify->pk);
961 /* Internal routine to verify public key. If the `completion' is provided
962 it will be called to indicate whether public was verified or not. For
963 server/router public key this will check for filename that includes the
964 remote host's IP address and remote host's hostname. */
967 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
968 const char *name, SilcSocketType conn_type,
969 unsigned char *pk, uint32 pk_len,
970 SilcSKEPKType pk_type,
971 SilcVerifyPublicKey completion, void *context)
974 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
975 char *fingerprint, *babbleprint, *format;
978 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
979 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
980 "server" : "client");
981 PublicKeyVerify verify;
983 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
984 printformat_module("fe-common/silc", NULL, NULL,
985 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
988 completion(FALSE, context);
992 pw = getpwuid(getuid());
995 completion(FALSE, context);
999 memset(filename, 0, sizeof(filename));
1000 memset(filename2, 0, sizeof(filename2));
1001 memset(file, 0, sizeof(file));
1003 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1004 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1006 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1007 conn->sock->ip, conn->sock->port);
1008 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1009 pw->pw_dir, entity, file);
1011 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1012 conn->sock->hostname, conn->sock->port);
1013 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1014 pw->pw_dir, entity, file);
1019 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1020 name, conn->sock->port);
1021 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1022 pw->pw_dir, entity, file);
1027 /* Replace all whitespaces with `_'. */
1028 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1029 for (i = 0; i < strlen(fingerprint); i++)
1030 if (fingerprint[i] == ' ')
1031 fingerprint[i] = '_';
1033 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1034 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1035 pw->pw_dir, entity, file);
1036 silc_free(fingerprint);
1041 /* Take fingerprint of the public key */
1042 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1043 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1045 verify = silc_calloc(1, sizeof(*verify));
1046 verify->client = client;
1047 verify->conn = conn;
1048 verify->filename = strdup(ipf);
1049 verify->entity = strdup(entity);
1050 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1051 (name ? strdup(name) : strdup(conn->sock->hostname))
1053 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1054 memcpy(verify->pk, pk, pk_len);
1055 verify->pk_len = pk_len;
1056 verify->pk_type = pk_type;
1057 verify->completion = completion;
1058 verify->context = context;
1060 /* Check whether this key already exists */
1061 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1062 /* Key does not exist, ask user to verify the key and save it */
1064 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1065 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1066 verify->entity_name : entity);
1067 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1068 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1069 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1070 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1071 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1072 SILCTXT_PUBKEY_ACCEPT);
1073 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1076 silc_free(fingerprint);
1079 /* The key already exists, verify it. */
1080 SilcPublicKey public_key;
1081 unsigned char *encpk;
1084 /* Load the key file, try for both IP filename and hostname filename */
1085 if (!silc_pkcs_load_public_key(ipf, &public_key,
1086 SILC_PKCS_FILE_PEM) &&
1087 !silc_pkcs_load_public_key(ipf, &public_key,
1088 SILC_PKCS_FILE_BIN) &&
1089 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1090 SILC_PKCS_FILE_PEM) &&
1091 !silc_pkcs_load_public_key(hostf, &public_key,
1092 SILC_PKCS_FILE_BIN)))) {
1093 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1094 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1095 verify->entity_name : entity);
1096 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1097 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1098 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1099 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1100 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1101 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1102 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1103 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1104 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1107 silc_free(fingerprint);
1111 /* Encode the key data */
1112 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1114 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1115 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1116 verify->entity_name : entity);
1117 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1118 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1119 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1120 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1121 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1122 SILCTXT_PUBKEY_MALFORMED, entity);
1123 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1124 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1125 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1128 silc_free(fingerprint);
1132 /* Compare the keys */
1133 if (memcmp(encpk, pk, encpk_len)) {
1134 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1135 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1136 verify->entity_name : entity);
1137 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1138 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1139 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1140 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1141 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1142 SILCTXT_PUBKEY_NO_MATCH, entity);
1143 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1144 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1145 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1146 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1148 /* Ask user to verify the key and save it */
1149 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1150 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1151 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1154 silc_free(fingerprint);
1158 /* Local copy matched */
1160 completion(TRUE, context);
1161 silc_free(fingerprint);
1165 /* Verifies received public key. The `conn_type' indicates which entity
1166 (server, client etc.) has sent the public key. If user decides to trust
1167 the key may be saved as trusted public key for later use. The
1168 `completion' must be called after the public key has been verified. */
1171 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1172 SilcSocketType conn_type, unsigned char *pk,
1173 uint32 pk_len, SilcSKEPKType pk_type,
1174 SilcVerifyPublicKey completion, void *context)
1176 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1178 completion, context);
1181 /* Asks passphrase from user on the input line. */
1184 SilcAskPassphrase completion;
1188 void ask_passphrase_completion(const char *passphrase, void *context)
1190 AskPassphrase p = (AskPassphrase)context;
1191 p->completion((unsigned char *)passphrase,
1192 passphrase ? strlen(passphrase) : 0, p->context);
1196 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1197 SilcAskPassphrase completion, void *context)
1199 AskPassphrase p = silc_calloc(1, sizeof(*p));
1200 p->completion = completion;
1201 p->context = context;
1203 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1204 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1208 SilcGetAuthMeth completion;
1210 } *InternalGetAuthMethod;
1212 /* Callback called when we've received the authentication method information
1213 from the server after we've requested it. This will get the authentication
1214 data from the user if needed. */
1216 static void silc_get_auth_method_callback(SilcClient client,
1217 SilcClientConnection conn,
1218 SilcAuthMethod auth_meth,
1221 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1223 SILC_LOG_DEBUG(("Start"));
1225 switch (auth_meth) {
1226 case SILC_AUTH_NONE:
1227 /* No authentication required. */
1228 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1230 case SILC_AUTH_PASSWORD:
1231 /* Do not ask the passphrase from user, the library will ask it if
1232 we do not provide it here. */
1233 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1235 case SILC_AUTH_PUBLIC_KEY:
1236 /* Do not get the authentication data now, the library will generate
1237 it using our default key, if we do not provide it here. */
1238 /* XXX In the future when we support multiple local keys and multiple
1239 local certificates we will need to ask from user which one to use. */
1240 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1244 silc_free(internal);
1247 /* Find authentication method and authentication data by hostname and
1248 port. The hostname may be IP address as well. The found authentication
1249 method and authentication data is returned to `auth_meth', `auth_data'
1250 and `auth_data_len'. The function returns TRUE if authentication method
1251 is found and FALSE if not. `conn' may be NULL. */
1253 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1254 char *hostname, uint16 port,
1255 SilcGetAuthMeth completion, void *context)
1257 InternalGetAuthMethod internal;
1259 SILC_LOG_DEBUG(("Start"));
1261 /* XXX must resolve from configuration whether this connection has
1262 any specific authentication data */
1264 /* If we do not have this connection configured by the user in a
1265 configuration file then resolve the authentication method from the
1266 server for this session. */
1267 internal = silc_calloc(1, sizeof(*internal));
1268 internal->completion = completion;
1269 internal->context = context;
1271 silc_client_request_authentication_method(client, conn,
1272 silc_get_auth_method_callback,
1276 /* Notifies application that failure packet was received. This is called
1277 if there is some protocol active in the client. The `protocol' is the
1278 protocol context. The `failure' is opaque pointer to the failure
1279 indication. Note, that the `failure' is protocol dependant and application
1280 must explicitly cast it to correct type. Usually `failure' is 32 bit
1281 failure type (see protocol specs for all protocol failure types). */
1283 void silc_failure(SilcClient client, SilcClientConnection conn,
1284 SilcProtocol protocol, void *failure)
1286 SILC_LOG_DEBUG(("Start"));
1288 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1289 SilcSKEStatus status = (SilcSKEStatus)failure;
1291 if (status == SILC_SKE_STATUS_BAD_VERSION)
1292 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1293 SILCTXT_KE_BAD_VERSION);
1294 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1295 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1296 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1297 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1298 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1299 SILCTXT_KE_UNKNOWN_GROUP);
1300 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1301 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1302 SILCTXT_KE_UNKNOWN_CIPHER);
1303 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1304 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1305 SILCTXT_KE_UNKNOWN_PKCS);
1306 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1307 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1308 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1309 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1310 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1311 SILCTXT_KE_UNKNOWN_HMAC);
1312 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1313 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1314 SILCTXT_KE_INCORRECT_SIGNATURE);
1315 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1316 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1317 SILCTXT_KE_INVALID_COOKIE);
1320 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1321 uint32 err = (uint32)failure;
1323 if (err == SILC_AUTH_FAILED)
1324 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1325 SILCTXT_AUTH_FAILED);
1329 /* Asks whether the user would like to perform the key agreement protocol.
1330 This is called after we have received an key agreement packet or an
1331 reply to our key agreement packet. This returns TRUE if the user wants
1332 the library to perform the key agreement protocol and FALSE if it is not
1333 desired (application may start it later by calling the function
1334 silc_client_perform_key_agreement). */
1336 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1337 SilcClientEntry client_entry, const char *hostname,
1338 uint16 port, SilcKeyAgreementCallback *completion,
1343 SILC_LOG_DEBUG(("Start"));
1345 /* We will just display the info on the screen and return FALSE and user
1346 will have to start the key agreement with a command. */
1349 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1352 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1353 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1355 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1356 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1357 client_entry->nickname, hostname, portstr);
1365 void silc_ftp(SilcClient client, SilcClientConnection conn,
1366 SilcClientEntry client_entry, uint32 session_id,
1367 const char *hostname, uint16 port)
1369 SILC_SERVER_REC *server;
1371 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1373 SILC_LOG_DEBUG(("Start"));
1375 server = conn->context;
1377 ftp->client_entry = client_entry;
1378 ftp->session_id = session_id;
1381 silc_dlist_add(server->ftp_sessions, ftp);
1382 server->current_session = ftp;
1385 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1388 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1389 SILCTXT_FILE_REQUEST, client_entry->nickname);
1391 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1392 SILCTXT_FILE_REQUEST_HOST,
1393 client_entry->nickname, hostname, portstr);
1396 /* SILC client operations */
1397 SilcClientOperations ops = {
1399 silc_channel_message,
1400 silc_private_message,
1406 silc_get_auth_method,
1407 silc_verify_public_key,
1408 silc_ask_passphrase,