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"));
93 server = conn == NULL ? NULL : conn->context;
94 chanrec = silc_channel_find_entry(server, channel);
98 nick = silc_nicklist_find(chanrec, sender);
100 /* We didn't find client but it clearly exists, add it. */
101 SilcChannelUser chu = silc_client_on_channel(channel, sender);
103 nick = silc_nicklist_insert(chanrec, chu, FALSE);
106 if (flags & SILC_MESSAGE_FLAG_ACTION)
107 printformat_module("fe-common/silc", server, channel->channel_name,
108 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
109 nick == NULL ? "[<unknown>]" : nick->nick, msg);
110 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
111 printformat_module("fe-common/silc", server, channel->channel_name,
112 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
113 nick == NULL ? "[<unknown>]" : nick->nick, msg);
115 signal_emit("message public", 6, server, msg,
116 nick == NULL ? "[<unknown>]" : nick->nick,
117 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
118 chanrec->name, nick);
121 /* Private message to the client. The `sender' is the nickname of the
122 sender received in the packet. */
124 void silc_private_message(SilcClient client, SilcClientConnection conn,
125 SilcClientEntry sender, SilcMessageFlags flags,
128 SILC_SERVER_REC *server;
131 SILC_LOG_DEBUG(("Start"));
133 server = conn == NULL ? NULL : conn->context;
134 memset(userhost, 0, sizeof(userhost));
135 if (sender->username)
136 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
137 sender->username, sender->hostname);
138 signal_emit("message private", 4, server, msg,
139 sender->nickname ? sender->nickname : "[<unknown>]",
140 sender->username ? userhost : NULL);
143 /* Notify message to the client. The notify arguments are sent in the
144 same order as servers sends them. The arguments are same as received
145 from the server except for ID's. If ID is received application receives
146 the corresponding entry to the ID. For example, if Client ID is received
147 application receives SilcClientEntry. Also, if the notify type is
148 for channel the channel entry is sent to application (even if server
149 does not send it). */
156 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
157 static NOTIFY_REC notifies[] = {
158 { SILC_NOTIFY_TYPE_NONE, NULL },
159 { SILC_NOTIFY_TYPE_INVITE, "invite" },
160 { SILC_NOTIFY_TYPE_JOIN, "join" },
161 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
162 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
163 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
164 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
165 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
166 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
167 { SILC_NOTIFY_TYPE_MOTD, "motd" },
168 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
169 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
170 { SILC_NOTIFY_TYPE_KICKED, "kick" },
171 { SILC_NOTIFY_TYPE_KILLED, "kill" },
172 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
173 { SILC_NOTIFY_TYPE_BAN, "ban" },
176 void silc_notify(SilcClient client, SilcClientConnection conn,
177 SilcNotifyType type, ...)
179 SILC_SERVER_REC *server;
182 SILC_LOG_DEBUG(("Start"));
184 server = conn == NULL ? NULL : conn->context;
187 if (type == SILC_NOTIFY_TYPE_NONE) {
188 /* Some generic notice from server */
189 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
190 } else if (type < MAX_NOTIFY) {
191 /* Send signal about the notify event */
193 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
194 signal_emit(signal, 2, server, va);
197 printformat_module("fe-common/silc", server, NULL,
198 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
204 /* Called to indicate that connection was either successfully established
205 or connecting failed. This is also the first time application receives
206 the SilcClientConnection object which it should save somewhere. */
208 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
210 SILC_SERVER_REC *server = conn->context;
212 if (!server && !success) {
213 silc_client_close_connection(client, NULL, conn);
218 server->connected = TRUE;
219 signal_emit("event connected", 1, server);
221 server->connection_lost = TRUE;
223 server->conn->context = NULL;
224 server_disconnect(SERVER(server));
228 /* Called to indicate that connection was disconnected to the server. */
230 void silc_disconnect(SilcClient client, SilcClientConnection conn)
232 SILC_SERVER_REC *server = conn->context;
234 SILC_LOG_DEBUG(("Start"));
237 nicklist_rename_unique(SERVER(server),
238 server->conn->local_entry, server->nick,
239 server->conn->local_entry,
240 silc_client->username);
241 silc_change_nick(server, silc_client->username);
244 server->conn->context = NULL;
246 server->connection_lost = TRUE;
247 server_disconnect(SERVER(server));
250 /* Command handler. This function is called always in the command function.
251 If error occurs it will be called as well. `conn' is the associated
252 client connection. `cmd_context' is the command context that was
253 originally sent to the command. `success' is FALSE if error occured
254 during command. `command' is the command being processed. It must be
255 noted that this is not reply from server. This is merely called just
256 after application has called the command. Just to tell application
257 that the command really was processed. */
259 void silc_command(SilcClient client, SilcClientConnection conn,
260 SilcClientCommandContext cmd_context, int success,
263 SILC_SERVER_REC *server = conn->context;
265 SILC_LOG_DEBUG(("Start"));
271 case SILC_COMMAND_INVITE:
272 printformat_module("fe-common/silc", server, NULL,
273 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
274 cmd_context->argv[2],
275 (cmd_context->argv[1][0] == '*' ?
276 (char *)conn->current_channel->channel_name :
277 (char *)cmd_context->argv[1]));
284 /* Client info resolving callback when JOIN command reply is received.
285 This will cache all users on the channel. */
287 static void silc_client_join_get_users(SilcClient client,
288 SilcClientConnection conn,
289 SilcClientEntry *clients,
290 uint32 clients_count,
293 SilcChannelEntry channel = (SilcChannelEntry)context;
294 SilcHashTableList htl;
296 SILC_SERVER_REC *server = conn->context;
297 SILC_CHANNEL_REC *chanrec;
298 SilcClientEntry founder = NULL;
304 chanrec = silc_channel_find(server, channel->channel_name);
308 silc_hash_table_list(channel->user_list, &htl);
309 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
310 if (!chu->client->nickname)
312 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
313 founder = chu->client;
314 silc_nicklist_insert(chanrec, chu, FALSE);
316 silc_hash_table_list_reset(&htl);
318 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
319 nicklist_set_own(CHANNEL(chanrec), ownnick);
320 signal_emit("channel joined", 1, chanrec);
323 printformat_module("fe-common/silc", server, channel->channel_name,
324 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
325 channel->channel_name, chanrec->topic);
327 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
330 if (founder == conn->local_entry)
331 printformat_module("fe-common/silc",
332 server, channel->channel_name, MSGLEVEL_CRAP,
333 SILCTXT_CHANNEL_FOUNDER_YOU,
334 channel->channel_name);
336 printformat_module("fe-common/silc",
337 server, channel->channel_name, MSGLEVEL_CRAP,
338 SILCTXT_CHANNEL_FOUNDER,
339 channel->channel_name, founder->nickname);
345 SilcClientConnection conn;
351 void silc_getkey_cb(bool success, void *context)
353 GetkeyContext getkey = (GetkeyContext)context;
354 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
355 char *name = (getkey->id_type == SILC_ID_CLIENT ?
356 ((SilcClientEntry)getkey->entry)->nickname :
357 ((SilcServerEntry)getkey->entry)->server_name);
360 printformat_module("fe-common/silc", NULL, NULL,
361 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
363 printformat_module("fe-common/silc", NULL, NULL,
364 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
367 silc_free(getkey->fingerprint);
371 /* Command reply handler. This function is called always in the command reply
372 function. If error occurs it will be called as well. Normal scenario
373 is that it will be called after the received command data has been parsed
374 and processed. The function is used to pass the received command data to
377 `conn' is the associated client connection. `cmd_payload' is the command
378 payload data received from server and it can be ignored. It is provided
379 if the application would like to re-parse the received command data,
380 however, it must be noted that the data is parsed already by the library
381 thus the payload can be ignored. `success' is FALSE if error occured.
382 In this case arguments are not sent to the application. `command' is the
383 command reply being processed. The function has variable argument list
384 and each command defines the number and type of arguments it passes to the
385 application (on error they are not sent). */
388 silc_command_reply(SilcClient client, SilcClientConnection conn,
389 SilcCommandPayload cmd_payload, int success,
390 SilcCommand command, SilcCommandStatus status, ...)
393 SILC_SERVER_REC *server = conn->context;
394 SILC_CHANNEL_REC *chanrec;
397 va_start(vp, status);
399 SILC_LOG_DEBUG(("Start"));
402 case SILC_COMMAND_WHOIS:
404 char buf[1024], *nickname, *username, *realname, *nick;
405 unsigned char *fingerprint;
408 SilcClientEntry client_entry;
410 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
411 /* Print the unknown nick for user */
413 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
416 silc_say_error("%s: %s", tmp,
417 silc_client_command_status_message(status));
419 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
420 /* Try to find the entry for the unknown client ID, since we
421 might have, and print the nickname of it for user. */
424 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
427 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
429 client_entry = silc_client_get_client_by_id(client, conn,
431 if (client_entry && client_entry->nickname)
432 silc_say_error("%s: %s", client_entry->nickname,
433 silc_client_command_status_message(status));
434 silc_free(client_id);
443 client_entry = va_arg(vp, SilcClientEntry);
444 nickname = va_arg(vp, char *);
445 username = va_arg(vp, char *);
446 realname = va_arg(vp, char *);
447 channels = va_arg(vp, SilcBuffer);
448 mode = va_arg(vp, uint32);
449 idle = va_arg(vp, uint32);
450 fingerprint = va_arg(vp, unsigned char *);
452 silc_parse_userfqdn(nickname, &nick, NULL);
453 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
454 SILCTXT_WHOIS_USERINFO, nickname,
455 client_entry->username, client_entry->hostname,
456 nick, client_entry->nickname);
457 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
458 SILCTXT_WHOIS_REALNAME, realname);
462 SilcDList list = silc_channel_payload_parse_list(channels->data,
465 SilcChannelPayload entry;
466 memset(buf, 0, sizeof(buf));
467 silc_dlist_start(list);
468 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
469 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
471 char *name = silc_channel_get_name(entry, &name_len);
474 strncat(buf, m, strlen(m));
475 strncat(buf, name, name_len);
476 strncat(buf, " ", 1);
480 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
481 SILCTXT_WHOIS_CHANNELS, buf);
482 silc_channel_payload_list_free(list);
487 memset(buf, 0, sizeof(buf));
489 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
490 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
491 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
493 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
494 "SILC Operator " : "[Unknown mode] ");
496 if (mode & SILC_UMODE_GONE)
499 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
500 SILCTXT_WHOIS_MODES, buf);
503 if (idle && nickname) {
504 memset(buf, 0, sizeof(buf));
505 snprintf(buf, sizeof(buf) - 1, "%lu %s",
506 idle > 60 ? (idle / 60) : idle,
507 idle > 60 ? "minutes" : "seconds");
509 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
510 SILCTXT_WHOIS_IDLE, buf);
514 fingerprint = silc_fingerprint(fingerprint, 20);
515 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
516 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
517 silc_free(fingerprint);
522 case SILC_COMMAND_IDENTIFY:
524 SilcClientEntry client_entry;
526 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
527 /* Print the unknown nick for user */
529 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
532 silc_say_error("%s: %s", tmp,
533 silc_client_command_status_message(status));
535 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
536 /* Try to find the entry for the unknown client ID, since we
537 might have, and print the nickname of it for user. */
540 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
543 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
545 client_entry = silc_client_get_client_by_id(client, conn,
547 if (client_entry && client_entry->nickname)
548 silc_say_error("%s: %s", client_entry->nickname,
549 silc_client_command_status_message(status));
550 silc_free(client_id);
559 case SILC_COMMAND_WHOWAS:
561 char *nickname, *username, *realname;
563 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
564 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
566 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
569 silc_say_error("%s: %s", tmp,
570 silc_client_command_status_message(status));
577 (void)va_arg(vp, SilcClientEntry);
578 nickname = va_arg(vp, char *);
579 username = va_arg(vp, char *);
580 realname = va_arg(vp, char *);
582 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
583 SILCTXT_WHOWAS_USERINFO, nickname, username,
584 realname ? realname : "");
588 case SILC_COMMAND_INVITE:
590 SilcChannelEntry channel;
592 SilcArgumentPayload args;
598 channel = va_arg(vp, SilcChannelEntry);
599 invite_list = va_arg(vp, char *);
601 args = silc_command_get_args(cmd_payload);
603 argc = silc_argument_get_arg_num(args);
606 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
607 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
610 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
611 SILCTXT_CHANNEL_NO_INVITE_LIST,
612 channel->channel_name);
616 case SILC_COMMAND_JOIN:
618 char *channel, *mode, *topic;
620 SilcChannelEntry channel_entry;
621 SilcBuffer client_id_list;
627 channel = va_arg(vp, char *);
628 channel_entry = va_arg(vp, SilcChannelEntry);
629 modei = va_arg(vp, uint32);
630 (void)va_arg(vp, uint32);
631 (void)va_arg(vp, unsigned char *);
632 (void)va_arg(vp, unsigned char *);
633 (void)va_arg(vp, unsigned char *);
634 topic = va_arg(vp, char *);
635 (void)va_arg(vp, unsigned char *);
636 list_count = va_arg(vp, uint32);
637 client_id_list = va_arg(vp, SilcBuffer);
639 chanrec = silc_channel_find(server, channel);
641 chanrec = silc_channel_create(server, channel, TRUE);
644 g_free_not_null(chanrec->topic);
645 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
646 signal_emit("channel topic changed", 1, chanrec);
649 mode = silc_client_chmode(modei,
650 channel_entry->channel_key ?
651 channel_entry->channel_key->cipher->name : "",
652 channel_entry->hmac ?
653 silc_hmac_get_name(channel_entry->hmac) : "");
654 g_free_not_null(chanrec->mode);
655 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
656 signal_emit("channel mode changed", 1, chanrec);
658 /* Resolve the client information */
659 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
660 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 SilcHashTableList htl;
756 SilcChannelEntry channel;
762 channel = va_arg(vp, SilcChannelEntry);
764 printformat_module("fe-common/silc", server, channel->channel_name,
765 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
766 channel->channel_name);
768 silc_hash_table_list(channel->user_list, &htl);
769 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
770 SilcClientEntry e = chu->client;
776 memset(stat, 0, sizeof(stat));
777 mode = silc_client_chumode_char(chu->mode);
778 if (e->mode & SILC_UMODE_GONE)
785 printformat_module("fe-common/silc", server, channel->channel_name,
786 MSGLEVEL_CRAP, SILCTXT_USERS,
788 e->username ? e->username : "",
789 e->hostname ? e->hostname : "",
790 e->realname ? e->realname : "");
794 silc_hash_table_list_reset(&htl);
798 case SILC_COMMAND_BAN:
800 SilcChannelEntry channel;
806 channel = va_arg(vp, SilcChannelEntry);
807 ban_list = va_arg(vp, char *);
810 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
811 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
814 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
815 SILCTXT_CHANNEL_NO_BAN_LIST,
816 channel->channel_name);
820 case SILC_COMMAND_GETKEY:
824 SilcPublicKey public_key;
827 GetkeyContext getkey;
833 id_type = va_arg(vp, uint32);
834 entry = va_arg(vp, void *);
835 public_key = va_arg(vp, SilcPublicKey);
838 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
840 getkey = silc_calloc(1, sizeof(*getkey));
841 getkey->entry = entry;
842 getkey->id_type = id_type;
843 getkey->client = client;
845 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
847 name = (id_type == SILC_ID_CLIENT ?
848 ((SilcClientEntry)entry)->nickname :
849 ((SilcServerEntry)entry)->server_name);
851 silc_verify_public_key_internal(client, conn, name,
852 (id_type == SILC_ID_CLIENT ?
853 SILC_SOCKET_TYPE_CLIENT :
854 SILC_SOCKET_TYPE_SERVER),
855 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
856 silc_getkey_cb, getkey);
859 printformat_module("fe-common/silc", server, NULL,
860 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
865 case SILC_COMMAND_INFO:
867 SilcServerEntry server_entry;
874 server_entry = va_arg(vp, SilcServerEntry);
875 server_name = va_arg(vp, char *);
876 server_info = va_arg(vp, char *);
878 if (server_name && server_info )
880 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
881 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
886 case SILC_COMMAND_TOPIC:
888 SilcChannelEntry channel;
894 channel = va_arg(vp, SilcChannelEntry);
895 topic = va_arg(vp, char *);
898 chanrec = silc_channel_find_entry(server, channel);
900 g_free_not_null(chanrec->topic);
901 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
902 signal_emit("channel topic changed", 1, chanrec);
904 printformat_module("fe-common/silc", server, channel->channel_name,
905 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
906 channel->channel_name, topic);
908 printformat_module("fe-common/silc", server, channel->channel_name,
909 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
910 channel->channel_name);
922 SilcClientConnection conn;
928 SilcSKEPKType pk_type;
929 SilcVerifyPublicKey completion;
933 static void verify_public_key_completion(const char *line, void *context)
935 PublicKeyVerify verify = (PublicKeyVerify)context;
937 if (line[0] == 'Y' || line[0] == 'y') {
938 /* Call the completion */
939 if (verify->completion)
940 verify->completion(TRUE, verify->context);
942 /* Save the key for future checking */
943 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
944 verify->pk_len, SILC_PKCS_FILE_PEM);
946 /* Call the completion */
947 if (verify->completion)
948 verify->completion(FALSE, verify->context);
950 printformat_module("fe-common/silc", NULL, NULL,
951 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
952 verify->entity_name ? verify->entity_name :
956 silc_free(verify->filename);
957 silc_free(verify->entity);
958 silc_free(verify->entity_name);
959 silc_free(verify->pk);
963 /* Internal routine to verify public key. If the `completion' is provided
964 it will be called to indicate whether public was verified or not. For
965 server/router public key this will check for filename that includes the
966 remote host's IP address and remote host's hostname. */
969 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
970 const char *name, SilcSocketType conn_type,
971 unsigned char *pk, uint32 pk_len,
972 SilcSKEPKType pk_type,
973 SilcVerifyPublicKey completion, void *context)
976 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
977 char *fingerprint, *babbleprint, *format;
980 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
981 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
982 "server" : "client");
983 PublicKeyVerify verify;
985 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
986 printformat_module("fe-common/silc", NULL, NULL,
987 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
990 completion(FALSE, context);
994 pw = getpwuid(getuid());
997 completion(FALSE, context);
1001 memset(filename, 0, sizeof(filename));
1002 memset(filename2, 0, sizeof(filename2));
1003 memset(file, 0, sizeof(file));
1005 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1006 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1008 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1009 conn->sock->ip, conn->sock->port);
1010 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1011 pw->pw_dir, entity, file);
1013 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1014 conn->sock->hostname, conn->sock->port);
1015 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1016 pw->pw_dir, entity, file);
1021 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1022 name, conn->sock->port);
1023 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1024 pw->pw_dir, entity, file);
1029 /* Replace all whitespaces with `_'. */
1030 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1031 for (i = 0; i < strlen(fingerprint); i++)
1032 if (fingerprint[i] == ' ')
1033 fingerprint[i] = '_';
1035 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1036 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1037 pw->pw_dir, entity, file);
1038 silc_free(fingerprint);
1043 /* Take fingerprint of the public key */
1044 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1045 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1047 verify = silc_calloc(1, sizeof(*verify));
1048 verify->client = client;
1049 verify->conn = conn;
1050 verify->filename = strdup(ipf);
1051 verify->entity = strdup(entity);
1052 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1053 (name ? strdup(name) : strdup(conn->sock->hostname))
1055 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1056 memcpy(verify->pk, pk, pk_len);
1057 verify->pk_len = pk_len;
1058 verify->pk_type = pk_type;
1059 verify->completion = completion;
1060 verify->context = context;
1062 /* Check whether this key already exists */
1063 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1064 /* Key does not exist, ask user to verify the key and save it */
1066 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1067 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1068 verify->entity_name : entity);
1069 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1070 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1071 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1072 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1073 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1074 SILCTXT_PUBKEY_ACCEPT);
1075 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1078 silc_free(fingerprint);
1081 /* The key already exists, verify it. */
1082 SilcPublicKey public_key;
1083 unsigned char *encpk;
1086 /* Load the key file, try for both IP filename and hostname filename */
1087 if (!silc_pkcs_load_public_key(ipf, &public_key,
1088 SILC_PKCS_FILE_PEM) &&
1089 !silc_pkcs_load_public_key(ipf, &public_key,
1090 SILC_PKCS_FILE_BIN) &&
1091 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1092 SILC_PKCS_FILE_PEM) &&
1093 !silc_pkcs_load_public_key(hostf, &public_key,
1094 SILC_PKCS_FILE_BIN)))) {
1095 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1096 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1097 verify->entity_name : entity);
1098 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1099 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1100 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1101 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1102 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1103 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1104 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1105 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1106 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1109 silc_free(fingerprint);
1113 /* Encode the key data */
1114 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1116 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1117 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1118 verify->entity_name : entity);
1119 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1120 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1121 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1122 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1123 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1124 SILCTXT_PUBKEY_MALFORMED, entity);
1125 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1126 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1127 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1130 silc_free(fingerprint);
1134 /* Compare the keys */
1135 if (memcmp(encpk, pk, encpk_len)) {
1136 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1137 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1138 verify->entity_name : entity);
1139 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1140 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1141 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1142 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1143 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1144 SILCTXT_PUBKEY_NO_MATCH, entity);
1145 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1146 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1147 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1148 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1150 /* Ask user to verify the key and save it */
1151 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1152 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1153 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1156 silc_free(fingerprint);
1160 /* Local copy matched */
1162 completion(TRUE, context);
1163 silc_free(fingerprint);
1167 /* Verifies received public key. The `conn_type' indicates which entity
1168 (server, client etc.) has sent the public key. If user decides to trust
1169 the key may be saved as trusted public key for later use. The
1170 `completion' must be called after the public key has been verified. */
1173 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1174 SilcSocketType conn_type, unsigned char *pk,
1175 uint32 pk_len, SilcSKEPKType pk_type,
1176 SilcVerifyPublicKey completion, void *context)
1178 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1180 completion, context);
1183 /* Asks passphrase from user on the input line. */
1186 SilcAskPassphrase completion;
1190 void ask_passphrase_completion(const char *passphrase, void *context)
1192 AskPassphrase p = (AskPassphrase)context;
1193 p->completion((unsigned char *)passphrase,
1194 passphrase ? strlen(passphrase) : 0, p->context);
1198 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1199 SilcAskPassphrase completion, void *context)
1201 AskPassphrase p = silc_calloc(1, sizeof(*p));
1202 p->completion = completion;
1203 p->context = context;
1205 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1206 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1210 SilcGetAuthMeth completion;
1212 } *InternalGetAuthMethod;
1214 /* Callback called when we've received the authentication method information
1215 from the server after we've requested it. This will get the authentication
1216 data from the user if needed. */
1218 static void silc_get_auth_method_callback(SilcClient client,
1219 SilcClientConnection conn,
1220 SilcAuthMethod auth_meth,
1223 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1225 SILC_LOG_DEBUG(("Start"));
1227 switch (auth_meth) {
1228 case SILC_AUTH_NONE:
1229 /* No authentication required. */
1230 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1232 case SILC_AUTH_PASSWORD:
1233 /* Do not ask the passphrase from user, the library will ask it if
1234 we do not provide it here. */
1235 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1237 case SILC_AUTH_PUBLIC_KEY:
1238 /* Do not get the authentication data now, the library will generate
1239 it using our default key, if we do not provide it here. */
1240 /* XXX In the future when we support multiple local keys and multiple
1241 local certificates we will need to ask from user which one to use. */
1242 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1246 silc_free(internal);
1249 /* Find authentication method and authentication data by hostname and
1250 port. The hostname may be IP address as well. The found authentication
1251 method and authentication data is returned to `auth_meth', `auth_data'
1252 and `auth_data_len'. The function returns TRUE if authentication method
1253 is found and FALSE if not. `conn' may be NULL. */
1255 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1256 char *hostname, uint16 port,
1257 SilcGetAuthMeth completion, void *context)
1259 InternalGetAuthMethod internal;
1261 SILC_LOG_DEBUG(("Start"));
1263 /* XXX must resolve from configuration whether this connection has
1264 any specific authentication data */
1266 /* If we do not have this connection configured by the user in a
1267 configuration file then resolve the authentication method from the
1268 server for this session. */
1269 internal = silc_calloc(1, sizeof(*internal));
1270 internal->completion = completion;
1271 internal->context = context;
1273 silc_client_request_authentication_method(client, conn,
1274 silc_get_auth_method_callback,
1278 /* Notifies application that failure packet was received. This is called
1279 if there is some protocol active in the client. The `protocol' is the
1280 protocol context. The `failure' is opaque pointer to the failure
1281 indication. Note, that the `failure' is protocol dependant and application
1282 must explicitly cast it to correct type. Usually `failure' is 32 bit
1283 failure type (see protocol specs for all protocol failure types). */
1285 void silc_failure(SilcClient client, SilcClientConnection conn,
1286 SilcProtocol protocol, void *failure)
1288 SILC_LOG_DEBUG(("Start"));
1290 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1291 SilcSKEStatus status = (SilcSKEStatus)failure;
1293 if (status == SILC_SKE_STATUS_BAD_VERSION)
1294 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1295 SILCTXT_KE_BAD_VERSION);
1296 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1297 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1298 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1299 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1300 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1301 SILCTXT_KE_UNKNOWN_GROUP);
1302 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1303 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1304 SILCTXT_KE_UNKNOWN_CIPHER);
1305 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1306 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1307 SILCTXT_KE_UNKNOWN_PKCS);
1308 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1309 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1310 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1311 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1312 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1313 SILCTXT_KE_UNKNOWN_HMAC);
1314 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1315 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1316 SILCTXT_KE_INCORRECT_SIGNATURE);
1317 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1318 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1319 SILCTXT_KE_INVALID_COOKIE);
1322 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1323 uint32 err = (uint32)failure;
1325 if (err == SILC_AUTH_FAILED)
1326 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1327 SILCTXT_AUTH_FAILED);
1331 /* Asks whether the user would like to perform the key agreement protocol.
1332 This is called after we have received an key agreement packet or an
1333 reply to our key agreement packet. This returns TRUE if the user wants
1334 the library to perform the key agreement protocol and FALSE if it is not
1335 desired (application may start it later by calling the function
1336 silc_client_perform_key_agreement). */
1338 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1339 SilcClientEntry client_entry, const char *hostname,
1340 uint16 port, SilcKeyAgreementCallback *completion,
1345 SILC_LOG_DEBUG(("Start"));
1347 /* We will just display the info on the screen and return FALSE and user
1348 will have to start the key agreement with a command. */
1351 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1354 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1355 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1357 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1358 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1359 client_entry->nickname, hostname, portstr);
1367 void silc_ftp(SilcClient client, SilcClientConnection conn,
1368 SilcClientEntry client_entry, uint32 session_id,
1369 const char *hostname, uint16 port)
1371 SILC_SERVER_REC *server;
1373 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1375 SILC_LOG_DEBUG(("Start"));
1377 server = conn->context;
1379 ftp->client_entry = client_entry;
1380 ftp->session_id = session_id;
1383 silc_dlist_add(server->ftp_sessions, ftp);
1384 server->current_session = ftp;
1387 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1390 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1391 SILCTXT_FILE_REQUEST, client_entry->nickname);
1393 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1394 SILCTXT_FILE_REQUEST_HOST,
1395 client_entry->nickname, hostname, portstr);
1398 /* SILC client operations */
1399 SilcClientOperations ops = {
1401 silc_channel_message,
1402 silc_private_message,
1408 silc_get_auth_method,
1409 silc_verify_public_key,
1410 silc_ask_passphrase,