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,
663 case SILC_COMMAND_NICK:
665 SilcClientEntry client = va_arg(vp, SilcClientEntry);
671 old = g_strdup(server->nick);
672 server_change_nick(SERVER(server), client->nickname);
673 nicklist_rename_unique(SERVER(server),
674 server->conn->local_entry, server->nick,
675 client, client->nickname);
677 signal_emit("message own_nick", 4, server, server->nick, old, "");
682 case SILC_COMMAND_LIST:
691 (void)va_arg(vp, SilcChannelEntry);
692 name = va_arg(vp, char *);
693 topic = va_arg(vp, char *);
694 usercount = va_arg(vp, int);
696 if (status == SILC_STATUS_LIST_START ||
697 status == SILC_STATUS_OK)
698 printformat_module("fe-common/silc", server, NULL,
699 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
702 snprintf(users, sizeof(users) - 1, "N/A");
704 snprintf(users, sizeof(users) - 1, "%d", usercount);
705 printformat_module("fe-common/silc", server, NULL,
706 MSGLEVEL_CRAP, SILCTXT_LIST,
707 name, users, topic ? topic : "");
711 case SILC_COMMAND_UMODE:
718 mode = va_arg(vp, uint32);
720 if (mode & SILC_UMODE_SERVER_OPERATOR &&
721 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
722 printformat_module("fe-common/silc", server, NULL,
723 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
725 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
726 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
727 printformat_module("fe-common/silc", server, NULL,
728 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
730 server->umode = mode;
734 case SILC_COMMAND_OPER:
738 printformat_module("fe-common/silc", server, NULL,
739 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
742 case SILC_COMMAND_SILCOPER:
746 printformat_module("fe-common/silc", server, NULL,
747 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
750 case SILC_COMMAND_USERS:
752 SilcHashTableList htl;
753 SilcChannelEntry channel;
759 channel = va_arg(vp, SilcChannelEntry);
761 printformat_module("fe-common/silc", server, channel->channel_name,
762 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
763 channel->channel_name);
765 silc_hash_table_list(channel->user_list, &htl);
766 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
767 SilcClientEntry e = chu->client;
773 memset(stat, 0, sizeof(stat));
774 mode = silc_client_chumode_char(chu->mode);
775 if (e->mode & SILC_UMODE_GONE)
782 printformat_module("fe-common/silc", server, channel->channel_name,
783 MSGLEVEL_CRAP, SILCTXT_USERS,
785 e->username ? e->username : "",
786 e->hostname ? e->hostname : "",
787 e->realname ? e->realname : "");
791 silc_hash_table_list_reset(&htl);
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;
830 id_type = va_arg(vp, uint32);
831 entry = va_arg(vp, void *);
832 public_key = va_arg(vp, SilcPublicKey);
835 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
837 getkey = silc_calloc(1, sizeof(*getkey));
838 getkey->entry = entry;
839 getkey->id_type = id_type;
840 getkey->client = client;
842 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
844 name = (id_type == SILC_ID_CLIENT ?
845 ((SilcClientEntry)entry)->nickname :
846 ((SilcServerEntry)entry)->server_name);
848 silc_verify_public_key_internal(client, conn, name,
849 (id_type == SILC_ID_CLIENT ?
850 SILC_SOCKET_TYPE_CLIENT :
851 SILC_SOCKET_TYPE_SERVER),
852 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
853 silc_getkey_cb, getkey);
856 printformat_module("fe-common/silc", server, NULL,
857 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
862 case SILC_COMMAND_INFO:
864 SilcServerEntry server_entry;
871 server_entry = va_arg(vp, SilcServerEntry);
872 server_name = va_arg(vp, char *);
873 server_info = va_arg(vp, char *);
875 if (server_name && server_info )
877 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
878 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
883 case SILC_COMMAND_TOPIC:
885 SilcChannelEntry channel;
891 channel = va_arg(vp, SilcChannelEntry);
892 topic = va_arg(vp, char *);
895 chanrec = silc_channel_find_entry(server, channel);
897 g_free_not_null(chanrec->topic);
898 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
899 signal_emit("channel topic changed", 1, chanrec);
901 printformat_module("fe-common/silc", server, channel->channel_name,
902 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
903 channel->channel_name, topic);
905 printformat_module("fe-common/silc", server, channel->channel_name,
906 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
907 channel->channel_name);
919 SilcClientConnection conn;
925 SilcSKEPKType pk_type;
926 SilcVerifyPublicKey completion;
930 static void verify_public_key_completion(const char *line, void *context)
932 PublicKeyVerify verify = (PublicKeyVerify)context;
934 if (line[0] == 'Y' || line[0] == 'y') {
935 /* Call the completion */
936 if (verify->completion)
937 verify->completion(TRUE, verify->context);
939 /* Save the key for future checking */
940 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
941 verify->pk_len, SILC_PKCS_FILE_PEM);
943 /* Call the completion */
944 if (verify->completion)
945 verify->completion(FALSE, verify->context);
947 printformat_module("fe-common/silc", NULL, NULL,
948 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
949 verify->entity_name ? verify->entity_name :
953 silc_free(verify->filename);
954 silc_free(verify->entity);
955 silc_free(verify->entity_name);
956 silc_free(verify->pk);
960 /* Internal routine to verify public key. If the `completion' is provided
961 it will be called to indicate whether public was verified or not. For
962 server/router public key this will check for filename that includes the
963 remote host's IP address and remote host's hostname. */
966 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
967 const char *name, SilcSocketType conn_type,
968 unsigned char *pk, uint32 pk_len,
969 SilcSKEPKType pk_type,
970 SilcVerifyPublicKey completion, void *context)
973 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
974 char *fingerprint, *babbleprint, *format;
977 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
978 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
979 "server" : "client");
980 PublicKeyVerify verify;
982 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
983 printformat_module("fe-common/silc", NULL, NULL,
984 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
987 completion(FALSE, context);
991 pw = getpwuid(getuid());
994 completion(FALSE, context);
998 memset(filename, 0, sizeof(filename));
999 memset(filename2, 0, sizeof(filename2));
1000 memset(file, 0, sizeof(file));
1002 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1003 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1005 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1006 conn->sock->ip, conn->sock->port);
1007 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1008 pw->pw_dir, entity, file);
1010 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1011 conn->sock->hostname, conn->sock->port);
1012 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1013 pw->pw_dir, entity, file);
1018 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1019 name, conn->sock->port);
1020 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1021 pw->pw_dir, entity, file);
1026 /* Replace all whitespaces with `_'. */
1027 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1028 for (i = 0; i < strlen(fingerprint); i++)
1029 if (fingerprint[i] == ' ')
1030 fingerprint[i] = '_';
1032 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1033 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1034 pw->pw_dir, entity, file);
1035 silc_free(fingerprint);
1040 /* Take fingerprint of the public key */
1041 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1042 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1044 verify = silc_calloc(1, sizeof(*verify));
1045 verify->client = client;
1046 verify->conn = conn;
1047 verify->filename = strdup(ipf);
1048 verify->entity = strdup(entity);
1049 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1050 (name ? strdup(name) : strdup(conn->sock->hostname))
1052 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1053 memcpy(verify->pk, pk, pk_len);
1054 verify->pk_len = pk_len;
1055 verify->pk_type = pk_type;
1056 verify->completion = completion;
1057 verify->context = context;
1059 /* Check whether this key already exists */
1060 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1061 /* Key does not exist, ask user to verify the key and save it */
1063 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1064 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1065 verify->entity_name : entity);
1066 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1067 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1068 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1069 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1070 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1071 SILCTXT_PUBKEY_ACCEPT);
1072 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1075 silc_free(fingerprint);
1078 /* The key already exists, verify it. */
1079 SilcPublicKey public_key;
1080 unsigned char *encpk;
1083 /* Load the key file, try for both IP filename and hostname filename */
1084 if (!silc_pkcs_load_public_key(ipf, &public_key,
1085 SILC_PKCS_FILE_PEM) &&
1086 !silc_pkcs_load_public_key(ipf, &public_key,
1087 SILC_PKCS_FILE_BIN) &&
1088 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1089 SILC_PKCS_FILE_PEM) &&
1090 !silc_pkcs_load_public_key(hostf, &public_key,
1091 SILC_PKCS_FILE_BIN)))) {
1092 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1093 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1094 verify->entity_name : entity);
1095 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1096 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1097 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1098 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1099 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1100 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1101 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1102 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1103 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1106 silc_free(fingerprint);
1110 /* Encode the key data */
1111 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1113 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1114 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1115 verify->entity_name : entity);
1116 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1117 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1118 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1119 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1120 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1121 SILCTXT_PUBKEY_MALFORMED, entity);
1122 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1123 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1124 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1127 silc_free(fingerprint);
1131 /* Compare the keys */
1132 if (memcmp(encpk, pk, encpk_len)) {
1133 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1134 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1135 verify->entity_name : entity);
1136 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1137 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1138 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1139 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1140 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1141 SILCTXT_PUBKEY_NO_MATCH, entity);
1142 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1143 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1144 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1145 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1147 /* Ask user to verify the key and save it */
1148 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1149 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1150 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1153 silc_free(fingerprint);
1157 /* Local copy matched */
1159 completion(TRUE, context);
1160 silc_free(fingerprint);
1164 /* Verifies received public key. The `conn_type' indicates which entity
1165 (server, client etc.) has sent the public key. If user decides to trust
1166 the key may be saved as trusted public key for later use. The
1167 `completion' must be called after the public key has been verified. */
1170 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1171 SilcSocketType conn_type, unsigned char *pk,
1172 uint32 pk_len, SilcSKEPKType pk_type,
1173 SilcVerifyPublicKey completion, void *context)
1175 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1177 completion, context);
1180 /* Asks passphrase from user on the input line. */
1183 SilcAskPassphrase completion;
1187 void ask_passphrase_completion(const char *passphrase, void *context)
1189 AskPassphrase p = (AskPassphrase)context;
1190 p->completion((unsigned char *)passphrase,
1191 passphrase ? strlen(passphrase) : 0, p->context);
1195 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1196 SilcAskPassphrase completion, void *context)
1198 AskPassphrase p = silc_calloc(1, sizeof(*p));
1199 p->completion = completion;
1200 p->context = context;
1202 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1203 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1207 SilcGetAuthMeth completion;
1209 } *InternalGetAuthMethod;
1211 /* Callback called when we've received the authentication method information
1212 from the server after we've requested it. This will get the authentication
1213 data from the user if needed. */
1215 static void silc_get_auth_method_callback(SilcClient client,
1216 SilcClientConnection conn,
1217 SilcAuthMethod auth_meth,
1220 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1222 SILC_LOG_DEBUG(("Start"));
1224 switch (auth_meth) {
1225 case SILC_AUTH_NONE:
1226 /* No authentication required. */
1227 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1229 case SILC_AUTH_PASSWORD:
1230 /* Do not ask the passphrase from user, the library will ask it if
1231 we do not provide it here. */
1232 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1234 case SILC_AUTH_PUBLIC_KEY:
1235 /* Do not get the authentication data now, the library will generate
1236 it using our default key, if we do not provide it here. */
1237 /* XXX In the future when we support multiple local keys and multiple
1238 local certificates we will need to ask from user which one to use. */
1239 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1243 silc_free(internal);
1246 /* Find authentication method and authentication data by hostname and
1247 port. The hostname may be IP address as well. The found authentication
1248 method and authentication data is returned to `auth_meth', `auth_data'
1249 and `auth_data_len'. The function returns TRUE if authentication method
1250 is found and FALSE if not. `conn' may be NULL. */
1252 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1253 char *hostname, uint16 port,
1254 SilcGetAuthMeth completion, void *context)
1256 InternalGetAuthMethod internal;
1258 SILC_LOG_DEBUG(("Start"));
1260 /* XXX must resolve from configuration whether this connection has
1261 any specific authentication data */
1263 /* If we do not have this connection configured by the user in a
1264 configuration file then resolve the authentication method from the
1265 server for this session. */
1266 internal = silc_calloc(1, sizeof(*internal));
1267 internal->completion = completion;
1268 internal->context = context;
1270 silc_client_request_authentication_method(client, conn,
1271 silc_get_auth_method_callback,
1275 /* Notifies application that failure packet was received. This is called
1276 if there is some protocol active in the client. The `protocol' is the
1277 protocol context. The `failure' is opaque pointer to the failure
1278 indication. Note, that the `failure' is protocol dependant and application
1279 must explicitly cast it to correct type. Usually `failure' is 32 bit
1280 failure type (see protocol specs for all protocol failure types). */
1282 void silc_failure(SilcClient client, SilcClientConnection conn,
1283 SilcProtocol protocol, void *failure)
1285 SILC_LOG_DEBUG(("Start"));
1287 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1288 SilcSKEStatus status = (SilcSKEStatus)failure;
1290 if (status == SILC_SKE_STATUS_BAD_VERSION)
1291 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1292 SILCTXT_KE_BAD_VERSION);
1293 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1294 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1295 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1296 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1297 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1298 SILCTXT_KE_UNKNOWN_GROUP);
1299 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1300 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1301 SILCTXT_KE_UNKNOWN_CIPHER);
1302 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1303 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1304 SILCTXT_KE_UNKNOWN_PKCS);
1305 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1306 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1307 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1308 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1309 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1310 SILCTXT_KE_UNKNOWN_HMAC);
1311 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1312 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1313 SILCTXT_KE_INCORRECT_SIGNATURE);
1314 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1315 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1316 SILCTXT_KE_INVALID_COOKIE);
1319 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1320 uint32 err = (uint32)failure;
1322 if (err == SILC_AUTH_FAILED)
1323 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1324 SILCTXT_AUTH_FAILED);
1328 /* Asks whether the user would like to perform the key agreement protocol.
1329 This is called after we have received an key agreement packet or an
1330 reply to our key agreement packet. This returns TRUE if the user wants
1331 the library to perform the key agreement protocol and FALSE if it is not
1332 desired (application may start it later by calling the function
1333 silc_client_perform_key_agreement). */
1335 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1336 SilcClientEntry client_entry, const char *hostname,
1337 uint16 port, SilcKeyAgreementCallback *completion,
1342 SILC_LOG_DEBUG(("Start"));
1344 /* We will just display the info on the screen and return FALSE and user
1345 will have to start the key agreement with a command. */
1348 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1351 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1352 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1354 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1355 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1356 client_entry->nickname, hostname, portstr);
1364 void silc_ftp(SilcClient client, SilcClientConnection conn,
1365 SilcClientEntry client_entry, uint32 session_id,
1366 const char *hostname, uint16 port)
1368 SILC_SERVER_REC *server;
1370 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1372 SILC_LOG_DEBUG(("Start"));
1374 server = conn->context;
1376 ftp->client_entry = client_entry;
1377 ftp->session_id = session_id;
1380 silc_dlist_add(server->ftp_sessions, ftp);
1381 server->current_session = ftp;
1384 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1387 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1388 SILCTXT_FILE_REQUEST, client_entry->nickname);
1390 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1391 SILCTXT_FILE_REQUEST_HOST,
1392 client_entry->nickname, hostname, portstr);
1395 /* SILC client operations */
1396 SilcClientOperations ops = {
1398 silc_channel_message,
1399 silc_private_message,
1405 silc_get_auth_method,
1406 silc_verify_public_key,
1407 silc_ask_passphrase,