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"));
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 nicklist_rename_unique(SERVER(server),
336 client_entry, client_entry->nickname,
337 client_entry2, client_entry2->nickname);
339 memset(userhost, 0, sizeof(userhost));
340 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
341 client_entry2->username, client_entry2->hostname);
342 signal_emit("message nick", 4, server, client_entry2->nickname,
343 client_entry2->nickname, userhost);
346 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
348 * Changed channel mode.
351 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
353 idtype = va_arg(va, int);
354 entry = va_arg(va, void *);
355 mode = va_arg(va, uint32);
356 (void)va_arg(va, char *);
357 (void)va_arg(va, char *);
358 channel = va_arg(va, SilcChannelEntry);
360 tmp = silc_client_chmode(mode,
361 channel->channel_key ?
362 channel->channel_key->cipher->name : "",
364 silc_hmac_get_name(channel->hmac) : "");
366 chanrec = silc_channel_find_entry(server, channel);
367 if (chanrec != NULL) {
368 g_free_not_null(chanrec->mode);
369 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
370 signal_emit("channel mode changed", 1, chanrec);
373 if (idtype == SILC_ID_CLIENT) {
374 client_entry = (SilcClientEntry)entry;
375 printformat_module("fe-common/silc", server, channel->channel_name,
376 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
377 channel->channel_name, tmp ? tmp : "removed all",
378 client_entry->nickname);
379 } else if (idtype == SILC_ID_SERVER) {
380 server_entry = (SilcServerEntry)entry;
381 printformat_module("fe-common/silc", server, channel->channel_name,
382 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
383 channel->channel_name, tmp ? tmp : "removed all",
384 server_entry->server_name);
390 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
392 * Changed user's mode on channel.
395 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
397 client_entry = va_arg(va, SilcClientEntry);
398 mode = va_arg(va, uint32);
399 client_entry2 = va_arg(va, SilcClientEntry);
400 channel = va_arg(va, SilcChannelEntry);
402 tmp = silc_client_chumode(mode);
403 chanrec = silc_channel_find_entry(server, channel);
404 if (chanrec != NULL) {
407 if (client_entry2 == server->conn->local_entry)
408 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
410 nick = silc_nicklist_find(chanrec, client_entry2);
412 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
413 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
414 signal_emit("nick mode changed", 2, chanrec, nick);
418 printformat_module("fe-common/silc", server, channel->channel_name,
419 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
420 channel->channel_name, client_entry2->nickname,
421 tmp ? tmp : "removed all",
422 client_entry->nickname);
424 if (mode & SILC_CHANNEL_UMODE_CHANFO)
425 printformat_module("fe-common/silc",
426 server, channel->channel_name, MSGLEVEL_CRAP,
427 SILCTXT_CHANNEL_FOUNDER,
428 channel->channel_name, client_entry2->nickname);
433 case SILC_NOTIFY_TYPE_MOTD:
438 SILC_LOG_DEBUG(("Notify: MOTD"));
440 tmp = va_arg(va, char *);
442 if (!settings_get_bool("skip_motd"))
443 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
446 case SILC_NOTIFY_TYPE_KICKED:
448 * Someone was kicked from channel.
451 SILC_LOG_DEBUG(("Notify: KICKED"));
453 client_entry = va_arg(va, SilcClientEntry);
454 tmp = va_arg(va, char *);
455 client_entry2 = va_arg(va, SilcClientEntry);
456 channel = va_arg(va, SilcChannelEntry);
458 chanrec = silc_channel_find_entry(server, channel);
460 if (client_entry == conn->local_entry) {
461 printformat_module("fe-common/silc", server, channel->channel_name,
462 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
463 client_entry2->nickname,
464 channel->channel_name, tmp ? tmp : "");
466 chanrec->kicked = TRUE;
467 channel_destroy((CHANNEL_REC *)chanrec);
470 printformat_module("fe-common/silc", server, channel->channel_name,
471 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
472 client_entry->nickname,
473 client_entry2->nickname,
474 channel->channel_name, tmp ? tmp : "");
477 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
479 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
484 case SILC_NOTIFY_TYPE_KILLED:
486 * Someone was killed from the network.
489 SILC_LOG_DEBUG(("Notify: KILLED"));
491 client_entry = va_arg(va, SilcClientEntry);
492 tmp = va_arg(va, char *);
494 if (client_entry == conn->local_entry) {
495 printformat_module("fe-common/silc", server, NULL,
496 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
499 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
500 for (list_tmp = list1; list_tmp != NULL; list_tmp =
501 list_tmp->next->next) {
502 CHANNEL_REC *channel = list_tmp->data;
503 NICK_REC *nickrec = list_tmp->next->data;
504 nicklist_remove(channel, nickrec);
507 printformat_module("fe-common/silc", server, NULL,
508 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
509 client_entry->nickname,
514 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
517 * Server has quit the network.
520 SilcClientEntry *clients;
521 uint32 clients_count;
523 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
525 (void)va_arg(va, void *);
526 clients = va_arg(va, SilcClientEntry *);
527 clients_count = va_arg(va, uint32);
529 for (i = 0; i < clients_count; i++) {
530 memset(userhost, 0, sizeof(userhost));
531 if (clients[i]->username)
532 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
533 clients[i]->username, clients[i]->hostname);
534 signal_emit("message quit", 4, server, clients[i]->nickname,
535 clients[i]->username ? userhost : "",
538 silc_server_free_ftp(server, clients[i]);
540 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
541 for (list_tmp = list1; list_tmp != NULL; list_tmp =
542 list_tmp->next->next) {
543 CHANNEL_REC *channel = list_tmp->data;
544 NICK_REC *nickrec = list_tmp->next->data;
545 nicklist_remove(channel, nickrec);
553 printformat_module("fe-common/silc", server, NULL,
554 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
561 /* Called to indicate that connection was either successfully established
562 or connecting failed. This is also the first time application receives
563 the SilcClientConnection object which it should save somewhere. */
565 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
567 SILC_SERVER_REC *server = conn->context;
569 if (!server && !success) {
570 silc_client_close_connection(client, NULL, conn);
575 server->connected = TRUE;
576 signal_emit("event connected", 1, server);
578 server->connection_lost = TRUE;
580 server->conn->context = NULL;
581 server_disconnect(SERVER(server));
585 /* Called to indicate that connection was disconnected to the server. */
587 void silc_disconnect(SilcClient client, SilcClientConnection conn)
589 SILC_SERVER_REC *server = conn->context;
591 SILC_LOG_DEBUG(("Start"));
593 if (server->conn && server->conn->local_entry) {
594 nicklist_rename_unique(SERVER(server),
595 server->conn->local_entry, server->nick,
596 server->conn->local_entry,
597 silc_client->username);
598 silc_change_nick(server, silc_client->username);
601 server->conn->context = NULL;
603 server->connection_lost = TRUE;
604 server_disconnect(SERVER(server));
607 /* Command handler. This function is called always in the command function.
608 If error occurs it will be called as well. `conn' is the associated
609 client connection. `cmd_context' is the command context that was
610 originally sent to the command. `success' is FALSE if error occured
611 during command. `command' is the command being processed. It must be
612 noted that this is not reply from server. This is merely called just
613 after application has called the command. Just to tell application
614 that the command really was processed. */
616 void silc_command(SilcClient client, SilcClientConnection conn,
617 SilcClientCommandContext cmd_context, int success,
620 SILC_SERVER_REC *server = conn->context;
622 SILC_LOG_DEBUG(("Start"));
628 case SILC_COMMAND_INVITE:
629 printformat_module("fe-common/silc", server, NULL,
630 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
631 cmd_context->argv[2],
632 (cmd_context->argv[1][0] == '*' ?
633 (char *)conn->current_channel->channel_name :
634 (char *)cmd_context->argv[1]));
641 /* Client info resolving callback when JOIN command reply is received.
642 This will cache all users on the channel. */
644 static void silc_client_join_get_users(SilcClient client,
645 SilcClientConnection conn,
646 SilcClientEntry *clients,
647 uint32 clients_count,
650 SilcChannelEntry channel = (SilcChannelEntry)context;
651 SilcHashTableList htl;
653 SILC_SERVER_REC *server = conn->context;
654 SILC_CHANNEL_REC *chanrec;
655 SilcClientEntry founder = NULL;
661 chanrec = silc_channel_find(server, channel->channel_name);
665 silc_hash_table_list(channel->user_list, &htl);
666 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
667 if (!chu->client->nickname)
669 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
670 founder = chu->client;
671 silc_nicklist_insert(chanrec, chu, FALSE);
673 silc_hash_table_list_reset(&htl);
675 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
676 nicklist_set_own(CHANNEL(chanrec), ownnick);
677 signal_emit("channel joined", 1, chanrec);
680 printformat_module("fe-common/silc", server, channel->channel_name,
681 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
682 channel->channel_name, chanrec->topic);
684 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
687 if (founder == conn->local_entry)
688 printformat_module("fe-common/silc",
689 server, channel->channel_name, MSGLEVEL_CRAP,
690 SILCTXT_CHANNEL_FOUNDER_YOU,
691 channel->channel_name);
693 printformat_module("fe-common/silc",
694 server, channel->channel_name, MSGLEVEL_CRAP,
695 SILCTXT_CHANNEL_FOUNDER,
696 channel->channel_name, founder->nickname);
702 SilcClientConnection conn;
708 void silc_getkey_cb(bool success, void *context)
710 GetkeyContext getkey = (GetkeyContext)context;
711 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
712 char *name = (getkey->id_type == SILC_ID_CLIENT ?
713 ((SilcClientEntry)getkey->entry)->nickname :
714 ((SilcServerEntry)getkey->entry)->server_name);
717 printformat_module("fe-common/silc", NULL, NULL,
718 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
720 printformat_module("fe-common/silc", NULL, NULL,
721 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
724 silc_free(getkey->fingerprint);
728 /* Command reply handler. This function is called always in the command reply
729 function. If error occurs it will be called as well. Normal scenario
730 is that it will be called after the received command data has been parsed
731 and processed. The function is used to pass the received command data to
734 `conn' is the associated client connection. `cmd_payload' is the command
735 payload data received from server and it can be ignored. It is provided
736 if the application would like to re-parse the received command data,
737 however, it must be noted that the data is parsed already by the library
738 thus the payload can be ignored. `success' is FALSE if error occured.
739 In this case arguments are not sent to the application. `command' is the
740 command reply being processed. The function has variable argument list
741 and each command defines the number and type of arguments it passes to the
742 application (on error they are not sent). */
745 silc_command_reply(SilcClient client, SilcClientConnection conn,
746 SilcCommandPayload cmd_payload, int success,
747 SilcCommand command, SilcCommandStatus status, ...)
750 SILC_SERVER_REC *server = conn->context;
751 SILC_CHANNEL_REC *chanrec;
754 va_start(vp, status);
756 SILC_LOG_DEBUG(("Start"));
759 case SILC_COMMAND_WHOIS:
761 char buf[1024], *nickname, *username, *realname, *nick;
762 unsigned char *fingerprint;
765 SilcClientEntry client_entry;
767 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
768 /* Print the unknown nick for user */
770 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
773 silc_say_error("%s: %s", tmp,
774 silc_client_command_status_message(status));
776 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
777 /* Try to find the entry for the unknown client ID, since we
778 might have, and print the nickname of it for user. */
781 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
784 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
786 client_entry = silc_client_get_client_by_id(client, conn,
788 if (client_entry && client_entry->nickname)
789 silc_say_error("%s: %s", client_entry->nickname,
790 silc_client_command_status_message(status));
791 silc_free(client_id);
800 client_entry = va_arg(vp, SilcClientEntry);
801 nickname = va_arg(vp, char *);
802 username = va_arg(vp, char *);
803 realname = va_arg(vp, char *);
804 channels = va_arg(vp, SilcBuffer);
805 mode = va_arg(vp, uint32);
806 idle = va_arg(vp, uint32);
807 fingerprint = va_arg(vp, unsigned char *);
809 silc_parse_userfqdn(nickname, &nick, NULL);
810 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
811 SILCTXT_WHOIS_USERINFO, nickname,
812 client_entry->username, client_entry->hostname,
813 nick, client_entry->nickname);
814 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
815 SILCTXT_WHOIS_REALNAME, realname);
819 SilcDList list = silc_channel_payload_parse_list(channels->data,
822 SilcChannelPayload entry;
823 memset(buf, 0, sizeof(buf));
824 silc_dlist_start(list);
825 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
826 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
828 char *name = silc_channel_get_name(entry, &name_len);
831 strncat(buf, m, strlen(m));
832 strncat(buf, name, name_len);
833 strncat(buf, " ", 1);
837 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
838 SILCTXT_WHOIS_CHANNELS, buf);
839 silc_channel_payload_list_free(list);
844 memset(buf, 0, sizeof(buf));
846 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
847 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
848 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
850 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
851 "SILC Operator " : "[Unknown mode] ");
853 if (mode & SILC_UMODE_GONE)
856 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
857 SILCTXT_WHOIS_MODES, buf);
860 if (idle && nickname) {
861 memset(buf, 0, sizeof(buf));
862 snprintf(buf, sizeof(buf) - 1, "%lu %s",
863 idle > 60 ? (idle / 60) : idle,
864 idle > 60 ? "minutes" : "seconds");
866 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
867 SILCTXT_WHOIS_IDLE, buf);
871 fingerprint = silc_fingerprint(fingerprint, 20);
872 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
873 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
874 silc_free(fingerprint);
879 case SILC_COMMAND_IDENTIFY:
881 SilcClientEntry client_entry;
883 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
884 /* Print the unknown nick for user */
886 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
889 silc_say_error("%s: %s", tmp,
890 silc_client_command_status_message(status));
892 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
893 /* Try to find the entry for the unknown client ID, since we
894 might have, and print the nickname of it for user. */
897 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
900 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
902 client_entry = silc_client_get_client_by_id(client, conn,
904 if (client_entry && client_entry->nickname)
905 silc_say_error("%s: %s", client_entry->nickname,
906 silc_client_command_status_message(status));
907 silc_free(client_id);
916 case SILC_COMMAND_WHOWAS:
918 char *nickname, *username, *realname;
920 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
921 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
923 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
926 silc_say_error("%s: %s", tmp,
927 silc_client_command_status_message(status));
934 (void)va_arg(vp, SilcClientEntry);
935 nickname = va_arg(vp, char *);
936 username = va_arg(vp, char *);
937 realname = va_arg(vp, char *);
939 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
940 SILCTXT_WHOWAS_USERINFO, nickname, username,
941 realname ? realname : "");
945 case SILC_COMMAND_INVITE:
947 SilcChannelEntry channel;
949 SilcArgumentPayload args;
955 channel = va_arg(vp, SilcChannelEntry);
956 invite_list = va_arg(vp, char *);
958 args = silc_command_get_args(cmd_payload);
960 argc = silc_argument_get_arg_num(args);
963 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
964 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
967 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
968 SILCTXT_CHANNEL_NO_INVITE_LIST,
969 channel->channel_name);
973 case SILC_COMMAND_JOIN:
975 char *channel, *mode, *topic;
977 SilcChannelEntry channel_entry;
978 SilcBuffer client_id_list;
984 channel = va_arg(vp, char *);
985 channel_entry = va_arg(vp, SilcChannelEntry);
986 modei = va_arg(vp, uint32);
987 (void)va_arg(vp, uint32);
988 (void)va_arg(vp, unsigned char *);
989 (void)va_arg(vp, unsigned char *);
990 (void)va_arg(vp, unsigned char *);
991 topic = va_arg(vp, char *);
992 (void)va_arg(vp, unsigned char *);
993 list_count = va_arg(vp, uint32);
994 client_id_list = va_arg(vp, SilcBuffer);
996 chanrec = silc_channel_find(server, channel);
998 chanrec = silc_channel_create(server, channel, TRUE);
1001 g_free_not_null(chanrec->topic);
1002 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1003 signal_emit("channel topic changed", 1, chanrec);
1006 mode = silc_client_chmode(modei,
1007 channel_entry->channel_key ?
1008 channel_entry->channel_key->cipher->name : "",
1009 channel_entry->hmac ?
1010 silc_hmac_get_name(channel_entry->hmac) : "");
1011 g_free_not_null(chanrec->mode);
1012 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1013 signal_emit("channel mode changed", 1, chanrec);
1015 /* Resolve the client information */
1016 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1017 silc_client_join_get_users,
1023 case SILC_COMMAND_NICK:
1025 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1031 old = g_strdup(server->nick);
1032 server_change_nick(SERVER(server), client->nickname);
1033 nicklist_rename_unique(SERVER(server),
1034 server->conn->local_entry, server->nick,
1035 client, client->nickname);
1037 signal_emit("message own_nick", 4, server, server->nick, old, "");
1042 case SILC_COMMAND_LIST:
1051 (void)va_arg(vp, SilcChannelEntry);
1052 name = va_arg(vp, char *);
1053 topic = va_arg(vp, char *);
1054 usercount = va_arg(vp, int);
1056 if (status == SILC_STATUS_LIST_START ||
1057 status == SILC_STATUS_OK)
1058 printformat_module("fe-common/silc", server, NULL,
1059 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1062 snprintf(users, sizeof(users) - 1, "N/A");
1064 snprintf(users, sizeof(users) - 1, "%d", usercount);
1065 printformat_module("fe-common/silc", server, NULL,
1066 MSGLEVEL_CRAP, SILCTXT_LIST,
1067 name, users, topic ? topic : "");
1071 case SILC_COMMAND_UMODE:
1078 mode = va_arg(vp, uint32);
1080 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1081 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1082 printformat_module("fe-common/silc", server, NULL,
1083 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1085 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1086 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1087 printformat_module("fe-common/silc", server, NULL,
1088 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1090 server->umode = mode;
1094 case SILC_COMMAND_OPER:
1098 printformat_module("fe-common/silc", server, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1102 case SILC_COMMAND_SILCOPER:
1106 printformat_module("fe-common/silc", server, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1110 case SILC_COMMAND_USERS:
1112 SilcHashTableList htl;
1113 SilcChannelEntry channel;
1114 SilcChannelUser chu;
1119 channel = va_arg(vp, SilcChannelEntry);
1121 printformat_module("fe-common/silc", server, channel->channel_name,
1122 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1123 channel->channel_name);
1125 silc_hash_table_list(channel->user_list, &htl);
1126 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1127 SilcClientEntry e = chu->client;
1128 char stat[5], *mode;
1133 memset(stat, 0, sizeof(stat));
1134 mode = silc_client_chumode_char(chu->mode);
1135 if (e->mode & SILC_UMODE_GONE)
1142 printformat_module("fe-common/silc", server, channel->channel_name,
1143 MSGLEVEL_CRAP, SILCTXT_USERS,
1145 e->username ? e->username : "",
1146 e->hostname ? e->hostname : "",
1147 e->realname ? e->realname : "");
1151 silc_hash_table_list_reset(&htl);
1155 case SILC_COMMAND_BAN:
1157 SilcChannelEntry channel;
1163 channel = va_arg(vp, SilcChannelEntry);
1164 ban_list = va_arg(vp, char *);
1167 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1168 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1171 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1172 SILCTXT_CHANNEL_NO_BAN_LIST,
1173 channel->channel_name);
1177 case SILC_COMMAND_GETKEY:
1181 SilcPublicKey public_key;
1184 GetkeyContext getkey;
1190 id_type = va_arg(vp, uint32);
1191 entry = va_arg(vp, void *);
1192 public_key = va_arg(vp, SilcPublicKey);
1195 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1197 getkey = silc_calloc(1, sizeof(*getkey));
1198 getkey->entry = entry;
1199 getkey->id_type = id_type;
1200 getkey->client = client;
1201 getkey->conn = conn;
1202 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1204 name = (id_type == SILC_ID_CLIENT ?
1205 ((SilcClientEntry)entry)->nickname :
1206 ((SilcServerEntry)entry)->server_name);
1208 silc_verify_public_key_internal(client, conn, name,
1209 (id_type == SILC_ID_CLIENT ?
1210 SILC_SOCKET_TYPE_CLIENT :
1211 SILC_SOCKET_TYPE_SERVER),
1212 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1213 silc_getkey_cb, getkey);
1216 printformat_module("fe-common/silc", server, NULL,
1217 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1222 case SILC_COMMAND_INFO:
1224 SilcServerEntry server_entry;
1231 server_entry = va_arg(vp, SilcServerEntry);
1232 server_name = va_arg(vp, char *);
1233 server_info = va_arg(vp, char *);
1235 if (server_name && server_info )
1237 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1238 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1243 case SILC_COMMAND_TOPIC:
1245 SilcChannelEntry channel;
1251 channel = va_arg(vp, SilcChannelEntry);
1252 topic = va_arg(vp, char *);
1255 chanrec = silc_channel_find_entry(server, channel);
1257 g_free_not_null(chanrec->topic);
1258 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1259 signal_emit("channel topic changed", 1, chanrec);
1261 printformat_module("fe-common/silc", server, channel->channel_name,
1262 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1263 channel->channel_name, topic);
1265 printformat_module("fe-common/silc", server, channel->channel_name,
1266 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1267 channel->channel_name);
1279 SilcClientConnection conn;
1285 SilcSKEPKType pk_type;
1286 SilcVerifyPublicKey completion;
1290 static void verify_public_key_completion(const char *line, void *context)
1292 PublicKeyVerify verify = (PublicKeyVerify)context;
1294 if (line[0] == 'Y' || line[0] == 'y') {
1295 /* Call the completion */
1296 if (verify->completion)
1297 verify->completion(TRUE, verify->context);
1299 /* Save the key for future checking */
1300 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1301 verify->pk_len, SILC_PKCS_FILE_PEM);
1303 /* Call the completion */
1304 if (verify->completion)
1305 verify->completion(FALSE, verify->context);
1307 printformat_module("fe-common/silc", NULL, NULL,
1308 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1309 verify->entity_name ? verify->entity_name :
1313 silc_free(verify->filename);
1314 silc_free(verify->entity);
1315 silc_free(verify->entity_name);
1316 silc_free(verify->pk);
1320 /* Internal routine to verify public key. If the `completion' is provided
1321 it will be called to indicate whether public was verified or not. For
1322 server/router public key this will check for filename that includes the
1323 remote host's IP address and remote host's hostname. */
1326 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1327 const char *name, SilcSocketType conn_type,
1328 unsigned char *pk, uint32 pk_len,
1329 SilcSKEPKType pk_type,
1330 SilcVerifyPublicKey completion, void *context)
1333 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1334 char *fingerprint, *babbleprint, *format;
1337 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1338 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1339 "server" : "client");
1340 PublicKeyVerify verify;
1342 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1343 printformat_module("fe-common/silc", NULL, NULL,
1344 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1347 completion(FALSE, context);
1351 pw = getpwuid(getuid());
1354 completion(FALSE, context);
1358 memset(filename, 0, sizeof(filename));
1359 memset(filename2, 0, sizeof(filename2));
1360 memset(file, 0, sizeof(file));
1362 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1363 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1365 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1366 conn->sock->ip, conn->sock->port);
1367 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1368 pw->pw_dir, entity, file);
1370 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1371 conn->sock->hostname, conn->sock->port);
1372 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1373 pw->pw_dir, entity, file);
1378 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1379 name, conn->sock->port);
1380 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1381 pw->pw_dir, entity, file);
1386 /* Replace all whitespaces with `_'. */
1387 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1388 for (i = 0; i < strlen(fingerprint); i++)
1389 if (fingerprint[i] == ' ')
1390 fingerprint[i] = '_';
1392 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1393 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1394 pw->pw_dir, entity, file);
1395 silc_free(fingerprint);
1400 /* Take fingerprint of the public key */
1401 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1402 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1404 verify = silc_calloc(1, sizeof(*verify));
1405 verify->client = client;
1406 verify->conn = conn;
1407 verify->filename = strdup(ipf);
1408 verify->entity = strdup(entity);
1409 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1410 (name ? strdup(name) : strdup(conn->sock->hostname))
1412 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1413 memcpy(verify->pk, pk, pk_len);
1414 verify->pk_len = pk_len;
1415 verify->pk_type = pk_type;
1416 verify->completion = completion;
1417 verify->context = context;
1419 /* Check whether this key already exists */
1420 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1421 /* Key does not exist, ask user to verify the key and save it */
1423 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1424 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1425 verify->entity_name : entity);
1426 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1427 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1428 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1429 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1430 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1431 SILCTXT_PUBKEY_ACCEPT);
1432 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1435 silc_free(fingerprint);
1438 /* The key already exists, verify it. */
1439 SilcPublicKey public_key;
1440 unsigned char *encpk;
1443 /* Load the key file, try for both IP filename and hostname filename */
1444 if (!silc_pkcs_load_public_key(ipf, &public_key,
1445 SILC_PKCS_FILE_PEM) &&
1446 !silc_pkcs_load_public_key(ipf, &public_key,
1447 SILC_PKCS_FILE_BIN) &&
1448 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1449 SILC_PKCS_FILE_PEM) &&
1450 !silc_pkcs_load_public_key(hostf, &public_key,
1451 SILC_PKCS_FILE_BIN)))) {
1452 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1453 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1454 verify->entity_name : entity);
1455 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1456 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1457 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1458 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1459 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1460 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1461 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1462 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1463 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1466 silc_free(fingerprint);
1470 /* Encode the key data */
1471 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1473 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1474 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1475 verify->entity_name : entity);
1476 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1477 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1478 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1479 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1481 SILCTXT_PUBKEY_MALFORMED, entity);
1482 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1483 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1484 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1487 silc_free(fingerprint);
1491 /* Compare the keys */
1492 if (memcmp(encpk, pk, encpk_len)) {
1493 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1494 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1495 verify->entity_name : entity);
1496 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1497 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1498 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1499 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1500 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1501 SILCTXT_PUBKEY_NO_MATCH, entity);
1502 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1503 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1505 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1507 /* Ask user to verify the key and save it */
1508 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1509 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1510 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1513 silc_free(fingerprint);
1517 /* Local copy matched */
1519 completion(TRUE, context);
1520 silc_free(fingerprint);
1524 /* Verifies received public key. The `conn_type' indicates which entity
1525 (server, client etc.) has sent the public key. If user decides to trust
1526 the key may be saved as trusted public key for later use. The
1527 `completion' must be called after the public key has been verified. */
1530 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1531 SilcSocketType conn_type, unsigned char *pk,
1532 uint32 pk_len, SilcSKEPKType pk_type,
1533 SilcVerifyPublicKey completion, void *context)
1535 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1537 completion, context);
1540 /* Asks passphrase from user on the input line. */
1543 SilcAskPassphrase completion;
1547 void ask_passphrase_completion(const char *passphrase, void *context)
1549 AskPassphrase p = (AskPassphrase)context;
1550 p->completion((unsigned char *)passphrase,
1551 passphrase ? strlen(passphrase) : 0, p->context);
1555 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1556 SilcAskPassphrase completion, void *context)
1558 AskPassphrase p = silc_calloc(1, sizeof(*p));
1559 p->completion = completion;
1560 p->context = context;
1562 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1563 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1567 SilcGetAuthMeth completion;
1569 } *InternalGetAuthMethod;
1571 /* Callback called when we've received the authentication method information
1572 from the server after we've requested it. This will get the authentication
1573 data from the user if needed. */
1575 static void silc_get_auth_method_callback(SilcClient client,
1576 SilcClientConnection conn,
1577 SilcAuthMethod auth_meth,
1580 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1582 SILC_LOG_DEBUG(("Start"));
1584 switch (auth_meth) {
1585 case SILC_AUTH_NONE:
1586 /* No authentication required. */
1587 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1589 case SILC_AUTH_PASSWORD:
1590 /* Do not ask the passphrase from user, the library will ask it if
1591 we do not provide it here. */
1592 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1594 case SILC_AUTH_PUBLIC_KEY:
1595 /* Do not get the authentication data now, the library will generate
1596 it using our default key, if we do not provide it here. */
1597 /* XXX In the future when we support multiple local keys and multiple
1598 local certificates we will need to ask from user which one to use. */
1599 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1603 silc_free(internal);
1606 /* Find authentication method and authentication data by hostname and
1607 port. The hostname may be IP address as well. The found authentication
1608 method and authentication data is returned to `auth_meth', `auth_data'
1609 and `auth_data_len'. The function returns TRUE if authentication method
1610 is found and FALSE if not. `conn' may be NULL. */
1612 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1613 char *hostname, uint16 port,
1614 SilcGetAuthMeth completion, void *context)
1616 InternalGetAuthMethod internal;
1618 SILC_LOG_DEBUG(("Start"));
1620 /* XXX must resolve from configuration whether this connection has
1621 any specific authentication data */
1623 /* If we do not have this connection configured by the user in a
1624 configuration file then resolve the authentication method from the
1625 server for this session. */
1626 internal = silc_calloc(1, sizeof(*internal));
1627 internal->completion = completion;
1628 internal->context = context;
1630 silc_client_request_authentication_method(client, conn,
1631 silc_get_auth_method_callback,
1635 /* Notifies application that failure packet was received. This is called
1636 if there is some protocol active in the client. The `protocol' is the
1637 protocol context. The `failure' is opaque pointer to the failure
1638 indication. Note, that the `failure' is protocol dependant and application
1639 must explicitly cast it to correct type. Usually `failure' is 32 bit
1640 failure type (see protocol specs for all protocol failure types). */
1642 void silc_failure(SilcClient client, SilcClientConnection conn,
1643 SilcProtocol protocol, void *failure)
1645 SILC_LOG_DEBUG(("Start"));
1647 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1648 SilcSKEStatus status = (SilcSKEStatus)failure;
1650 if (status == SILC_SKE_STATUS_BAD_VERSION)
1651 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1652 SILCTXT_KE_BAD_VERSION);
1653 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1654 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1655 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1656 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1657 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1658 SILCTXT_KE_UNKNOWN_GROUP);
1659 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1660 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1661 SILCTXT_KE_UNKNOWN_CIPHER);
1662 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1663 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1664 SILCTXT_KE_UNKNOWN_PKCS);
1665 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1666 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1667 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1668 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1669 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1670 SILCTXT_KE_UNKNOWN_HMAC);
1671 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1672 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1673 SILCTXT_KE_INCORRECT_SIGNATURE);
1674 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1675 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1676 SILCTXT_KE_INVALID_COOKIE);
1679 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1680 uint32 err = (uint32)failure;
1682 if (err == SILC_AUTH_FAILED)
1683 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1684 SILCTXT_AUTH_FAILED);
1688 /* Asks whether the user would like to perform the key agreement protocol.
1689 This is called after we have received an key agreement packet or an
1690 reply to our key agreement packet. This returns TRUE if the user wants
1691 the library to perform the key agreement protocol and FALSE if it is not
1692 desired (application may start it later by calling the function
1693 silc_client_perform_key_agreement). */
1695 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1696 SilcClientEntry client_entry, const char *hostname,
1697 uint16 port, SilcKeyAgreementCallback *completion,
1702 SILC_LOG_DEBUG(("Start"));
1704 /* We will just display the info on the screen and return FALSE and user
1705 will have to start the key agreement with a command. */
1708 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1711 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1712 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1714 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1715 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1716 client_entry->nickname, hostname, portstr);
1724 void silc_ftp(SilcClient client, SilcClientConnection conn,
1725 SilcClientEntry client_entry, uint32 session_id,
1726 const char *hostname, uint16 port)
1728 SILC_SERVER_REC *server;
1730 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1732 SILC_LOG_DEBUG(("Start"));
1734 server = conn->context;
1736 ftp->client_entry = client_entry;
1737 ftp->session_id = session_id;
1740 silc_dlist_add(server->ftp_sessions, ftp);
1741 server->current_session = ftp;
1744 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1747 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1748 SILCTXT_FILE_REQUEST, client_entry->nickname);
1750 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1751 SILCTXT_FILE_REQUEST_HOST,
1752 client_entry->nickname, hostname, portstr);
1755 /* SILC client operations */
1756 SilcClientOperations ops = {
1758 silc_channel_message,
1759 silc_private_message,
1765 silc_get_auth_method,
1766 silc_verify_public_key,
1767 silc_ask_passphrase,