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"
44 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
45 const char *name, SilcSocketType conn_type,
46 unsigned char *pk, SilcUInt32 pk_len,
47 SilcSKEPKType pk_type,
48 SilcVerifyPublicKey completion, void *context);
50 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
53 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
54 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
55 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
57 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
58 "[SILC operator]" : "[unknown mode]");
60 if (mode & SILC_UMODE_GONE)
61 strcat(buf, " [away]");
62 if (mode & SILC_UMODE_INDISPOSED)
63 strcat(buf, " [indisposed]");
64 if (mode & SILC_UMODE_BUSY)
65 strcat(buf, " [busy]");
66 if (mode & SILC_UMODE_PAGE)
67 strcat(buf, " [page to reach]");
68 if (mode & SILC_UMODE_HYPER)
69 strcat(buf, " [hyper active]");
70 if (mode & SILC_UMODE_ROBOT)
71 strcat(buf, " [robot]");
72 if (mode & SILC_UMODE_ANONYMOUS)
73 strcat(buf, " [anonymous]");
74 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
75 strcat(buf, " [blocks private messages]");
76 if (mode & SILC_UMODE_DETACHED)
77 strcat(buf, " [detached]");
80 void silc_say(SilcClient client, SilcClientConnection conn,
81 SilcClientMessageType type, char *msg, ...)
83 SILC_SERVER_REC *server;
87 server = conn == NULL ? NULL : conn->context;
90 str = g_strdup_vprintf(msg, va);
91 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
96 void silc_say_error(char *msg, ...)
102 str = g_strdup_vprintf(msg, va);
103 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
109 /* Message for a channel. The `sender' is the nickname of the sender
110 received in the packet. The `channel_name' is the name of the channel. */
112 void silc_channel_message(SilcClient client, SilcClientConnection conn,
113 SilcClientEntry sender, SilcChannelEntry channel,
114 SilcMessageFlags flags, const unsigned char *message,
115 SilcUInt32 message_len)
117 SILC_SERVER_REC *server;
119 SILC_CHANNEL_REC *chanrec;
121 SILC_LOG_DEBUG(("Start"));
126 server = conn == NULL ? NULL : conn->context;
127 chanrec = silc_channel_find_entry(server, channel);
131 nick = silc_nicklist_find(chanrec, sender);
133 /* We didn't find client but it clearly exists, add it. */
134 SilcChannelUser chu = silc_client_on_channel(channel, sender);
136 nick = silc_nicklist_insert(chanrec, chu, FALSE);
139 if (flags & SILC_MESSAGE_FLAG_DATA) {
140 /* MIME object received, try to display it as well as we can */
144 memset(type, 0, sizeof(type));
145 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
146 NULL, 0, &data, NULL))
149 /* Then figure out what we can display */
150 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
151 !strstr(type, "text/vnd")) {
152 /* It is something textual, display it */
153 message = (const unsigned char *)data;
162 if (flags & SILC_MESSAGE_FLAG_ACTION)
163 printformat_module("fe-common/silc", server, channel->channel_name,
164 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
165 nick == NULL ? "[<unknown>]" : nick->nick, message);
166 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
167 printformat_module("fe-common/silc", server, channel->channel_name,
168 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
169 nick == NULL ? "[<unknown>]" : nick->nick, message);
171 signal_emit("message public", 6, server, message,
172 nick == NULL ? "[<unknown>]" : nick->nick,
173 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
174 chanrec->name, nick);
177 /* Private message to the client. The `sender' is the nickname of the
178 sender received in the packet. */
180 void silc_private_message(SilcClient client, SilcClientConnection conn,
181 SilcClientEntry sender, SilcMessageFlags flags,
182 const unsigned char *message,
183 SilcUInt32 message_len)
185 SILC_SERVER_REC *server;
188 SILC_LOG_DEBUG(("Start"));
190 server = conn == NULL ? NULL : conn->context;
191 memset(userhost, 0, sizeof(userhost));
192 if (sender->username)
193 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
194 sender->username, sender->hostname);
196 if (flags & SILC_MESSAGE_FLAG_DATA) {
197 /* MIME object received, try to display it as well as we can */
201 memset(type, 0, sizeof(type));
202 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
203 NULL, 0, &data, NULL))
206 /* Then figure out what we can display */
207 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
208 !strstr(type, "text/vnd")) {
209 /* It is something textual, display it */
210 message = (const unsigned char *)data;
219 signal_emit("message private", 4, server, message,
220 sender->nickname ? sender->nickname : "[<unknown>]",
221 sender->username ? userhost : NULL);
224 /* Notify message to the client. The notify arguments are sent in the
225 same order as servers sends them. The arguments are same as received
226 from the server except for ID's. If ID is received application receives
227 the corresponding entry to the ID. For example, if Client ID is received
228 application receives SilcClientEntry. Also, if the notify type is
229 for channel the channel entry is sent to application (even if server
230 does not send it). */
232 void silc_notify(SilcClient client, SilcClientConnection conn,
233 SilcNotifyType type, ...)
236 SILC_SERVER_REC *server;
237 SILC_CHANNEL_REC *chanrec;
238 SILC_NICK_REC *nickrec;
239 SilcClientEntry client_entry, client_entry2;
240 SilcChannelEntry channel, channel2;
241 SilcServerEntry server_entry;
247 GSList *list1, *list_tmp;
249 SILC_LOG_DEBUG(("Start"));
253 server = conn == NULL ? NULL : conn->context;
256 case SILC_NOTIFY_TYPE_NONE:
257 /* Some generic notice from server */
258 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
261 case SILC_NOTIFY_TYPE_INVITE:
263 * Invited or modified invite list.
266 SILC_LOG_DEBUG(("Notify: INVITE"));
268 channel = va_arg(va, SilcChannelEntry);
269 name = va_arg(va, char *);
270 client_entry = va_arg(va, SilcClientEntry);
272 memset(buf, 0, sizeof(buf));
273 snprintf(buf, sizeof(buf) - 1, "%s@%s",
274 client_entry->username, client_entry->hostname);
275 signal_emit("message invite", 4, server, channel ? channel->channel_name :
276 name, client_entry->nickname, buf);
279 case SILC_NOTIFY_TYPE_JOIN:
284 SILC_LOG_DEBUG(("Notify: JOIN"));
286 client_entry = va_arg(va, SilcClientEntry);
287 channel = va_arg(va, SilcChannelEntry);
289 if (client_entry == server->conn->local_entry) {
290 /* You joined to channel */
291 chanrec = silc_channel_find(server, channel->channel_name);
292 if (chanrec != NULL && !chanrec->joined)
293 chanrec->entry = channel;
295 chanrec = silc_channel_find_entry(server, channel);
296 if (chanrec != NULL) {
297 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
299 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
303 memset(buf, 0, sizeof(buf));
304 if (client_entry->username)
305 snprintf(buf, sizeof(buf) - 1, "%s@%s",
306 client_entry->username, client_entry->hostname);
307 signal_emit("message join", 4, server, channel->channel_name,
308 client_entry->nickname,
309 client_entry->username == NULL ? "" : buf);
312 case SILC_NOTIFY_TYPE_LEAVE:
317 SILC_LOG_DEBUG(("Notify: LEAVE"));
319 client_entry = va_arg(va, SilcClientEntry);
320 channel = va_arg(va, SilcChannelEntry);
322 memset(buf, 0, sizeof(buf));
323 if (client_entry->username)
324 snprintf(buf, sizeof(buf) - 1, "%s@%s",
325 client_entry->username, client_entry->hostname);
326 signal_emit("message part", 5, server, channel->channel_name,
327 client_entry->nickname, client_entry->username ?
328 buf : "", client_entry->nickname);
330 chanrec = silc_channel_find_entry(server, channel);
331 if (chanrec != NULL) {
332 nickrec = silc_nicklist_find(chanrec, client_entry);
334 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
338 case SILC_NOTIFY_TYPE_SIGNOFF:
343 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
345 client_entry = va_arg(va, SilcClientEntry);
346 tmp = va_arg(va, char *);
348 silc_server_free_ftp(server, client_entry);
350 memset(buf, 0, sizeof(buf));
351 if (client_entry->username)
352 snprintf(buf, sizeof(buf) - 1, "%s@%s",
353 client_entry->username, client_entry->hostname);
354 signal_emit("message quit", 4, server, client_entry->nickname,
355 client_entry->username ? buf : "",
358 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
359 for (list_tmp = list1; list_tmp != NULL; list_tmp =
360 list_tmp->next->next) {
361 CHANNEL_REC *channel = list_tmp->data;
362 NICK_REC *nickrec = list_tmp->next->data;
364 nicklist_remove(channel, nickrec);
368 case SILC_NOTIFY_TYPE_TOPIC_SET:
373 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
375 idtype = va_arg(va, int);
376 entry = va_arg(va, void *);
377 tmp = va_arg(va, char *);
378 channel = va_arg(va, SilcChannelEntry);
380 chanrec = silc_channel_find_entry(server, channel);
381 if (chanrec != NULL) {
382 g_free_not_null(chanrec->topic);
383 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
384 signal_emit("channel topic changed", 1, chanrec);
387 if (idtype == SILC_ID_CLIENT) {
388 client_entry = (SilcClientEntry)entry;
389 memset(buf, 0, sizeof(buf));
390 snprintf(buf, sizeof(buf) - 1, "%s@%s",
391 client_entry->username, client_entry->hostname);
392 signal_emit("message topic", 5, server, channel->channel_name,
393 tmp, client_entry->nickname, buf);
394 } else if (idtype == SILC_ID_SERVER) {
395 server_entry = (SilcServerEntry)entry;
396 signal_emit("message topic", 5, server, channel->channel_name,
397 tmp, server_entry->server_name,
398 server_entry->server_name);
399 } else if (idtype == SILC_ID_CHANNEL) {
400 channel = (SilcChannelEntry)entry;
401 signal_emit("message topic", 5, server, channel->channel_name,
402 tmp, channel->channel_name, channel->channel_name);
406 case SILC_NOTIFY_TYPE_NICK_CHANGE:
411 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
413 client_entry = va_arg(va, SilcClientEntry);
414 client_entry2 = va_arg(va, SilcClientEntry);
416 if (!strcmp(client_entry->nickname, client_entry2->nickname))
419 memset(buf, 0, sizeof(buf));
420 snprintf(buf, sizeof(buf) - 1, "%s@%s",
421 client_entry2->username, client_entry2->hostname);
422 nicklist_rename_unique(SERVER(server),
423 client_entry, client_entry->nickname,
424 client_entry2, client_entry2->nickname);
425 signal_emit("message nick", 4, server, client_entry2->nickname,
426 client_entry->nickname, buf);
429 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
431 * Changed channel mode.
434 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
436 idtype = va_arg(va, int);
437 entry = va_arg(va, void *);
438 mode = va_arg(va, SilcUInt32);
439 (void)va_arg(va, char *);
440 (void)va_arg(va, char *);
441 channel = va_arg(va, SilcChannelEntry);
443 tmp = silc_client_chmode(mode,
444 channel->channel_key ?
445 channel->channel_key->cipher->name : "",
447 silc_hmac_get_name(channel->hmac) : "");
449 chanrec = silc_channel_find_entry(server, channel);
450 if (chanrec != NULL) {
451 g_free_not_null(chanrec->mode);
452 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
453 signal_emit("channel mode changed", 1, chanrec);
456 if (idtype == SILC_ID_CLIENT) {
457 client_entry = (SilcClientEntry)entry;
458 printformat_module("fe-common/silc", server, channel->channel_name,
459 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
460 channel->channel_name, tmp ? tmp : "removed all",
461 client_entry->nickname);
462 } else if (idtype == SILC_ID_SERVER) {
463 server_entry = (SilcServerEntry)entry;
464 printformat_module("fe-common/silc", server, channel->channel_name,
465 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
466 channel->channel_name, tmp ? tmp : "removed all",
467 server_entry->server_name);
468 } else if (idtype == SILC_ID_CHANNEL) {
469 channel2 = (SilcChannelEntry)entry;
470 printformat_module("fe-common/silc", server, channel->channel_name,
471 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
472 channel->channel_name, tmp ? tmp : "removed all",
473 channel2->channel_name);
479 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
481 * Changed user's mode on channel.
484 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
486 idtype = va_arg(va, int);
487 entry = va_arg(va, void *);
488 mode = va_arg(va, SilcUInt32);
489 client_entry2 = va_arg(va, SilcClientEntry);
490 channel = va_arg(va, SilcChannelEntry);
492 tmp = silc_client_chumode(mode);
493 chanrec = silc_channel_find_entry(server, channel);
494 if (chanrec != NULL) {
497 if (client_entry2 == server->conn->local_entry)
498 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
500 nick = silc_nicklist_find(chanrec, client_entry2);
502 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
503 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
504 signal_emit("nick mode changed", 2, chanrec, nick);
508 if (idtype == SILC_ID_CLIENT) {
509 client_entry = (SilcClientEntry)entry;
510 printformat_module("fe-common/silc", server, channel->channel_name,
511 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
512 channel->channel_name, client_entry2->nickname,
513 tmp ? tmp : "removed all",
514 client_entry->nickname);
515 } else if (idtype == SILC_ID_SERVER) {
516 server_entry = (SilcServerEntry)entry;
517 printformat_module("fe-common/silc", server, channel->channel_name,
518 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
519 channel->channel_name, client_entry2->nickname,
520 tmp ? tmp : "removed all",
521 server_entry->server_name);
522 } else if (idtype == SILC_ID_CHANNEL) {
523 channel2 = (SilcChannelEntry)entry;
524 printformat_module("fe-common/silc", server, channel->channel_name,
525 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
526 channel->channel_name, client_entry2->nickname,
527 tmp ? tmp : "removed all",
528 channel2->channel_name);
531 if (mode & SILC_CHANNEL_UMODE_CHANFO)
532 printformat_module("fe-common/silc",
533 server, channel->channel_name, MSGLEVEL_CRAP,
534 SILCTXT_CHANNEL_FOUNDER,
535 channel->channel_name, client_entry2->nickname);
540 case SILC_NOTIFY_TYPE_MOTD:
545 SILC_LOG_DEBUG(("Notify: MOTD"));
547 tmp = va_arg(va, char *);
549 if (!settings_get_bool("skip_motd"))
550 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
553 case SILC_NOTIFY_TYPE_KICKED:
555 * Someone was kicked from channel.
558 SILC_LOG_DEBUG(("Notify: KICKED"));
560 client_entry = va_arg(va, SilcClientEntry);
561 tmp = va_arg(va, char *);
562 client_entry2 = va_arg(va, SilcClientEntry);
563 channel = va_arg(va, SilcChannelEntry);
565 chanrec = silc_channel_find_entry(server, channel);
567 if (client_entry == conn->local_entry) {
568 printformat_module("fe-common/silc", server, channel->channel_name,
569 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
570 channel->channel_name,
571 client_entry ? client_entry2->nickname : "",
574 chanrec->kicked = TRUE;
575 channel_destroy((CHANNEL_REC *)chanrec);
578 printformat_module("fe-common/silc", server, channel->channel_name,
579 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
580 client_entry->nickname, channel->channel_name,
581 client_entry2 ? client_entry2->nickname : "",
585 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
587 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
592 case SILC_NOTIFY_TYPE_KILLED:
594 * Someone was killed from the network.
597 SILC_LOG_DEBUG(("Notify: KILLED"));
599 client_entry = va_arg(va, SilcClientEntry);
600 tmp = va_arg(va, char *);
601 idtype = va_arg(va, int);
602 entry = va_arg(va, SilcClientEntry);
604 if (client_entry == conn->local_entry) {
605 if (idtype == SILC_ID_CLIENT) {
606 client_entry2 = (SilcClientEntry)entry;
607 printformat_module("fe-common/silc", server, NULL,
608 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
609 client_entry2 ? client_entry2->nickname : "",
611 } else if (idtype == SILC_ID_SERVER) {
612 server_entry = (SilcServerEntry)entry;
613 printformat_module("fe-common/silc", server, NULL,
614 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
615 server_entry->server_name, tmp ? tmp : "");
616 } else if (idtype == SILC_ID_CHANNEL) {
617 channel = (SilcChannelEntry)entry;
618 printformat_module("fe-common/silc", server, NULL,
619 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
620 channel->channel_name, tmp ? tmp : "");
623 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
624 for (list_tmp = list1; list_tmp != NULL; list_tmp =
625 list_tmp->next->next) {
626 CHANNEL_REC *channel = list_tmp->data;
627 NICK_REC *nickrec = list_tmp->next->data;
628 nicklist_remove(channel, nickrec);
631 if (idtype == SILC_ID_CLIENT) {
632 client_entry2 = (SilcClientEntry)entry;
633 printformat_module("fe-common/silc", server, NULL,
634 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
635 client_entry->nickname,
636 client_entry2 ? client_entry2->nickname : "",
638 } else if (idtype == SILC_ID_SERVER) {
639 server_entry = (SilcServerEntry)entry;
640 printformat_module("fe-common/silc", server, NULL,
641 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
642 client_entry->nickname,
643 server_entry->server_name, tmp ? tmp : "");
644 } else if (idtype == SILC_ID_CHANNEL) {
645 channel = (SilcChannelEntry)entry;
646 printformat_module("fe-common/silc", server, NULL,
647 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
648 client_entry->nickname,
649 channel->channel_name, tmp ? tmp : "");
654 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
657 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
660 * Server has quit the network.
663 SilcClientEntry *clients;
664 SilcUInt32 clients_count;
666 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
668 (void)va_arg(va, void *);
669 clients = va_arg(va, SilcClientEntry *);
670 clients_count = va_arg(va, SilcUInt32);
672 for (i = 0; i < clients_count; i++) {
673 memset(buf, 0, sizeof(buf));
674 if (clients[i]->username)
675 snprintf(buf, sizeof(buf) - 1, "%s@%s",
676 clients[i]->username, clients[i]->hostname);
677 signal_emit("message quit", 4, server, clients[i]->nickname,
678 clients[i]->username ? buf : "",
681 silc_server_free_ftp(server, clients[i]);
683 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
684 for (list_tmp = list1; list_tmp != NULL; list_tmp =
685 list_tmp->next->next) {
686 CHANNEL_REC *channel = list_tmp->data;
687 NICK_REC *nickrec = list_tmp->next->data;
688 nicklist_remove(channel, nickrec);
694 case SILC_NOTIFY_TYPE_ERROR:
696 SilcStatus error = va_arg(va, int);
698 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
699 "%s", silc_get_status_message(error));
703 case SILC_NOTIFY_TYPE_WATCH:
705 SilcNotifyType notify;
707 client_entry = va_arg(va, SilcClientEntry);
708 name = va_arg(va, char *); /* Maybe NULL */
709 mode = va_arg(va, SilcUInt32);
710 notify = va_arg(va, int);
712 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
714 printformat_module("fe-common/silc", server, NULL,
715 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
716 client_entry->nickname, name);
718 printformat_module("fe-common/silc", server, NULL,
719 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
720 client_entry->nickname);
721 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
722 /* See if client was away and is now present */
723 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
724 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
725 SILC_UMODE_DETACHED)) &&
726 (client_entry->mode & SILC_UMODE_GONE ||
727 client_entry->mode & SILC_UMODE_INDISPOSED ||
728 client_entry->mode & SILC_UMODE_BUSY ||
729 client_entry->mode & SILC_UMODE_PAGE ||
730 client_entry->mode & SILC_UMODE_DETACHED)) {
731 printformat_module("fe-common/silc", server, NULL,
732 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
733 client_entry->nickname);
737 memset(buf, 0, sizeof(buf));
738 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
739 printformat_module("fe-common/silc", server, NULL,
740 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
741 client_entry->nickname, buf);
743 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
744 printformat_module("fe-common/silc", server, NULL,
745 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
746 client_entry->nickname);
747 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
748 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
749 printformat_module("fe-common/silc", server, NULL,
750 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
751 client_entry->nickname);
752 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
753 /* Client logged in to the network */
754 printformat_module("fe-common/silc", server, NULL,
755 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
756 client_entry->nickname);
763 printformat_module("fe-common/silc", server, NULL,
764 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
771 /* Called to indicate that connection was either successfully established
772 or connecting failed. This is also the first time application receives
773 the SilcClientConnection object which it should save somewhere. */
775 void silc_connect(SilcClient client, SilcClientConnection conn,
776 SilcClientConnectionStatus status)
778 SILC_SERVER_REC *server = conn->context;
781 silc_client_close_connection(client, conn);
786 case SILC_CLIENT_CONN_SUCCESS:
787 /* We have successfully connected to server */
788 server->connected = TRUE;
789 signal_emit("event connected", 1, server);
792 case SILC_CLIENT_CONN_SUCCESS_RESUME:
793 /* We have successfully resumed old detached session */
794 server->connected = TRUE;
795 signal_emit("event connected", 1, server);
797 /* If we resumed old session check whether we need to update
799 if (strcmp(server->nick, conn->local_entry->nickname)) {
801 old = g_strdup(server->nick);
802 server_change_nick(SERVER(server), conn->local_entry->nickname);
803 nicklist_rename_unique(SERVER(server),
804 conn->local_entry, server->nick,
805 conn->local_entry, conn->local_entry->nickname);
806 signal_emit("message own_nick", 4, server, server->nick, old, "");
812 server->connection_lost = TRUE;
814 server->conn->context = NULL;
815 server_disconnect(SERVER(server));
820 /* Called to indicate that connection was disconnected to the server. */
822 void silc_disconnect(SilcClient client, SilcClientConnection conn)
824 SILC_SERVER_REC *server = conn->context;
826 SILC_LOG_DEBUG(("Start"));
828 if (!server || server->connection_lost)
831 if (server->conn && server->conn->local_entry) {
832 nicklist_rename_unique(SERVER(server),
833 server->conn->local_entry, server->nick,
834 server->conn->local_entry,
835 silc_client->username);
836 silc_change_nick(server, silc_client->username);
839 server->conn->context = NULL;
841 server->connection_lost = TRUE;
842 server_disconnect(SERVER(server));
845 /* Command handler. This function is called always in the command function.
846 If error occurs it will be called as well. `conn' is the associated
847 client connection. `cmd_context' is the command context that was
848 originally sent to the command. `success' is FALSE if error occured
849 during command. `command' is the command being processed. It must be
850 noted that this is not reply from server. This is merely called just
851 after application has called the command. Just to tell application
852 that the command really was processed. */
854 void silc_command(SilcClient client, SilcClientConnection conn,
855 SilcClientCommandContext cmd_context, bool success,
856 SilcCommand command, SilcStatus status)
858 SILC_SERVER_REC *server = conn->context;
860 SILC_LOG_DEBUG(("Start"));
866 case SILC_COMMAND_INVITE:
867 printformat_module("fe-common/silc", server, NULL,
868 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
869 cmd_context->argv[2],
870 (cmd_context->argv[1][0] == '*' ?
871 (char *)conn->current_channel->channel_name :
872 (char *)cmd_context->argv[1]));
879 /* Client info resolving callback when JOIN command reply is received.
880 This will cache all users on the channel. */
882 static void silc_client_join_get_users(SilcClient client,
883 SilcClientConnection conn,
884 SilcClientEntry *clients,
885 SilcUInt32 clients_count,
888 SilcChannelEntry channel = (SilcChannelEntry)context;
889 SilcHashTableList htl;
891 SILC_SERVER_REC *server = conn->context;
892 SILC_CHANNEL_REC *chanrec;
893 SilcClientEntry founder = NULL;
896 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
897 silc_hash_table_count(channel->user_list)));
902 chanrec = silc_channel_find(server, channel->channel_name);
906 silc_hash_table_list(channel->user_list, &htl);
907 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
908 if (!chu->client->nickname)
910 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
911 founder = chu->client;
912 silc_nicklist_insert(chanrec, chu, FALSE);
914 silc_hash_table_list_reset(&htl);
916 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
917 nicklist_set_own(CHANNEL(chanrec), ownnick);
918 signal_emit("channel joined", 1, chanrec);
919 chanrec->entry = channel;
922 printformat_module("fe-common/silc", server, channel->channel_name,
923 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
924 channel->channel_name, chanrec->topic);
926 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
929 if (founder == conn->local_entry)
930 printformat_module("fe-common/silc",
931 server, channel->channel_name, MSGLEVEL_CRAP,
932 SILCTXT_CHANNEL_FOUNDER_YOU,
933 channel->channel_name);
935 printformat_module("fe-common/silc",
936 server, channel->channel_name, MSGLEVEL_CRAP,
937 SILCTXT_CHANNEL_FOUNDER,
938 channel->channel_name, founder->nickname);
944 SilcClientConnection conn;
950 void silc_getkey_cb(bool success, void *context)
952 GetkeyContext getkey = (GetkeyContext)context;
953 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
954 char *name = (getkey->id_type == SILC_ID_CLIENT ?
955 ((SilcClientEntry)getkey->entry)->nickname :
956 ((SilcServerEntry)getkey->entry)->server_name);
959 printformat_module("fe-common/silc", NULL, NULL,
960 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
962 printformat_module("fe-common/silc", NULL, NULL,
963 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
966 silc_free(getkey->fingerprint);
970 /* Command reply handler. This function is called always in the command reply
971 function. If error occurs it will be called as well. Normal scenario
972 is that it will be called after the received command data has been parsed
973 and processed. The function is used to pass the received command data to
976 `conn' is the associated client connection. `cmd_payload' is the command
977 payload data received from server and it can be ignored. It is provided
978 if the application would like to re-parse the received command data,
979 however, it must be noted that the data is parsed already by the library
980 thus the payload can be ignored. `success' is FALSE if error occured.
981 In this case arguments are not sent to the application. `command' is the
982 command reply being processed. The function has variable argument list
983 and each command defines the number and type of arguments it passes to the
984 application (on error they are not sent). */
987 silc_command_reply(SilcClient client, SilcClientConnection conn,
988 SilcCommandPayload cmd_payload, bool success,
989 SilcCommand command, SilcStatus status, ...)
992 SILC_SERVER_REC *server = conn->context;
993 SILC_CHANNEL_REC *chanrec;
996 va_start(vp, status);
998 SILC_LOG_DEBUG(("Start"));
1001 case SILC_COMMAND_WHOIS:
1003 char buf[1024], *nickname, *username, *realname, *nick;
1004 unsigned char *fingerprint;
1005 SilcUInt32 idle, mode;
1006 SilcBuffer channels, user_modes;
1007 SilcClientEntry client_entry;
1009 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1010 /* Print the unknown nick for user */
1011 unsigned char *tmp =
1012 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1015 silc_say_error("%s: %s", tmp,
1016 silc_get_status_message(status));
1018 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1019 /* Try to find the entry for the unknown client ID, since we
1020 might have, and print the nickname of it for user. */
1022 unsigned char *tmp =
1023 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1026 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1029 client_entry = silc_client_get_client_by_id(client, conn,
1031 if (client_entry && client_entry->nickname)
1032 silc_say_error("%s: %s", client_entry->nickname,
1033 silc_get_status_message(status));
1034 silc_free(client_id);
1043 client_entry = va_arg(vp, SilcClientEntry);
1044 nickname = va_arg(vp, char *);
1045 username = va_arg(vp, char *);
1046 realname = va_arg(vp, char *);
1047 channels = va_arg(vp, SilcBuffer);
1048 mode = va_arg(vp, SilcUInt32);
1049 idle = va_arg(vp, SilcUInt32);
1050 fingerprint = va_arg(vp, unsigned char *);
1051 user_modes = va_arg(vp, SilcBuffer);
1053 silc_parse_userfqdn(nickname, &nick, NULL);
1054 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1055 SILCTXT_WHOIS_USERINFO, nickname,
1056 client_entry->username, client_entry->hostname,
1057 nick, client_entry->nickname);
1058 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1059 SILCTXT_WHOIS_REALNAME, realname);
1062 if (channels && user_modes) {
1064 SilcDList list = silc_channel_payload_parse_list(channels->data,
1066 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1068 SilcChannelPayload entry;
1071 memset(buf, 0, sizeof(buf));
1072 silc_dlist_start(list);
1073 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1074 SilcUInt32 name_len;
1075 char *m = silc_client_chumode_char(umodes[i++]);
1076 char *name = silc_channel_get_name(entry, &name_len);
1079 strncat(buf, m, strlen(m));
1080 strncat(buf, name, name_len);
1081 strncat(buf, " ", 1);
1085 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1086 SILCTXT_WHOIS_CHANNELS, buf);
1087 silc_channel_payload_list_free(list);
1093 memset(buf, 0, sizeof(buf));
1094 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1095 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1096 SILCTXT_WHOIS_MODES, buf);
1099 if (idle && nickname) {
1100 memset(buf, 0, sizeof(buf));
1101 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1102 idle > 60 ? (idle / 60) : idle,
1103 idle > 60 ? "minutes" : "seconds");
1105 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1106 SILCTXT_WHOIS_IDLE, buf);
1110 fingerprint = silc_fingerprint(fingerprint, 20);
1111 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1112 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1113 silc_free(fingerprint);
1118 case SILC_COMMAND_IDENTIFY:
1120 SilcClientEntry client_entry;
1122 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1123 /* Print the unknown nick for user */
1124 unsigned char *tmp =
1125 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1128 silc_say_error("%s: %s", tmp,
1129 silc_get_status_message(status));
1131 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1132 /* Try to find the entry for the unknown client ID, since we
1133 might have, and print the nickname of it for user. */
1135 unsigned char *tmp =
1136 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1139 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1142 client_entry = silc_client_get_client_by_id(client, conn,
1144 if (client_entry && client_entry->nickname)
1145 silc_say_error("%s: %s", client_entry->nickname,
1146 silc_get_status_message(status));
1147 silc_free(client_id);
1156 case SILC_COMMAND_WHOWAS:
1158 char *nickname, *username, *realname;
1160 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1161 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1163 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1166 silc_say_error("%s: %s", tmp,
1167 silc_get_status_message(status));
1174 (void)va_arg(vp, SilcClientEntry);
1175 nickname = va_arg(vp, char *);
1176 username = va_arg(vp, char *);
1177 realname = va_arg(vp, char *);
1179 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1180 SILCTXT_WHOWAS_USERINFO, nickname, username,
1181 realname ? realname : "");
1185 case SILC_COMMAND_INVITE:
1187 SilcChannelEntry channel;
1189 SilcArgumentPayload args;
1195 channel = va_arg(vp, SilcChannelEntry);
1196 invite_list = va_arg(vp, char *);
1198 args = silc_command_get_args(cmd_payload);
1200 argc = silc_argument_get_arg_num(args);
1203 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1204 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1207 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1208 SILCTXT_CHANNEL_NO_INVITE_LIST,
1209 channel->channel_name);
1213 case SILC_COMMAND_JOIN:
1215 char *channel, *mode, *topic;
1217 SilcChannelEntry channel_entry;
1218 SilcBuffer client_id_list;
1219 SilcUInt32 list_count;
1224 channel = va_arg(vp, char *);
1225 channel_entry = va_arg(vp, SilcChannelEntry);
1226 modei = va_arg(vp, SilcUInt32);
1227 (void)va_arg(vp, SilcUInt32);
1228 (void)va_arg(vp, unsigned char *);
1229 (void)va_arg(vp, unsigned char *);
1230 (void)va_arg(vp, unsigned char *);
1231 topic = va_arg(vp, char *);
1232 (void)va_arg(vp, unsigned char *);
1233 list_count = va_arg(vp, SilcUInt32);
1234 client_id_list = va_arg(vp, SilcBuffer);
1236 chanrec = silc_channel_find(server, channel);
1238 chanrec = silc_channel_create(server, channel, TRUE);
1241 g_free_not_null(chanrec->topic);
1242 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1243 signal_emit("channel topic changed", 1, chanrec);
1246 mode = silc_client_chmode(modei,
1247 channel_entry->channel_key ?
1248 channel_entry->channel_key->cipher->name : "",
1249 channel_entry->hmac ?
1250 silc_hmac_get_name(channel_entry->hmac) : "");
1251 g_free_not_null(chanrec->mode);
1252 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1253 signal_emit("channel mode changed", 1, chanrec);
1255 /* Resolve the client information */
1256 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1257 silc_client_join_get_users,
1263 case SILC_COMMAND_NICK:
1265 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1271 old = g_strdup(server->nick);
1272 server_change_nick(SERVER(server), client->nickname);
1273 nicklist_rename_unique(SERVER(server),
1274 server->conn->local_entry, server->nick,
1275 client, client->nickname);
1276 signal_emit("message own_nick", 4, server, server->nick, old, "");
1281 case SILC_COMMAND_LIST:
1290 (void)va_arg(vp, SilcChannelEntry);
1291 name = va_arg(vp, char *);
1292 topic = va_arg(vp, char *);
1293 usercount = va_arg(vp, int);
1295 if (status == SILC_STATUS_LIST_START ||
1296 status == SILC_STATUS_OK)
1297 printformat_module("fe-common/silc", server, NULL,
1298 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1301 snprintf(users, sizeof(users) - 1, "N/A");
1303 snprintf(users, sizeof(users) - 1, "%d", usercount);
1304 printformat_module("fe-common/silc", server, NULL,
1305 MSGLEVEL_CRAP, SILCTXT_LIST,
1306 name, users, topic ? topic : "");
1310 case SILC_COMMAND_UMODE:
1317 mode = va_arg(vp, SilcUInt32);
1319 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1320 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1321 printformat_module("fe-common/silc", server, NULL,
1322 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1324 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1325 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1326 printformat_module("fe-common/silc", server, NULL,
1327 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1329 server->umode = mode;
1330 signal_emit("user mode changed", 2, server, NULL);
1334 case SILC_COMMAND_OPER:
1338 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1339 signal_emit("user mode changed", 2, server, NULL);
1341 printformat_module("fe-common/silc", server, NULL,
1342 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1345 case SILC_COMMAND_SILCOPER:
1349 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1350 signal_emit("user mode changed", 2, server, NULL);
1352 printformat_module("fe-common/silc", server, NULL,
1353 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1356 case SILC_COMMAND_USERS:
1358 SilcHashTableList htl;
1359 SilcChannelEntry channel;
1360 SilcChannelUser chu;
1365 channel = va_arg(vp, SilcChannelEntry);
1367 printformat_module("fe-common/silc", server, channel->channel_name,
1368 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1369 channel->channel_name);
1371 silc_hash_table_list(channel->user_list, &htl);
1372 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1373 SilcClientEntry e = chu->client;
1374 char stat[5], *mode;
1379 memset(stat, 0, sizeof(stat));
1380 mode = silc_client_chumode_char(chu->mode);
1381 if (e->mode & SILC_UMODE_GONE)
1383 else if (e->mode & SILC_UMODE_INDISPOSED)
1385 else if (e->mode & SILC_UMODE_BUSY)
1387 else if (e->mode & SILC_UMODE_PAGE)
1389 else if (e->mode & SILC_UMODE_HYPER)
1391 else if (e->mode & SILC_UMODE_ROBOT)
1393 else if (e->mode & SILC_UMODE_ANONYMOUS)
1400 printformat_module("fe-common/silc", server, channel->channel_name,
1401 MSGLEVEL_CRAP, SILCTXT_USERS,
1403 e->username ? e->username : "",
1404 e->hostname ? e->hostname : "",
1405 e->realname ? e->realname : "");
1409 silc_hash_table_list_reset(&htl);
1413 case SILC_COMMAND_BAN:
1415 SilcChannelEntry channel;
1421 channel = va_arg(vp, SilcChannelEntry);
1422 ban_list = va_arg(vp, char *);
1425 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1426 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1429 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1430 SILCTXT_CHANNEL_NO_BAN_LIST,
1431 channel->channel_name);
1435 case SILC_COMMAND_GETKEY:
1439 SilcPublicKey public_key;
1442 GetkeyContext getkey;
1448 id_type = va_arg(vp, SilcUInt32);
1449 entry = va_arg(vp, void *);
1450 public_key = va_arg(vp, SilcPublicKey);
1453 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1455 getkey = silc_calloc(1, sizeof(*getkey));
1456 getkey->entry = entry;
1457 getkey->id_type = id_type;
1458 getkey->client = client;
1459 getkey->conn = conn;
1460 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1462 name = (id_type == SILC_ID_CLIENT ?
1463 ((SilcClientEntry)entry)->nickname :
1464 ((SilcServerEntry)entry)->server_name);
1466 silc_verify_public_key_internal(client, conn, name,
1467 (id_type == SILC_ID_CLIENT ?
1468 SILC_SOCKET_TYPE_CLIENT :
1469 SILC_SOCKET_TYPE_SERVER),
1470 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1471 silc_getkey_cb, getkey);
1474 printformat_module("fe-common/silc", server, NULL,
1475 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1480 case SILC_COMMAND_INFO:
1482 SilcServerEntry server_entry;
1489 server_entry = va_arg(vp, SilcServerEntry);
1490 server_name = va_arg(vp, char *);
1491 server_info = va_arg(vp, char *);
1493 if (server_name && server_info )
1495 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1496 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1501 case SILC_COMMAND_TOPIC:
1503 SilcChannelEntry channel;
1509 channel = va_arg(vp, SilcChannelEntry);
1510 topic = va_arg(vp, char *);
1513 chanrec = silc_channel_find_entry(server, channel);
1515 g_free_not_null(chanrec->topic);
1516 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1517 signal_emit("channel topic changed", 1, chanrec);
1519 printformat_module("fe-common/silc", server, channel->channel_name,
1520 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1521 channel->channel_name, topic);
1523 printformat_module("fe-common/silc", server, channel->channel_name,
1524 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1525 channel->channel_name);
1530 case SILC_COMMAND_WATCH:
1539 SilcClientConnection conn;
1545 SilcSKEPKType pk_type;
1546 SilcVerifyPublicKey completion;
1550 static void verify_public_key_completion(const char *line, void *context)
1552 PublicKeyVerify verify = (PublicKeyVerify)context;
1554 if (line[0] == 'Y' || line[0] == 'y') {
1555 /* Call the completion */
1556 if (verify->completion)
1557 verify->completion(TRUE, verify->context);
1559 /* Save the key for future checking */
1560 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1561 verify->pk_len, SILC_PKCS_FILE_PEM);
1563 /* Call the completion */
1564 if (verify->completion)
1565 verify->completion(FALSE, verify->context);
1567 printformat_module("fe-common/silc", NULL, NULL,
1568 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1569 verify->entity_name ? verify->entity_name :
1573 silc_free(verify->filename);
1574 silc_free(verify->entity);
1575 silc_free(verify->entity_name);
1576 silc_free(verify->pk);
1580 /* Internal routine to verify public key. If the `completion' is provided
1581 it will be called to indicate whether public was verified or not. For
1582 server/router public key this will check for filename that includes the
1583 remote host's IP address and remote host's hostname. */
1586 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1587 const char *name, SilcSocketType conn_type,
1588 unsigned char *pk, SilcUInt32 pk_len,
1589 SilcSKEPKType pk_type,
1590 SilcVerifyPublicKey completion, void *context)
1593 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1594 char *fingerprint, *babbleprint, *format;
1597 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1598 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1599 "server" : "client");
1600 PublicKeyVerify verify;
1602 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1603 printformat_module("fe-common/silc", NULL, NULL,
1604 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1607 completion(FALSE, context);
1611 pw = getpwuid(getuid());
1614 completion(FALSE, context);
1618 memset(filename, 0, sizeof(filename));
1619 memset(filename2, 0, sizeof(filename2));
1620 memset(file, 0, sizeof(file));
1622 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1623 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1625 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1626 conn->sock->ip, conn->sock->port);
1627 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1628 get_irssi_dir(), entity, file);
1630 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1631 conn->sock->hostname, conn->sock->port);
1632 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1633 get_irssi_dir(), entity, file);
1638 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1639 name, conn->sock->port);
1640 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1641 get_irssi_dir(), entity, file);
1646 /* Replace all whitespaces with `_'. */
1647 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1648 for (i = 0; i < strlen(fingerprint); i++)
1649 if (fingerprint[i] == ' ')
1650 fingerprint[i] = '_';
1652 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1653 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1654 get_irssi_dir(), entity, file);
1655 silc_free(fingerprint);
1660 /* Take fingerprint of the public key */
1661 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1662 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1664 verify = silc_calloc(1, sizeof(*verify));
1665 verify->client = client;
1666 verify->conn = conn;
1667 verify->filename = strdup(ipf);
1668 verify->entity = strdup(entity);
1669 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1670 (name ? strdup(name) : strdup(conn->sock->hostname))
1672 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1673 memcpy(verify->pk, pk, pk_len);
1674 verify->pk_len = pk_len;
1675 verify->pk_type = pk_type;
1676 verify->completion = completion;
1677 verify->context = context;
1679 /* Check whether this key already exists */
1680 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1681 /* Key does not exist, ask user to verify the key and save it */
1683 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1684 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1685 verify->entity_name : entity);
1686 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1687 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1688 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1689 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1690 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1691 SILCTXT_PUBKEY_ACCEPT);
1692 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1695 silc_free(fingerprint);
1698 /* The key already exists, verify it. */
1699 SilcPublicKey public_key;
1700 unsigned char *encpk;
1701 SilcUInt32 encpk_len;
1703 /* Load the key file, try for both IP filename and hostname filename */
1704 if (!silc_pkcs_load_public_key(ipf, &public_key,
1705 SILC_PKCS_FILE_PEM) &&
1706 !silc_pkcs_load_public_key(ipf, &public_key,
1707 SILC_PKCS_FILE_BIN) &&
1708 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1709 SILC_PKCS_FILE_PEM) &&
1710 !silc_pkcs_load_public_key(hostf, &public_key,
1711 SILC_PKCS_FILE_BIN)))) {
1712 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1713 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1714 verify->entity_name : entity);
1715 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1716 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1717 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1718 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1719 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1720 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1721 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1722 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1723 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1726 silc_free(fingerprint);
1730 /* Encode the key data */
1731 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1733 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1734 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1735 verify->entity_name : entity);
1736 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1737 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1738 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1739 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1740 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1741 SILCTXT_PUBKEY_MALFORMED, entity);
1742 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1743 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1744 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1747 silc_free(fingerprint);
1751 /* Compare the keys */
1752 if (memcmp(encpk, pk, encpk_len)) {
1753 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1754 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1755 verify->entity_name : entity);
1756 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1757 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1758 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1759 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1760 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1761 SILCTXT_PUBKEY_NO_MATCH, entity);
1762 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1763 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1764 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1765 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1767 /* Ask user to verify the key and save it */
1768 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1769 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1770 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1773 silc_free(fingerprint);
1777 /* Local copy matched */
1779 completion(TRUE, context);
1780 silc_free(fingerprint);
1784 /* Verifies received public key. The `conn_type' indicates which entity
1785 (server, client etc.) has sent the public key. If user decides to trust
1786 the key may be saved as trusted public key for later use. The
1787 `completion' must be called after the public key has been verified. */
1790 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1791 SilcSocketType conn_type, unsigned char *pk,
1792 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1793 SilcVerifyPublicKey completion, void *context)
1795 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1797 completion, context);
1800 /* Asks passphrase from user on the input line. */
1803 SilcAskPassphrase completion;
1807 void ask_passphrase_completion(const char *passphrase, void *context)
1809 AskPassphrase p = (AskPassphrase)context;
1810 p->completion((unsigned char *)passphrase,
1811 passphrase ? strlen(passphrase) : 0, p->context);
1815 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1816 SilcAskPassphrase completion, void *context)
1818 AskPassphrase p = silc_calloc(1, sizeof(*p));
1819 p->completion = completion;
1820 p->context = context;
1822 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1823 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1827 SilcGetAuthMeth completion;
1829 } *InternalGetAuthMethod;
1831 /* Callback called when we've received the authentication method information
1832 from the server after we've requested it. This will get the authentication
1833 data from the user if needed. */
1835 static void silc_get_auth_method_callback(SilcClient client,
1836 SilcClientConnection conn,
1837 SilcAuthMethod auth_meth,
1840 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1842 SILC_LOG_DEBUG(("Start"));
1844 switch (auth_meth) {
1845 case SILC_AUTH_NONE:
1846 /* No authentication required. */
1847 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1849 case SILC_AUTH_PASSWORD:
1850 /* Do not ask the passphrase from user, the library will ask it if
1851 we do not provide it here. */
1852 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1854 case SILC_AUTH_PUBLIC_KEY:
1855 /* Do not get the authentication data now, the library will generate
1856 it using our default key, if we do not provide it here. */
1857 /* XXX In the future when we support multiple local keys and multiple
1858 local certificates we will need to ask from user which one to use. */
1859 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1863 silc_free(internal);
1866 /* Find authentication method and authentication data by hostname and
1867 port. The hostname may be IP address as well. The found authentication
1868 method and authentication data is returned to `auth_meth', `auth_data'
1869 and `auth_data_len'. The function returns TRUE if authentication method
1870 is found and FALSE if not. `conn' may be NULL. */
1872 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1873 char *hostname, SilcUInt16 port,
1874 SilcGetAuthMeth completion, void *context)
1876 InternalGetAuthMethod internal;
1878 SILC_LOG_DEBUG(("Start"));
1880 /* XXX must resolve from configuration whether this connection has
1881 any specific authentication data */
1883 /* If we do not have this connection configured by the user in a
1884 configuration file then resolve the authentication method from the
1885 server for this session. */
1886 internal = silc_calloc(1, sizeof(*internal));
1887 internal->completion = completion;
1888 internal->context = context;
1890 silc_client_request_authentication_method(client, conn,
1891 silc_get_auth_method_callback,
1895 /* Notifies application that failure packet was received. This is called
1896 if there is some protocol active in the client. The `protocol' is the
1897 protocol context. The `failure' is opaque pointer to the failure
1898 indication. Note, that the `failure' is protocol dependant and application
1899 must explicitly cast it to correct type. Usually `failure' is 32 bit
1900 failure type (see protocol specs for all protocol failure types). */
1902 void silc_failure(SilcClient client, SilcClientConnection conn,
1903 SilcProtocol protocol, void *failure)
1905 SILC_LOG_DEBUG(("Start"));
1907 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1908 SilcSKEStatus status = (SilcSKEStatus)failure;
1910 if (status == SILC_SKE_STATUS_BAD_VERSION)
1911 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1912 SILCTXT_KE_BAD_VERSION);
1913 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1914 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1915 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1916 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1917 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1918 SILCTXT_KE_UNKNOWN_GROUP);
1919 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1920 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1921 SILCTXT_KE_UNKNOWN_CIPHER);
1922 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1923 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1924 SILCTXT_KE_UNKNOWN_PKCS);
1925 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1926 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1927 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1928 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1929 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1930 SILCTXT_KE_UNKNOWN_HMAC);
1931 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1932 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1933 SILCTXT_KE_INCORRECT_SIGNATURE);
1934 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1935 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1936 SILCTXT_KE_INVALID_COOKIE);
1939 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1940 SilcUInt32 err = (SilcUInt32)failure;
1942 if (err == SILC_AUTH_FAILED)
1943 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1944 SILCTXT_AUTH_FAILED);
1948 /* Asks whether the user would like to perform the key agreement protocol.
1949 This is called after we have received an key agreement packet or an
1950 reply to our key agreement packet. This returns TRUE if the user wants
1951 the library to perform the key agreement protocol and FALSE if it is not
1952 desired (application may start it later by calling the function
1953 silc_client_perform_key_agreement). */
1955 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1956 SilcClientEntry client_entry, const char *hostname,
1957 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1962 SILC_LOG_DEBUG(("Start"));
1964 /* We will just display the info on the screen and return FALSE and user
1965 will have to start the key agreement with a command. */
1968 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1971 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1972 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1974 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1975 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1976 client_entry->nickname, hostname, portstr);
1984 /* Notifies application that file transfer protocol session is being
1985 requested by the remote client indicated by the `client_entry' from
1986 the `hostname' and `port'. The `session_id' is the file transfer
1987 session and it can be used to either accept or reject the file
1988 transfer request, by calling the silc_client_file_receive or
1989 silc_client_file_close, respectively. */
1991 void silc_ftp(SilcClient client, SilcClientConnection conn,
1992 SilcClientEntry client_entry, SilcUInt32 session_id,
1993 const char *hostname, SilcUInt16 port)
1995 SILC_SERVER_REC *server;
1997 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1999 SILC_LOG_DEBUG(("Start"));
2001 server = conn->context;
2003 ftp->client_entry = client_entry;
2004 ftp->session_id = session_id;
2007 silc_dlist_add(server->ftp_sessions, ftp);
2008 server->current_session = ftp;
2011 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2014 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2015 SILCTXT_FILE_REQUEST, client_entry->nickname);
2017 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2018 SILCTXT_FILE_REQUEST_HOST,
2019 client_entry->nickname, hostname, portstr);
2022 /* Delivers SILC session detachment data indicated by `detach_data' to the
2023 application. If application has issued SILC_COMMAND_DETACH command
2024 the client session in the SILC network is not quit. The client remains
2025 in the network but is detached. The detachment data may be used later
2026 to resume the session in the SILC Network. The appliation is
2027 responsible of saving the `detach_data', to for example in a file.
2029 The detachment data can be given as argument to the functions
2030 silc_client_connect_to_server, or silc_client_add_connection when
2031 creating connection to remote server, inside SilcClientConnectionParams
2032 structure. If it is provided the client library will attempt to resume
2033 the session in the network. After the connection is created
2034 successfully, the application is responsible of setting the user
2035 interface for user into the same state it was before detaching (showing
2036 same channels, channel modes, etc). It can do this by fetching the
2037 information (like joined channels) from the client library. */
2040 silc_detach(SilcClient client, SilcClientConnection conn,
2041 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2045 /* Save the detachment data to file. */
2047 memset(file, 0, sizeof(file));
2048 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2049 silc_file_writefile(file, detach_data, detach_data_len);
2053 /* SILC client operations */
2054 SilcClientOperations ops = {
2056 silc_channel_message,
2057 silc_private_message,
2063 silc_get_auth_method,
2064 silc_verify_public_key,
2065 silc_ask_passphrase,