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. */
98 SilcChannelUser chu = silc_client_on_channel(channel, sender);
100 nick = silc_nicklist_insert(chanrec, chu, FALSE);
103 if (flags & SILC_MESSAGE_FLAG_ACTION)
104 printformat_module("fe-common/silc", server, channel->channel_name,
105 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
106 nick == NULL ? "[<unknown>]" : nick->nick, msg);
107 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
108 printformat_module("fe-common/silc", server, channel->channel_name,
109 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
110 nick == NULL ? "[<unknown>]" : nick->nick, msg);
112 signal_emit("message public", 6, server, msg,
113 nick == NULL ? "[<unknown>]" : nick->nick,
114 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
115 chanrec->name, nick);
118 /* Private message to the client. The `sender' is the nickname of the
119 sender received in the packet. */
121 void silc_private_message(SilcClient client, SilcClientConnection conn,
122 SilcClientEntry sender, SilcMessageFlags flags,
125 SILC_SERVER_REC *server;
128 SILC_LOG_DEBUG(("Start"));
130 server = conn == NULL ? NULL : conn->context;
131 memset(userhost, 0, sizeof(userhost));
132 if (sender->username)
133 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
134 sender->username, sender->hostname);
135 signal_emit("message private", 4, server, msg,
136 sender->nickname ? sender->nickname : "[<unknown>]",
137 sender->username ? userhost : NULL);
140 /* Notify message to the client. The notify arguments are sent in the
141 same order as servers sends them. The arguments are same as received
142 from the server except for ID's. If ID is received application receives
143 the corresponding entry to the ID. For example, if Client ID is received
144 application receives SilcClientEntry. Also, if the notify type is
145 for channel the channel entry is sent to application (even if server
146 does not send it). */
153 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
154 static NOTIFY_REC notifies[] = {
155 { SILC_NOTIFY_TYPE_NONE, NULL },
156 { SILC_NOTIFY_TYPE_INVITE, "invite" },
157 { SILC_NOTIFY_TYPE_JOIN, "join" },
158 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
159 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
160 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
161 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
162 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
163 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
164 { SILC_NOTIFY_TYPE_MOTD, "motd" },
165 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
166 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
167 { SILC_NOTIFY_TYPE_KICKED, "kick" },
168 { SILC_NOTIFY_TYPE_KILLED, "kill" },
169 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
170 { SILC_NOTIFY_TYPE_BAN, "ban" },
173 void silc_notify(SilcClient client, SilcClientConnection conn,
174 SilcNotifyType type, ...)
176 SILC_SERVER_REC *server;
179 SILC_LOG_DEBUG(("Start"));
181 server = conn == NULL ? NULL : conn->context;
184 if (type == SILC_NOTIFY_TYPE_NONE) {
185 /* Some generic notice from server */
186 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
187 } else if (type < MAX_NOTIFY) {
188 /* Send signal about the notify event */
190 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
191 signal_emit(signal, 2, server, va);
194 printformat_module("fe-common/silc", server, NULL,
195 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
201 /* Called to indicate that connection was either successfully established
202 or connecting failed. This is also the first time application receives
203 the SilcClientConnection object which it should save somewhere. */
205 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
207 SILC_SERVER_REC *server = conn->context;
209 if (!server && !success) {
210 silc_client_close_connection(client, NULL, conn);
215 server->connected = TRUE;
216 signal_emit("event connected", 1, server);
218 server->connection_lost = TRUE;
220 server->conn->context = NULL;
221 server_disconnect(SERVER(server));
225 /* Called to indicate that connection was disconnected to the server. */
227 void silc_disconnect(SilcClient client, SilcClientConnection conn)
229 SILC_SERVER_REC *server = conn->context;
231 SILC_LOG_DEBUG(("Start"));
234 nicklist_rename_unique(SERVER(server),
235 server->conn->local_entry, server->nick,
236 server->conn->local_entry,
237 silc_client->username);
238 silc_change_nick(server, silc_client->username);
241 server->conn->context = NULL;
243 server->connection_lost = TRUE;
244 server_disconnect(SERVER(server));
247 /* Command handler. This function is called always in the command function.
248 If error occurs it will be called as well. `conn' is the associated
249 client connection. `cmd_context' is the command context that was
250 originally sent to the command. `success' is FALSE if error occured
251 during command. `command' is the command being processed. It must be
252 noted that this is not reply from server. This is merely called just
253 after application has called the command. Just to tell application
254 that the command really was processed. */
256 void silc_command(SilcClient client, SilcClientConnection conn,
257 SilcClientCommandContext cmd_context, int success,
260 SILC_SERVER_REC *server = conn->context;
262 SILC_LOG_DEBUG(("Start"));
268 case SILC_COMMAND_INVITE:
269 printformat_module("fe-common/silc", server, NULL,
270 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
271 cmd_context->argv[2],
272 (cmd_context->argv[1][0] == '*' ?
273 (char *)conn->current_channel->channel_name :
274 (char *)cmd_context->argv[1]));
281 /* Client info resolving callback when JOIN command reply is received.
282 This will cache all users on the channel. */
284 static void silc_client_join_get_users(SilcClient client,
285 SilcClientConnection conn,
286 SilcClientEntry *clients,
287 uint32 clients_count,
290 SilcChannelEntry channel = (SilcChannelEntry)context;
291 SilcHashTableList htl;
293 SILC_SERVER_REC *server = conn->context;
294 SILC_CHANNEL_REC *chanrec;
295 SilcClientEntry founder = NULL;
301 chanrec = silc_channel_find(server, channel->channel_name);
305 silc_hash_table_list(channel->user_list, &htl);
306 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
307 if (!chu->client->nickname)
309 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
310 founder = chu->client;
311 silc_nicklist_insert(chanrec, chu, FALSE);
313 silc_hash_table_list_reset(&htl);
315 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
316 nicklist_set_own(CHANNEL(chanrec), ownnick);
317 signal_emit("channel joined", 1, chanrec);
320 printformat_module("fe-common/silc", server, channel->channel_name,
321 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
322 channel->channel_name, chanrec->topic);
324 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
327 if (founder == conn->local_entry)
328 printformat_module("fe-common/silc",
329 server, channel->channel_name, MSGLEVEL_CRAP,
330 SILCTXT_CHANNEL_FOUNDER_YOU,
331 channel->channel_name);
333 printformat_module("fe-common/silc",
334 server, channel->channel_name, MSGLEVEL_CRAP,
335 SILCTXT_CHANNEL_FOUNDER,
336 channel->channel_name, founder->nickname);
342 SilcClientConnection conn;
348 void silc_getkey_cb(bool success, void *context)
350 GetkeyContext getkey = (GetkeyContext)context;
351 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
352 char *name = (getkey->id_type == SILC_ID_CLIENT ?
353 ((SilcClientEntry)getkey->entry)->nickname :
354 ((SilcServerEntry)getkey->entry)->server_name);
357 printformat_module("fe-common/silc", NULL, NULL,
358 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
360 printformat_module("fe-common/silc", NULL, NULL,
361 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
364 silc_free(getkey->fingerprint);
368 /* Command reply handler. This function is called always in the command reply
369 function. If error occurs it will be called as well. Normal scenario
370 is that it will be called after the received command data has been parsed
371 and processed. The function is used to pass the received command data to
374 `conn' is the associated client connection. `cmd_payload' is the command
375 payload data received from server and it can be ignored. It is provided
376 if the application would like to re-parse the received command data,
377 however, it must be noted that the data is parsed already by the library
378 thus the payload can be ignored. `success' is FALSE if error occured.
379 In this case arguments are not sent to the application. `command' is the
380 command reply being processed. The function has variable argument list
381 and each command defines the number and type of arguments it passes to the
382 application (on error they are not sent). */
385 silc_command_reply(SilcClient client, SilcClientConnection conn,
386 SilcCommandPayload cmd_payload, int success,
387 SilcCommand command, SilcCommandStatus status, ...)
390 SILC_SERVER_REC *server = conn->context;
391 SILC_CHANNEL_REC *chanrec;
394 va_start(vp, status);
396 SILC_LOG_DEBUG(("Start"));
399 case SILC_COMMAND_WHOIS:
401 char buf[1024], *nickname, *username, *realname, *nick;
402 unsigned char *fingerprint;
405 SilcClientEntry client_entry;
407 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
408 /* Print the unknown nick for user */
410 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
413 silc_say_error("%s: %s", tmp,
414 silc_client_command_status_message(status));
416 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
417 /* Try to find the entry for the unknown client ID, since we
418 might have, and print the nickname of it for user. */
421 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
424 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
426 client_entry = silc_client_get_client_by_id(client, conn,
428 if (client_entry && client_entry->nickname)
429 silc_say_error("%s: %s", client_entry->nickname,
430 silc_client_command_status_message(status));
431 silc_free(client_id);
440 client_entry = va_arg(vp, SilcClientEntry);
441 nickname = va_arg(vp, char *);
442 username = va_arg(vp, char *);
443 realname = va_arg(vp, char *);
444 channels = va_arg(vp, SilcBuffer);
445 mode = va_arg(vp, uint32);
446 idle = va_arg(vp, uint32);
447 fingerprint = va_arg(vp, unsigned char *);
449 silc_parse_userfqdn(nickname, &nick, NULL);
450 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
451 SILCTXT_WHOIS_USERINFO, nickname,
452 client_entry->username, client_entry->hostname,
453 nick, client_entry->nickname);
454 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
455 SILCTXT_WHOIS_REALNAME, realname);
459 SilcDList list = silc_channel_payload_parse_list(channels->data,
462 SilcChannelPayload entry;
463 memset(buf, 0, sizeof(buf));
464 silc_dlist_start(list);
465 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
466 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
468 char *name = silc_channel_get_name(entry, &name_len);
471 strncat(buf, m, strlen(m));
472 strncat(buf, name, name_len);
473 strncat(buf, " ", 1);
477 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
478 SILCTXT_WHOIS_CHANNELS, buf);
479 silc_channel_payload_list_free(list);
484 memset(buf, 0, sizeof(buf));
486 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
487 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
488 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
490 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
491 "SILC Operator " : "[Unknown mode] ");
493 if (mode & SILC_UMODE_GONE)
496 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
497 SILCTXT_WHOIS_MODES, buf);
500 if (idle && nickname) {
501 memset(buf, 0, sizeof(buf));
502 snprintf(buf, sizeof(buf) - 1, "%lu %s",
503 idle > 60 ? (idle / 60) : idle,
504 idle > 60 ? "minutes" : "seconds");
506 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
507 SILCTXT_WHOIS_IDLE, buf);
511 fingerprint = silc_fingerprint(fingerprint, 20);
512 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
513 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
514 silc_free(fingerprint);
519 case SILC_COMMAND_IDENTIFY:
521 SilcClientEntry client_entry;
523 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
524 /* Print the unknown nick for user */
526 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
529 silc_say_error("%s: %s", tmp,
530 silc_client_command_status_message(status));
532 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
533 /* Try to find the entry for the unknown client ID, since we
534 might have, and print the nickname of it for user. */
537 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
540 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
542 client_entry = silc_client_get_client_by_id(client, conn,
544 if (client_entry && client_entry->nickname)
545 silc_say_error("%s: %s", client_entry->nickname,
546 silc_client_command_status_message(status));
547 silc_free(client_id);
556 case SILC_COMMAND_WHOWAS:
558 char *nickname, *username, *realname;
560 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
561 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
563 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
566 silc_say_error("%s: %s", tmp,
567 silc_client_command_status_message(status));
574 (void)va_arg(vp, SilcClientEntry);
575 nickname = va_arg(vp, char *);
576 username = va_arg(vp, char *);
577 realname = va_arg(vp, char *);
579 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
580 SILCTXT_WHOWAS_USERINFO, nickname, username,
581 realname ? realname : "");
585 case SILC_COMMAND_INVITE:
587 SilcChannelEntry channel;
589 SilcArgumentPayload args;
595 channel = va_arg(vp, SilcChannelEntry);
596 invite_list = va_arg(vp, char *);
598 args = silc_command_get_args(cmd_payload);
600 argc = silc_argument_get_arg_num(args);
603 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
604 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
607 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
608 SILCTXT_CHANNEL_NO_INVITE_LIST,
609 channel->channel_name);
613 case SILC_COMMAND_JOIN:
615 char *channel, *mode, *topic;
617 SilcChannelEntry channel_entry;
618 SilcBuffer client_id_list;
624 channel = va_arg(vp, char *);
625 channel_entry = va_arg(vp, SilcChannelEntry);
626 modei = va_arg(vp, uint32);
627 (void)va_arg(vp, uint32);
628 (void)va_arg(vp, unsigned char *);
629 (void)va_arg(vp, unsigned char *);
630 (void)va_arg(vp, unsigned char *);
631 topic = va_arg(vp, char *);
632 (void)va_arg(vp, unsigned char *);
633 list_count = va_arg(vp, uint32);
634 client_id_list = va_arg(vp, SilcBuffer);
636 chanrec = silc_channel_find(server, channel);
638 chanrec = silc_channel_create(server, channel, TRUE);
641 g_free_not_null(chanrec->topic);
642 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
643 signal_emit("channel topic changed", 1, chanrec);
646 mode = silc_client_chmode(modei,
647 channel_entry->channel_key ?
648 channel_entry->channel_key->cipher->name : "",
649 channel_entry->hmac ?
650 silc_hmac_get_name(channel_entry->hmac) : "");
651 g_free_not_null(chanrec->mode);
652 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
653 signal_emit("channel mode changed", 1, chanrec);
655 /* Resolve the client information */
656 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
657 silc_client_join_get_users,
662 case SILC_COMMAND_NICK:
664 SilcClientEntry client = va_arg(vp, SilcClientEntry);
670 old = g_strdup(server->nick);
671 server_change_nick(SERVER(server), client->nickname);
672 nicklist_rename_unique(SERVER(server),
673 server->conn->local_entry, server->nick,
674 client, client->nickname);
676 signal_emit("message own_nick", 4, server, server->nick, old, "");
681 case SILC_COMMAND_LIST:
690 (void)va_arg(vp, SilcChannelEntry);
691 name = va_arg(vp, char *);
692 topic = va_arg(vp, char *);
693 usercount = va_arg(vp, int);
695 if (status == SILC_STATUS_LIST_START ||
696 status == SILC_STATUS_OK)
697 printformat_module("fe-common/silc", server, NULL,
698 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
701 snprintf(users, sizeof(users) - 1, "N/A");
703 snprintf(users, sizeof(users) - 1, "%d", usercount);
704 printformat_module("fe-common/silc", server, NULL,
705 MSGLEVEL_CRAP, SILCTXT_LIST,
706 name, users, topic ? topic : "");
710 case SILC_COMMAND_UMODE:
717 mode = va_arg(vp, uint32);
719 if (mode & SILC_UMODE_SERVER_OPERATOR &&
720 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
721 printformat_module("fe-common/silc", server, NULL,
722 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
724 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
725 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
726 printformat_module("fe-common/silc", server, NULL,
727 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
729 server->umode = mode;
733 case SILC_COMMAND_OPER:
737 printformat_module("fe-common/silc", server, NULL,
738 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
741 case SILC_COMMAND_SILCOPER:
745 printformat_module("fe-common/silc", server, NULL,
746 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
749 case SILC_COMMAND_USERS:
751 SilcHashTableList htl;
752 SilcChannelEntry channel;
758 channel = va_arg(vp, SilcChannelEntry);
760 printformat_module("fe-common/silc", server, channel->channel_name,
761 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
762 channel->channel_name);
764 silc_hash_table_list(channel->user_list, &htl);
765 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
766 SilcClientEntry e = chu->client;
772 memset(stat, 0, sizeof(stat));
773 mode = silc_client_chumode_char(chu->mode);
774 if (e->mode & SILC_UMODE_GONE)
781 printformat_module("fe-common/silc", server, channel->channel_name,
782 MSGLEVEL_CRAP, SILCTXT_USERS,
784 e->username ? e->username : "",
785 e->hostname ? e->hostname : "",
786 e->realname ? e->realname : "");
790 silc_hash_table_list_reset(&htl);
794 case SILC_COMMAND_BAN:
796 SilcChannelEntry channel;
802 channel = va_arg(vp, SilcChannelEntry);
803 ban_list = va_arg(vp, char *);
806 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
807 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
810 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
811 SILCTXT_CHANNEL_NO_BAN_LIST,
812 channel->channel_name);
816 case SILC_COMMAND_GETKEY:
820 SilcPublicKey public_key;
823 GetkeyContext getkey;
829 id_type = va_arg(vp, uint32);
830 entry = va_arg(vp, void *);
831 public_key = va_arg(vp, SilcPublicKey);
834 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
836 getkey = silc_calloc(1, sizeof(*getkey));
837 getkey->entry = entry;
838 getkey->id_type = id_type;
839 getkey->client = client;
841 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
843 name = (id_type == SILC_ID_CLIENT ?
844 ((SilcClientEntry)entry)->nickname :
845 ((SilcServerEntry)entry)->server_name);
847 silc_verify_public_key_internal(client, conn, name,
848 (id_type == SILC_ID_CLIENT ?
849 SILC_SOCKET_TYPE_CLIENT :
850 SILC_SOCKET_TYPE_SERVER),
851 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
852 silc_getkey_cb, getkey);
855 printformat_module("fe-common/silc", server, NULL,
856 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
861 case SILC_COMMAND_INFO:
863 SilcServerEntry server_entry;
870 server_entry = va_arg(vp, SilcServerEntry);
871 server_name = va_arg(vp, char *);
872 server_info = va_arg(vp, char *);
874 if (server_name && server_info )
876 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
877 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
882 case SILC_COMMAND_TOPIC:
884 SilcChannelEntry channel;
890 channel = va_arg(vp, SilcChannelEntry);
891 topic = va_arg(vp, char *);
894 chanrec = silc_channel_find_entry(server, channel);
896 g_free_not_null(chanrec->topic);
897 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
898 signal_emit("channel topic changed", 1, chanrec);
900 printformat_module("fe-common/silc", server, channel->channel_name,
901 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
902 channel->channel_name, topic);
904 printformat_module("fe-common/silc", server, channel->channel_name,
905 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
906 channel->channel_name);
918 SilcClientConnection conn;
924 SilcSKEPKType pk_type;
925 SilcVerifyPublicKey completion;
929 static void verify_public_key_completion(const char *line, void *context)
931 PublicKeyVerify verify = (PublicKeyVerify)context;
933 if (line[0] == 'Y' || line[0] == 'y') {
934 /* Call the completion */
935 if (verify->completion)
936 verify->completion(TRUE, verify->context);
938 /* Save the key for future checking */
939 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
940 verify->pk_len, SILC_PKCS_FILE_PEM);
942 /* Call the completion */
943 if (verify->completion)
944 verify->completion(FALSE, verify->context);
946 printformat_module("fe-common/silc", NULL, NULL,
947 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
948 verify->entity_name ? verify->entity_name :
952 silc_free(verify->filename);
953 silc_free(verify->entity);
954 silc_free(verify->entity_name);
955 silc_free(verify->pk);
959 /* Internal routine to verify public key. If the `completion' is provided
960 it will be called to indicate whether public was verified or not. For
961 server/router public key this will check for filename that includes the
962 remote host's IP address and remote host's hostname. */
965 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
966 const char *name, SilcSocketType conn_type,
967 unsigned char *pk, uint32 pk_len,
968 SilcSKEPKType pk_type,
969 SilcVerifyPublicKey completion, void *context)
972 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
973 char *fingerprint, *babbleprint, *format;
976 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
977 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
978 "server" : "client");
979 PublicKeyVerify verify;
981 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
982 printformat_module("fe-common/silc", NULL, NULL,
983 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
986 completion(FALSE, context);
990 pw = getpwuid(getuid());
993 completion(FALSE, context);
997 memset(filename, 0, sizeof(filename));
998 memset(filename2, 0, sizeof(filename2));
999 memset(file, 0, sizeof(file));
1001 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1002 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1004 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1005 conn->sock->ip, conn->sock->port);
1006 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1007 pw->pw_dir, entity, file);
1009 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1010 conn->sock->hostname, conn->sock->port);
1011 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1012 pw->pw_dir, entity, file);
1017 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1018 name, conn->sock->port);
1019 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1020 pw->pw_dir, entity, file);
1025 /* Replace all whitespaces with `_'. */
1026 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1027 for (i = 0; i < strlen(fingerprint); i++)
1028 if (fingerprint[i] == ' ')
1029 fingerprint[i] = '_';
1031 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1032 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1033 pw->pw_dir, entity, file);
1034 silc_free(fingerprint);
1039 /* Take fingerprint of the public key */
1040 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1041 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1043 verify = silc_calloc(1, sizeof(*verify));
1044 verify->client = client;
1045 verify->conn = conn;
1046 verify->filename = strdup(ipf);
1047 verify->entity = strdup(entity);
1048 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1049 (name ? strdup(name) : strdup(conn->sock->hostname))
1051 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1052 memcpy(verify->pk, pk, pk_len);
1053 verify->pk_len = pk_len;
1054 verify->pk_type = pk_type;
1055 verify->completion = completion;
1056 verify->context = context;
1058 /* Check whether this key already exists */
1059 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1060 /* Key does not exist, ask user to verify the key and save it */
1062 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1063 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1064 verify->entity_name : entity);
1065 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1066 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1067 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1068 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1069 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1070 SILCTXT_PUBKEY_ACCEPT);
1071 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1074 silc_free(fingerprint);
1077 /* The key already exists, verify it. */
1078 SilcPublicKey public_key;
1079 unsigned char *encpk;
1082 /* Load the key file, try for both IP filename and hostname filename */
1083 if (!silc_pkcs_load_public_key(ipf, &public_key,
1084 SILC_PKCS_FILE_PEM) &&
1085 !silc_pkcs_load_public_key(ipf, &public_key,
1086 SILC_PKCS_FILE_BIN) &&
1087 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1088 SILC_PKCS_FILE_PEM) &&
1089 !silc_pkcs_load_public_key(hostf, &public_key,
1090 SILC_PKCS_FILE_BIN)))) {
1091 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1092 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1093 verify->entity_name : entity);
1094 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1095 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1096 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1097 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1098 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1099 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1100 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1101 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1102 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1105 silc_free(fingerprint);
1109 /* Encode the key data */
1110 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1112 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1113 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1114 verify->entity_name : entity);
1115 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1116 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1117 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1118 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1119 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1120 SILCTXT_PUBKEY_MALFORMED, entity);
1121 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1122 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1123 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1126 silc_free(fingerprint);
1130 /* Compare the keys */
1131 if (memcmp(encpk, pk, encpk_len)) {
1132 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1133 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1134 verify->entity_name : entity);
1135 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1136 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1137 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1138 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1139 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1140 SILCTXT_PUBKEY_NO_MATCH, entity);
1141 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1142 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1143 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1144 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1146 /* Ask user to verify the key and save it */
1147 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1148 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1149 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1152 silc_free(fingerprint);
1156 /* Local copy matched */
1158 completion(TRUE, context);
1159 silc_free(fingerprint);
1163 /* Verifies received public key. The `conn_type' indicates which entity
1164 (server, client etc.) has sent the public key. If user decides to trust
1165 the key may be saved as trusted public key for later use. The
1166 `completion' must be called after the public key has been verified. */
1169 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1170 SilcSocketType conn_type, unsigned char *pk,
1171 uint32 pk_len, SilcSKEPKType pk_type,
1172 SilcVerifyPublicKey completion, void *context)
1174 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1176 completion, context);
1179 /* Asks passphrase from user on the input line. */
1182 SilcAskPassphrase completion;
1186 void ask_passphrase_completion(const char *passphrase, void *context)
1188 AskPassphrase p = (AskPassphrase)context;
1189 p->completion((unsigned char *)passphrase,
1190 passphrase ? strlen(passphrase) : 0, p->context);
1194 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1195 SilcAskPassphrase completion, void *context)
1197 AskPassphrase p = silc_calloc(1, sizeof(*p));
1198 p->completion = completion;
1199 p->context = context;
1201 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1202 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1206 SilcGetAuthMeth completion;
1208 } *InternalGetAuthMethod;
1210 /* Callback called when we've received the authentication method information
1211 from the server after we've requested it. This will get the authentication
1212 data from the user if needed. */
1214 static void silc_get_auth_method_callback(SilcClient client,
1215 SilcClientConnection conn,
1216 SilcAuthMethod auth_meth,
1219 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1221 SILC_LOG_DEBUG(("Start"));
1223 switch (auth_meth) {
1224 case SILC_AUTH_NONE:
1225 /* No authentication required. */
1226 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1228 case SILC_AUTH_PASSWORD:
1229 /* Do not ask the passphrase from user, the library will ask it if
1230 we do not provide it here. */
1231 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1233 case SILC_AUTH_PUBLIC_KEY:
1234 /* Do not get the authentication data now, the library will generate
1235 it using our default key, if we do not provide it here. */
1236 /* XXX In the future when we support multiple local keys and multiple
1237 local certificates we will need to ask from user which one to use. */
1238 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1242 silc_free(internal);
1245 /* Find authentication method and authentication data by hostname and
1246 port. The hostname may be IP address as well. The found authentication
1247 method and authentication data is returned to `auth_meth', `auth_data'
1248 and `auth_data_len'. The function returns TRUE if authentication method
1249 is found and FALSE if not. `conn' may be NULL. */
1251 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1252 char *hostname, uint16 port,
1253 SilcGetAuthMeth completion, void *context)
1255 InternalGetAuthMethod internal;
1257 SILC_LOG_DEBUG(("Start"));
1259 /* XXX must resolve from configuration whether this connection has
1260 any specific authentication data */
1262 /* If we do not have this connection configured by the user in a
1263 configuration file then resolve the authentication method from the
1264 server for this session. */
1265 internal = silc_calloc(1, sizeof(*internal));
1266 internal->completion = completion;
1267 internal->context = context;
1269 silc_client_request_authentication_method(client, conn,
1270 silc_get_auth_method_callback,
1274 /* Notifies application that failure packet was received. This is called
1275 if there is some protocol active in the client. The `protocol' is the
1276 protocol context. The `failure' is opaque pointer to the failure
1277 indication. Note, that the `failure' is protocol dependant and application
1278 must explicitly cast it to correct type. Usually `failure' is 32 bit
1279 failure type (see protocol specs for all protocol failure types). */
1281 void silc_failure(SilcClient client, SilcClientConnection conn,
1282 SilcProtocol protocol, void *failure)
1284 SILC_LOG_DEBUG(("Start"));
1286 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1287 SilcSKEStatus status = (SilcSKEStatus)failure;
1289 if (status == SILC_SKE_STATUS_BAD_VERSION)
1290 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1291 SILCTXT_KE_BAD_VERSION);
1292 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1293 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1294 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1295 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1296 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1297 SILCTXT_KE_UNKNOWN_GROUP);
1298 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1299 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1300 SILCTXT_KE_UNKNOWN_CIPHER);
1301 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1302 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1303 SILCTXT_KE_UNKNOWN_PKCS);
1304 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1305 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1306 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1307 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1308 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1309 SILCTXT_KE_UNKNOWN_HMAC);
1310 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1311 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1312 SILCTXT_KE_INCORRECT_SIGNATURE);
1313 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1314 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1315 SILCTXT_KE_INVALID_COOKIE);
1318 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1319 uint32 err = (uint32)failure;
1321 if (err == SILC_AUTH_FAILED)
1322 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1323 SILCTXT_AUTH_FAILED);
1327 /* Asks whether the user would like to perform the key agreement protocol.
1328 This is called after we have received an key agreement packet or an
1329 reply to our key agreement packet. This returns TRUE if the user wants
1330 the library to perform the key agreement protocol and FALSE if it is not
1331 desired (application may start it later by calling the function
1332 silc_client_perform_key_agreement). */
1334 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1335 SilcClientEntry client_entry, const char *hostname,
1336 uint16 port, SilcKeyAgreementCallback *completion,
1341 SILC_LOG_DEBUG(("Start"));
1343 /* We will just display the info on the screen and return FALSE and user
1344 will have to start the key agreement with a command. */
1347 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1350 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1351 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1353 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1354 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1355 client_entry->nickname, hostname, portstr);
1363 void silc_ftp(SilcClient client, SilcClientConnection conn,
1364 SilcClientEntry client_entry, uint32 session_id,
1365 const char *hostname, uint16 port)
1367 SILC_SERVER_REC *server;
1369 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1371 SILC_LOG_DEBUG(("Start"));
1373 server = conn->context;
1375 ftp->client_entry = client_entry;
1376 ftp->session_id = session_id;
1379 silc_dlist_add(server->ftp_sessions, ftp);
1380 server->current_session = ftp;
1383 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1386 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1387 SILCTXT_FILE_REQUEST, client_entry->nickname);
1389 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1390 SILCTXT_FILE_REQUEST_HOST,
1391 client_entry->nickname, hostname, portstr);
1394 /* SILC client operations */
1395 SilcClientOperations ops = {
1397 silc_channel_message,
1398 silc_private_message,
1404 silc_get_auth_method,
1405 silc_verify_public_key,
1406 silc_ask_passphrase,