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, SilcUInt32 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"));
93 server = conn == NULL ? NULL : conn->context;
94 chanrec = silc_channel_find_entry(server, channel);
98 nick = silc_nicklist_find(chanrec, sender);
100 /* We didn't find client but it clearly exists, add it. */
101 SilcChannelUser chu = silc_client_on_channel(channel, sender);
103 nick = silc_nicklist_insert(chanrec, chu, FALSE);
106 if (flags & SILC_MESSAGE_FLAG_ACTION)
107 printformat_module("fe-common/silc", server, channel->channel_name,
108 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
109 nick == NULL ? "[<unknown>]" : nick->nick, msg);
110 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
111 printformat_module("fe-common/silc", server, channel->channel_name,
112 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
113 nick == NULL ? "[<unknown>]" : nick->nick, msg);
115 signal_emit("message public", 6, server, msg,
116 nick == NULL ? "[<unknown>]" : nick->nick,
117 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
118 chanrec->name, nick);
121 /* Private message to the client. The `sender' is the nickname of the
122 sender received in the packet. */
124 void silc_private_message(SilcClient client, SilcClientConnection conn,
125 SilcClientEntry sender, SilcMessageFlags flags,
128 SILC_SERVER_REC *server;
131 SILC_LOG_DEBUG(("Start"));
133 server = conn == NULL ? NULL : conn->context;
134 memset(userhost, 0, sizeof(userhost));
135 if (sender->username)
136 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
137 sender->username, sender->hostname);
138 signal_emit("message private", 4, server, msg,
139 sender->nickname ? sender->nickname : "[<unknown>]",
140 sender->username ? userhost : NULL);
143 /* Notify message to the client. The notify arguments are sent in the
144 same order as servers sends them. The arguments are same as received
145 from the server except for ID's. If ID is received application receives
146 the corresponding entry to the ID. For example, if Client ID is received
147 application receives SilcClientEntry. Also, if the notify type is
148 for channel the channel entry is sent to application (even if server
149 does not send it). */
151 void silc_notify(SilcClient client, SilcClientConnection conn,
152 SilcNotifyType type, ...)
155 SILC_SERVER_REC *server;
156 SILC_CHANNEL_REC *chanrec;
157 SILC_NICK_REC *nickrec;
158 SilcClientEntry client_entry, client_entry2;
159 SilcChannelEntry channel;
160 SilcServerEntry server_entry;
166 GSList *list1, *list_tmp;
168 SILC_LOG_DEBUG(("Start"));
172 server = conn == NULL ? NULL : conn->context;
175 case SILC_NOTIFY_TYPE_NONE:
176 /* Some generic notice from server */
177 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
180 case SILC_NOTIFY_TYPE_INVITE:
182 * Invited or modified invite list.
185 SILC_LOG_DEBUG(("Notify: INVITE"));
187 channel = va_arg(va, SilcChannelEntry);
188 name = va_arg(va, char *);
189 client_entry = va_arg(va, SilcClientEntry);
191 memset(userhost, 0, sizeof(userhost));
192 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
193 client_entry->username, client_entry->hostname);
194 signal_emit("message invite", 4, server, channel ? channel->channel_name :
195 name, client_entry->nickname, userhost);
198 case SILC_NOTIFY_TYPE_JOIN:
203 SILC_LOG_DEBUG(("Notify: JOIN"));
205 client_entry = va_arg(va, SilcClientEntry);
206 channel = va_arg(va, SilcChannelEntry);
208 if (client_entry == server->conn->local_entry) {
209 /* You joined to channel */
210 chanrec = silc_channel_find(server, channel->channel_name);
211 if (chanrec != NULL && !chanrec->joined)
212 chanrec->entry = channel;
214 chanrec = silc_channel_find_entry(server, channel);
215 if (chanrec != NULL) {
216 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
218 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
222 memset(userhost, 0, sizeof(userhost));
223 if (client_entry->username)
224 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
225 client_entry->username, client_entry->hostname);
226 signal_emit("message join", 4, server, channel->channel_name,
227 client_entry->nickname,
228 client_entry->username == NULL ? "" : userhost);
231 case SILC_NOTIFY_TYPE_LEAVE:
236 SILC_LOG_DEBUG(("Notify: LEAVE"));
238 client_entry = va_arg(va, SilcClientEntry);
239 channel = va_arg(va, SilcChannelEntry);
241 memset(userhost, 0, sizeof(userhost));
242 if (client_entry->username)
243 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
244 client_entry->username, client_entry->hostname);
245 signal_emit("message part", 5, server, channel->channel_name,
246 client_entry->nickname, client_entry->username ?
247 userhost : "", client_entry->nickname);
249 chanrec = silc_channel_find_entry(server, channel);
250 if (chanrec != NULL) {
251 nickrec = silc_nicklist_find(chanrec, client_entry);
253 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
257 case SILC_NOTIFY_TYPE_SIGNOFF:
262 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
264 client_entry = va_arg(va, SilcClientEntry);
265 tmp = va_arg(va, char *);
267 silc_server_free_ftp(server, client_entry);
269 memset(userhost, 0, sizeof(userhost));
270 if (client_entry->username)
271 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
272 client_entry->username, client_entry->hostname);
273 signal_emit("message quit", 4, server, client_entry->nickname,
274 client_entry->username ? userhost : "",
277 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
278 for (list_tmp = list1; list_tmp != NULL; list_tmp =
279 list_tmp->next->next) {
280 CHANNEL_REC *channel = list_tmp->data;
281 NICK_REC *nickrec = list_tmp->next->data;
283 nicklist_remove(channel, nickrec);
287 case SILC_NOTIFY_TYPE_TOPIC_SET:
292 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
294 idtype = va_arg(va, int);
295 entry = va_arg(va, void *);
296 tmp = va_arg(va, char *);
297 channel = va_arg(va, SilcChannelEntry);
299 chanrec = silc_channel_find_entry(server, channel);
300 if (chanrec != NULL) {
301 g_free_not_null(chanrec->topic);
302 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
303 signal_emit("channel topic changed", 1, chanrec);
306 if (idtype == SILC_ID_CLIENT) {
307 client_entry = (SilcClientEntry)entry;
308 memset(userhost, 0, sizeof(userhost));
309 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
310 client_entry->username, client_entry->hostname);
311 signal_emit("message topic", 5, server, channel->channel_name,
312 tmp, client_entry->nickname, userhost);
313 } else if (idtype == SILC_ID_SERVER) {
314 server_entry = (SilcServerEntry)entry;
315 signal_emit("message topic", 5, server, channel->channel_name,
316 tmp, server_entry->server_name,
317 server_entry->server_name);
319 channel = (SilcChannelEntry)entry;
320 signal_emit("message topic", 5, server, channel->channel_name,
321 tmp, channel->channel_name, channel->channel_name);
325 case SILC_NOTIFY_TYPE_NICK_CHANGE:
330 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
332 client_entry = va_arg(va, SilcClientEntry);
333 client_entry2 = va_arg(va, SilcClientEntry);
335 memset(userhost, 0, sizeof(userhost));
336 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
337 client_entry2->username, client_entry2->hostname);
338 nicklist_rename_unique(SERVER(server),
339 client_entry, client_entry->nickname,
340 client_entry2, client_entry2->nickname);
341 signal_emit("message nick", 4, server, client_entry2->nickname,
342 client_entry->nickname, userhost);
345 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
347 * Changed channel mode.
350 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
352 idtype = va_arg(va, int);
353 entry = va_arg(va, void *);
354 mode = va_arg(va, SilcUInt32);
355 (void)va_arg(va, char *);
356 (void)va_arg(va, char *);
357 channel = va_arg(va, SilcChannelEntry);
359 tmp = silc_client_chmode(mode,
360 channel->channel_key ?
361 channel->channel_key->cipher->name : "",
363 silc_hmac_get_name(channel->hmac) : "");
365 chanrec = silc_channel_find_entry(server, channel);
366 if (chanrec != NULL) {
367 g_free_not_null(chanrec->mode);
368 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
369 signal_emit("channel mode changed", 1, chanrec);
372 if (idtype == SILC_ID_CLIENT) {
373 client_entry = (SilcClientEntry)entry;
374 printformat_module("fe-common/silc", server, channel->channel_name,
375 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
376 channel->channel_name, tmp ? tmp : "removed all",
377 client_entry->nickname);
378 } else if (idtype == SILC_ID_SERVER) {
379 server_entry = (SilcServerEntry)entry;
380 printformat_module("fe-common/silc", server, channel->channel_name,
381 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
382 channel->channel_name, tmp ? tmp : "removed all",
383 server_entry->server_name);
389 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
391 * Changed user's mode on channel.
394 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
396 client_entry = va_arg(va, SilcClientEntry);
397 mode = va_arg(va, SilcUInt32);
398 client_entry2 = va_arg(va, SilcClientEntry);
399 channel = va_arg(va, SilcChannelEntry);
401 tmp = silc_client_chumode(mode);
402 chanrec = silc_channel_find_entry(server, channel);
403 if (chanrec != NULL) {
406 if (client_entry2 == server->conn->local_entry)
407 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
409 nick = silc_nicklist_find(chanrec, client_entry2);
411 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
412 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
413 signal_emit("nick mode changed", 2, chanrec, nick);
417 printformat_module("fe-common/silc", server, channel->channel_name,
418 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
419 channel->channel_name, client_entry2->nickname,
420 tmp ? tmp : "removed all",
421 client_entry->nickname);
423 if (mode & SILC_CHANNEL_UMODE_CHANFO)
424 printformat_module("fe-common/silc",
425 server, channel->channel_name, MSGLEVEL_CRAP,
426 SILCTXT_CHANNEL_FOUNDER,
427 channel->channel_name, client_entry2->nickname);
432 case SILC_NOTIFY_TYPE_MOTD:
437 SILC_LOG_DEBUG(("Notify: MOTD"));
439 tmp = va_arg(va, char *);
441 if (!settings_get_bool("skip_motd"))
442 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
445 case SILC_NOTIFY_TYPE_KICKED:
447 * Someone was kicked from channel.
450 SILC_LOG_DEBUG(("Notify: KICKED"));
452 client_entry = va_arg(va, SilcClientEntry);
453 tmp = va_arg(va, char *);
454 client_entry2 = va_arg(va, SilcClientEntry);
455 channel = va_arg(va, SilcChannelEntry);
457 chanrec = silc_channel_find_entry(server, channel);
459 if (client_entry == conn->local_entry) {
460 printformat_module("fe-common/silc", server, channel->channel_name,
461 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
462 channel->channel_name, client_entry2->nickname,
465 chanrec->kicked = TRUE;
466 channel_destroy((CHANNEL_REC *)chanrec);
469 printformat_module("fe-common/silc", server, channel->channel_name,
470 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
471 client_entry->nickname, channel->channel_name,
472 client_entry2->nickname, tmp ? tmp : "");
475 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
477 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
482 case SILC_NOTIFY_TYPE_KILLED:
484 * Someone was killed from the network.
487 SILC_LOG_DEBUG(("Notify: KILLED"));
489 client_entry = va_arg(va, SilcClientEntry);
490 tmp = va_arg(va, char *);
492 if (client_entry == conn->local_entry) {
493 printformat_module("fe-common/silc", server, NULL,
494 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
497 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
498 for (list_tmp = list1; list_tmp != NULL; list_tmp =
499 list_tmp->next->next) {
500 CHANNEL_REC *channel = list_tmp->data;
501 NICK_REC *nickrec = list_tmp->next->data;
502 nicklist_remove(channel, nickrec);
505 printformat_module("fe-common/silc", server, NULL,
506 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
507 client_entry->nickname,
512 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
515 * Server has quit the network.
518 SilcClientEntry *clients;
519 SilcUInt32 clients_count;
521 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
523 (void)va_arg(va, void *);
524 clients = va_arg(va, SilcClientEntry *);
525 clients_count = va_arg(va, SilcUInt32);
527 for (i = 0; i < clients_count; i++) {
528 memset(userhost, 0, sizeof(userhost));
529 if (clients[i]->username)
530 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
531 clients[i]->username, clients[i]->hostname);
532 signal_emit("message quit", 4, server, clients[i]->nickname,
533 clients[i]->username ? userhost : "",
536 silc_server_free_ftp(server, clients[i]);
538 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
539 for (list_tmp = list1; list_tmp != NULL; list_tmp =
540 list_tmp->next->next) {
541 CHANNEL_REC *channel = list_tmp->data;
542 NICK_REC *nickrec = list_tmp->next->data;
543 nicklist_remove(channel, nickrec);
551 printformat_module("fe-common/silc", server, NULL,
552 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
559 /* Called to indicate that connection was either successfully established
560 or connecting failed. This is also the first time application receives
561 the SilcClientConnection object which it should save somewhere. */
563 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
565 SILC_SERVER_REC *server = conn->context;
567 if (!server && !success) {
568 silc_client_close_connection(client, NULL, conn);
573 server->connected = TRUE;
574 signal_emit("event connected", 1, server);
576 server->connection_lost = TRUE;
578 server->conn->context = NULL;
579 server_disconnect(SERVER(server));
583 /* Called to indicate that connection was disconnected to the server. */
585 void silc_disconnect(SilcClient client, SilcClientConnection conn)
587 SILC_SERVER_REC *server = conn->context;
589 SILC_LOG_DEBUG(("Start"));
591 if (server->conn && server->conn->local_entry) {
592 nicklist_rename_unique(SERVER(server),
593 server->conn->local_entry, server->nick,
594 server->conn->local_entry,
595 silc_client->username);
596 silc_change_nick(server, silc_client->username);
599 server->conn->context = NULL;
601 server->connection_lost = TRUE;
602 server_disconnect(SERVER(server));
605 /* Command handler. This function is called always in the command function.
606 If error occurs it will be called as well. `conn' is the associated
607 client connection. `cmd_context' is the command context that was
608 originally sent to the command. `success' is FALSE if error occured
609 during command. `command' is the command being processed. It must be
610 noted that this is not reply from server. This is merely called just
611 after application has called the command. Just to tell application
612 that the command really was processed. */
614 void silc_command(SilcClient client, SilcClientConnection conn,
615 SilcClientCommandContext cmd_context, int success,
618 SILC_SERVER_REC *server = conn->context;
620 SILC_LOG_DEBUG(("Start"));
626 case SILC_COMMAND_INVITE:
627 printformat_module("fe-common/silc", server, NULL,
628 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
629 cmd_context->argv[2],
630 (cmd_context->argv[1][0] == '*' ?
631 (char *)conn->current_channel->channel_name :
632 (char *)cmd_context->argv[1]));
639 /* Client info resolving callback when JOIN command reply is received.
640 This will cache all users on the channel. */
642 static void silc_client_join_get_users(SilcClient client,
643 SilcClientConnection conn,
644 SilcClientEntry *clients,
645 SilcUInt32 clients_count,
648 SilcChannelEntry channel = (SilcChannelEntry)context;
649 SilcHashTableList htl;
651 SILC_SERVER_REC *server = conn->context;
652 SILC_CHANNEL_REC *chanrec;
653 SilcClientEntry founder = NULL;
659 chanrec = silc_channel_find(server, channel->channel_name);
663 silc_hash_table_list(channel->user_list, &htl);
664 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
665 if (!chu->client->nickname)
667 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
668 founder = chu->client;
669 silc_nicklist_insert(chanrec, chu, FALSE);
671 silc_hash_table_list_reset(&htl);
673 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
674 nicklist_set_own(CHANNEL(chanrec), ownnick);
675 signal_emit("channel joined", 1, chanrec);
678 printformat_module("fe-common/silc", server, channel->channel_name,
679 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
680 channel->channel_name, chanrec->topic);
682 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
685 if (founder == conn->local_entry)
686 printformat_module("fe-common/silc",
687 server, channel->channel_name, MSGLEVEL_CRAP,
688 SILCTXT_CHANNEL_FOUNDER_YOU,
689 channel->channel_name);
691 printformat_module("fe-common/silc",
692 server, channel->channel_name, MSGLEVEL_CRAP,
693 SILCTXT_CHANNEL_FOUNDER,
694 channel->channel_name, founder->nickname);
700 SilcClientConnection conn;
706 void silc_getkey_cb(bool success, void *context)
708 GetkeyContext getkey = (GetkeyContext)context;
709 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
710 char *name = (getkey->id_type == SILC_ID_CLIENT ?
711 ((SilcClientEntry)getkey->entry)->nickname :
712 ((SilcServerEntry)getkey->entry)->server_name);
715 printformat_module("fe-common/silc", NULL, NULL,
716 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
718 printformat_module("fe-common/silc", NULL, NULL,
719 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
722 silc_free(getkey->fingerprint);
726 /* Command reply handler. This function is called always in the command reply
727 function. If error occurs it will be called as well. Normal scenario
728 is that it will be called after the received command data has been parsed
729 and processed. The function is used to pass the received command data to
732 `conn' is the associated client connection. `cmd_payload' is the command
733 payload data received from server and it can be ignored. It is provided
734 if the application would like to re-parse the received command data,
735 however, it must be noted that the data is parsed already by the library
736 thus the payload can be ignored. `success' is FALSE if error occured.
737 In this case arguments are not sent to the application. `command' is the
738 command reply being processed. The function has variable argument list
739 and each command defines the number and type of arguments it passes to the
740 application (on error they are not sent). */
743 silc_command_reply(SilcClient client, SilcClientConnection conn,
744 SilcCommandPayload cmd_payload, int success,
745 SilcCommand command, SilcCommandStatus status, ...)
748 SILC_SERVER_REC *server = conn->context;
749 SILC_CHANNEL_REC *chanrec;
752 va_start(vp, status);
754 SILC_LOG_DEBUG(("Start"));
757 case SILC_COMMAND_WHOIS:
759 char buf[1024], *nickname, *username, *realname, *nick;
760 unsigned char *fingerprint;
761 SilcUInt32 idle, mode;
763 SilcClientEntry client_entry;
765 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
766 /* Print the unknown nick for user */
768 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
771 silc_say_error("%s: %s", tmp,
772 silc_client_command_status_message(status));
774 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
775 /* Try to find the entry for the unknown client ID, since we
776 might have, and print the nickname of it for user. */
779 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
782 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
784 client_entry = silc_client_get_client_by_id(client, conn,
786 if (client_entry && client_entry->nickname)
787 silc_say_error("%s: %s", client_entry->nickname,
788 silc_client_command_status_message(status));
789 silc_free(client_id);
798 client_entry = va_arg(vp, SilcClientEntry);
799 nickname = va_arg(vp, char *);
800 username = va_arg(vp, char *);
801 realname = va_arg(vp, char *);
802 channels = va_arg(vp, SilcBuffer);
803 mode = va_arg(vp, SilcUInt32);
804 idle = va_arg(vp, SilcUInt32);
805 fingerprint = va_arg(vp, unsigned char *);
807 silc_parse_userfqdn(nickname, &nick, NULL);
808 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
809 SILCTXT_WHOIS_USERINFO, nickname,
810 client_entry->username, client_entry->hostname,
811 nick, client_entry->nickname);
812 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
813 SILCTXT_WHOIS_REALNAME, realname);
817 SilcDList list = silc_channel_payload_parse_list(channels->data,
820 SilcChannelPayload entry;
821 memset(buf, 0, sizeof(buf));
822 silc_dlist_start(list);
823 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
824 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
826 char *name = silc_channel_get_name(entry, &name_len);
829 strncat(buf, m, strlen(m));
830 strncat(buf, name, name_len);
831 strncat(buf, " ", 1);
835 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
836 SILCTXT_WHOIS_CHANNELS, buf);
837 silc_channel_payload_list_free(list);
842 memset(buf, 0, sizeof(buf));
844 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
845 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
846 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
848 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
849 "SILC Operator " : "[Unknown mode] ");
851 if (mode & SILC_UMODE_GONE)
854 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
855 SILCTXT_WHOIS_MODES, buf);
858 if (idle && nickname) {
859 memset(buf, 0, sizeof(buf));
860 snprintf(buf, sizeof(buf) - 1, "%lu %s",
861 idle > 60 ? (idle / 60) : idle,
862 idle > 60 ? "minutes" : "seconds");
864 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
865 SILCTXT_WHOIS_IDLE, buf);
869 fingerprint = silc_fingerprint(fingerprint, 20);
870 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
871 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
872 silc_free(fingerprint);
877 case SILC_COMMAND_IDENTIFY:
879 SilcClientEntry client_entry;
881 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
882 /* Print the unknown nick for user */
884 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
887 silc_say_error("%s: %s", tmp,
888 silc_client_command_status_message(status));
890 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
891 /* Try to find the entry for the unknown client ID, since we
892 might have, and print the nickname of it for user. */
895 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
898 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
900 client_entry = silc_client_get_client_by_id(client, conn,
902 if (client_entry && client_entry->nickname)
903 silc_say_error("%s: %s", client_entry->nickname,
904 silc_client_command_status_message(status));
905 silc_free(client_id);
914 case SILC_COMMAND_WHOWAS:
916 char *nickname, *username, *realname;
918 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
919 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
921 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
924 silc_say_error("%s: %s", tmp,
925 silc_client_command_status_message(status));
932 (void)va_arg(vp, SilcClientEntry);
933 nickname = va_arg(vp, char *);
934 username = va_arg(vp, char *);
935 realname = va_arg(vp, char *);
937 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
938 SILCTXT_WHOWAS_USERINFO, nickname, username,
939 realname ? realname : "");
943 case SILC_COMMAND_INVITE:
945 SilcChannelEntry channel;
947 SilcArgumentPayload args;
953 channel = va_arg(vp, SilcChannelEntry);
954 invite_list = va_arg(vp, char *);
956 args = silc_command_get_args(cmd_payload);
958 argc = silc_argument_get_arg_num(args);
961 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
962 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
965 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
966 SILCTXT_CHANNEL_NO_INVITE_LIST,
967 channel->channel_name);
971 case SILC_COMMAND_JOIN:
973 char *channel, *mode, *topic;
975 SilcChannelEntry channel_entry;
976 SilcBuffer client_id_list;
977 SilcUInt32 list_count;
982 channel = va_arg(vp, char *);
983 channel_entry = va_arg(vp, SilcChannelEntry);
984 modei = va_arg(vp, SilcUInt32);
985 (void)va_arg(vp, SilcUInt32);
986 (void)va_arg(vp, unsigned char *);
987 (void)va_arg(vp, unsigned char *);
988 (void)va_arg(vp, unsigned char *);
989 topic = va_arg(vp, char *);
990 (void)va_arg(vp, unsigned char *);
991 list_count = va_arg(vp, SilcUInt32);
992 client_id_list = va_arg(vp, SilcBuffer);
994 chanrec = silc_channel_find(server, channel);
996 chanrec = silc_channel_create(server, channel, TRUE);
999 g_free_not_null(chanrec->topic);
1000 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1001 signal_emit("channel topic changed", 1, chanrec);
1004 mode = silc_client_chmode(modei,
1005 channel_entry->channel_key ?
1006 channel_entry->channel_key->cipher->name : "",
1007 channel_entry->hmac ?
1008 silc_hmac_get_name(channel_entry->hmac) : "");
1009 g_free_not_null(chanrec->mode);
1010 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1011 signal_emit("channel mode changed", 1, chanrec);
1013 /* Resolve the client information */
1014 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1015 silc_client_join_get_users,
1021 case SILC_COMMAND_NICK:
1023 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1029 old = g_strdup(server->nick);
1030 server_change_nick(SERVER(server), client->nickname);
1031 nicklist_rename_unique(SERVER(server),
1032 server->conn->local_entry, server->nick,
1033 client, client->nickname);
1034 signal_emit("message own_nick", 4, server, server->nick, old, "");
1039 case SILC_COMMAND_LIST:
1048 (void)va_arg(vp, SilcChannelEntry);
1049 name = va_arg(vp, char *);
1050 topic = va_arg(vp, char *);
1051 usercount = va_arg(vp, int);
1053 if (status == SILC_STATUS_LIST_START ||
1054 status == SILC_STATUS_OK)
1055 printformat_module("fe-common/silc", server, NULL,
1056 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1059 snprintf(users, sizeof(users) - 1, "N/A");
1061 snprintf(users, sizeof(users) - 1, "%d", usercount);
1062 printformat_module("fe-common/silc", server, NULL,
1063 MSGLEVEL_CRAP, SILCTXT_LIST,
1064 name, users, topic ? topic : "");
1068 case SILC_COMMAND_UMODE:
1075 mode = va_arg(vp, SilcUInt32);
1077 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1078 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1079 printformat_module("fe-common/silc", server, NULL,
1080 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1082 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1083 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1084 printformat_module("fe-common/silc", server, NULL,
1085 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1087 server->umode = mode;
1088 signal_emit("user mode changed", 2, server, NULL);
1092 case SILC_COMMAND_OPER:
1096 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1097 signal_emit("user mode changed", 2, server, NULL);
1099 printformat_module("fe-common/silc", server, NULL,
1100 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1103 case SILC_COMMAND_SILCOPER:
1107 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1108 signal_emit("user mode changed", 2, server, NULL);
1110 printformat_module("fe-common/silc", server, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1114 case SILC_COMMAND_USERS:
1116 SilcHashTableList htl;
1117 SilcChannelEntry channel;
1118 SilcChannelUser chu;
1123 channel = va_arg(vp, SilcChannelEntry);
1125 printformat_module("fe-common/silc", server, channel->channel_name,
1126 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1127 channel->channel_name);
1129 silc_hash_table_list(channel->user_list, &htl);
1130 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1131 SilcClientEntry e = chu->client;
1132 char stat[5], *mode;
1137 memset(stat, 0, sizeof(stat));
1138 mode = silc_client_chumode_char(chu->mode);
1139 if (e->mode & SILC_UMODE_GONE)
1146 printformat_module("fe-common/silc", server, channel->channel_name,
1147 MSGLEVEL_CRAP, SILCTXT_USERS,
1149 e->username ? e->username : "",
1150 e->hostname ? e->hostname : "",
1151 e->realname ? e->realname : "");
1155 silc_hash_table_list_reset(&htl);
1159 case SILC_COMMAND_BAN:
1161 SilcChannelEntry channel;
1167 channel = va_arg(vp, SilcChannelEntry);
1168 ban_list = va_arg(vp, char *);
1171 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1172 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1175 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1176 SILCTXT_CHANNEL_NO_BAN_LIST,
1177 channel->channel_name);
1181 case SILC_COMMAND_GETKEY:
1185 SilcPublicKey public_key;
1188 GetkeyContext getkey;
1194 id_type = va_arg(vp, SilcUInt32);
1195 entry = va_arg(vp, void *);
1196 public_key = va_arg(vp, SilcPublicKey);
1199 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1201 getkey = silc_calloc(1, sizeof(*getkey));
1202 getkey->entry = entry;
1203 getkey->id_type = id_type;
1204 getkey->client = client;
1205 getkey->conn = conn;
1206 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1208 name = (id_type == SILC_ID_CLIENT ?
1209 ((SilcClientEntry)entry)->nickname :
1210 ((SilcServerEntry)entry)->server_name);
1212 silc_verify_public_key_internal(client, conn, name,
1213 (id_type == SILC_ID_CLIENT ?
1214 SILC_SOCKET_TYPE_CLIENT :
1215 SILC_SOCKET_TYPE_SERVER),
1216 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1217 silc_getkey_cb, getkey);
1220 printformat_module("fe-common/silc", server, NULL,
1221 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1226 case SILC_COMMAND_INFO:
1228 SilcServerEntry server_entry;
1235 server_entry = va_arg(vp, SilcServerEntry);
1236 server_name = va_arg(vp, char *);
1237 server_info = va_arg(vp, char *);
1239 if (server_name && server_info )
1241 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1242 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1247 case SILC_COMMAND_TOPIC:
1249 SilcChannelEntry channel;
1255 channel = va_arg(vp, SilcChannelEntry);
1256 topic = va_arg(vp, char *);
1259 chanrec = silc_channel_find_entry(server, channel);
1261 g_free_not_null(chanrec->topic);
1262 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1263 signal_emit("channel topic changed", 1, chanrec);
1265 printformat_module("fe-common/silc", server, channel->channel_name,
1266 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1267 channel->channel_name, topic);
1269 printformat_module("fe-common/silc", server, channel->channel_name,
1270 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1271 channel->channel_name);
1283 SilcClientConnection conn;
1289 SilcSKEPKType pk_type;
1290 SilcVerifyPublicKey completion;
1294 static void verify_public_key_completion(const char *line, void *context)
1296 PublicKeyVerify verify = (PublicKeyVerify)context;
1298 if (line[0] == 'Y' || line[0] == 'y') {
1299 /* Call the completion */
1300 if (verify->completion)
1301 verify->completion(TRUE, verify->context);
1303 /* Save the key for future checking */
1304 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1305 verify->pk_len, SILC_PKCS_FILE_PEM);
1307 /* Call the completion */
1308 if (verify->completion)
1309 verify->completion(FALSE, verify->context);
1311 printformat_module("fe-common/silc", NULL, NULL,
1312 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1313 verify->entity_name ? verify->entity_name :
1317 silc_free(verify->filename);
1318 silc_free(verify->entity);
1319 silc_free(verify->entity_name);
1320 silc_free(verify->pk);
1324 /* Internal routine to verify public key. If the `completion' is provided
1325 it will be called to indicate whether public was verified or not. For
1326 server/router public key this will check for filename that includes the
1327 remote host's IP address and remote host's hostname. */
1330 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1331 const char *name, SilcSocketType conn_type,
1332 unsigned char *pk, SilcUInt32 pk_len,
1333 SilcSKEPKType pk_type,
1334 SilcVerifyPublicKey completion, void *context)
1337 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1338 char *fingerprint, *babbleprint, *format;
1341 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1342 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1343 "server" : "client");
1344 PublicKeyVerify verify;
1346 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1347 printformat_module("fe-common/silc", NULL, NULL,
1348 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1351 completion(FALSE, context);
1355 pw = getpwuid(getuid());
1358 completion(FALSE, context);
1362 memset(filename, 0, sizeof(filename));
1363 memset(filename2, 0, sizeof(filename2));
1364 memset(file, 0, sizeof(file));
1366 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1367 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1369 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1370 conn->sock->ip, conn->sock->port);
1371 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1372 pw->pw_dir, entity, file);
1374 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1375 conn->sock->hostname, conn->sock->port);
1376 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1377 pw->pw_dir, entity, file);
1382 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1383 name, conn->sock->port);
1384 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1385 pw->pw_dir, entity, file);
1390 /* Replace all whitespaces with `_'. */
1391 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1392 for (i = 0; i < strlen(fingerprint); i++)
1393 if (fingerprint[i] == ' ')
1394 fingerprint[i] = '_';
1396 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1397 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1398 pw->pw_dir, entity, file);
1399 silc_free(fingerprint);
1404 /* Take fingerprint of the public key */
1405 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1406 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1408 verify = silc_calloc(1, sizeof(*verify));
1409 verify->client = client;
1410 verify->conn = conn;
1411 verify->filename = strdup(ipf);
1412 verify->entity = strdup(entity);
1413 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1414 (name ? strdup(name) : strdup(conn->sock->hostname))
1416 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1417 memcpy(verify->pk, pk, pk_len);
1418 verify->pk_len = pk_len;
1419 verify->pk_type = pk_type;
1420 verify->completion = completion;
1421 verify->context = context;
1423 /* Check whether this key already exists */
1424 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1425 /* Key does not exist, ask user to verify the key and save it */
1427 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1428 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1429 verify->entity_name : entity);
1430 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1431 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1432 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1433 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1434 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1435 SILCTXT_PUBKEY_ACCEPT);
1436 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1439 silc_free(fingerprint);
1442 /* The key already exists, verify it. */
1443 SilcPublicKey public_key;
1444 unsigned char *encpk;
1445 SilcUInt32 encpk_len;
1447 /* Load the key file, try for both IP filename and hostname filename */
1448 if (!silc_pkcs_load_public_key(ipf, &public_key,
1449 SILC_PKCS_FILE_PEM) &&
1450 !silc_pkcs_load_public_key(ipf, &public_key,
1451 SILC_PKCS_FILE_BIN) &&
1452 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1453 SILC_PKCS_FILE_PEM) &&
1454 !silc_pkcs_load_public_key(hostf, &public_key,
1455 SILC_PKCS_FILE_BIN)))) {
1456 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1457 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1458 verify->entity_name : entity);
1459 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1460 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1461 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1462 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1463 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1464 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1465 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1466 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1467 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1470 silc_free(fingerprint);
1474 /* Encode the key data */
1475 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1477 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1478 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1479 verify->entity_name : entity);
1480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1481 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1482 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1483 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1484 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1485 SILCTXT_PUBKEY_MALFORMED, entity);
1486 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1487 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1488 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1491 silc_free(fingerprint);
1495 /* Compare the keys */
1496 if (memcmp(encpk, pk, encpk_len)) {
1497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1498 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1499 verify->entity_name : entity);
1500 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1501 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1502 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1503 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1505 SILCTXT_PUBKEY_NO_MATCH, entity);
1506 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1507 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1508 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1509 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1511 /* Ask user to verify the key and save it */
1512 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1513 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1514 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1517 silc_free(fingerprint);
1521 /* Local copy matched */
1523 completion(TRUE, context);
1524 silc_free(fingerprint);
1528 /* Verifies received public key. The `conn_type' indicates which entity
1529 (server, client etc.) has sent the public key. If user decides to trust
1530 the key may be saved as trusted public key for later use. The
1531 `completion' must be called after the public key has been verified. */
1534 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1535 SilcSocketType conn_type, unsigned char *pk,
1536 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1537 SilcVerifyPublicKey completion, void *context)
1539 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1541 completion, context);
1544 /* Asks passphrase from user on the input line. */
1547 SilcAskPassphrase completion;
1551 void ask_passphrase_completion(const char *passphrase, void *context)
1553 AskPassphrase p = (AskPassphrase)context;
1554 p->completion((unsigned char *)passphrase,
1555 passphrase ? strlen(passphrase) : 0, p->context);
1559 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1560 SilcAskPassphrase completion, void *context)
1562 AskPassphrase p = silc_calloc(1, sizeof(*p));
1563 p->completion = completion;
1564 p->context = context;
1566 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1567 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1571 SilcGetAuthMeth completion;
1573 } *InternalGetAuthMethod;
1575 /* Callback called when we've received the authentication method information
1576 from the server after we've requested it. This will get the authentication
1577 data from the user if needed. */
1579 static void silc_get_auth_method_callback(SilcClient client,
1580 SilcClientConnection conn,
1581 SilcAuthMethod auth_meth,
1584 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1586 SILC_LOG_DEBUG(("Start"));
1588 switch (auth_meth) {
1589 case SILC_AUTH_NONE:
1590 /* No authentication required. */
1591 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1593 case SILC_AUTH_PASSWORD:
1594 /* Do not ask the passphrase from user, the library will ask it if
1595 we do not provide it here. */
1596 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1598 case SILC_AUTH_PUBLIC_KEY:
1599 /* Do not get the authentication data now, the library will generate
1600 it using our default key, if we do not provide it here. */
1601 /* XXX In the future when we support multiple local keys and multiple
1602 local certificates we will need to ask from user which one to use. */
1603 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1607 silc_free(internal);
1610 /* Find authentication method and authentication data by hostname and
1611 port. The hostname may be IP address as well. The found authentication
1612 method and authentication data is returned to `auth_meth', `auth_data'
1613 and `auth_data_len'. The function returns TRUE if authentication method
1614 is found and FALSE if not. `conn' may be NULL. */
1616 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1617 char *hostname, SilcUInt16 port,
1618 SilcGetAuthMeth completion, void *context)
1620 InternalGetAuthMethod internal;
1622 SILC_LOG_DEBUG(("Start"));
1624 /* XXX must resolve from configuration whether this connection has
1625 any specific authentication data */
1627 /* If we do not have this connection configured by the user in a
1628 configuration file then resolve the authentication method from the
1629 server for this session. */
1630 internal = silc_calloc(1, sizeof(*internal));
1631 internal->completion = completion;
1632 internal->context = context;
1634 silc_client_request_authentication_method(client, conn,
1635 silc_get_auth_method_callback,
1639 /* Notifies application that failure packet was received. This is called
1640 if there is some protocol active in the client. The `protocol' is the
1641 protocol context. The `failure' is opaque pointer to the failure
1642 indication. Note, that the `failure' is protocol dependant and application
1643 must explicitly cast it to correct type. Usually `failure' is 32 bit
1644 failure type (see protocol specs for all protocol failure types). */
1646 void silc_failure(SilcClient client, SilcClientConnection conn,
1647 SilcProtocol protocol, void *failure)
1649 SILC_LOG_DEBUG(("Start"));
1651 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1652 SilcSKEStatus status = (SilcSKEStatus)failure;
1654 if (status == SILC_SKE_STATUS_BAD_VERSION)
1655 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1656 SILCTXT_KE_BAD_VERSION);
1657 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1658 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1659 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1660 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1661 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1662 SILCTXT_KE_UNKNOWN_GROUP);
1663 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1664 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1665 SILCTXT_KE_UNKNOWN_CIPHER);
1666 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1667 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1668 SILCTXT_KE_UNKNOWN_PKCS);
1669 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1670 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1671 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1672 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1673 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1674 SILCTXT_KE_UNKNOWN_HMAC);
1675 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1676 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1677 SILCTXT_KE_INCORRECT_SIGNATURE);
1678 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1679 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1680 SILCTXT_KE_INVALID_COOKIE);
1683 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1684 SilcUInt32 err = (SilcUInt32)failure;
1686 if (err == SILC_AUTH_FAILED)
1687 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1688 SILCTXT_AUTH_FAILED);
1692 /* Asks whether the user would like to perform the key agreement protocol.
1693 This is called after we have received an key agreement packet or an
1694 reply to our key agreement packet. This returns TRUE if the user wants
1695 the library to perform the key agreement protocol and FALSE if it is not
1696 desired (application may start it later by calling the function
1697 silc_client_perform_key_agreement). */
1699 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1700 SilcClientEntry client_entry, const char *hostname,
1701 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1706 SILC_LOG_DEBUG(("Start"));
1708 /* We will just display the info on the screen and return FALSE and user
1709 will have to start the key agreement with a command. */
1712 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1715 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1716 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1718 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1719 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1720 client_entry->nickname, hostname, portstr);
1728 void silc_ftp(SilcClient client, SilcClientConnection conn,
1729 SilcClientEntry client_entry, SilcUInt32 session_id,
1730 const char *hostname, SilcUInt16 port)
1732 SILC_SERVER_REC *server;
1734 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1736 SILC_LOG_DEBUG(("Start"));
1738 server = conn->context;
1740 ftp->client_entry = client_entry;
1741 ftp->session_id = session_id;
1744 silc_dlist_add(server->ftp_sessions, ftp);
1745 server->current_session = ftp;
1748 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1751 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_FILE_REQUEST, client_entry->nickname);
1754 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1755 SILCTXT_FILE_REQUEST_HOST,
1756 client_entry->nickname, hostname, portstr);
1759 /* SILC client operations */
1760 SilcClientOperations ops = {
1762 silc_channel_message,
1763 silc_private_message,
1769 silc_get_auth_method,
1770 silc_verify_public_key,
1771 silc_ask_passphrase,