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"
45 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
46 const char *name, SilcSocketType conn_type,
47 unsigned char *pk, SilcUInt32 pk_len,
48 SilcSKEPKType pk_type,
49 SilcVerifyPublicKey completion, void *context);
51 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
54 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
55 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
56 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
58 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
59 "[SILC operator]" : "[unknown mode]");
61 if (mode & SILC_UMODE_GONE)
62 strcat(buf, " [away]");
63 if (mode & SILC_UMODE_INDISPOSED)
64 strcat(buf, " [indisposed]");
65 if (mode & SILC_UMODE_BUSY)
66 strcat(buf, " [busy]");
67 if (mode & SILC_UMODE_PAGE)
68 strcat(buf, " [page to reach]");
69 if (mode & SILC_UMODE_HYPER)
70 strcat(buf, " [hyper active]");
71 if (mode & SILC_UMODE_ROBOT)
72 strcat(buf, " [robot]");
73 if (mode & SILC_UMODE_ANONYMOUS)
74 strcat(buf, " [anonymous]");
75 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
76 strcat(buf, " [blocks private messages]");
77 if (mode & SILC_UMODE_DETACHED)
78 strcat(buf, " [detached]");
79 if (mode & SILC_UMODE_REJECT_WATCHING)
80 strcat(buf, " [rejects watching]");
81 if (mode & SILC_UMODE_BLOCK_INVITE)
82 strcat(buf, " [blocks invites]");
85 void silc_say(SilcClient client, SilcClientConnection conn,
86 SilcClientMessageType type, char *msg, ...)
88 SILC_SERVER_REC *server;
92 server = conn == NULL ? NULL : conn->context;
95 str = g_strdup_vprintf(msg, va);
96 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
101 void silc_say_error(char *msg, ...)
107 str = g_strdup_vprintf(msg, va);
108 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
114 void silc_emit_mime_sig(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
115 const char *data, SilcUInt32 data_len,
116 const char *encoding, const char *type,
122 blob.octets = data_len;
123 blob.data = (char *)data;
125 signal_emit("mime", 6, server, channel, &blob, encoding, type, nick);
128 /* Message for a channel. The `sender' is the nickname of the sender
129 received in the packet. The `channel_name' is the name of the channel. */
131 void silc_channel_message(SilcClient client, SilcClientConnection conn,
132 SilcClientEntry sender, SilcChannelEntry channel,
133 SilcMessageFlags flags, const unsigned char *message,
134 SilcUInt32 message_len)
136 SILC_SERVER_REC *server;
138 SILC_CHANNEL_REC *chanrec;
140 SILC_LOG_DEBUG(("Start"));
145 server = conn == NULL ? NULL : conn->context;
146 chanrec = silc_channel_find_entry(server, channel);
150 nick = silc_nicklist_find(chanrec, sender);
152 /* We didn't find client but it clearly exists, add it. */
153 SilcChannelUser chu = silc_client_on_channel(channel, sender);
155 nick = silc_nicklist_insert(chanrec, chu, FALSE);
158 if (flags & SILC_MESSAGE_FLAG_DATA) {
159 /* MIME object received, try to display it as well as we can */
160 char type[128], enc[128];
164 memset(type, 0, sizeof(type));
165 memset(enc, 0, sizeof(enc));
166 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
167 enc, sizeof(enc) - 1, &data, &data_len))
170 /* Then figure out what we can display */
171 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
172 !strstr(type, "text/vnd")) {
173 /* It is something textual, display it */
174 message = (const unsigned char *)data;
176 silc_emit_mime_sig(server, chanrec, data, data_len,
177 enc, type, nick->nick);
185 if (flags & SILC_MESSAGE_FLAG_ACTION)
186 printformat_module("fe-common/silc", server, channel->channel_name,
187 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
188 nick == NULL ? "[<unknown>]" : nick->nick, message);
189 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
190 printformat_module("fe-common/silc", server, channel->channel_name,
191 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
192 nick == NULL ? "[<unknown>]" : nick->nick, message);
194 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
195 char tmp[256], *cp, *dm = NULL;
197 memset(tmp, 0, sizeof(tmp));
199 if (message_len > sizeof(tmp) - 1) {
200 dm = silc_calloc(message_len + 1, sizeof(*dm));
204 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
206 signal_emit("message public", 6, server, cp,
207 nick == NULL ? "[<unknown>]" : nick->nick,
208 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
209 chanrec->name, nick);
214 signal_emit("message public", 6, server, message,
215 nick == NULL ? "[<unknown>]" : nick->nick,
216 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
217 chanrec->name, nick);
221 /* Private message to the client. The `sender' is the nickname of the
222 sender received in the packet. */
224 void silc_private_message(SilcClient client, SilcClientConnection conn,
225 SilcClientEntry sender, SilcMessageFlags flags,
226 const unsigned char *message,
227 SilcUInt32 message_len)
229 SILC_SERVER_REC *server;
232 SILC_LOG_DEBUG(("Start"));
234 server = conn == NULL ? NULL : conn->context;
235 memset(userhost, 0, sizeof(userhost));
236 if (sender->username)
237 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
238 sender->username, sender->hostname);
240 if (flags & SILC_MESSAGE_FLAG_DATA) {
241 /* MIME object received, try to display it as well as we can */
242 char type[128], enc[128];
246 memset(type, 0, sizeof(type));
247 memset(enc, 0, sizeof(enc));
248 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
249 enc, sizeof(enc) - 1, &data, &data_len))
252 /* Then figure out what we can display */
253 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
254 !strstr(type, "text/vnd")) {
255 /* It is something textual, display it */
256 message = (const unsigned char *)data;
258 silc_emit_mime_sig(server, NULL, data, data_len,
259 enc, type, sender->nickname);
267 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
268 char tmp[256], *cp, *dm = NULL;
270 memset(tmp, 0, sizeof(tmp));
272 if (message_len > sizeof(tmp) - 1) {
273 dm = silc_calloc(message_len + 1, sizeof(*dm));
277 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
279 signal_emit("message private", 4, server, cp,
280 sender->nickname ? sender->nickname : "[<unknown>]",
281 sender->username ? userhost : NULL);
286 signal_emit("message private", 4, server, message,
287 sender->nickname ? sender->nickname : "[<unknown>]",
288 sender->username ? userhost : NULL);
291 /* Notify message to the client. The notify arguments are sent in the
292 same order as servers sends them. The arguments are same as received
293 from the server except for ID's. If ID is received application receives
294 the corresponding entry to the ID. For example, if Client ID is received
295 application receives SilcClientEntry. Also, if the notify type is
296 for channel the channel entry is sent to application (even if server
297 does not send it). */
299 void silc_notify(SilcClient client, SilcClientConnection conn,
300 SilcNotifyType type, ...)
303 SILC_SERVER_REC *server;
304 SILC_CHANNEL_REC *chanrec;
305 SILC_NICK_REC *nickrec;
306 SilcClientEntry client_entry, client_entry2;
307 SilcChannelEntry channel, channel2;
308 SilcServerEntry server_entry;
314 GSList *list1, *list_tmp;
316 SILC_LOG_DEBUG(("Start"));
320 server = conn == NULL ? NULL : conn->context;
323 case SILC_NOTIFY_TYPE_NONE:
324 /* Some generic notice from server */
325 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
328 case SILC_NOTIFY_TYPE_INVITE:
330 * Invited or modified invite list.
333 SILC_LOG_DEBUG(("Notify: INVITE"));
335 channel = va_arg(va, SilcChannelEntry);
336 name = va_arg(va, char *);
337 client_entry = va_arg(va, SilcClientEntry);
339 memset(buf, 0, sizeof(buf));
340 snprintf(buf, sizeof(buf) - 1, "%s@%s",
341 client_entry->username, client_entry->hostname);
342 signal_emit("message invite", 4, server, channel ? channel->channel_name :
343 name, client_entry->nickname, buf);
346 case SILC_NOTIFY_TYPE_JOIN:
351 SILC_LOG_DEBUG(("Notify: JOIN"));
353 client_entry = va_arg(va, SilcClientEntry);
354 channel = va_arg(va, SilcChannelEntry);
356 if (client_entry == server->conn->local_entry) {
357 /* You joined to channel */
358 chanrec = silc_channel_find(server, channel->channel_name);
359 if (chanrec != NULL && !chanrec->joined)
360 chanrec->entry = channel;
362 chanrec = silc_channel_find_entry(server, channel);
363 if (chanrec != NULL) {
364 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
366 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
370 memset(buf, 0, sizeof(buf));
371 if (client_entry->username)
372 snprintf(buf, sizeof(buf) - 1, "%s@%s",
373 client_entry->username, client_entry->hostname);
374 signal_emit("message join", 4, server, channel->channel_name,
375 client_entry->nickname,
376 client_entry->username == NULL ? "" : buf);
379 case SILC_NOTIFY_TYPE_LEAVE:
384 SILC_LOG_DEBUG(("Notify: LEAVE"));
386 client_entry = va_arg(va, SilcClientEntry);
387 channel = va_arg(va, SilcChannelEntry);
389 memset(buf, 0, sizeof(buf));
390 if (client_entry->username)
391 snprintf(buf, sizeof(buf) - 1, "%s@%s",
392 client_entry->username, client_entry->hostname);
393 signal_emit("message part", 5, server, channel->channel_name,
394 client_entry->nickname, client_entry->username ?
395 buf : "", client_entry->nickname);
397 chanrec = silc_channel_find_entry(server, channel);
398 if (chanrec != NULL) {
399 nickrec = silc_nicklist_find(chanrec, client_entry);
401 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
405 case SILC_NOTIFY_TYPE_SIGNOFF:
410 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
412 client_entry = va_arg(va, SilcClientEntry);
413 tmp = va_arg(va, char *);
415 silc_server_free_ftp(server, client_entry);
417 memset(buf, 0, sizeof(buf));
418 if (client_entry->username)
419 snprintf(buf, sizeof(buf) - 1, "%s@%s",
420 client_entry->username, client_entry->hostname);
421 signal_emit("message quit", 4, server, client_entry->nickname,
422 client_entry->username ? buf : "",
425 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
426 for (list_tmp = list1; list_tmp != NULL; list_tmp =
427 list_tmp->next->next) {
428 CHANNEL_REC *channel = list_tmp->data;
429 NICK_REC *nickrec = list_tmp->next->data;
431 nicklist_remove(channel, nickrec);
435 case SILC_NOTIFY_TYPE_TOPIC_SET:
440 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
442 idtype = va_arg(va, int);
443 entry = va_arg(va, void *);
444 tmp = va_arg(va, char *);
445 channel = va_arg(va, SilcChannelEntry);
447 chanrec = silc_channel_find_entry(server, channel);
448 if (chanrec != NULL) {
449 g_free_not_null(chanrec->topic);
450 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
451 signal_emit("channel topic changed", 1, chanrec);
454 if (idtype == SILC_ID_CLIENT) {
455 client_entry = (SilcClientEntry)entry;
456 memset(buf, 0, sizeof(buf));
457 snprintf(buf, sizeof(buf) - 1, "%s@%s",
458 client_entry->username, client_entry->hostname);
459 signal_emit("message topic", 5, server, channel->channel_name,
460 tmp, client_entry->nickname, buf);
461 } else if (idtype == SILC_ID_SERVER) {
462 server_entry = (SilcServerEntry)entry;
463 signal_emit("message topic", 5, server, channel->channel_name,
464 tmp, server_entry->server_name,
465 server_entry->server_name);
466 } else if (idtype == SILC_ID_CHANNEL) {
467 channel = (SilcChannelEntry)entry;
468 signal_emit("message topic", 5, server, channel->channel_name,
469 tmp, channel->channel_name, channel->channel_name);
473 case SILC_NOTIFY_TYPE_NICK_CHANGE:
478 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
480 client_entry = va_arg(va, SilcClientEntry);
481 client_entry2 = va_arg(va, SilcClientEntry);
483 if (!strcmp(client_entry->nickname, client_entry2->nickname))
486 memset(buf, 0, sizeof(buf));
487 snprintf(buf, sizeof(buf) - 1, "%s@%s",
488 client_entry2->username, client_entry2->hostname);
489 nicklist_rename_unique(SERVER(server),
490 client_entry, client_entry->nickname,
491 client_entry2, client_entry2->nickname);
492 signal_emit("message nick", 4, server, client_entry2->nickname,
493 client_entry->nickname, buf);
496 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
498 * Changed channel mode.
501 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
503 idtype = va_arg(va, int);
504 entry = va_arg(va, void *);
505 mode = va_arg(va, SilcUInt32);
506 (void)va_arg(va, char *);
507 (void)va_arg(va, char *);
508 channel = va_arg(va, SilcChannelEntry);
510 tmp = silc_client_chmode(mode,
511 channel->channel_key ?
512 channel->channel_key->cipher->name : "",
514 silc_hmac_get_name(channel->hmac) : "");
516 chanrec = silc_channel_find_entry(server, channel);
517 if (chanrec != NULL) {
518 g_free_not_null(chanrec->mode);
519 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
520 signal_emit("channel mode changed", 1, chanrec);
523 if (idtype == SILC_ID_CLIENT) {
524 client_entry = (SilcClientEntry)entry;
525 printformat_module("fe-common/silc", server, channel->channel_name,
526 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
527 channel->channel_name, tmp ? tmp : "removed all",
528 client_entry->nickname);
529 } else if (idtype == SILC_ID_SERVER) {
530 server_entry = (SilcServerEntry)entry;
531 printformat_module("fe-common/silc", server, channel->channel_name,
532 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
533 channel->channel_name, tmp ? tmp : "removed all",
534 server_entry->server_name);
535 } else if (idtype == SILC_ID_CHANNEL) {
536 channel2 = (SilcChannelEntry)entry;
537 printformat_module("fe-common/silc", server, channel->channel_name,
538 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
539 channel->channel_name, tmp ? tmp : "removed all",
540 channel2->channel_name);
546 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
548 * Changed user's mode on channel.
551 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
553 idtype = va_arg(va, int);
554 entry = va_arg(va, void *);
555 mode = va_arg(va, SilcUInt32);
556 client_entry2 = va_arg(va, SilcClientEntry);
557 channel = va_arg(va, SilcChannelEntry);
559 tmp = silc_client_chumode(mode);
560 chanrec = silc_channel_find_entry(server, channel);
561 if (chanrec != NULL) {
564 if (client_entry2 == server->conn->local_entry)
565 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
567 nick = silc_nicklist_find(chanrec, client_entry2);
569 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
570 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
571 signal_emit("nick mode changed", 2, chanrec, nick);
575 if (idtype == SILC_ID_CLIENT) {
576 client_entry = (SilcClientEntry)entry;
577 printformat_module("fe-common/silc", server, channel->channel_name,
578 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
579 channel->channel_name, client_entry2->nickname,
580 tmp ? tmp : "removed all",
581 client_entry->nickname);
582 } else if (idtype == SILC_ID_SERVER) {
583 server_entry = (SilcServerEntry)entry;
584 printformat_module("fe-common/silc", server, channel->channel_name,
585 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
586 channel->channel_name, client_entry2->nickname,
587 tmp ? tmp : "removed all",
588 server_entry->server_name);
589 } else if (idtype == SILC_ID_CHANNEL) {
590 channel2 = (SilcChannelEntry)entry;
591 printformat_module("fe-common/silc", server, channel->channel_name,
592 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
593 channel->channel_name, client_entry2->nickname,
594 tmp ? tmp : "removed all",
595 channel2->channel_name);
598 if (mode & SILC_CHANNEL_UMODE_CHANFO)
599 printformat_module("fe-common/silc",
600 server, channel->channel_name, MSGLEVEL_CRAP,
601 SILCTXT_CHANNEL_FOUNDER,
602 channel->channel_name, client_entry2->nickname);
604 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
605 printformat_module("fe-common/silc",
606 server, channel->channel_name, MSGLEVEL_CRAP,
607 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
612 case SILC_NOTIFY_TYPE_MOTD:
617 SILC_LOG_DEBUG(("Notify: MOTD"));
619 tmp = va_arg(va, char *);
621 if (!settings_get_bool("skip_motd"))
622 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
625 case SILC_NOTIFY_TYPE_KICKED:
627 * Someone was kicked from channel.
630 SILC_LOG_DEBUG(("Notify: KICKED"));
632 client_entry = va_arg(va, SilcClientEntry);
633 tmp = va_arg(va, char *);
634 client_entry2 = va_arg(va, SilcClientEntry);
635 channel = va_arg(va, SilcChannelEntry);
637 chanrec = silc_channel_find_entry(server, channel);
639 if (client_entry == conn->local_entry) {
640 printformat_module("fe-common/silc", server, channel->channel_name,
641 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
642 channel->channel_name,
643 client_entry ? client_entry2->nickname : "",
646 chanrec->kicked = TRUE;
647 channel_destroy((CHANNEL_REC *)chanrec);
650 printformat_module("fe-common/silc", server, channel->channel_name,
651 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
652 client_entry->nickname, channel->channel_name,
653 client_entry2 ? client_entry2->nickname : "",
657 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
659 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
664 case SILC_NOTIFY_TYPE_KILLED:
666 * Someone was killed from the network.
669 SILC_LOG_DEBUG(("Notify: KILLED"));
671 client_entry = va_arg(va, SilcClientEntry);
672 tmp = va_arg(va, char *);
673 idtype = va_arg(va, int);
674 entry = va_arg(va, SilcClientEntry);
676 if (client_entry == conn->local_entry) {
677 if (idtype == SILC_ID_CLIENT) {
678 client_entry2 = (SilcClientEntry)entry;
679 printformat_module("fe-common/silc", server, NULL,
680 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
681 client_entry2 ? client_entry2->nickname : "",
683 } else if (idtype == SILC_ID_SERVER) {
684 server_entry = (SilcServerEntry)entry;
685 printformat_module("fe-common/silc", server, NULL,
686 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
687 server_entry->server_name, tmp ? tmp : "");
688 } else if (idtype == SILC_ID_CHANNEL) {
689 channel = (SilcChannelEntry)entry;
690 printformat_module("fe-common/silc", server, NULL,
691 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
692 channel->channel_name, tmp ? tmp : "");
695 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
696 for (list_tmp = list1; list_tmp != NULL; list_tmp =
697 list_tmp->next->next) {
698 CHANNEL_REC *channel = list_tmp->data;
699 NICK_REC *nickrec = list_tmp->next->data;
700 nicklist_remove(channel, nickrec);
703 if (idtype == SILC_ID_CLIENT) {
704 client_entry2 = (SilcClientEntry)entry;
705 printformat_module("fe-common/silc", server, NULL,
706 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
707 client_entry->nickname,
708 client_entry2 ? client_entry2->nickname : "",
710 } else if (idtype == SILC_ID_SERVER) {
711 server_entry = (SilcServerEntry)entry;
712 printformat_module("fe-common/silc", server, NULL,
713 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
714 client_entry->nickname,
715 server_entry->server_name, tmp ? tmp : "");
716 } else if (idtype == SILC_ID_CHANNEL) {
717 channel = (SilcChannelEntry)entry;
718 printformat_module("fe-common/silc", server, NULL,
719 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
720 client_entry->nickname,
721 channel->channel_name, tmp ? tmp : "");
726 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
729 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
732 * Server has quit the network.
735 SilcClientEntry *clients;
736 SilcUInt32 clients_count;
738 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
740 (void)va_arg(va, void *);
741 clients = va_arg(va, SilcClientEntry *);
742 clients_count = va_arg(va, SilcUInt32);
744 for (i = 0; i < clients_count; i++) {
745 memset(buf, 0, sizeof(buf));
746 if (clients[i]->username)
747 snprintf(buf, sizeof(buf) - 1, "%s@%s",
748 clients[i]->username, clients[i]->hostname);
749 signal_emit("message quit", 4, server, clients[i]->nickname,
750 clients[i]->username ? buf : "",
753 silc_server_free_ftp(server, clients[i]);
755 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
756 for (list_tmp = list1; list_tmp != NULL; list_tmp =
757 list_tmp->next->next) {
758 CHANNEL_REC *channel = list_tmp->data;
759 NICK_REC *nickrec = list_tmp->next->data;
760 nicklist_remove(channel, nickrec);
766 case SILC_NOTIFY_TYPE_ERROR:
768 SilcStatus error = va_arg(va, int);
770 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
771 "%s", silc_get_status_message(error));
775 case SILC_NOTIFY_TYPE_WATCH:
777 SilcNotifyType notify;
779 client_entry = va_arg(va, SilcClientEntry);
780 name = va_arg(va, char *); /* Maybe NULL */
781 mode = va_arg(va, SilcUInt32);
782 notify = va_arg(va, int);
784 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
786 printformat_module("fe-common/silc", server, NULL,
787 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
788 client_entry->nickname, name);
790 printformat_module("fe-common/silc", server, NULL,
791 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
792 client_entry->nickname);
793 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
794 /* See if client was away and is now present */
795 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
796 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
797 SILC_UMODE_DETACHED)) &&
798 (client_entry->mode & SILC_UMODE_GONE ||
799 client_entry->mode & SILC_UMODE_INDISPOSED ||
800 client_entry->mode & SILC_UMODE_BUSY ||
801 client_entry->mode & SILC_UMODE_PAGE ||
802 client_entry->mode & SILC_UMODE_DETACHED)) {
803 printformat_module("fe-common/silc", server, NULL,
804 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
805 client_entry->nickname);
809 memset(buf, 0, sizeof(buf));
810 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
811 printformat_module("fe-common/silc", server, NULL,
812 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
813 client_entry->nickname, buf);
815 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
816 printformat_module("fe-common/silc", server, NULL,
817 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
818 client_entry->nickname);
819 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
820 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
821 printformat_module("fe-common/silc", server, NULL,
822 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
823 client_entry->nickname);
824 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
825 /* Client logged in to the network */
826 printformat_module("fe-common/silc", server, NULL,
827 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
828 client_entry->nickname);
835 printformat_module("fe-common/silc", server, NULL,
836 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
843 /* Called to indicate that connection was either successfully established
844 or connecting failed. This is also the first time application receives
845 the SilcClientConnection object which it should save somewhere. */
847 void silc_connect(SilcClient client, SilcClientConnection conn,
848 SilcClientConnectionStatus status)
850 SILC_SERVER_REC *server = conn->context;
852 if (!server || server->disconnected) {
853 silc_client_close_connection(client, conn);
858 case SILC_CLIENT_CONN_SUCCESS:
859 /* We have successfully connected to server */
860 server->connected = TRUE;
861 signal_emit("event connected", 1, server);
864 case SILC_CLIENT_CONN_SUCCESS_RESUME:
865 /* We have successfully resumed old detached session */
866 server->connected = TRUE;
867 signal_emit("event connected", 1, server);
869 /* If we resumed old session check whether we need to update
871 if (strcmp(server->nick, conn->local_entry->nickname)) {
873 old = g_strdup(server->nick);
874 server_change_nick(SERVER(server), conn->local_entry->nickname);
875 nicklist_rename_unique(SERVER(server),
876 conn->local_entry, server->nick,
877 conn->local_entry, conn->local_entry->nickname);
878 signal_emit("message own_nick", 4, server, server->nick, old, "");
884 server->connection_lost = TRUE;
886 server->conn->context = NULL;
887 server_disconnect(SERVER(server));
892 /* Called to indicate that connection was disconnected to the server. */
894 void silc_disconnect(SilcClient client, SilcClientConnection conn,
895 SilcStatus status, const char *message)
897 SILC_SERVER_REC *server = conn->context;
899 SILC_LOG_DEBUG(("Start"));
901 if (!server || server->connection_lost)
904 if (server->conn && server->conn->local_entry) {
905 nicklist_rename_unique(SERVER(server),
906 server->conn->local_entry, server->nick,
907 server->conn->local_entry,
908 silc_client->username);
909 silc_change_nick(server, silc_client->username);
913 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
914 "Server closed connection: %s (%d) %s",
915 silc_get_status_message(status), status,
916 message ? message : "");
918 server->conn->context = NULL;
920 server->connection_lost = TRUE;
921 server_disconnect(SERVER(server));
924 /* Command handler. This function is called always in the command function.
925 If error occurs it will be called as well. `conn' is the associated
926 client connection. `cmd_context' is the command context that was
927 originally sent to the command. `success' is FALSE if error occured
928 during command. `command' is the command being processed. It must be
929 noted that this is not reply from server. This is merely called just
930 after application has called the command. Just to tell application
931 that the command really was processed. */
933 void silc_command(SilcClient client, SilcClientConnection conn,
934 SilcClientCommandContext cmd_context, bool success,
935 SilcCommand command, SilcStatus status)
937 SILC_SERVER_REC *server = conn->context;
939 SILC_LOG_DEBUG(("Start"));
942 silc_say_error("%s", silc_get_status_message(status));
947 case SILC_COMMAND_INVITE:
948 printformat_module("fe-common/silc", server, NULL,
949 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
950 cmd_context->argv[2],
951 (cmd_context->argv[1][0] == '*' ?
952 (char *)conn->current_channel->channel_name :
953 (char *)cmd_context->argv[1]));
960 /* Client info resolving callback when JOIN command reply is received.
961 This will cache all users on the channel. */
963 static void silc_client_join_get_users(SilcClient client,
964 SilcClientConnection conn,
965 SilcClientEntry *clients,
966 SilcUInt32 clients_count,
969 SilcChannelEntry channel = (SilcChannelEntry)context;
970 SilcHashTableList htl;
972 SILC_SERVER_REC *server = conn->context;
973 SILC_CHANNEL_REC *chanrec;
974 SilcClientEntry founder = NULL;
977 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
978 silc_hash_table_count(channel->user_list)));
983 chanrec = silc_channel_find(server, channel->channel_name);
987 silc_hash_table_list(channel->user_list, &htl);
988 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
989 if (!chu->client->nickname)
991 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
992 founder = chu->client;
993 silc_nicklist_insert(chanrec, chu, FALSE);
995 silc_hash_table_list_reset(&htl);
997 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
998 nicklist_set_own(CHANNEL(chanrec), ownnick);
999 signal_emit("channel joined", 1, chanrec);
1000 chanrec->entry = channel;
1003 printformat_module("fe-common/silc", server, channel->channel_name,
1004 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1005 channel->channel_name, chanrec->topic);
1007 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
1010 if (founder == conn->local_entry)
1011 printformat_module("fe-common/silc",
1012 server, channel->channel_name, MSGLEVEL_CRAP,
1013 SILCTXT_CHANNEL_FOUNDER_YOU,
1014 channel->channel_name);
1016 printformat_module("fe-common/silc",
1017 server, channel->channel_name, MSGLEVEL_CRAP,
1018 SILCTXT_CHANNEL_FOUNDER,
1019 channel->channel_name, founder->nickname);
1025 SilcClientConnection conn;
1031 void silc_getkey_cb(bool success, void *context)
1033 GetkeyContext getkey = (GetkeyContext)context;
1034 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1035 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1036 ((SilcClientEntry)getkey->entry)->nickname :
1037 ((SilcServerEntry)getkey->entry)->server_name);
1040 printformat_module("fe-common/silc", NULL, NULL,
1041 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
1043 printformat_module("fe-common/silc", NULL, NULL,
1044 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
1047 silc_free(getkey->fingerprint);
1051 /* Command reply handler. This function is called always in the command reply
1052 function. If error occurs it will be called as well. Normal scenario
1053 is that it will be called after the received command data has been parsed
1054 and processed. The function is used to pass the received command data to
1057 `conn' is the associated client connection. `cmd_payload' is the command
1058 payload data received from server and it can be ignored. It is provided
1059 if the application would like to re-parse the received command data,
1060 however, it must be noted that the data is parsed already by the library
1061 thus the payload can be ignored. `success' is FALSE if error occured.
1062 In this case arguments are not sent to the application. `command' is the
1063 command reply being processed. The function has variable argument list
1064 and each command defines the number and type of arguments it passes to the
1065 application (on error they are not sent). */
1068 silc_command_reply(SilcClient client, SilcClientConnection conn,
1069 SilcCommandPayload cmd_payload, bool success,
1070 SilcCommand command, SilcStatus status, ...)
1073 SILC_SERVER_REC *server = conn->context;
1074 SILC_CHANNEL_REC *chanrec;
1077 va_start(vp, status);
1079 SILC_LOG_DEBUG(("Start"));
1082 case SILC_COMMAND_WHOIS:
1084 char buf[1024], *nickname, *username, *realname, *nick;
1085 unsigned char *fingerprint;
1086 SilcUInt32 idle, mode;
1087 SilcBuffer channels, user_modes;
1088 SilcClientEntry client_entry;
1090 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1091 /* Print the unknown nick for user */
1092 unsigned char *tmp =
1093 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1096 silc_say_error("%s: %s", tmp,
1097 silc_get_status_message(status));
1099 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1100 /* Try to find the entry for the unknown client ID, since we
1101 might have, and print the nickname of it for user. */
1103 unsigned char *tmp =
1104 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1107 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1110 client_entry = silc_client_get_client_by_id(client, conn,
1112 if (client_entry && client_entry->nickname)
1113 silc_say_error("%s: %s", client_entry->nickname,
1114 silc_get_status_message(status));
1115 silc_free(client_id);
1124 client_entry = va_arg(vp, SilcClientEntry);
1125 nickname = va_arg(vp, char *);
1126 username = va_arg(vp, char *);
1127 realname = va_arg(vp, char *);
1128 channels = va_arg(vp, SilcBuffer);
1129 mode = va_arg(vp, SilcUInt32);
1130 idle = va_arg(vp, SilcUInt32);
1131 fingerprint = va_arg(vp, unsigned char *);
1132 user_modes = va_arg(vp, SilcBuffer);
1134 silc_parse_userfqdn(nickname, &nick, NULL);
1135 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1136 SILCTXT_WHOIS_USERINFO, nickname,
1137 client_entry->username, client_entry->hostname,
1138 nick, client_entry->nickname);
1139 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1140 SILCTXT_WHOIS_REALNAME, realname);
1143 if (channels && user_modes) {
1145 SilcDList list = silc_channel_payload_parse_list(channels->data,
1147 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1149 SilcChannelPayload entry;
1152 memset(buf, 0, sizeof(buf));
1153 silc_dlist_start(list);
1154 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1155 SilcUInt32 name_len;
1156 char *m = silc_client_chumode_char(umodes[i++]);
1157 char *name = silc_channel_get_name(entry, &name_len);
1160 strncat(buf, m, strlen(m));
1161 strncat(buf, name, name_len);
1162 strncat(buf, " ", 1);
1166 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1167 SILCTXT_WHOIS_CHANNELS, buf);
1168 silc_channel_payload_list_free(list);
1174 memset(buf, 0, sizeof(buf));
1175 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1176 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1177 SILCTXT_WHOIS_MODES, buf);
1180 if (idle && nickname) {
1181 memset(buf, 0, sizeof(buf));
1182 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1183 idle > 60 ? (idle / 60) : idle,
1184 idle > 60 ? "minutes" : "seconds");
1186 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1187 SILCTXT_WHOIS_IDLE, buf);
1191 fingerprint = silc_fingerprint(fingerprint, 20);
1192 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1193 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1194 silc_free(fingerprint);
1199 case SILC_COMMAND_IDENTIFY:
1201 SilcClientEntry client_entry;
1203 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1204 /* Print the unknown nick for user */
1205 unsigned char *tmp =
1206 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1209 silc_say_error("%s: %s", tmp,
1210 silc_get_status_message(status));
1212 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1213 /* Try to find the entry for the unknown client ID, since we
1214 might have, and print the nickname of it for user. */
1216 unsigned char *tmp =
1217 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1220 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1223 client_entry = silc_client_get_client_by_id(client, conn,
1225 if (client_entry && client_entry->nickname)
1226 silc_say_error("%s: %s", client_entry->nickname,
1227 silc_get_status_message(status));
1228 silc_free(client_id);
1237 case SILC_COMMAND_WHOWAS:
1239 char *nickname, *username, *realname;
1241 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1242 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1244 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1247 silc_say_error("%s: %s", tmp,
1248 silc_get_status_message(status));
1255 (void)va_arg(vp, SilcClientEntry);
1256 nickname = va_arg(vp, char *);
1257 username = va_arg(vp, char *);
1258 realname = va_arg(vp, char *);
1260 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1261 SILCTXT_WHOWAS_USERINFO, nickname, username,
1262 realname ? realname : "");
1266 case SILC_COMMAND_INVITE:
1268 SilcChannelEntry channel;
1270 SilcArgumentPayload args;
1276 channel = va_arg(vp, SilcChannelEntry);
1277 invite_list = va_arg(vp, char *);
1279 args = silc_command_get_args(cmd_payload);
1281 argc = silc_argument_get_arg_num(args);
1284 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1285 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1288 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1289 SILCTXT_CHANNEL_NO_INVITE_LIST,
1290 channel->channel_name);
1294 case SILC_COMMAND_JOIN:
1296 char *channel, *mode, *topic;
1298 SilcChannelEntry channel_entry;
1299 SilcBuffer client_id_list;
1300 SilcUInt32 list_count;
1305 channel = va_arg(vp, char *);
1306 channel_entry = va_arg(vp, SilcChannelEntry);
1307 modei = va_arg(vp, SilcUInt32);
1308 (void)va_arg(vp, SilcUInt32);
1309 (void)va_arg(vp, unsigned char *);
1310 (void)va_arg(vp, unsigned char *);
1311 (void)va_arg(vp, unsigned char *);
1312 topic = va_arg(vp, char *);
1313 (void)va_arg(vp, unsigned char *);
1314 list_count = va_arg(vp, SilcUInt32);
1315 client_id_list = va_arg(vp, SilcBuffer);
1317 chanrec = silc_channel_find(server, channel);
1319 chanrec = silc_channel_create(server, channel, TRUE);
1322 g_free_not_null(chanrec->topic);
1323 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1324 signal_emit("channel topic changed", 1, chanrec);
1327 mode = silc_client_chmode(modei,
1328 channel_entry->channel_key ?
1329 channel_entry->channel_key->cipher->name : "",
1330 channel_entry->hmac ?
1331 silc_hmac_get_name(channel_entry->hmac) : "");
1332 g_free_not_null(chanrec->mode);
1333 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1334 signal_emit("channel mode changed", 1, chanrec);
1336 /* Resolve the client information */
1337 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1338 silc_client_join_get_users,
1344 case SILC_COMMAND_NICK:
1347 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1352 old = g_strdup(server->nick);
1353 server_change_nick(SERVER(server), client->nickname);
1354 nicklist_rename_unique(SERVER(server),
1355 server->conn->local_entry, server->nick,
1356 client, client->nickname);
1357 signal_emit("message own_nick", 4, server, server->nick, old, "");
1362 case SILC_COMMAND_LIST:
1371 (void)va_arg(vp, SilcChannelEntry);
1372 name = va_arg(vp, char *);
1373 topic = va_arg(vp, char *);
1374 usercount = va_arg(vp, int);
1376 if (status == SILC_STATUS_LIST_START ||
1377 status == SILC_STATUS_OK)
1378 printformat_module("fe-common/silc", server, NULL,
1379 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1382 snprintf(users, sizeof(users) - 1, "N/A");
1384 snprintf(users, sizeof(users) - 1, "%d", usercount);
1385 printformat_module("fe-common/silc", server, NULL,
1386 MSGLEVEL_CRAP, SILCTXT_LIST,
1387 name, users, topic ? topic : "");
1391 case SILC_COMMAND_UMODE:
1398 mode = va_arg(vp, SilcUInt32);
1400 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1401 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1402 printformat_module("fe-common/silc", server, NULL,
1403 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1405 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1406 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1407 printformat_module("fe-common/silc", server, NULL,
1408 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1410 server->umode = mode;
1411 signal_emit("user mode changed", 2, server, NULL);
1415 case SILC_COMMAND_OPER:
1419 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1420 signal_emit("user mode changed", 2, server, NULL);
1422 printformat_module("fe-common/silc", server, NULL,
1423 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1426 case SILC_COMMAND_SILCOPER:
1430 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1431 signal_emit("user mode changed", 2, server, NULL);
1433 printformat_module("fe-common/silc", server, NULL,
1434 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1437 case SILC_COMMAND_USERS:
1439 SilcHashTableList htl;
1440 SilcChannelEntry channel;
1441 SilcChannelUser chu;
1446 channel = va_arg(vp, SilcChannelEntry);
1448 printformat_module("fe-common/silc", server, channel->channel_name,
1449 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1450 channel->channel_name);
1452 silc_hash_table_list(channel->user_list, &htl);
1453 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1454 SilcClientEntry e = chu->client;
1455 char stat[5], *mode;
1460 memset(stat, 0, sizeof(stat));
1461 mode = silc_client_chumode_char(chu->mode);
1462 if (e->mode & SILC_UMODE_GONE)
1464 else if (e->mode & SILC_UMODE_INDISPOSED)
1466 else if (e->mode & SILC_UMODE_BUSY)
1468 else if (e->mode & SILC_UMODE_PAGE)
1470 else if (e->mode & SILC_UMODE_HYPER)
1472 else if (e->mode & SILC_UMODE_ROBOT)
1474 else if (e->mode & SILC_UMODE_ANONYMOUS)
1481 printformat_module("fe-common/silc", server, channel->channel_name,
1482 MSGLEVEL_CRAP, SILCTXT_USERS,
1484 e->username ? e->username : "",
1485 e->hostname ? e->hostname : "",
1486 e->realname ? e->realname : "");
1490 silc_hash_table_list_reset(&htl);
1494 case SILC_COMMAND_BAN:
1496 SilcChannelEntry channel;
1502 channel = va_arg(vp, SilcChannelEntry);
1503 ban_list = va_arg(vp, char *);
1506 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1507 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1510 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1511 SILCTXT_CHANNEL_NO_BAN_LIST,
1512 channel->channel_name);
1516 case SILC_COMMAND_GETKEY:
1520 SilcPublicKey public_key;
1523 GetkeyContext getkey;
1529 id_type = va_arg(vp, SilcUInt32);
1530 entry = va_arg(vp, void *);
1531 public_key = va_arg(vp, SilcPublicKey);
1534 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1536 getkey = silc_calloc(1, sizeof(*getkey));
1537 getkey->entry = entry;
1538 getkey->id_type = id_type;
1539 getkey->client = client;
1540 getkey->conn = conn;
1541 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1543 name = (id_type == SILC_ID_CLIENT ?
1544 ((SilcClientEntry)entry)->nickname :
1545 ((SilcServerEntry)entry)->server_name);
1547 silc_verify_public_key_internal(client, conn, name,
1548 (id_type == SILC_ID_CLIENT ?
1549 SILC_SOCKET_TYPE_CLIENT :
1550 SILC_SOCKET_TYPE_SERVER),
1551 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1552 silc_getkey_cb, getkey);
1555 printformat_module("fe-common/silc", server, NULL,
1556 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1561 case SILC_COMMAND_INFO:
1563 SilcServerEntry server_entry;
1570 server_entry = va_arg(vp, SilcServerEntry);
1571 server_name = va_arg(vp, char *);
1572 server_info = va_arg(vp, char *);
1574 if (server_name && server_info )
1576 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1577 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1582 case SILC_COMMAND_TOPIC:
1584 SilcChannelEntry channel;
1590 channel = va_arg(vp, SilcChannelEntry);
1591 topic = va_arg(vp, char *);
1594 chanrec = silc_channel_find_entry(server, channel);
1596 g_free_not_null(chanrec->topic);
1597 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1598 signal_emit("channel topic changed", 1, chanrec);
1600 printformat_module("fe-common/silc", server, channel->channel_name,
1601 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1602 channel->channel_name, topic);
1604 printformat_module("fe-common/silc", server, channel->channel_name,
1605 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1606 channel->channel_name);
1611 case SILC_COMMAND_WATCH:
1620 SilcClientConnection conn;
1626 SilcSKEPKType pk_type;
1627 SilcVerifyPublicKey completion;
1631 static void verify_public_key_completion(const char *line, void *context)
1633 PublicKeyVerify verify = (PublicKeyVerify)context;
1635 if (line[0] == 'Y' || line[0] == 'y') {
1636 /* Call the completion */
1637 if (verify->completion)
1638 verify->completion(TRUE, verify->context);
1640 /* Save the key for future checking */
1641 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1642 verify->pk_len, SILC_PKCS_FILE_PEM);
1644 /* Call the completion */
1645 if (verify->completion)
1646 verify->completion(FALSE, verify->context);
1648 printformat_module("fe-common/silc", NULL, NULL,
1649 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1650 verify->entity_name ? verify->entity_name :
1654 silc_free(verify->filename);
1655 silc_free(verify->entity);
1656 silc_free(verify->entity_name);
1657 silc_free(verify->pk);
1661 /* Internal routine to verify public key. If the `completion' is provided
1662 it will be called to indicate whether public was verified or not. For
1663 server/router public key this will check for filename that includes the
1664 remote host's IP address and remote host's hostname. */
1667 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1668 const char *name, SilcSocketType conn_type,
1669 unsigned char *pk, SilcUInt32 pk_len,
1670 SilcSKEPKType pk_type,
1671 SilcVerifyPublicKey completion, void *context)
1674 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1675 char *fingerprint, *babbleprint, *format;
1678 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1679 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1680 "server" : "client");
1681 PublicKeyVerify verify;
1683 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1684 printformat_module("fe-common/silc", NULL, NULL,
1685 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1688 completion(FALSE, context);
1692 pw = getpwuid(getuid());
1695 completion(FALSE, context);
1699 memset(filename, 0, sizeof(filename));
1700 memset(filename2, 0, sizeof(filename2));
1701 memset(file, 0, sizeof(file));
1703 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1704 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1706 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1707 conn->sock->ip, conn->sock->port);
1708 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1709 get_irssi_dir(), entity, file);
1711 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1712 conn->sock->hostname, conn->sock->port);
1713 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1714 get_irssi_dir(), entity, file);
1719 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1720 name, conn->sock->port);
1721 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1722 get_irssi_dir(), entity, file);
1727 /* Replace all whitespaces with `_'. */
1728 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1729 for (i = 0; i < strlen(fingerprint); i++)
1730 if (fingerprint[i] == ' ')
1731 fingerprint[i] = '_';
1733 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1734 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1735 get_irssi_dir(), entity, file);
1736 silc_free(fingerprint);
1741 /* Take fingerprint of the public key */
1742 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1743 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1745 verify = silc_calloc(1, sizeof(*verify));
1746 verify->client = client;
1747 verify->conn = conn;
1748 verify->filename = strdup(ipf);
1749 verify->entity = strdup(entity);
1750 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1751 (name ? strdup(name) : strdup(conn->sock->hostname))
1753 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1754 memcpy(verify->pk, pk, pk_len);
1755 verify->pk_len = pk_len;
1756 verify->pk_type = pk_type;
1757 verify->completion = completion;
1758 verify->context = context;
1760 /* Check whether this key already exists */
1761 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1762 /* Key does not exist, ask user to verify the key and save it */
1764 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1765 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1766 verify->entity_name : entity);
1767 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1768 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1769 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1770 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1771 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1772 SILCTXT_PUBKEY_ACCEPT);
1773 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1776 silc_free(fingerprint);
1779 /* The key already exists, verify it. */
1780 SilcPublicKey public_key;
1781 unsigned char *encpk;
1782 SilcUInt32 encpk_len;
1784 /* Load the key file, try for both IP filename and hostname filename */
1785 if (!silc_pkcs_load_public_key(ipf, &public_key,
1786 SILC_PKCS_FILE_PEM) &&
1787 !silc_pkcs_load_public_key(ipf, &public_key,
1788 SILC_PKCS_FILE_BIN) &&
1789 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1790 SILC_PKCS_FILE_PEM) &&
1791 !silc_pkcs_load_public_key(hostf, &public_key,
1792 SILC_PKCS_FILE_BIN)))) {
1793 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1794 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1795 verify->entity_name : entity);
1796 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1797 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1798 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1799 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1800 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1801 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1802 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1803 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1804 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1807 silc_free(fingerprint);
1811 /* Encode the key data */
1812 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1814 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1815 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1816 verify->entity_name : entity);
1817 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1818 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1819 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1820 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1821 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1822 SILCTXT_PUBKEY_MALFORMED, entity);
1823 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1824 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1825 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1828 silc_free(fingerprint);
1832 /* Compare the keys */
1833 if (memcmp(encpk, pk, encpk_len)) {
1834 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1835 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1836 verify->entity_name : entity);
1837 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1838 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1839 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1840 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1841 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1842 SILCTXT_PUBKEY_NO_MATCH, entity);
1843 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1844 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1845 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1846 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1848 /* Ask user to verify the key and save it */
1849 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1850 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1851 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1854 silc_free(fingerprint);
1858 /* Local copy matched */
1860 completion(TRUE, context);
1861 silc_free(fingerprint);
1865 /* Verifies received public key. The `conn_type' indicates which entity
1866 (server, client etc.) has sent the public key. If user decides to trust
1867 the key may be saved as trusted public key for later use. The
1868 `completion' must be called after the public key has been verified. */
1871 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1872 SilcSocketType conn_type, unsigned char *pk,
1873 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1874 SilcVerifyPublicKey completion, void *context)
1876 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1878 completion, context);
1881 /* Asks passphrase from user on the input line. */
1884 SilcAskPassphrase completion;
1888 void ask_passphrase_completion(const char *passphrase, void *context)
1890 AskPassphrase p = (AskPassphrase)context;
1891 if (passphrase && passphrase[0] == '\0')
1893 p->completion((unsigned char *)passphrase,
1894 passphrase ? strlen(passphrase) : 0, p->context);
1898 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1899 SilcAskPassphrase completion, void *context)
1901 AskPassphrase p = silc_calloc(1, sizeof(*p));
1902 p->completion = completion;
1903 p->context = context;
1905 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1906 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1910 SilcGetAuthMeth completion;
1912 } *InternalGetAuthMethod;
1914 /* Callback called when we've received the authentication method information
1915 from the server after we've requested it. This will get the authentication
1916 data from the user if needed. */
1918 static void silc_get_auth_method_callback(SilcClient client,
1919 SilcClientConnection conn,
1920 SilcAuthMethod auth_meth,
1923 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1925 SILC_LOG_DEBUG(("Start"));
1927 switch (auth_meth) {
1928 case SILC_AUTH_NONE:
1929 /* No authentication required. */
1930 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1932 case SILC_AUTH_PASSWORD:
1933 /* Do not ask the passphrase from user, the library will ask it if
1934 we do not provide it here. */
1935 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1937 case SILC_AUTH_PUBLIC_KEY:
1938 /* Do not get the authentication data now, the library will generate
1939 it using our default key, if we do not provide it here. */
1940 /* XXX In the future when we support multiple local keys and multiple
1941 local certificates we will need to ask from user which one to use. */
1942 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1946 silc_free(internal);
1949 /* Find authentication method and authentication data by hostname and
1950 port. The hostname may be IP address as well. The found authentication
1951 method and authentication data is returned to `auth_meth', `auth_data'
1952 and `auth_data_len'. The function returns TRUE if authentication method
1953 is found and FALSE if not. `conn' may be NULL. */
1955 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1956 char *hostname, SilcUInt16 port,
1957 SilcGetAuthMeth completion, void *context)
1959 InternalGetAuthMethod internal;
1961 SILC_LOG_DEBUG(("Start"));
1963 /* XXX must resolve from configuration whether this connection has
1964 any specific authentication data */
1966 /* If we do not have this connection configured by the user in a
1967 configuration file then resolve the authentication method from the
1968 server for this session. */
1969 internal = silc_calloc(1, sizeof(*internal));
1970 internal->completion = completion;
1971 internal->context = context;
1973 silc_client_request_authentication_method(client, conn,
1974 silc_get_auth_method_callback,
1978 /* Notifies application that failure packet was received. This is called
1979 if there is some protocol active in the client. The `protocol' is the
1980 protocol context. The `failure' is opaque pointer to the failure
1981 indication. Note, that the `failure' is protocol dependant and application
1982 must explicitly cast it to correct type. Usually `failure' is 32 bit
1983 failure type (see protocol specs for all protocol failure types). */
1985 void silc_failure(SilcClient client, SilcClientConnection conn,
1986 SilcProtocol protocol, void *failure)
1988 SILC_LOG_DEBUG(("Start"));
1990 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1991 SilcSKEStatus status = (SilcSKEStatus)failure;
1993 if (status == SILC_SKE_STATUS_BAD_VERSION)
1994 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1995 SILCTXT_KE_BAD_VERSION);
1996 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1997 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1998 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1999 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2000 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2001 SILCTXT_KE_UNKNOWN_GROUP);
2002 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2003 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2004 SILCTXT_KE_UNKNOWN_CIPHER);
2005 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2006 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2007 SILCTXT_KE_UNKNOWN_PKCS);
2008 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2009 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2010 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2011 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2012 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2013 SILCTXT_KE_UNKNOWN_HMAC);
2014 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2015 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2016 SILCTXT_KE_INCORRECT_SIGNATURE);
2017 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2018 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2019 SILCTXT_KE_INVALID_COOKIE);
2022 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2023 SilcUInt32 err = (SilcUInt32)failure;
2025 if (err == SILC_AUTH_FAILED)
2026 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2027 SILCTXT_AUTH_FAILED);
2031 /* Asks whether the user would like to perform the key agreement protocol.
2032 This is called after we have received an key agreement packet or an
2033 reply to our key agreement packet. This returns TRUE if the user wants
2034 the library to perform the key agreement protocol and FALSE if it is not
2035 desired (application may start it later by calling the function
2036 silc_client_perform_key_agreement). */
2038 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
2039 SilcClientEntry client_entry, const char *hostname,
2040 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2045 SILC_LOG_DEBUG(("Start"));
2047 /* We will just display the info on the screen and return FALSE and user
2048 will have to start the key agreement with a command. */
2051 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2054 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2055 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2057 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2058 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2059 client_entry->nickname, hostname, portstr);
2067 /* Notifies application that file transfer protocol session is being
2068 requested by the remote client indicated by the `client_entry' from
2069 the `hostname' and `port'. The `session_id' is the file transfer
2070 session and it can be used to either accept or reject the file
2071 transfer request, by calling the silc_client_file_receive or
2072 silc_client_file_close, respectively. */
2074 void silc_ftp(SilcClient client, SilcClientConnection conn,
2075 SilcClientEntry client_entry, SilcUInt32 session_id,
2076 const char *hostname, SilcUInt16 port)
2078 SILC_SERVER_REC *server;
2080 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2082 SILC_LOG_DEBUG(("Start"));
2084 server = conn->context;
2086 ftp->client_entry = client_entry;
2087 ftp->session_id = session_id;
2090 silc_dlist_add(server->ftp_sessions, ftp);
2091 server->current_session = ftp;
2094 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2097 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2098 SILCTXT_FILE_REQUEST, client_entry->nickname);
2100 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2101 SILCTXT_FILE_REQUEST_HOST,
2102 client_entry->nickname, hostname, portstr);
2105 /* Delivers SILC session detachment data indicated by `detach_data' to the
2106 application. If application has issued SILC_COMMAND_DETACH command
2107 the client session in the SILC network is not quit. The client remains
2108 in the network but is detached. The detachment data may be used later
2109 to resume the session in the SILC Network. The appliation is
2110 responsible of saving the `detach_data', to for example in a file.
2112 The detachment data can be given as argument to the functions
2113 silc_client_connect_to_server, or silc_client_add_connection when
2114 creating connection to remote server, inside SilcClientConnectionParams
2115 structure. If it is provided the client library will attempt to resume
2116 the session in the network. After the connection is created
2117 successfully, the application is responsible of setting the user
2118 interface for user into the same state it was before detaching (showing
2119 same channels, channel modes, etc). It can do this by fetching the
2120 information (like joined channels) from the client library. */
2123 silc_detach(SilcClient client, SilcClientConnection conn,
2124 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2128 /* Save the detachment data to file. */
2130 memset(file, 0, sizeof(file));
2131 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2132 silc_file_writefile(file, detach_data, detach_data_len);
2136 /* SILC client operations */
2137 SilcClientOperations ops = {
2139 silc_channel_message,
2140 silc_private_message,
2146 silc_get_auth_method,
2147 silc_verify_public_key,
2148 silc_ask_passphrase,