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 SilcSocketType conn_type, unsigned char *pk,
44 uint32 pk_len, SilcSKEPKType pk_type,
45 SilcVerifyPublicKey completion, void *context);
47 void silc_say(SilcClient client, SilcClientConnection conn,
48 SilcClientMessageType type, char *msg, ...)
50 SILC_SERVER_REC *server;
54 server = conn == NULL ? NULL : conn->context;
57 str = g_strdup_vprintf(msg, va);
58 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
63 void silc_say_error(char *msg, ...)
69 str = g_strdup_vprintf(msg, va);
70 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
76 /* Message for a channel. The `sender' is the nickname of the sender
77 received in the packet. The `channel_name' is the name of the channel. */
79 void silc_channel_message(SilcClient client, SilcClientConnection conn,
80 SilcClientEntry sender, SilcChannelEntry channel,
81 SilcMessageFlags flags, char *msg)
83 SILC_SERVER_REC *server;
85 SILC_CHANNEL_REC *chanrec;
87 SILC_LOG_DEBUG(("Start"));
89 server = conn == NULL ? NULL : conn->context;
90 chanrec = silc_channel_find_entry(server, channel);
94 nick = silc_nicklist_find(chanrec, sender);
96 /* We didn't find client but it clearly exists, add it. It must be
97 found on the channel->clients list. */
100 silc_list_start(channel->clients);
101 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
102 if (chu->client == sender) {
103 nick = silc_nicklist_insert(chanrec, chu, FALSE);
109 if (flags & SILC_MESSAGE_FLAG_ACTION)
110 printformat_module("fe-common/silc", server, channel->channel_name,
111 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
112 nick == NULL ? "[<unknown>]" : nick->nick, msg);
113 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
114 printformat_module("fe-common/silc", server, channel->channel_name,
115 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
116 nick == NULL ? "[<unknown>]" : nick->nick, msg);
118 signal_emit("message public", 6, server, msg,
119 nick == NULL ? "[<unknown>]" : nick->nick,
120 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
121 chanrec->name, nick);
124 /* Private message to the client. The `sender' is the nickname of the
125 sender received in the packet. */
127 void silc_private_message(SilcClient client, SilcClientConnection conn,
128 SilcClientEntry sender, SilcMessageFlags flags,
131 SILC_SERVER_REC *server;
134 SILC_LOG_DEBUG(("Start"));
136 server = conn == NULL ? NULL : conn->context;
137 memset(userhost, 0, sizeof(userhost));
138 if (sender->username)
139 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
140 sender->username, sender->hostname);
141 signal_emit("message private", 4, server, msg,
142 sender->nickname ? sender->nickname : "[<unknown>]",
143 sender->username ? userhost : NULL);
146 /* Notify message to the client. The notify arguments are sent in the
147 same order as servers sends them. The arguments are same as received
148 from the server except for ID's. If ID is received application receives
149 the corresponding entry to the ID. For example, if Client ID is received
150 application receives SilcClientEntry. Also, if the notify type is
151 for channel the channel entry is sent to application (even if server
152 does not send it). */
159 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
160 static NOTIFY_REC notifies[] = {
161 { SILC_NOTIFY_TYPE_NONE, NULL },
162 { SILC_NOTIFY_TYPE_INVITE, "invite" },
163 { SILC_NOTIFY_TYPE_JOIN, "join" },
164 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
165 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
166 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
167 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
168 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
169 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
170 { SILC_NOTIFY_TYPE_MOTD, "motd" },
171 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
172 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
173 { SILC_NOTIFY_TYPE_KICKED, "kick" },
174 { SILC_NOTIFY_TYPE_KILLED, "kill" },
175 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
176 { SILC_NOTIFY_TYPE_BAN, "ban" },
179 void silc_notify(SilcClient client, SilcClientConnection conn,
180 SilcNotifyType type, ...)
182 SILC_SERVER_REC *server;
185 SILC_LOG_DEBUG(("Start"));
187 server = conn == NULL ? NULL : conn->context;
190 if (type == SILC_NOTIFY_TYPE_NONE) {
191 /* Some generic notice from server */
192 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
193 } else if (type < MAX_NOTIFY) {
194 /* Send signal about the notify event */
196 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
197 signal_emit(signal, 2, server, va);
200 printformat_module("fe-common/silc", server, NULL,
201 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
207 /* Called to indicate that connection was either successfully established
208 or connecting failed. This is also the first time application receives
209 the SilcClientConnection object which it should save somewhere. */
211 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
213 SILC_SERVER_REC *server = conn->context;
215 if (!server && !success) {
216 silc_client_close_connection(client, NULL, conn);
221 server->connected = TRUE;
222 signal_emit("event connected", 1, server);
224 server->connection_lost = TRUE;
225 server->conn->context = NULL;
226 server_disconnect(SERVER(server));
230 /* Called to indicate that connection was disconnected to the server. */
232 void silc_disconnect(SilcClient client, SilcClientConnection conn)
234 SILC_SERVER_REC *server = conn->context;
236 SILC_LOG_DEBUG(("Start"));
239 nicklist_rename_unique(SERVER(server),
240 server->conn->local_entry, server->nick,
241 server->conn->local_entry,
242 silc_client->username);
243 silc_change_nick(server, silc_client->username);
246 server->conn->context = NULL;
248 server->connection_lost = TRUE;
249 server_disconnect(SERVER(server));
252 /* Command handler. This function is called always in the command function.
253 If error occurs it will be called as well. `conn' is the associated
254 client connection. `cmd_context' is the command context that was
255 originally sent to the command. `success' is FALSE if error occured
256 during command. `command' is the command being processed. It must be
257 noted that this is not reply from server. This is merely called just
258 after application has called the command. Just to tell application
259 that the command really was processed. */
261 void silc_command(SilcClient client, SilcClientConnection conn,
262 SilcClientCommandContext cmd_context, int success,
265 SILC_SERVER_REC *server = conn->context;
267 SILC_LOG_DEBUG(("Start"));
273 case SILC_COMMAND_INVITE:
274 printformat_module("fe-common/silc", server, NULL,
275 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
276 cmd_context->argv[2],
277 (cmd_context->argv[1][0] == '*' ?
278 (char *)conn->current_channel->channel_name :
279 (char *)cmd_context->argv[1]));
286 /* Client info resolving callback when JOIN command reply is received.
287 This will cache all users on the channel. */
289 static void silc_client_join_get_users(SilcClient client,
290 SilcClientConnection conn,
291 SilcClientEntry *clients,
292 uint32 clients_count,
295 SilcChannelEntry channel = (SilcChannelEntry)context;
297 SILC_SERVER_REC *server = conn->context;
298 SILC_CHANNEL_REC *chanrec;
299 SilcClientEntry founder = NULL;
305 chanrec = silc_channel_find(server, channel->channel_name);
309 silc_list_start(channel->clients);
310 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
311 if (!chu->client->nickname)
313 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
314 founder = chu->client;
315 silc_nicklist_insert(chanrec, chu, FALSE);
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,
665 case SILC_COMMAND_NICK:
667 SilcClientEntry client = va_arg(vp, SilcClientEntry);
673 old = g_strdup(server->nick);
674 server_change_nick(SERVER(server), client->nickname);
675 nicklist_rename_unique(SERVER(server),
676 server->conn->local_entry, server->nick,
677 client, client->nickname);
679 signal_emit("message own_nick", 4, server, server->nick, old, "");
684 case SILC_COMMAND_LIST:
693 (void)va_arg(vp, SilcChannelEntry);
694 name = va_arg(vp, char *);
695 topic = va_arg(vp, char *);
696 usercount = va_arg(vp, int);
698 if (status == SILC_STATUS_LIST_START ||
699 status == SILC_STATUS_OK)
700 printformat_module("fe-common/silc", server, NULL,
701 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
704 snprintf(users, sizeof(users) - 1, "N/A");
706 snprintf(users, sizeof(users) - 1, "%d", usercount);
707 printformat_module("fe-common/silc", server, NULL,
708 MSGLEVEL_CRAP, SILCTXT_LIST,
709 name, users, topic ? topic : "");
713 case SILC_COMMAND_UMODE:
720 mode = va_arg(vp, uint32);
722 if (mode & SILC_UMODE_SERVER_OPERATOR &&
723 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
724 printformat_module("fe-common/silc", server, NULL,
725 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
727 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
728 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
729 printformat_module("fe-common/silc", server, NULL,
730 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
732 server->umode = mode;
736 case SILC_COMMAND_OPER:
740 printformat_module("fe-common/silc", server, NULL,
741 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
744 case SILC_COMMAND_SILCOPER:
748 printformat_module("fe-common/silc", server, NULL,
749 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
752 case SILC_COMMAND_USERS:
754 SilcChannelEntry channel;
760 channel = va_arg(vp, SilcChannelEntry);
762 printformat_module("fe-common/silc", server, channel->channel_name,
763 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
764 channel->channel_name);
766 silc_list_start(channel->clients);
767 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
768 SilcClientEntry e = chu->client;
774 memset(stat, 0, sizeof(stat));
775 mode = silc_client_chumode_char(chu->mode);
776 if (e->mode & SILC_UMODE_GONE)
783 printformat_module("fe-common/silc", server, channel->channel_name,
784 MSGLEVEL_CRAP, SILCTXT_USERS,
786 e->username ? e->username : "",
787 e->hostname ? e->hostname : "",
788 e->realname ? e->realname : "");
795 case SILC_COMMAND_BAN:
797 SilcChannelEntry channel;
803 channel = va_arg(vp, SilcChannelEntry);
804 ban_list = va_arg(vp, char *);
807 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
808 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
811 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
812 SILCTXT_CHANNEL_NO_BAN_LIST,
813 channel->channel_name);
817 case SILC_COMMAND_GETKEY:
821 SilcPublicKey public_key;
824 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 silc_verify_public_key_internal(client, conn,
844 (id_type == SILC_ID_CLIENT ?
845 SILC_SOCKET_TYPE_CLIENT :
846 SILC_SOCKET_TYPE_SERVER),
847 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
848 silc_getkey_cb, getkey);
851 printformat_module("fe-common/silc", server, NULL,
852 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
857 case SILC_COMMAND_INFO:
859 SilcServerEntry server_entry;
866 server_entry = va_arg(vp, SilcServerEntry);
867 server_name = va_arg(vp, char *);
868 server_info = va_arg(vp, char *);
870 if (server_name && server_info )
872 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
873 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
878 case SILC_COMMAND_TOPIC:
880 SilcChannelEntry channel;
886 channel = va_arg(vp, SilcChannelEntry);
887 topic = va_arg(vp, char *);
890 chanrec = silc_channel_find_entry(server, channel);
892 g_free_not_null(chanrec->topic);
893 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
894 signal_emit("channel topic changed", 1, chanrec);
896 printformat_module("fe-common/silc", server, channel->channel_name,
897 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
898 channel->channel_name, topic);
900 printformat_module("fe-common/silc", server, channel->channel_name,
901 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
902 channel->channel_name);
912 /* Internal routine to verify public key. If the `completion' is provided
913 it will be called to indicate whether public was verified or not. */
917 SilcClientConnection conn;
922 SilcSKEPKType pk_type;
923 SilcVerifyPublicKey completion;
927 static void verify_public_key_completion(const char *line, void *context)
929 PublicKeyVerify verify = (PublicKeyVerify)context;
931 if (line[0] == 'Y' || line[0] == 'y') {
932 /* Call the completion */
933 if (verify->completion)
934 verify->completion(TRUE, verify->context);
936 /* Save the key for future checking */
937 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
938 verify->pk_len, SILC_PKCS_FILE_PEM);
940 /* Call the completion */
941 if (verify->completion)
942 verify->completion(FALSE, verify->context);
944 printformat_module("fe-common/silc", NULL, NULL,
945 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
948 silc_free(verify->filename);
949 silc_free(verify->entity);
950 silc_free(verify->pk);
955 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
956 SilcSocketType conn_type, unsigned char *pk,
957 uint32 pk_len, SilcSKEPKType pk_type,
958 SilcVerifyPublicKey completion, void *context)
961 char file[256], filename[256], *fingerprint, *babbleprint, *format;
964 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
965 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
966 "server" : "client");
967 PublicKeyVerify verify;
969 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
970 printformat_module("fe-common/silc", NULL, NULL,
971 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
974 completion(FALSE, context);
978 pw = getpwuid(getuid());
981 completion(FALSE, context);
985 memset(filename, 0, sizeof(filename));
986 memset(file, 0, sizeof(file));
988 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
989 conn_type == SILC_SOCKET_TYPE_ROUTER) {
990 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
991 conn->sock->ip, conn->sock->port);
992 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
993 pw->pw_dir, entity, file);
995 /* Replace all whitespaces with `_'. */
996 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
997 for (i = 0; i < strlen(fingerprint); i++)
998 if (fingerprint[i] == ' ')
999 fingerprint[i] = '_';
1001 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1002 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1003 pw->pw_dir, entity, file);
1004 silc_free(fingerprint);
1007 /* Take fingerprint of the public key */
1008 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1009 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1011 verify = silc_calloc(1, sizeof(*verify));
1012 verify->client = client;
1013 verify->conn = conn;
1014 verify->filename = strdup(filename);
1015 verify->entity = strdup(entity);
1016 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1017 memcpy(verify->pk, pk, pk_len);
1018 verify->pk_len = pk_len;
1019 verify->pk_type = pk_type;
1020 verify->completion = completion;
1021 verify->context = context;
1023 /* Check whether this key already exists */
1024 if (stat(filename, &st) < 0) {
1025 /* Key does not exist, ask user to verify the key and save it */
1027 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1028 SILCTXT_PUBKEY_RECEIVED, entity);
1029 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1030 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1031 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1032 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1033 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1034 SILCTXT_PUBKEY_ACCEPT);
1035 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1038 silc_free(fingerprint);
1041 /* The key already exists, verify it. */
1042 SilcPublicKey public_key;
1043 unsigned char *encpk;
1046 /* Load the key file */
1047 if (!silc_pkcs_load_public_key(filename, &public_key,
1048 SILC_PKCS_FILE_PEM))
1049 if (!silc_pkcs_load_public_key(filename, &public_key,
1050 SILC_PKCS_FILE_BIN)) {
1051 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1052 SILCTXT_PUBKEY_RECEIVED, entity);
1053 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1054 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1055 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1056 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1057 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1058 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1059 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1060 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1061 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1064 silc_free(fingerprint);
1068 /* Encode the key data */
1069 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1071 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1072 SILCTXT_PUBKEY_RECEIVED, entity);
1073 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1074 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1075 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1076 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1077 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1078 SILCTXT_PUBKEY_MALFORMED, entity);
1079 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1080 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1081 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1084 silc_free(fingerprint);
1088 /* Compare the keys */
1089 if (memcmp(encpk, pk, encpk_len)) {
1090 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1091 SILCTXT_PUBKEY_RECEIVED, entity);
1092 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1093 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1094 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1095 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1096 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1097 SILCTXT_PUBKEY_NO_MATCH, entity);
1098 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1099 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1100 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1101 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1103 /* Ask user to verify the key and save it */
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 /* Local copy matched */
1115 completion(TRUE, context);
1116 silc_free(fingerprint);
1120 /* Verifies received public key. The `conn_type' indicates which entity
1121 (server, client etc.) has sent the public key. If user decides to trust
1122 the key may be saved as trusted public key for later use. The
1123 `completion' must be called after the public key has been verified. */
1126 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1127 SilcSocketType conn_type, unsigned char *pk,
1128 uint32 pk_len, SilcSKEPKType pk_type,
1129 SilcVerifyPublicKey completion, void *context)
1131 silc_verify_public_key_internal(client, conn, conn_type, pk,
1133 completion, context);
1136 /* Asks passphrase from user on the input line. */
1139 SilcAskPassphrase completion;
1143 void ask_passphrase_completion(const char *passphrase, void *context)
1145 AskPassphrase p = (AskPassphrase)context;
1146 p->completion((unsigned char *)passphrase,
1147 passphrase ? strlen(passphrase) : 0, p->context);
1151 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1152 SilcAskPassphrase completion, void *context)
1154 AskPassphrase p = silc_calloc(1, sizeof(*p));
1155 p->completion = completion;
1156 p->context = context;
1158 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1159 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1163 SilcGetAuthMeth completion;
1165 } *InternalGetAuthMethod;
1167 /* Callback called when we've received the authentication method information
1168 from the server after we've requested it. This will get the authentication
1169 data from the user if needed. */
1171 static void silc_get_auth_method_callback(SilcClient client,
1172 SilcClientConnection conn,
1173 SilcAuthMethod auth_meth,
1176 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1178 SILC_LOG_DEBUG(("Start"));
1180 switch (auth_meth) {
1181 case SILC_AUTH_NONE:
1182 /* No authentication required. */
1183 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1185 case SILC_AUTH_PASSWORD:
1186 /* Do not ask the passphrase from user, the library will ask it if
1187 we do not provide it here. */
1188 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1190 case SILC_AUTH_PUBLIC_KEY:
1191 /* Do not get the authentication data now, the library will generate
1192 it using our default key, if we do not provide it here. */
1193 /* XXX In the future when we support multiple local keys and multiple
1194 local certificates we will need to ask from user which one to use. */
1195 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1199 silc_free(internal);
1202 /* Find authentication method and authentication data by hostname and
1203 port. The hostname may be IP address as well. The found authentication
1204 method and authentication data is returned to `auth_meth', `auth_data'
1205 and `auth_data_len'. The function returns TRUE if authentication method
1206 is found and FALSE if not. `conn' may be NULL. */
1208 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1209 char *hostname, uint16 port,
1210 SilcGetAuthMeth completion, void *context)
1212 InternalGetAuthMethod internal;
1214 SILC_LOG_DEBUG(("Start"));
1216 /* XXX must resolve from configuration whether this connection has
1217 any specific authentication data */
1219 /* If we do not have this connection configured by the user in a
1220 configuration file then resolve the authentication method from the
1221 server for this session. */
1222 internal = silc_calloc(1, sizeof(*internal));
1223 internal->completion = completion;
1224 internal->context = context;
1226 silc_client_request_authentication_method(client, conn,
1227 silc_get_auth_method_callback,
1231 /* Notifies application that failure packet was received. This is called
1232 if there is some protocol active in the client. The `protocol' is the
1233 protocol context. The `failure' is opaque pointer to the failure
1234 indication. Note, that the `failure' is protocol dependant and application
1235 must explicitly cast it to correct type. Usually `failure' is 32 bit
1236 failure type (see protocol specs for all protocol failure types). */
1238 void silc_failure(SilcClient client, SilcClientConnection conn,
1239 SilcProtocol protocol, void *failure)
1241 SILC_LOG_DEBUG(("Start"));
1243 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1244 SilcSKEStatus status = (SilcSKEStatus)failure;
1246 if (status == SILC_SKE_STATUS_BAD_VERSION)
1247 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1248 SILCTXT_KE_BAD_VERSION);
1249 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1250 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1251 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1252 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1253 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1254 SILCTXT_KE_UNKNOWN_GROUP);
1255 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1256 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1257 SILCTXT_KE_UNKNOWN_CIPHER);
1258 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1259 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1260 SILCTXT_KE_UNKNOWN_PKCS);
1261 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1262 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1263 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1264 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1265 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1266 SILCTXT_KE_UNKNOWN_HMAC);
1267 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1268 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1269 SILCTXT_KE_INCORRECT_SIGNATURE);
1270 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1271 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1272 SILCTXT_KE_INVALID_COOKIE);
1275 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1276 uint32 err = (uint32)failure;
1278 if (err == SILC_AUTH_FAILED)
1279 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1280 SILCTXT_AUTH_FAILED);
1284 /* Asks whether the user would like to perform the key agreement protocol.
1285 This is called after we have received an key agreement packet or an
1286 reply to our key agreement packet. This returns TRUE if the user wants
1287 the library to perform the key agreement protocol and FALSE if it is not
1288 desired (application may start it later by calling the function
1289 silc_client_perform_key_agreement). */
1291 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1292 SilcClientEntry client_entry, const char *hostname,
1293 uint16 port, SilcKeyAgreementCallback *completion,
1298 SILC_LOG_DEBUG(("Start"));
1300 /* We will just display the info on the screen and return FALSE and user
1301 will have to start the key agreement with a command. */
1304 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1307 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1308 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1310 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1311 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1312 client_entry->nickname, hostname, portstr);
1320 void silc_ftp(SilcClient client, SilcClientConnection conn,
1321 SilcClientEntry client_entry, uint32 session_id,
1322 const char *hostname, uint16 port)
1324 SILC_SERVER_REC *server;
1326 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1328 SILC_LOG_DEBUG(("Start"));
1330 server = conn->context;
1332 ftp->client_entry = client_entry;
1333 ftp->session_id = session_id;
1336 silc_dlist_add(server->ftp_sessions, ftp);
1337 server->current_session = ftp;
1340 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1343 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1344 SILCTXT_FILE_REQUEST, client_entry->nickname);
1346 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1347 SILCTXT_FILE_REQUEST_HOST,
1348 client_entry->nickname, hostname, portstr);
1351 /* SILC client operations */
1352 SilcClientOperations ops = {
1354 silc_channel_message,
1355 silc_private_message,
1361 silc_get_auth_method,
1362 silc_verify_public_key,
1363 silc_ask_passphrase,