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. */
99 silc_list_start(channel->clients);
100 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
101 if (chu->client == sender) {
102 nick = silc_nicklist_insert(chanrec, chu, FALSE);
108 if (flags & SILC_MESSAGE_FLAG_ACTION)
109 printformat_module("fe-common/silc", server, channel->channel_name,
110 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
111 nick == NULL ? "[<unknown>]" : nick->nick, msg);
112 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
113 printformat_module("fe-common/silc", server, channel->channel_name,
114 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
115 nick == NULL ? "[<unknown>]" : nick->nick, msg);
117 signal_emit("message public", 6, server, msg,
118 nick == NULL ? "[<unknown>]" : nick->nick,
119 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
120 chanrec->name, nick);
123 /* Private message to the client. The `sender' is the nickname of the
124 sender received in the packet. */
126 void silc_private_message(SilcClient client, SilcClientConnection conn,
127 SilcClientEntry sender, SilcMessageFlags flags,
130 SILC_SERVER_REC *server;
133 SILC_LOG_DEBUG(("Start"));
135 server = conn == NULL ? NULL : conn->context;
136 memset(userhost, 0, sizeof(userhost));
137 if (sender->username)
138 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
139 sender->username, sender->hostname);
140 signal_emit("message private", 4, server, msg,
141 sender->nickname ? sender->nickname : "[<unknown>]",
142 sender->username ? userhost : NULL);
145 /* Notify message to the client. The notify arguments are sent in the
146 same order as servers sends them. The arguments are same as received
147 from the server except for ID's. If ID is received application receives
148 the corresponding entry to the ID. For example, if Client ID is received
149 application receives SilcClientEntry. Also, if the notify type is
150 for channel the channel entry is sent to application (even if server
151 does not send it). */
158 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
159 static NOTIFY_REC notifies[] = {
160 { SILC_NOTIFY_TYPE_NONE, NULL },
161 { SILC_NOTIFY_TYPE_INVITE, "invite" },
162 { SILC_NOTIFY_TYPE_JOIN, "join" },
163 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
164 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
165 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
166 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
167 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
168 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
169 { SILC_NOTIFY_TYPE_MOTD, "motd" },
170 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
171 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
172 { SILC_NOTIFY_TYPE_KICKED, "kick" },
173 { SILC_NOTIFY_TYPE_KILLED, "kill" },
174 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
175 { SILC_NOTIFY_TYPE_BAN, "ban" },
178 void silc_notify(SilcClient client, SilcClientConnection conn,
179 SilcNotifyType type, ...)
181 SILC_SERVER_REC *server;
184 SILC_LOG_DEBUG(("Start"));
186 server = conn == NULL ? NULL : conn->context;
189 if (type == SILC_NOTIFY_TYPE_NONE) {
190 /* Some generic notice from server */
191 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
192 } else if (type < MAX_NOTIFY) {
193 /* Send signal about the notify event */
195 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
196 signal_emit(signal, 2, server, va);
199 printformat_module("fe-common/silc", server, NULL,
200 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
206 /* Called to indicate that connection was either successfully established
207 or connecting failed. This is also the first time application receives
208 the SilcClientConnection object which it should save somewhere. */
210 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
212 SILC_SERVER_REC *server = conn->context;
214 if (!server && !success) {
215 silc_client_close_connection(client, NULL, conn);
220 server->connected = TRUE;
221 signal_emit("event connected", 1, server);
223 server->connection_lost = TRUE;
224 server->conn->context = NULL;
225 server_disconnect(SERVER(server));
229 /* Called to indicate that connection was disconnected to the server. */
231 void silc_disconnect(SilcClient client, SilcClientConnection conn)
233 SILC_SERVER_REC *server = conn->context;
235 SILC_LOG_DEBUG(("Start"));
238 nicklist_rename_unique(SERVER(server),
239 server->conn->local_entry, server->nick,
240 server->conn->local_entry,
241 silc_client->username);
242 silc_change_nick(server, silc_client->username);
245 server->conn->context = NULL;
247 server->connection_lost = TRUE;
248 server_disconnect(SERVER(server));
251 /* Command handler. This function is called always in the command function.
252 If error occurs it will be called as well. `conn' is the associated
253 client connection. `cmd_context' is the command context that was
254 originally sent to the command. `success' is FALSE if error occured
255 during command. `command' is the command being processed. It must be
256 noted that this is not reply from server. This is merely called just
257 after application has called the command. Just to tell application
258 that the command really was processed. */
260 void silc_command(SilcClient client, SilcClientConnection conn,
261 SilcClientCommandContext cmd_context, int success,
264 SILC_SERVER_REC *server = conn->context;
266 SILC_LOG_DEBUG(("Start"));
272 case SILC_COMMAND_INVITE:
273 printformat_module("fe-common/silc", server, NULL,
274 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
275 cmd_context->argv[2],
276 (cmd_context->argv[1][0] == '*' ?
277 (char *)conn->current_channel->channel_name :
278 (char *)cmd_context->argv[1]));
285 /* Client info resolving callback when JOIN command reply is received.
286 This will cache all users on the channel. */
288 static void silc_client_join_get_users(SilcClient client,
289 SilcClientConnection conn,
290 SilcClientEntry *clients,
291 uint32 clients_count,
294 SilcChannelEntry channel = (SilcChannelEntry)context;
296 SILC_SERVER_REC *server = conn->context;
297 SILC_CHANNEL_REC *chanrec;
298 SilcClientEntry founder = NULL;
304 chanrec = silc_channel_find(server, channel->channel_name);
308 silc_list_start(channel->clients);
309 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
310 if (!chu->client->nickname)
312 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
313 founder = chu->client;
314 silc_nicklist_insert(chanrec, chu, FALSE);
317 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
318 nicklist_set_own(CHANNEL(chanrec), ownnick);
319 signal_emit("channel joined", 1, chanrec);
322 printformat_module("fe-common/silc", server, channel->channel_name,
323 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
324 channel->channel_name, chanrec->topic);
326 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
329 if (founder == conn->local_entry)
330 printformat_module("fe-common/silc",
331 server, channel->channel_name, MSGLEVEL_CRAP,
332 SILCTXT_CHANNEL_FOUNDER_YOU,
333 channel->channel_name);
335 printformat_module("fe-common/silc",
336 server, channel->channel_name, MSGLEVEL_CRAP,
337 SILCTXT_CHANNEL_FOUNDER,
338 channel->channel_name, founder->nickname);
344 SilcClientConnection conn;
350 void silc_getkey_cb(bool success, void *context)
352 GetkeyContext getkey = (GetkeyContext)context;
353 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
354 char *name = (getkey->id_type == SILC_ID_CLIENT ?
355 ((SilcClientEntry)getkey->entry)->nickname :
356 ((SilcServerEntry)getkey->entry)->server_name);
359 printformat_module("fe-common/silc", NULL, NULL,
360 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
362 printformat_module("fe-common/silc", NULL, NULL,
363 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
366 silc_free(getkey->fingerprint);
370 /* Command reply handler. This function is called always in the command reply
371 function. If error occurs it will be called as well. Normal scenario
372 is that it will be called after the received command data has been parsed
373 and processed. The function is used to pass the received command data to
376 `conn' is the associated client connection. `cmd_payload' is the command
377 payload data received from server and it can be ignored. It is provided
378 if the application would like to re-parse the received command data,
379 however, it must be noted that the data is parsed already by the library
380 thus the payload can be ignored. `success' is FALSE if error occured.
381 In this case arguments are not sent to the application. `command' is the
382 command reply being processed. The function has variable argument list
383 and each command defines the number and type of arguments it passes to the
384 application (on error they are not sent). */
387 silc_command_reply(SilcClient client, SilcClientConnection conn,
388 SilcCommandPayload cmd_payload, int success,
389 SilcCommand command, SilcCommandStatus status, ...)
392 SILC_SERVER_REC *server = conn->context;
393 SILC_CHANNEL_REC *chanrec;
396 va_start(vp, status);
398 SILC_LOG_DEBUG(("Start"));
401 case SILC_COMMAND_WHOIS:
403 char buf[1024], *nickname, *username, *realname, *nick;
404 unsigned char *fingerprint;
407 SilcClientEntry client_entry;
409 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
410 /* Print the unknown nick for user */
412 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
415 silc_say_error("%s: %s", tmp,
416 silc_client_command_status_message(status));
418 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
419 /* Try to find the entry for the unknown client ID, since we
420 might have, and print the nickname of it for user. */
423 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
426 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
428 client_entry = silc_client_get_client_by_id(client, conn,
430 if (client_entry && client_entry->nickname)
431 silc_say_error("%s: %s", client_entry->nickname,
432 silc_client_command_status_message(status));
433 silc_free(client_id);
441 client_entry = va_arg(vp, SilcClientEntry);
442 nickname = va_arg(vp, char *);
443 username = va_arg(vp, char *);
444 realname = va_arg(vp, char *);
445 channels = va_arg(vp, SilcBuffer);
446 mode = va_arg(vp, uint32);
447 idle = va_arg(vp, uint32);
448 fingerprint = va_arg(vp, unsigned char *);
450 silc_parse_userfqdn(nickname, &nick, NULL);
451 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
452 SILCTXT_WHOIS_USERINFO, nickname,
453 client_entry->username, client_entry->hostname,
454 nick, client_entry->nickname);
455 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
456 SILCTXT_WHOIS_REALNAME, realname);
460 SilcDList list = silc_channel_payload_parse_list(channels->data,
463 SilcChannelPayload entry;
464 memset(buf, 0, sizeof(buf));
465 silc_dlist_start(list);
466 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
467 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
469 char *name = silc_channel_get_name(entry, &name_len);
472 strncat(buf, m, strlen(m));
473 strncat(buf, name, name_len);
474 strncat(buf, " ", 1);
478 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
479 SILCTXT_WHOIS_CHANNELS, buf);
480 silc_channel_payload_list_free(list);
485 memset(buf, 0, sizeof(buf));
487 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
488 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
489 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
491 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
492 "SILC Operator " : "[Unknown mode] ");
494 if (mode & SILC_UMODE_GONE)
497 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
498 SILCTXT_WHOIS_MODES, buf);
501 if (idle && nickname) {
502 memset(buf, 0, sizeof(buf));
503 snprintf(buf, sizeof(buf) - 1, "%lu %s",
504 idle > 60 ? (idle / 60) : idle,
505 idle > 60 ? "minutes" : "seconds");
507 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
508 SILCTXT_WHOIS_IDLE, buf);
512 fingerprint = silc_fingerprint(fingerprint, 20);
513 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
514 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
515 silc_free(fingerprint);
520 case SILC_COMMAND_IDENTIFY:
522 SilcClientEntry client_entry;
524 /* Identify command is used only internally by the client library
525 but it still might send some interesting stuff for user interface
526 so let's print errors. */
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);
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,