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;
227 server->conn->context = NULL;
228 server_disconnect(SERVER(server));
232 /* Called to indicate that connection was disconnected to the server. */
234 void silc_disconnect(SilcClient client, SilcClientConnection conn)
236 SILC_SERVER_REC *server = conn->context;
238 SILC_LOG_DEBUG(("Start"));
241 nicklist_rename_unique(SERVER(server),
242 server->conn->local_entry, server->nick,
243 server->conn->local_entry,
244 silc_client->username);
245 silc_change_nick(server, silc_client->username);
248 server->conn->context = NULL;
250 server->connection_lost = TRUE;
251 server_disconnect(SERVER(server));
254 /* Command handler. This function is called always in the command function.
255 If error occurs it will be called as well. `conn' is the associated
256 client connection. `cmd_context' is the command context that was
257 originally sent to the command. `success' is FALSE if error occured
258 during command. `command' is the command being processed. It must be
259 noted that this is not reply from server. This is merely called just
260 after application has called the command. Just to tell application
261 that the command really was processed. */
263 void silc_command(SilcClient client, SilcClientConnection conn,
264 SilcClientCommandContext cmd_context, int success,
267 SILC_SERVER_REC *server = conn->context;
269 SILC_LOG_DEBUG(("Start"));
275 case SILC_COMMAND_INVITE:
276 printformat_module("fe-common/silc", server, NULL,
277 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
278 cmd_context->argv[2],
279 (cmd_context->argv[1][0] == '*' ?
280 (char *)conn->current_channel->channel_name :
281 (char *)cmd_context->argv[1]));
288 /* Client info resolving callback when JOIN command reply is received.
289 This will cache all users on the channel. */
291 static void silc_client_join_get_users(SilcClient client,
292 SilcClientConnection conn,
293 SilcClientEntry *clients,
294 uint32 clients_count,
297 SilcChannelEntry channel = (SilcChannelEntry)context;
299 SILC_SERVER_REC *server = conn->context;
300 SILC_CHANNEL_REC *chanrec;
301 SilcClientEntry founder = NULL;
307 chanrec = silc_channel_find(server, channel->channel_name);
311 silc_list_start(channel->clients);
312 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
313 if (!chu->client->nickname)
315 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
316 founder = chu->client;
317 silc_nicklist_insert(chanrec, chu, FALSE);
320 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
321 nicklist_set_own(CHANNEL(chanrec), ownnick);
322 signal_emit("channel joined", 1, chanrec);
325 printformat_module("fe-common/silc", server, channel->channel_name,
326 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
327 channel->channel_name, chanrec->topic);
329 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
332 if (founder == conn->local_entry)
333 printformat_module("fe-common/silc",
334 server, channel->channel_name, MSGLEVEL_CRAP,
335 SILCTXT_CHANNEL_FOUNDER_YOU,
336 channel->channel_name);
338 printformat_module("fe-common/silc",
339 server, channel->channel_name, MSGLEVEL_CRAP,
340 SILCTXT_CHANNEL_FOUNDER,
341 channel->channel_name, founder->nickname);
347 SilcClientConnection conn;
353 void silc_getkey_cb(bool success, void *context)
355 GetkeyContext getkey = (GetkeyContext)context;
356 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
357 char *name = (getkey->id_type == SILC_ID_CLIENT ?
358 ((SilcClientEntry)getkey->entry)->nickname :
359 ((SilcServerEntry)getkey->entry)->server_name);
362 printformat_module("fe-common/silc", NULL, NULL,
363 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
365 printformat_module("fe-common/silc", NULL, NULL,
366 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
369 silc_free(getkey->fingerprint);
373 /* Command reply handler. This function is called always in the command reply
374 function. If error occurs it will be called as well. Normal scenario
375 is that it will be called after the received command data has been parsed
376 and processed. The function is used to pass the received command data to
379 `conn' is the associated client connection. `cmd_payload' is the command
380 payload data received from server and it can be ignored. It is provided
381 if the application would like to re-parse the received command data,
382 however, it must be noted that the data is parsed already by the library
383 thus the payload can be ignored. `success' is FALSE if error occured.
384 In this case arguments are not sent to the application. `command' is the
385 command reply being processed. The function has variable argument list
386 and each command defines the number and type of arguments it passes to the
387 application (on error they are not sent). */
390 silc_command_reply(SilcClient client, SilcClientConnection conn,
391 SilcCommandPayload cmd_payload, int success,
392 SilcCommand command, SilcCommandStatus status, ...)
395 SILC_SERVER_REC *server = conn->context;
396 SILC_CHANNEL_REC *chanrec;
399 va_start(vp, status);
401 SILC_LOG_DEBUG(("Start"));
404 case SILC_COMMAND_WHOIS:
406 char buf[1024], *nickname, *username, *realname, *nick;
407 unsigned char *fingerprint;
410 SilcClientEntry client_entry;
412 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
413 /* Print the unknown nick for user */
415 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
418 silc_say_error("%s: %s", tmp,
419 silc_client_command_status_message(status));
421 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
422 /* Try to find the entry for the unknown client ID, since we
423 might have, and print the nickname of it for user. */
426 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
429 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
431 client_entry = silc_client_get_client_by_id(client, conn,
433 if (client_entry && client_entry->nickname)
434 silc_say_error("%s: %s", client_entry->nickname,
435 silc_client_command_status_message(status));
436 silc_free(client_id);
445 client_entry = va_arg(vp, SilcClientEntry);
446 nickname = va_arg(vp, char *);
447 username = va_arg(vp, char *);
448 realname = va_arg(vp, char *);
449 channels = va_arg(vp, SilcBuffer);
450 mode = va_arg(vp, uint32);
451 idle = va_arg(vp, uint32);
452 fingerprint = va_arg(vp, unsigned char *);
454 silc_parse_userfqdn(nickname, &nick, NULL);
455 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
456 SILCTXT_WHOIS_USERINFO, nickname,
457 client_entry->username, client_entry->hostname,
458 nick, client_entry->nickname);
459 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
460 SILCTXT_WHOIS_REALNAME, realname);
464 SilcDList list = silc_channel_payload_parse_list(channels->data,
467 SilcChannelPayload entry;
468 memset(buf, 0, sizeof(buf));
469 silc_dlist_start(list);
470 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
471 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
473 char *name = silc_channel_get_name(entry, &name_len);
476 strncat(buf, m, strlen(m));
477 strncat(buf, name, name_len);
478 strncat(buf, " ", 1);
482 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
483 SILCTXT_WHOIS_CHANNELS, buf);
484 silc_channel_payload_list_free(list);
489 memset(buf, 0, sizeof(buf));
491 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
492 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
493 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
495 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
496 "SILC Operator " : "[Unknown mode] ");
498 if (mode & SILC_UMODE_GONE)
501 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
502 SILCTXT_WHOIS_MODES, buf);
505 if (idle && nickname) {
506 memset(buf, 0, sizeof(buf));
507 snprintf(buf, sizeof(buf) - 1, "%lu %s",
508 idle > 60 ? (idle / 60) : idle,
509 idle > 60 ? "minutes" : "seconds");
511 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
512 SILCTXT_WHOIS_IDLE, buf);
516 fingerprint = silc_fingerprint(fingerprint, 20);
517 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
518 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
519 silc_free(fingerprint);
524 case SILC_COMMAND_IDENTIFY:
526 SilcClientEntry client_entry;
528 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
529 /* Print the unknown nick for user */
531 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
534 silc_say_error("%s: %s", tmp,
535 silc_client_command_status_message(status));
537 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
538 /* Try to find the entry for the unknown client ID, since we
539 might have, and print the nickname of it for user. */
542 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
545 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
547 client_entry = silc_client_get_client_by_id(client, conn,
549 if (client_entry && client_entry->nickname)
550 silc_say_error("%s: %s", client_entry->nickname,
551 silc_client_command_status_message(status));
552 silc_free(client_id);
561 case SILC_COMMAND_WHOWAS:
563 char *nickname, *username, *realname;
565 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
566 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
568 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
571 silc_say_error("%s: %s", tmp,
572 silc_client_command_status_message(status));
579 (void)va_arg(vp, SilcClientEntry);
580 nickname = va_arg(vp, char *);
581 username = va_arg(vp, char *);
582 realname = va_arg(vp, char *);
584 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
585 SILCTXT_WHOWAS_USERINFO, nickname, username,
586 realname ? realname : "");
590 case SILC_COMMAND_INVITE:
592 SilcChannelEntry channel;
594 SilcArgumentPayload args;
600 channel = va_arg(vp, SilcChannelEntry);
601 invite_list = va_arg(vp, char *);
603 args = silc_command_get_args(cmd_payload);
605 argc = silc_argument_get_arg_num(args);
608 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
609 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
612 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
613 SILCTXT_CHANNEL_NO_INVITE_LIST,
614 channel->channel_name);
618 case SILC_COMMAND_JOIN:
620 char *channel, *mode, *topic;
622 SilcChannelEntry channel_entry;
623 SilcBuffer client_id_list;
629 channel = va_arg(vp, char *);
630 channel_entry = va_arg(vp, SilcChannelEntry);
631 modei = va_arg(vp, uint32);
632 (void)va_arg(vp, uint32);
633 (void)va_arg(vp, unsigned char *);
634 (void)va_arg(vp, unsigned char *);
635 (void)va_arg(vp, unsigned char *);
636 topic = va_arg(vp, char *);
637 (void)va_arg(vp, unsigned char *);
638 list_count = va_arg(vp, uint32);
639 client_id_list = va_arg(vp, SilcBuffer);
641 chanrec = silc_channel_find(server, channel);
643 chanrec = silc_channel_create(server, channel, TRUE);
646 g_free_not_null(chanrec->topic);
647 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
648 signal_emit("channel topic changed", 1, chanrec);
651 mode = silc_client_chmode(modei,
652 channel_entry->channel_key ?
653 channel_entry->channel_key->cipher->name : "",
654 channel_entry->hmac ?
655 silc_hmac_get_name(channel_entry->hmac) : "");
656 g_free_not_null(chanrec->mode);
657 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
658 signal_emit("channel mode changed", 1, chanrec);
660 /* Resolve the client information */
661 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
662 silc_client_join_get_users,
667 case SILC_COMMAND_NICK:
669 SilcClientEntry client = va_arg(vp, SilcClientEntry);
675 old = g_strdup(server->nick);
676 server_change_nick(SERVER(server), client->nickname);
677 nicklist_rename_unique(SERVER(server),
678 server->conn->local_entry, server->nick,
679 client, client->nickname);
681 signal_emit("message own_nick", 4, server, server->nick, old, "");
686 case SILC_COMMAND_LIST:
695 (void)va_arg(vp, SilcChannelEntry);
696 name = va_arg(vp, char *);
697 topic = va_arg(vp, char *);
698 usercount = va_arg(vp, int);
700 if (status == SILC_STATUS_LIST_START ||
701 status == SILC_STATUS_OK)
702 printformat_module("fe-common/silc", server, NULL,
703 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
706 snprintf(users, sizeof(users) - 1, "N/A");
708 snprintf(users, sizeof(users) - 1, "%d", usercount);
709 printformat_module("fe-common/silc", server, NULL,
710 MSGLEVEL_CRAP, SILCTXT_LIST,
711 name, users, topic ? topic : "");
715 case SILC_COMMAND_UMODE:
722 mode = va_arg(vp, uint32);
724 if (mode & SILC_UMODE_SERVER_OPERATOR &&
725 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
726 printformat_module("fe-common/silc", server, NULL,
727 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
729 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
730 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
731 printformat_module("fe-common/silc", server, NULL,
732 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
734 server->umode = mode;
738 case SILC_COMMAND_OPER:
742 printformat_module("fe-common/silc", server, NULL,
743 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
746 case SILC_COMMAND_SILCOPER:
750 printformat_module("fe-common/silc", server, NULL,
751 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
754 case SILC_COMMAND_USERS:
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_list_start(channel->clients);
769 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
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 : "");
797 case SILC_COMMAND_BAN:
799 SilcChannelEntry channel;
805 channel = va_arg(vp, SilcChannelEntry);
806 ban_list = va_arg(vp, char *);
809 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
810 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
813 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
814 SILCTXT_CHANNEL_NO_BAN_LIST,
815 channel->channel_name);
819 case SILC_COMMAND_GETKEY:
823 SilcPublicKey public_key;
826 GetkeyContext getkey;
832 id_type = va_arg(vp, uint32);
833 entry = va_arg(vp, void *);
834 public_key = va_arg(vp, SilcPublicKey);
837 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
839 getkey = silc_calloc(1, sizeof(*getkey));
840 getkey->entry = entry;
841 getkey->id_type = id_type;
842 getkey->client = client;
844 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
846 name = (id_type == SILC_ID_CLIENT ?
847 ((SilcClientEntry)entry)->nickname :
848 ((SilcServerEntry)entry)->server_name);
850 silc_verify_public_key_internal(client, conn, name,
851 (id_type == SILC_ID_CLIENT ?
852 SILC_SOCKET_TYPE_CLIENT :
853 SILC_SOCKET_TYPE_SERVER),
854 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
855 silc_getkey_cb, getkey);
858 printformat_module("fe-common/silc", server, NULL,
859 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
864 case SILC_COMMAND_INFO:
866 SilcServerEntry server_entry;
873 server_entry = va_arg(vp, SilcServerEntry);
874 server_name = va_arg(vp, char *);
875 server_info = va_arg(vp, char *);
877 if (server_name && server_info )
879 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
880 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
885 case SILC_COMMAND_TOPIC:
887 SilcChannelEntry channel;
893 channel = va_arg(vp, SilcChannelEntry);
894 topic = va_arg(vp, char *);
897 chanrec = silc_channel_find_entry(server, channel);
899 g_free_not_null(chanrec->topic);
900 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
901 signal_emit("channel topic changed", 1, chanrec);
903 printformat_module("fe-common/silc", server, channel->channel_name,
904 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
905 channel->channel_name, topic);
907 printformat_module("fe-common/silc", server, channel->channel_name,
908 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
909 channel->channel_name);
921 SilcClientConnection conn;
927 SilcSKEPKType pk_type;
928 SilcVerifyPublicKey completion;
932 static void verify_public_key_completion(const char *line, void *context)
934 PublicKeyVerify verify = (PublicKeyVerify)context;
936 if (line[0] == 'Y' || line[0] == 'y') {
937 /* Call the completion */
938 if (verify->completion)
939 verify->completion(TRUE, verify->context);
941 /* Save the key for future checking */
942 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
943 verify->pk_len, SILC_PKCS_FILE_PEM);
945 /* Call the completion */
946 if (verify->completion)
947 verify->completion(FALSE, verify->context);
949 printformat_module("fe-common/silc", NULL, NULL,
950 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
951 verify->entity_name ? verify->entity_name :
955 silc_free(verify->filename);
956 silc_free(verify->entity);
957 silc_free(verify->entity_name);
958 silc_free(verify->pk);
962 /* Internal routine to verify public key. If the `completion' is provided
963 it will be called to indicate whether public was verified or not. For
964 server/router public key this will check for filename that includes the
965 remote host's IP address and remote host's hostname. */
968 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
969 const char *name, SilcSocketType conn_type,
970 unsigned char *pk, uint32 pk_len,
971 SilcSKEPKType pk_type,
972 SilcVerifyPublicKey completion, void *context)
975 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
976 char *fingerprint, *babbleprint, *format;
979 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
980 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
981 "server" : "client");
982 PublicKeyVerify verify;
984 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
985 printformat_module("fe-common/silc", NULL, NULL,
986 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
989 completion(FALSE, context);
993 pw = getpwuid(getuid());
996 completion(FALSE, context);
1000 memset(filename, 0, sizeof(filename));
1001 memset(filename2, 0, sizeof(filename2));
1002 memset(file, 0, sizeof(file));
1004 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1005 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1007 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1008 conn->sock->ip, conn->sock->port);
1009 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1010 pw->pw_dir, entity, file);
1012 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1013 conn->sock->hostname, conn->sock->port);
1014 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1015 pw->pw_dir, entity, file);
1020 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1021 name, conn->sock->port);
1022 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1023 pw->pw_dir, entity, file);
1028 /* Replace all whitespaces with `_'. */
1029 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1030 for (i = 0; i < strlen(fingerprint); i++)
1031 if (fingerprint[i] == ' ')
1032 fingerprint[i] = '_';
1034 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1035 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1036 pw->pw_dir, entity, file);
1037 silc_free(fingerprint);
1042 /* Take fingerprint of the public key */
1043 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1044 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1046 verify = silc_calloc(1, sizeof(*verify));
1047 verify->client = client;
1048 verify->conn = conn;
1049 verify->filename = strdup(ipf);
1050 verify->entity = strdup(entity);
1051 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1052 (name ? strdup(name) : strdup(conn->sock->hostname))
1054 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1055 memcpy(verify->pk, pk, pk_len);
1056 verify->pk_len = pk_len;
1057 verify->pk_type = pk_type;
1058 verify->completion = completion;
1059 verify->context = context;
1061 /* Check whether this key already exists */
1062 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1063 /* Key does not exist, ask user to verify the key and save it */
1065 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1066 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1067 verify->entity_name : entity);
1068 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1069 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1070 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1071 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1072 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1073 SILCTXT_PUBKEY_ACCEPT);
1074 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1077 silc_free(fingerprint);
1080 /* The key already exists, verify it. */
1081 SilcPublicKey public_key;
1082 unsigned char *encpk;
1085 /* Load the key file, try for both IP filename and hostname filename */
1086 if (!silc_pkcs_load_public_key(ipf, &public_key,
1087 SILC_PKCS_FILE_PEM) &&
1088 !silc_pkcs_load_public_key(ipf, &public_key,
1089 SILC_PKCS_FILE_BIN) &&
1090 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1091 SILC_PKCS_FILE_PEM) &&
1092 !silc_pkcs_load_public_key(hostf, &public_key,
1093 SILC_PKCS_FILE_BIN)))) {
1094 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1095 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1096 verify->entity_name : entity);
1097 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1098 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1099 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1100 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1101 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1102 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1103 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1104 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1105 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1108 silc_free(fingerprint);
1112 /* Encode the key data */
1113 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1115 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1116 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1117 verify->entity_name : entity);
1118 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1119 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1120 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1121 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1122 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1123 SILCTXT_PUBKEY_MALFORMED, entity);
1124 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1125 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1126 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1129 silc_free(fingerprint);
1133 /* Compare the keys */
1134 if (memcmp(encpk, pk, encpk_len)) {
1135 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1136 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1137 verify->entity_name : entity);
1138 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1139 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1140 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1141 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1142 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1143 SILCTXT_PUBKEY_NO_MATCH, entity);
1144 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1145 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1146 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1147 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1149 /* Ask user to verify the key and save it */
1150 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1151 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1152 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1155 silc_free(fingerprint);
1159 /* Local copy matched */
1161 completion(TRUE, context);
1162 silc_free(fingerprint);
1166 /* Verifies received public key. The `conn_type' indicates which entity
1167 (server, client etc.) has sent the public key. If user decides to trust
1168 the key may be saved as trusted public key for later use. The
1169 `completion' must be called after the public key has been verified. */
1172 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1173 SilcSocketType conn_type, unsigned char *pk,
1174 uint32 pk_len, SilcSKEPKType pk_type,
1175 SilcVerifyPublicKey completion, void *context)
1177 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1179 completion, context);
1182 /* Asks passphrase from user on the input line. */
1185 SilcAskPassphrase completion;
1189 void ask_passphrase_completion(const char *passphrase, void *context)
1191 AskPassphrase p = (AskPassphrase)context;
1192 p->completion((unsigned char *)passphrase,
1193 passphrase ? strlen(passphrase) : 0, p->context);
1197 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1198 SilcAskPassphrase completion, void *context)
1200 AskPassphrase p = silc_calloc(1, sizeof(*p));
1201 p->completion = completion;
1202 p->context = context;
1204 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1205 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1209 SilcGetAuthMeth completion;
1211 } *InternalGetAuthMethod;
1213 /* Callback called when we've received the authentication method information
1214 from the server after we've requested it. This will get the authentication
1215 data from the user if needed. */
1217 static void silc_get_auth_method_callback(SilcClient client,
1218 SilcClientConnection conn,
1219 SilcAuthMethod auth_meth,
1222 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1224 SILC_LOG_DEBUG(("Start"));
1226 switch (auth_meth) {
1227 case SILC_AUTH_NONE:
1228 /* No authentication required. */
1229 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1231 case SILC_AUTH_PASSWORD:
1232 /* Do not ask the passphrase from user, the library will ask it if
1233 we do not provide it here. */
1234 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1236 case SILC_AUTH_PUBLIC_KEY:
1237 /* Do not get the authentication data now, the library will generate
1238 it using our default key, if we do not provide it here. */
1239 /* XXX In the future when we support multiple local keys and multiple
1240 local certificates we will need to ask from user which one to use. */
1241 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1245 silc_free(internal);
1248 /* Find authentication method and authentication data by hostname and
1249 port. The hostname may be IP address as well. The found authentication
1250 method and authentication data is returned to `auth_meth', `auth_data'
1251 and `auth_data_len'. The function returns TRUE if authentication method
1252 is found and FALSE if not. `conn' may be NULL. */
1254 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1255 char *hostname, uint16 port,
1256 SilcGetAuthMeth completion, void *context)
1258 InternalGetAuthMethod internal;
1260 SILC_LOG_DEBUG(("Start"));
1262 /* XXX must resolve from configuration whether this connection has
1263 any specific authentication data */
1265 /* If we do not have this connection configured by the user in a
1266 configuration file then resolve the authentication method from the
1267 server for this session. */
1268 internal = silc_calloc(1, sizeof(*internal));
1269 internal->completion = completion;
1270 internal->context = context;
1272 silc_client_request_authentication_method(client, conn,
1273 silc_get_auth_method_callback,
1277 /* Notifies application that failure packet was received. This is called
1278 if there is some protocol active in the client. The `protocol' is the
1279 protocol context. The `failure' is opaque pointer to the failure
1280 indication. Note, that the `failure' is protocol dependant and application
1281 must explicitly cast it to correct type. Usually `failure' is 32 bit
1282 failure type (see protocol specs for all protocol failure types). */
1284 void silc_failure(SilcClient client, SilcClientConnection conn,
1285 SilcProtocol protocol, void *failure)
1287 SILC_LOG_DEBUG(("Start"));
1289 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1290 SilcSKEStatus status = (SilcSKEStatus)failure;
1292 if (status == SILC_SKE_STATUS_BAD_VERSION)
1293 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1294 SILCTXT_KE_BAD_VERSION);
1295 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1296 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1297 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1298 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1299 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1300 SILCTXT_KE_UNKNOWN_GROUP);
1301 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1302 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1303 SILCTXT_KE_UNKNOWN_CIPHER);
1304 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1305 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1306 SILCTXT_KE_UNKNOWN_PKCS);
1307 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1308 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1309 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1310 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1311 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1312 SILCTXT_KE_UNKNOWN_HMAC);
1313 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1314 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1315 SILCTXT_KE_INCORRECT_SIGNATURE);
1316 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1317 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1318 SILCTXT_KE_INVALID_COOKIE);
1321 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1322 uint32 err = (uint32)failure;
1324 if (err == SILC_AUTH_FAILED)
1325 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1326 SILCTXT_AUTH_FAILED);
1330 /* Asks whether the user would like to perform the key agreement protocol.
1331 This is called after we have received an key agreement packet or an
1332 reply to our key agreement packet. This returns TRUE if the user wants
1333 the library to perform the key agreement protocol and FALSE if it is not
1334 desired (application may start it later by calling the function
1335 silc_client_perform_key_agreement). */
1337 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1338 SilcClientEntry client_entry, const char *hostname,
1339 uint16 port, SilcKeyAgreementCallback *completion,
1344 SILC_LOG_DEBUG(("Start"));
1346 /* We will just display the info on the screen and return FALSE and user
1347 will have to start the key agreement with a command. */
1350 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1353 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1354 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1356 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1357 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1358 client_entry->nickname, hostname, portstr);
1366 void silc_ftp(SilcClient client, SilcClientConnection conn,
1367 SilcClientEntry client_entry, uint32 session_id,
1368 const char *hostname, uint16 port)
1370 SILC_SERVER_REC *server;
1372 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1374 SILC_LOG_DEBUG(("Start"));
1376 server = conn->context;
1378 ftp->client_entry = client_entry;
1379 ftp->session_id = session_id;
1382 silc_dlist_add(server->ftp_sessions, ftp);
1383 server->current_session = ftp;
1386 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1389 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1390 SILCTXT_FILE_REQUEST, client_entry->nickname);
1392 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1393 SILCTXT_FILE_REQUEST_HOST,
1394 client_entry->nickname, hostname, portstr);
1397 /* SILC client operations */
1398 SilcClientOperations ops = {
1400 silc_channel_message,
1401 silc_private_message,
1407 silc_get_auth_method,
1408 silc_verify_public_key,
1409 silc_ask_passphrase,