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"
37 #include "fe-common/core/printtext.h"
38 #include "fe-common/core/fe-channels.h"
39 #include "fe-common/core/keyboard.h"
40 #include "fe-common/core/window-items.h"
41 #include "fe-common/silc/module-formats.h"
46 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
47 const char *name, SilcSocketType conn_type,
48 unsigned char *pk, SilcUInt32 pk_len,
49 SilcSKEPKType pk_type,
50 SilcVerifyPublicKey completion, void *context);
52 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
55 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
56 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
57 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
59 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
60 "[SILC operator]" : "[unknown mode]");
62 if (mode & SILC_UMODE_GONE)
63 strcat(buf, " [away]");
64 if (mode & SILC_UMODE_INDISPOSED)
65 strcat(buf, " [indisposed]");
66 if (mode & SILC_UMODE_BUSY)
67 strcat(buf, " [busy]");
68 if (mode & SILC_UMODE_PAGE)
69 strcat(buf, " [page to reach]");
70 if (mode & SILC_UMODE_HYPER)
71 strcat(buf, " [hyper active]");
72 if (mode & SILC_UMODE_ROBOT)
73 strcat(buf, " [robot]");
74 if (mode & SILC_UMODE_ANONYMOUS)
75 strcat(buf, " [anonymous]");
76 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
77 strcat(buf, " [blocks private messages]");
78 if (mode & SILC_UMODE_DETACHED)
79 strcat(buf, " [detached]");
80 if (mode & SILC_UMODE_REJECT_WATCHING)
81 strcat(buf, " [rejects watching]");
82 if (mode & SILC_UMODE_BLOCK_INVITE)
83 strcat(buf, " [blocks invites]");
86 /* print "nick appears as" message to every channel of a server */
88 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
89 const char *newnick, const char *oldnick,
92 if (ignore_check(SERVER(server), oldnick, address,
93 channel, newnick, MSGLEVEL_NICKS))
96 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
97 SILCTXT_CHANNEL_APPEARS,
98 oldnick, newnick, channel, address);
102 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
103 const char *oldnick, const char *address)
105 GSList *tmp, *windows;
107 /* Print to each channel/query where the nick is.
108 Don't print more than once to the same window. */
111 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
112 CHANNEL_REC *channel = tmp->data;
113 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
115 if (nicklist_find(channel, newnick) == NULL ||
116 g_slist_find(windows, window) != NULL)
119 windows = g_slist_append(windows, window);
120 silc_print_nick_change_channel(server, channel->visible_name,
121 newnick, oldnick, address);
124 g_slist_free(windows);
127 void silc_say(SilcClient client, SilcClientConnection conn,
128 SilcClientMessageType type, char *msg, ...)
130 SILC_SERVER_REC *server;
134 server = conn == NULL ? NULL : conn->context;
137 str = g_strdup_vprintf(msg, va);
138 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
143 void silc_say_error(char *msg, ...)
149 str = g_strdup_vprintf(msg, va);
150 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
156 /* try to verify a message using locally stored public key data */
157 int verify_message_signature(SilcClientEntry sender,
158 SilcMessageSignedPayload sig,
159 SilcMessagePayload message)
162 char file[256], filename[256];
163 char *fingerprint, *fingerprint2;
164 unsigned char *pk_data;
165 SilcUInt32 pk_datalen;
167 int ret = SILC_MSG_SIGNED_VERIFIED, i;
170 return SILC_MSG_SIGNED_UNKNOWN;
172 /* get public key from the signature payload and compare it with the
173 one stored in the client entry */
174 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
177 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
179 if (sender->fingerprint) {
180 fingerprint2 = silc_fingerprint(sender->fingerprint,
181 sender->fingerprint_len);
182 if (strcmp(fingerprint, fingerprint2)) {
183 /* since the public key differs from the senders public key, the
184 verification _failed_ */
185 silc_pkcs_public_key_free(pk);
186 silc_free(fingerprint);
187 ret = SILC_MSG_SIGNED_UNKNOWN;
189 silc_free(fingerprint2);
191 } else if (sender->fingerprint)
192 fingerprint = silc_fingerprint(sender->fingerprint,
193 sender->fingerprint_len);
195 /* no idea, who or what signed that message ... */
196 return SILC_MSG_SIGNED_UNKNOWN;
198 /* search our local client key cache */
199 for (i = 0; i < strlen(fingerprint); i++)
200 if (fingerprint[i] == ' ')
201 fingerprint[i] = '_';
203 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
204 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
205 get_irssi_dir(), file);
206 silc_free(fingerprint);
208 if (stat(filename, &st) < 0)
209 /* we don't have the public key cached ... use the one from the sig */
210 ret = SILC_MSG_SIGNED_UNKNOWN;
212 SilcPublicKey cached_pk=NULL;
214 /* try to load the file */
215 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
216 !silc_pkcs_load_public_key(filename, &cached_pk,
217 SILC_PKCS_FILE_BIN)) {
218 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
219 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
221 return SILC_MSG_SIGNED_UNKNOWN;
223 ret = SILC_MSG_SIGNED_UNKNOWN;
228 silc_pkcs_public_key_free(pk);
233 /* the public key is now in pk, our "level of trust" in ret */
234 if ((pk) && silc_message_signed_verify(sig, message, pk,
235 silc_client->sha1hash)!= SILC_AUTH_OK)
236 ret = SILC_MSG_SIGNED_FAILED;
239 silc_pkcs_public_key_free(pk);
244 /* Message for a channel. The `sender' is the nickname of the sender
245 received in the packet. The `channel_name' is the name of the channel. */
247 void silc_channel_message(SilcClient client, SilcClientConnection conn,
248 SilcClientEntry sender, SilcChannelEntry channel,
249 SilcMessagePayload payload,
250 SilcMessageFlags flags, const unsigned char *message,
251 SilcUInt32 message_len)
253 SILC_SERVER_REC *server;
255 SILC_CHANNEL_REC *chanrec;
258 SILC_LOG_DEBUG(("Start"));
263 server = conn == NULL ? NULL : conn->context;
264 chanrec = silc_channel_find_entry(server, channel);
268 nick = silc_nicklist_find(chanrec, sender);
270 /* We didn't find client but it clearly exists, add it. */
271 SilcChannelUser chu = silc_client_on_channel(channel, sender);
273 nick = silc_nicklist_insert(chanrec, chu, FALSE);
276 /* If the messages is digitally signed, verify it, if possible. */
277 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
278 if (!settings_get_bool("ignore_message_signatures")) {
279 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
280 verified = verify_message_signature(sender, sig, payload);
282 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
286 if (flags & SILC_MESSAGE_FLAG_DATA) {
287 /* MIME object received, try to display it as well as we can */
288 char type[128], enc[128];
292 memset(type, 0, sizeof(type));
293 memset(enc, 0, sizeof(enc));
294 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
295 enc, sizeof(enc) - 1, &data, &data_len))
298 /* Then figure out what we can display */
299 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
300 !strstr(type, "text/vnd")) {
301 /* It is something textual, display it */
302 message = (const unsigned char *)data;
304 printformat_module("fe-common/silc", server, channel->channel_name,
305 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
306 nick == NULL ? "[<unknown>]" : nick->nick, type);
314 /* FIXME: replace those printformat calls with signals and add signature
315 information to them (if present) */
316 if (flags & SILC_MESSAGE_FLAG_ACTION)
317 printformat_module("fe-common/silc", server, channel->channel_name,
318 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
319 nick == NULL ? "[<unknown>]" : nick->nick, message);
320 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
321 printformat_module("fe-common/silc", server, channel->channel_name,
322 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
323 nick == NULL ? "[<unknown>]" : nick->nick, message);
325 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
326 char tmp[256], *cp, *dm = NULL;
328 memset(tmp, 0, sizeof(tmp));
330 if (message_len > sizeof(tmp) - 1) {
331 dm = silc_calloc(message_len + 1, sizeof(*dm));
335 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
337 if (flags & SILC_MESSAGE_FLAG_SIGNED)
338 signal_emit("message signed_public", 6, server, cp,
339 nick == NULL ? "[<unknown>]" : nick->nick,
340 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
341 chanrec->name, verified);
343 signal_emit("message public", 6, server, cp,
344 nick == NULL ? "[<unknown>]" : nick->nick,
345 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
346 chanrec->name, nick);
351 if (flags & SILC_MESSAGE_FLAG_SIGNED)
352 signal_emit("message signed_public", 6, server, message,
353 nick == NULL ? "[<unknown>]" : nick->nick,
354 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
355 chanrec->name, verified);
357 signal_emit("message public", 6, server, message,
358 nick == NULL ? "[<unknown>]" : nick->nick,
359 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
360 chanrec->name, nick);
364 /* Private message to the client. The `sender' is the nickname of the
365 sender received in the packet. */
367 void silc_private_message(SilcClient client, SilcClientConnection conn,
368 SilcClientEntry sender, SilcMessagePayload payload,
369 SilcMessageFlags flags,
370 const unsigned char *message,
371 SilcUInt32 message_len)
373 SILC_SERVER_REC *server;
377 SILC_LOG_DEBUG(("Start"));
379 server = conn == NULL ? NULL : conn->context;
380 memset(userhost, 0, sizeof(userhost));
381 if (sender->username)
382 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
383 sender->username, sender->hostname);
385 /* If the messages is digitally signed, verify it, if possible. */
386 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
387 if (!settings_get_bool("ignore_message_signatures")) {
388 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
389 verified = verify_message_signature(sender, sig, payload);
391 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
395 if (flags & SILC_MESSAGE_FLAG_DATA) {
396 /* MIME object received, try to display it as well as we can */
397 char type[128], enc[128];
401 memset(type, 0, sizeof(type));
402 memset(enc, 0, sizeof(enc));
403 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
404 enc, sizeof(enc) - 1, &data, &data_len))
407 /* Then figure out what we can display */
408 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
409 !strstr(type, "text/vnd")) {
410 /* It is something textual, display it */
411 message = (const unsigned char *)data;
413 printformat_module("fe-common/silc", server, NULL,
414 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
415 sender->nickname ? sender->nickname : "[<unknown>]",
424 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
425 char tmp[256], *cp, *dm = NULL;
427 memset(tmp, 0, sizeof(tmp));
429 if (message_len > sizeof(tmp) - 1) {
430 dm = silc_calloc(message_len + 1, sizeof(*dm));
434 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
436 if (flags & SILC_MESSAGE_FLAG_SIGNED)
437 signal_emit("message signed_private", 5, server, cp,
438 sender->nickname ? sender->nickname : "[<unknown>]",
439 sender->username ? userhost : NULL, verified);
441 signal_emit("message private", 4, server, cp,
442 sender->nickname ? sender->nickname : "[<unknown>]",
443 sender->username ? userhost : NULL);
448 if (flags & SILC_MESSAGE_FLAG_SIGNED)
449 signal_emit("message signed_private", 5, server, message,
450 sender->nickname ? sender->nickname : "[<unknown>]",
451 sender->username ? userhost : NULL, verified);
453 signal_emit("message private", 4, server, message,
454 sender->nickname ? sender->nickname : "[<unknown>]",
455 sender->username ? userhost : NULL);
458 /* Notify message to the client. The notify arguments are sent in the
459 same order as servers sends them. The arguments are same as received
460 from the server except for ID's. If ID is received application receives
461 the corresponding entry to the ID. For example, if Client ID is received
462 application receives SilcClientEntry. Also, if the notify type is
463 for channel the channel entry is sent to application (even if server
464 does not send it). */
466 void silc_notify(SilcClient client, SilcClientConnection conn,
467 SilcNotifyType type, ...)
470 SILC_SERVER_REC *server;
471 SILC_CHANNEL_REC *chanrec;
472 SILC_NICK_REC *nickrec;
473 SilcClientEntry client_entry, client_entry2;
474 SilcChannelEntry channel, channel2;
475 SilcServerEntry server_entry;
481 GSList *list1, *list_tmp;
483 SILC_LOG_DEBUG(("Start"));
487 server = conn == NULL ? NULL : conn->context;
490 case SILC_NOTIFY_TYPE_NONE:
491 /* Some generic notice from server */
492 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
495 case SILC_NOTIFY_TYPE_INVITE:
497 * Invited or modified invite list.
500 SILC_LOG_DEBUG(("Notify: INVITE"));
502 channel = va_arg(va, SilcChannelEntry);
503 name = va_arg(va, char *);
504 client_entry = va_arg(va, SilcClientEntry);
506 memset(buf, 0, sizeof(buf));
507 snprintf(buf, sizeof(buf) - 1, "%s@%s",
508 client_entry->username, client_entry->hostname);
509 signal_emit("message invite", 4, server, channel ? channel->channel_name :
510 name, client_entry->nickname, buf);
513 case SILC_NOTIFY_TYPE_JOIN:
518 SILC_LOG_DEBUG(("Notify: JOIN"));
520 client_entry = va_arg(va, SilcClientEntry);
521 channel = va_arg(va, SilcChannelEntry);
523 if (client_entry == server->conn->local_entry) {
524 /* You joined to channel */
525 chanrec = silc_channel_find(server, channel->channel_name);
526 if (chanrec != NULL && !chanrec->joined)
527 chanrec->entry = channel;
529 chanrec = silc_channel_find_entry(server, channel);
530 if (chanrec != NULL) {
531 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
533 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
537 memset(buf, 0, sizeof(buf));
538 if (client_entry->username)
539 snprintf(buf, sizeof(buf) - 1, "%s@%s",
540 client_entry->username, client_entry->hostname);
541 signal_emit("message join", 4, server, channel->channel_name,
542 client_entry->nickname,
543 client_entry->username == NULL ? "" : buf);
546 case SILC_NOTIFY_TYPE_LEAVE:
551 SILC_LOG_DEBUG(("Notify: LEAVE"));
553 client_entry = va_arg(va, SilcClientEntry);
554 channel = va_arg(va, SilcChannelEntry);
556 memset(buf, 0, sizeof(buf));
557 if (client_entry->username)
558 snprintf(buf, sizeof(buf) - 1, "%s@%s",
559 client_entry->username, client_entry->hostname);
560 signal_emit("message part", 5, server, channel->channel_name,
561 client_entry->nickname, client_entry->username ?
562 buf : "", client_entry->nickname);
564 chanrec = silc_channel_find_entry(server, channel);
565 if (chanrec != NULL) {
566 nickrec = silc_nicklist_find(chanrec, client_entry);
568 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
572 case SILC_NOTIFY_TYPE_SIGNOFF:
577 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
579 client_entry = va_arg(va, SilcClientEntry);
580 tmp = va_arg(va, char *);
582 silc_server_free_ftp(server, client_entry);
584 /* Print only if we have the nickname. If this cliente has just quit
585 when we were only resolving it, it is possible we don't have the
587 if (client_entry->nickname) {
588 memset(buf, 0, sizeof(buf));
589 if (client_entry->username)
590 snprintf(buf, sizeof(buf) - 1, "%s@%s",
591 client_entry->username, client_entry->hostname);
592 signal_emit("message quit", 4, server, client_entry->nickname,
593 client_entry->username ? buf : "",
597 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
598 for (list_tmp = list1; list_tmp != NULL; list_tmp =
599 list_tmp->next->next) {
600 CHANNEL_REC *channel = list_tmp->data;
601 NICK_REC *nickrec = list_tmp->next->data;
603 nicklist_remove(channel, nickrec);
607 case SILC_NOTIFY_TYPE_TOPIC_SET:
612 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
614 idtype = va_arg(va, int);
615 entry = va_arg(va, void *);
616 tmp = va_arg(va, char *);
617 channel = va_arg(va, SilcChannelEntry);
619 chanrec = silc_channel_find_entry(server, channel);
620 if (chanrec != NULL) {
621 char tmp2[256], *cp, *dm = NULL;
623 g_free_not_null(chanrec->topic);
624 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
625 memset(tmp2, 0, sizeof(tmp2));
627 if (strlen(tmp) > sizeof(tmp2) - 1) {
628 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
632 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
637 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
638 signal_emit("channel topic changed", 1, chanrec);
643 if (idtype == SILC_ID_CLIENT) {
644 client_entry = (SilcClientEntry)entry;
645 memset(buf, 0, sizeof(buf));
646 snprintf(buf, sizeof(buf) - 1, "%s@%s",
647 client_entry->username, client_entry->hostname);
648 signal_emit("message topic", 5, server, channel->channel_name,
649 tmp, client_entry->nickname, buf);
650 } else if (idtype == SILC_ID_SERVER) {
651 server_entry = (SilcServerEntry)entry;
652 signal_emit("message topic", 5, server, channel->channel_name,
653 tmp, server_entry->server_name,
654 server_entry->server_name);
655 } else if (idtype == SILC_ID_CHANNEL) {
656 channel = (SilcChannelEntry)entry;
657 signal_emit("message topic", 5, server, channel->channel_name,
658 tmp, channel->channel_name, channel->channel_name);
662 case SILC_NOTIFY_TYPE_NICK_CHANGE:
667 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
669 client_entry = va_arg(va, SilcClientEntry);
670 client_entry2 = va_arg(va, SilcClientEntry);
672 if (!strcmp(client_entry->nickname, client_entry2->nickname))
675 memset(buf, 0, sizeof(buf));
676 snprintf(buf, sizeof(buf) - 1, "%s@%s",
677 client_entry2->username, client_entry2->hostname);
678 nicklist_rename_unique(SERVER(server),
679 client_entry, client_entry->nickname,
680 client_entry2, client_entry2->nickname);
681 signal_emit("message nick", 4, server, client_entry2->nickname,
682 client_entry->nickname, buf);
685 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
687 * Changed channel mode.
690 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
692 idtype = va_arg(va, int);
693 entry = va_arg(va, void *);
694 mode = va_arg(va, SilcUInt32);
695 (void)va_arg(va, char *);
696 (void)va_arg(va, char *);
697 channel = va_arg(va, SilcChannelEntry);
699 tmp = silc_client_chmode(mode,
700 channel->channel_key ?
701 silc_cipher_get_name(channel->channel_key) : "",
703 silc_hmac_get_name(channel->hmac) : "");
705 chanrec = silc_channel_find_entry(server, channel);
706 if (chanrec != NULL) {
707 g_free_not_null(chanrec->mode);
708 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
709 signal_emit("channel mode changed", 1, chanrec);
712 if (idtype == SILC_ID_CLIENT) {
713 client_entry = (SilcClientEntry)entry;
714 printformat_module("fe-common/silc", server, channel->channel_name,
715 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
716 channel->channel_name, tmp ? tmp : "removed all",
717 client_entry->nickname);
718 } else if (idtype == SILC_ID_SERVER) {
719 server_entry = (SilcServerEntry)entry;
720 printformat_module("fe-common/silc", server, channel->channel_name,
721 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
722 channel->channel_name, tmp ? tmp : "removed all",
723 server_entry->server_name);
724 } else if (idtype == SILC_ID_CHANNEL) {
725 channel2 = (SilcChannelEntry)entry;
726 printformat_module("fe-common/silc", server, channel->channel_name,
727 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
728 channel->channel_name, tmp ? tmp : "removed all",
729 channel2->channel_name);
735 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
737 * Changed user's mode on channel.
740 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
742 idtype = va_arg(va, int);
743 entry = va_arg(va, void *);
744 mode = va_arg(va, SilcUInt32);
745 client_entry2 = va_arg(va, SilcClientEntry);
746 channel = va_arg(va, SilcChannelEntry);
748 tmp = silc_client_chumode(mode);
749 chanrec = silc_channel_find_entry(server, channel);
750 if (chanrec != NULL) {
753 if (client_entry2 == server->conn->local_entry)
754 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
756 nick = silc_nicklist_find(chanrec, client_entry2);
758 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
759 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
760 signal_emit("nick mode changed", 2, chanrec, nick);
764 if (idtype == SILC_ID_CLIENT) {
765 client_entry = (SilcClientEntry)entry;
766 printformat_module("fe-common/silc", server, channel->channel_name,
767 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
768 channel->channel_name, client_entry2->nickname,
769 tmp ? tmp : "removed all",
770 client_entry->nickname);
771 } else if (idtype == SILC_ID_SERVER) {
772 server_entry = (SilcServerEntry)entry;
773 printformat_module("fe-common/silc", server, channel->channel_name,
774 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
775 channel->channel_name, client_entry2->nickname,
776 tmp ? tmp : "removed all",
777 server_entry->server_name);
778 } else if (idtype == SILC_ID_CHANNEL) {
779 channel2 = (SilcChannelEntry)entry;
780 printformat_module("fe-common/silc", server, channel->channel_name,
781 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
782 channel->channel_name, client_entry2->nickname,
783 tmp ? tmp : "removed all",
784 channel2->channel_name);
787 if (mode & SILC_CHANNEL_UMODE_CHANFO)
788 printformat_module("fe-common/silc",
789 server, channel->channel_name, MSGLEVEL_CRAP,
790 SILCTXT_CHANNEL_FOUNDER,
791 channel->channel_name, client_entry2->nickname);
793 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
794 printformat_module("fe-common/silc",
795 server, channel->channel_name, MSGLEVEL_CRAP,
796 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
801 case SILC_NOTIFY_TYPE_MOTD:
806 SILC_LOG_DEBUG(("Notify: MOTD"));
808 tmp = va_arg(va, char *);
810 if (!settings_get_bool("skip_motd"))
811 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
814 case SILC_NOTIFY_TYPE_KICKED:
816 * Someone was kicked from channel.
819 SILC_LOG_DEBUG(("Notify: KICKED"));
821 client_entry = va_arg(va, SilcClientEntry);
822 tmp = va_arg(va, char *);
823 client_entry2 = va_arg(va, SilcClientEntry);
824 channel = va_arg(va, SilcChannelEntry);
826 chanrec = silc_channel_find_entry(server, channel);
828 if (client_entry == conn->local_entry) {
829 printformat_module("fe-common/silc", server, channel->channel_name,
830 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
831 channel->channel_name,
832 client_entry ? client_entry2->nickname : "",
835 chanrec->kicked = TRUE;
836 channel_destroy((CHANNEL_REC *)chanrec);
839 printformat_module("fe-common/silc", server, channel->channel_name,
840 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
841 client_entry->nickname, channel->channel_name,
842 client_entry2 ? client_entry2->nickname : "",
846 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
848 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
853 case SILC_NOTIFY_TYPE_KILLED:
855 * Someone was killed from the network.
858 SILC_LOG_DEBUG(("Notify: KILLED"));
860 client_entry = va_arg(va, SilcClientEntry);
861 tmp = va_arg(va, char *);
862 idtype = va_arg(va, int);
863 entry = va_arg(va, SilcClientEntry);
865 if (client_entry == conn->local_entry) {
866 if (idtype == SILC_ID_CLIENT) {
867 client_entry2 = (SilcClientEntry)entry;
868 printformat_module("fe-common/silc", server, NULL,
869 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
870 client_entry2 ? client_entry2->nickname : "",
872 } else if (idtype == SILC_ID_SERVER) {
873 server_entry = (SilcServerEntry)entry;
874 printformat_module("fe-common/silc", server, NULL,
875 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
876 server_entry->server_name, tmp ? tmp : "");
877 } else if (idtype == SILC_ID_CHANNEL) {
878 channel = (SilcChannelEntry)entry;
879 printformat_module("fe-common/silc", server, NULL,
880 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
881 channel->channel_name, tmp ? tmp : "");
884 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
885 for (list_tmp = list1; list_tmp != NULL; list_tmp =
886 list_tmp->next->next) {
887 CHANNEL_REC *channel = list_tmp->data;
888 NICK_REC *nickrec = list_tmp->next->data;
889 nicklist_remove(channel, nickrec);
892 if (idtype == SILC_ID_CLIENT) {
893 client_entry2 = (SilcClientEntry)entry;
894 printformat_module("fe-common/silc", server, NULL,
895 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
896 client_entry->nickname,
897 client_entry2 ? client_entry2->nickname : "",
899 } else if (idtype == SILC_ID_SERVER) {
900 server_entry = (SilcServerEntry)entry;
901 printformat_module("fe-common/silc", server, NULL,
902 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
903 client_entry->nickname,
904 server_entry->server_name, tmp ? tmp : "");
905 } else if (idtype == SILC_ID_CHANNEL) {
906 channel = (SilcChannelEntry)entry;
907 printformat_module("fe-common/silc", server, NULL,
908 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
909 client_entry->nickname,
910 channel->channel_name, tmp ? tmp : "");
915 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
918 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
921 * Server has quit the network.
924 SilcClientEntry *clients;
925 SilcUInt32 clients_count;
927 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
929 (void)va_arg(va, void *);
930 clients = va_arg(va, SilcClientEntry *);
931 clients_count = va_arg(va, SilcUInt32);
933 for (i = 0; i < clients_count; i++) {
934 memset(buf, 0, sizeof(buf));
935 if (clients[i]->username)
936 snprintf(buf, sizeof(buf) - 1, "%s@%s",
937 clients[i]->username, clients[i]->hostname);
938 signal_emit("message quit", 4, server, clients[i]->nickname,
939 clients[i]->username ? buf : "",
942 silc_server_free_ftp(server, clients[i]);
944 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
945 for (list_tmp = list1; list_tmp != NULL; list_tmp =
946 list_tmp->next->next) {
947 CHANNEL_REC *channel = list_tmp->data;
948 NICK_REC *nickrec = list_tmp->next->data;
949 nicklist_remove(channel, nickrec);
955 case SILC_NOTIFY_TYPE_ERROR:
957 SilcStatus error = va_arg(va, int);
959 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
960 "%s", silc_get_status_message(error));
964 case SILC_NOTIFY_TYPE_WATCH:
966 SilcNotifyType notify;
968 client_entry = va_arg(va, SilcClientEntry);
969 name = va_arg(va, char *); /* Maybe NULL */
970 mode = va_arg(va, SilcUInt32);
971 notify = va_arg(va, int);
973 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
975 printformat_module("fe-common/silc", server, NULL,
976 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
977 client_entry->nickname, name);
979 printformat_module("fe-common/silc", server, NULL,
980 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
981 client_entry->nickname);
982 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
983 /* See if client was away and is now present */
984 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
985 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
986 SILC_UMODE_DETACHED)) &&
987 (client_entry->mode & SILC_UMODE_GONE ||
988 client_entry->mode & SILC_UMODE_INDISPOSED ||
989 client_entry->mode & SILC_UMODE_BUSY ||
990 client_entry->mode & SILC_UMODE_PAGE ||
991 client_entry->mode & SILC_UMODE_DETACHED)) {
992 printformat_module("fe-common/silc", server, NULL,
993 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
994 client_entry->nickname);
998 memset(buf, 0, sizeof(buf));
999 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1000 printformat_module("fe-common/silc", server, NULL,
1001 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1002 client_entry->nickname, buf);
1004 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1005 printformat_module("fe-common/silc", server, NULL,
1006 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1007 client_entry->nickname);
1008 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1009 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1010 printformat_module("fe-common/silc", server, NULL,
1011 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1012 client_entry->nickname);
1013 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1014 /* Client logged in to the network */
1015 printformat_module("fe-common/silc", server, NULL,
1016 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1017 client_entry->nickname);
1023 /* Unknown notify */
1024 printformat_module("fe-common/silc", server, NULL,
1025 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1032 /* Called to indicate that connection was either successfully established
1033 or connecting failed. This is also the first time application receives
1034 the SilcClientConnection object which it should save somewhere. */
1036 void silc_connect(SilcClient client, SilcClientConnection conn,
1037 SilcClientConnectionStatus status)
1039 SILC_SERVER_REC *server = conn->context;
1041 if (!server || server->disconnected) {
1042 silc_client_close_connection(client, conn);
1047 case SILC_CLIENT_CONN_SUCCESS:
1048 /* We have successfully connected to server */
1049 server->connected = TRUE;
1050 signal_emit("event connected", 1, server);
1053 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1054 /* We have successfully resumed old detached session */
1055 server->connected = TRUE;
1056 signal_emit("event connected", 1, server);
1058 /* If we resumed old session check whether we need to update
1060 if (strcmp(server->nick, conn->local_entry->nickname)) {
1062 old = g_strdup(server->nick);
1063 server_change_nick(SERVER(server), conn->local_entry->nickname);
1064 nicklist_rename_unique(SERVER(server),
1065 conn->local_entry, server->nick,
1066 conn->local_entry, conn->local_entry->nickname);
1067 signal_emit("message own_nick", 4, server, server->nick, old, "");
1073 server->connection_lost = TRUE;
1075 server->conn->context = NULL;
1076 server_disconnect(SERVER(server));
1081 /* Called to indicate that connection was disconnected to the server. */
1083 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1084 SilcStatus status, const char *message)
1086 SILC_SERVER_REC *server = conn->context;
1088 SILC_LOG_DEBUG(("Start"));
1090 if (!server || server->connection_lost)
1093 if (server->conn && server->conn->local_entry) {
1094 nicklist_rename_unique(SERVER(server),
1095 server->conn->local_entry, server->nick,
1096 server->conn->local_entry,
1097 silc_client->username);
1098 silc_change_nick(server, silc_client->username);
1102 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1103 "Server closed connection: %s (%d) %s",
1104 silc_get_status_message(status), status,
1105 message ? message : "");
1107 server->conn->context = NULL;
1108 server->conn = NULL;
1109 server->connection_lost = TRUE;
1110 server_disconnect(SERVER(server));
1113 /* Command handler. This function is called always in the command function.
1114 If error occurs it will be called as well. `conn' is the associated
1115 client connection. `cmd_context' is the command context that was
1116 originally sent to the command. `success' is FALSE if error occured
1117 during command. `command' is the command being processed. It must be
1118 noted that this is not reply from server. This is merely called just
1119 after application has called the command. Just to tell application
1120 that the command really was processed. */
1122 void silc_command(SilcClient client, SilcClientConnection conn,
1123 SilcClientCommandContext cmd_context, bool success,
1124 SilcCommand command, SilcStatus status)
1126 SILC_SERVER_REC *server = conn->context;
1128 SILC_LOG_DEBUG(("Start"));
1131 silc_say_error("%s", silc_get_status_message(status));
1137 case SILC_COMMAND_INVITE:
1138 if (cmd_context->argc > 2)
1139 printformat_module("fe-common/silc", server, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1141 cmd_context->argv[2],
1142 (cmd_context->argv[1][0] == '*' ?
1143 (char *)conn->current_channel->channel_name :
1144 (char *)cmd_context->argv[1]));
1147 case SILC_COMMAND_DETACH:
1148 server->no_reconnect = TRUE;
1156 /* Client info resolving callback when JOIN command reply is received.
1157 This will cache all users on the channel. */
1159 static void silc_client_join_get_users(SilcClient client,
1160 SilcClientConnection conn,
1161 SilcClientEntry *clients,
1162 SilcUInt32 clients_count,
1165 SilcChannelEntry channel = (SilcChannelEntry)context;
1166 SilcHashTableList htl;
1167 SilcChannelUser chu;
1168 SILC_SERVER_REC *server = conn->context;
1169 SILC_CHANNEL_REC *chanrec;
1170 SilcClientEntry founder = NULL;
1173 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1174 silc_hash_table_count(channel->user_list)));
1179 chanrec = silc_channel_find(server, channel->channel_name);
1180 if (chanrec == NULL)
1183 silc_hash_table_list(channel->user_list, &htl);
1184 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1185 if (!chu->client->nickname)
1187 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1188 founder = chu->client;
1189 silc_nicklist_insert(chanrec, chu, FALSE);
1191 silc_hash_table_list_reset(&htl);
1193 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1194 nicklist_set_own(CHANNEL(chanrec), ownnick);
1195 signal_emit("channel joined", 1, chanrec);
1196 chanrec->entry = channel;
1199 printformat_module("fe-common/silc", server, channel->channel_name,
1200 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1201 channel->channel_name, chanrec->topic);
1204 if (founder == conn->local_entry)
1205 printformat_module("fe-common/silc",
1206 server, channel->channel_name, MSGLEVEL_CRAP,
1207 SILCTXT_CHANNEL_FOUNDER_YOU,
1208 channel->channel_name);
1210 printformat_module("fe-common/silc",
1211 server, channel->channel_name, MSGLEVEL_CRAP,
1212 SILCTXT_CHANNEL_FOUNDER,
1213 channel->channel_name, founder->nickname);
1219 SilcClientConnection conn;
1225 void silc_getkey_cb(bool success, void *context)
1227 GetkeyContext getkey = (GetkeyContext)context;
1228 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1229 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1230 ((SilcClientEntry)getkey->entry)->nickname :
1231 ((SilcServerEntry)getkey->entry)->server_name);
1234 printformat_module("fe-common/silc", NULL, NULL,
1235 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1237 printformat_module("fe-common/silc", NULL, NULL,
1238 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1242 silc_free(getkey->fingerprint);
1246 /* Parse an invite or ban list */
1247 void silc_parse_inviteban_list(SilcClient client,
1248 SilcClientConnection conn,
1249 SILC_SERVER_REC *server,
1250 SilcChannelEntry channel,
1251 const char *list_type,
1252 SilcArgumentPayload list)
1255 SilcUInt32 type, len;
1256 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1257 int counter=0, resolving = FALSE;
1259 if (!silc_argument_get_arg_num(list)) {
1260 printformat_module("fe-common/silc", server,
1261 (chanrec ? chanrec->visible_name : NULL),
1262 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1263 channel->channel_name, list_type);
1267 printformat_module("fe-common/silc", server,
1268 (chanrec ? chanrec->visible_name : NULL),
1269 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1270 channel->channel_name, list_type);
1272 /* parse the list */
1273 tmp = silc_argument_get_first_arg(list, &type, &len);
1278 /* an invite string */
1282 if (tmp[len-1] == ',')
1285 list = g_strsplit(tmp, ",", -1);
1287 printformat_module("fe-common/silc", server,
1288 (chanrec ? chanrec->visible_name : NULL),
1289 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1290 ++counter, channel->channel_name, list_type,
1299 char *fingerprint, *babbleprint;
1301 /* tmp is Public Key Payload, take public key from it. */
1302 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1303 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1305 printformat_module("fe-common/silc", server,
1306 (chanrec ? chanrec->visible_name : NULL),
1307 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1308 ++counter, channel->channel_name, list_type,
1309 fingerprint, babbleprint);
1316 SilcClientID *client_id;
1317 SilcClientEntry client_entry;
1319 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1321 if (client_id == NULL) {
1322 silc_say_error("Invalid data in %s list encountered", list_type);
1326 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1329 printformat_module("fe-common/silc", server,
1330 (chanrec ? chanrec->visible_name : NULL),
1331 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1332 ++counter, channel->channel_name, list_type,
1333 client_entry->nickname);
1336 silc_client_get_client_by_id_resolve(client, conn, client_id,
1340 silc_free(client_id);
1346 silc_say_error("Unkown type in %s list: %u (len %u)",
1347 list_type, type, len);
1349 tmp = silc_argument_get_next_arg(list, &type, &len);
1353 printformat_module("fe-common/silc", server,
1354 (chanrec ? chanrec->visible_name : NULL),
1355 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1356 list_type, channel->channel_name);
1359 /* Command reply handler. This function is called always in the command reply
1360 function. If error occurs it will be called as well. Normal scenario
1361 is that it will be called after the received command data has been parsed
1362 and processed. The function is used to pass the received command data to
1365 `conn' is the associated client connection. `cmd_payload' is the command
1366 payload data received from server and it can be ignored. It is provided
1367 if the application would like to re-parse the received command data,
1368 however, it must be noted that the data is parsed already by the library
1369 thus the payload can be ignored. `success' is FALSE if error occured.
1370 In this case arguments are not sent to the application. `command' is the
1371 command reply being processed. The function has variable argument list
1372 and each command defines the number and type of arguments it passes to the
1373 application (on error they are not sent). */
1376 silc_command_reply(SilcClient client, SilcClientConnection conn,
1377 SilcCommandPayload cmd_payload, bool success,
1378 SilcCommand command, SilcStatus status, ...)
1381 SILC_SERVER_REC *server = conn->context;
1382 SILC_CHANNEL_REC *chanrec;
1385 va_start(vp, status);
1387 SILC_LOG_DEBUG(("Start"));
1390 case SILC_COMMAND_WHOIS:
1392 char buf[1024], *nickname, *username, *realname, *nick;
1393 unsigned char *fingerprint;
1394 SilcUInt32 idle, mode;
1395 SilcBuffer channels, user_modes;
1396 SilcClientEntry client_entry;
1399 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1400 /* Print the unknown nick for user */
1401 unsigned char *tmp =
1402 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1405 silc_say_error("%s: %s", tmp,
1406 silc_get_status_message(status));
1408 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1409 /* Try to find the entry for the unknown client ID, since we
1410 might have, and print the nickname of it for user. */
1412 unsigned char *tmp =
1413 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1416 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1419 client_entry = silc_client_get_client_by_id(client, conn,
1421 if (client_entry && client_entry->nickname)
1422 silc_say_error("%s: %s", client_entry->nickname,
1423 silc_get_status_message(status));
1424 silc_free(client_id);
1428 } else if (!success) {
1429 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1433 client_entry = va_arg(vp, SilcClientEntry);
1434 nickname = va_arg(vp, char *);
1435 username = va_arg(vp, char *);
1436 realname = va_arg(vp, char *);
1437 channels = va_arg(vp, SilcBuffer);
1438 mode = va_arg(vp, SilcUInt32);
1439 idle = va_arg(vp, SilcUInt32);
1440 fingerprint = va_arg(vp, unsigned char *);
1441 user_modes = va_arg(vp, SilcBuffer);
1442 attrs = va_arg(vp, SilcDList);
1444 silc_parse_userfqdn(nickname, &nick, NULL);
1445 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1446 SILCTXT_WHOIS_USERINFO, nickname,
1447 client_entry->username, client_entry->hostname,
1448 nick, client_entry->nickname);
1449 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1450 SILCTXT_WHOIS_REALNAME, realname);
1453 if (channels && user_modes) {
1455 SilcDList list = silc_channel_payload_parse_list(channels->data,
1457 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1459 SilcChannelPayload entry;
1462 memset(buf, 0, sizeof(buf));
1463 silc_dlist_start(list);
1464 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1465 SilcUInt32 name_len;
1466 char *m = silc_client_chumode_char(umodes[i++]);
1467 char *name = silc_channel_get_name(entry, &name_len);
1470 strncat(buf, m, strlen(m));
1471 strncat(buf, name, name_len);
1472 strncat(buf, " ", 1);
1476 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1477 SILCTXT_WHOIS_CHANNELS, buf);
1478 silc_channel_payload_list_free(list);
1484 memset(buf, 0, sizeof(buf));
1485 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1486 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1487 SILCTXT_WHOIS_MODES, buf);
1490 if (idle && nickname) {
1491 memset(buf, 0, sizeof(buf));
1492 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1493 idle > 60 ? (idle / 60) : idle,
1494 idle > 60 ? "minutes" : "seconds");
1496 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1497 SILCTXT_WHOIS_IDLE, buf);
1501 fingerprint = silc_fingerprint(fingerprint, 20);
1502 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1503 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1504 silc_free(fingerprint);
1508 silc_query_attributes_print(server, silc_client, conn, attrs,
1513 case SILC_COMMAND_IDENTIFY:
1515 SilcClientEntry client_entry;
1517 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1518 /* Print the unknown nick for user */
1519 unsigned char *tmp =
1520 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1523 silc_say_error("%s: %s", tmp,
1524 silc_get_status_message(status));
1526 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1527 /* Try to find the entry for the unknown client ID, since we
1528 might have, and print the nickname of it for user. */
1530 unsigned char *tmp =
1531 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1534 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1537 client_entry = silc_client_get_client_by_id(client, conn,
1539 if (client_entry && client_entry->nickname)
1540 silc_say_error("%s: %s", client_entry->nickname,
1541 silc_get_status_message(status));
1542 silc_free(client_id);
1551 case SILC_COMMAND_WHOWAS:
1553 char *nickname, *username, *realname;
1555 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1556 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1558 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1561 silc_say_error("%s: %s", tmp,
1562 silc_get_status_message(status));
1564 } else if (!success) {
1565 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1569 (void)va_arg(vp, SilcClientEntry);
1570 nickname = va_arg(vp, char *);
1571 username = va_arg(vp, char *);
1572 realname = va_arg(vp, char *);
1574 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1575 SILCTXT_WHOWAS_USERINFO, nickname, username,
1576 realname ? realname : "");
1580 case SILC_COMMAND_INVITE:
1582 SilcChannelEntry channel;
1584 SilcArgumentPayload invite_list;
1590 channel = va_arg(vp, SilcChannelEntry);
1591 payload = va_arg(vp, SilcBuffer);
1594 SILC_GET16_MSB(argc, payload->data);
1595 invite_list = silc_argument_payload_parse(payload->data + 2,
1596 payload->len - 2, argc);
1598 silc_parse_inviteban_list(client, conn, server, channel,
1599 "invite", invite_list);
1600 silc_argument_payload_free(invite_list);
1606 case SILC_COMMAND_JOIN:
1608 char *channel, *mode, *topic;
1610 SilcChannelEntry channel_entry;
1611 SilcBuffer client_id_list;
1612 SilcUInt32 list_count;
1617 channel = va_arg(vp, char *);
1618 channel_entry = va_arg(vp, SilcChannelEntry);
1619 modei = va_arg(vp, SilcUInt32);
1620 (void)va_arg(vp, SilcUInt32);
1621 (void)va_arg(vp, unsigned char *);
1622 (void)va_arg(vp, unsigned char *);
1623 (void)va_arg(vp, unsigned char *);
1624 topic = va_arg(vp, char *);
1625 (void)va_arg(vp, unsigned char *);
1626 list_count = va_arg(vp, SilcUInt32);
1627 client_id_list = va_arg(vp, SilcBuffer);
1629 chanrec = silc_channel_find(server, channel);
1631 chanrec = silc_channel_create(server, channel, channel, TRUE);
1634 char tmp[256], *cp, *dm = NULL;
1635 g_free_not_null(chanrec->topic);
1637 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1638 memset(tmp, 0, sizeof(tmp));
1640 if (strlen(topic) > sizeof(tmp) - 1) {
1641 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1645 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1650 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1651 signal_emit("channel topic changed", 1, chanrec);
1656 mode = silc_client_chmode(modei,
1657 channel_entry->channel_key ?
1658 silc_cipher_get_name(channel_entry->
1660 channel_entry->hmac ?
1661 silc_hmac_get_name(channel_entry->hmac) : "");
1662 g_free_not_null(chanrec->mode);
1663 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1664 signal_emit("channel mode changed", 1, chanrec);
1666 /* Resolve the client information */
1667 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1668 silc_client_join_get_users,
1674 case SILC_COMMAND_NICK:
1677 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1683 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1684 if (nicks != NULL) {
1686 SilcClientEntry collider, old;
1688 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1689 collider = silc_client_get_client_by_id(client, conn,
1692 memset(buf, 0, sizeof(buf));
1693 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1694 collider->username, collider->hostname);
1695 nicklist_rename_unique(SERVER(server),
1697 collider, collider->nickname);
1698 silc_print_nick_change(server, collider->nickname,
1699 client_entry->nickname, buf);
1700 g_slist_free(nicks);
1703 old = g_strdup(server->nick);
1704 server_change_nick(SERVER(server), client_entry->nickname);
1705 nicklist_rename_unique(SERVER(server),
1706 server->conn->local_entry, server->nick,
1707 client_entry, client_entry->nickname);
1708 signal_emit("message own_nick", 4, server, server->nick, old, "");
1713 case SILC_COMMAND_LIST:
1718 char tmp[256], *cp, *dm = NULL;
1723 (void)va_arg(vp, SilcChannelEntry);
1724 name = va_arg(vp, char *);
1725 topic = va_arg(vp, char *);
1726 usercount = va_arg(vp, int);
1728 if (topic && !silc_term_utf8() &&
1729 silc_utf8_valid(topic, strlen(topic))) {
1730 memset(tmp, 0, sizeof(tmp));
1732 if (strlen(topic) > sizeof(tmp) - 1) {
1733 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1737 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1742 if (status == SILC_STATUS_LIST_START ||
1743 status == SILC_STATUS_OK)
1744 printformat_module("fe-common/silc", server, NULL,
1745 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1748 snprintf(users, sizeof(users) - 1, "N/A");
1750 snprintf(users, sizeof(users) - 1, "%d", usercount);
1751 printformat_module("fe-common/silc", server, NULL,
1752 MSGLEVEL_CRAP, SILCTXT_LIST,
1753 name, users, topic ? topic : "");
1758 case SILC_COMMAND_UMODE:
1766 mode = va_arg(vp, SilcUInt32);
1768 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1769 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1770 printformat_module("fe-common/silc", server, NULL,
1771 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1773 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1774 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1775 printformat_module("fe-common/silc", server, NULL,
1776 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1778 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1779 if (mode & SILC_UMODE_GONE) {
1780 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1781 reason = g_strdup(server->away_reason);
1783 reason = g_strdup("away");
1785 reason = g_strdup("");
1787 silc_set_away(reason, server);
1792 server->umode = mode;
1793 signal_emit("user mode changed", 2, server, NULL);
1797 case SILC_COMMAND_OPER:
1801 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1802 signal_emit("user mode changed", 2, server, NULL);
1804 printformat_module("fe-common/silc", server, NULL,
1805 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1808 case SILC_COMMAND_SILCOPER:
1812 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1813 signal_emit("user mode changed", 2, server, NULL);
1815 printformat_module("fe-common/silc", server, NULL,
1816 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1819 case SILC_COMMAND_USERS:
1821 SilcHashTableList htl;
1822 SilcChannelEntry channel;
1823 SilcChannelUser chu;
1828 channel = va_arg(vp, SilcChannelEntry);
1830 printformat_module("fe-common/silc", server, channel->channel_name,
1831 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1832 channel->channel_name);
1834 silc_hash_table_list(channel->user_list, &htl);
1835 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1836 SilcClientEntry e = chu->client;
1837 char stat[5], *mode;
1842 memset(stat, 0, sizeof(stat));
1843 mode = silc_client_chumode_char(chu->mode);
1844 if (e->mode & SILC_UMODE_GONE)
1846 else if (e->mode & SILC_UMODE_INDISPOSED)
1848 else if (e->mode & SILC_UMODE_BUSY)
1850 else if (e->mode & SILC_UMODE_PAGE)
1852 else if (e->mode & SILC_UMODE_HYPER)
1854 else if (e->mode & SILC_UMODE_ROBOT)
1856 else if (e->mode & SILC_UMODE_ANONYMOUS)
1863 printformat_module("fe-common/silc", server, channel->channel_name,
1864 MSGLEVEL_CRAP, SILCTXT_USERS,
1866 e->username ? e->username : "",
1867 e->hostname ? e->hostname : "",
1868 e->realname ? e->realname : "");
1872 silc_hash_table_list_reset(&htl);
1876 case SILC_COMMAND_BAN:
1878 SilcChannelEntry channel;
1880 SilcArgumentPayload ban_list;
1886 channel = va_arg(vp, SilcChannelEntry);
1887 payload = va_arg(vp, SilcBuffer);
1890 SILC_GET16_MSB(argc, payload->data);
1891 ban_list = silc_argument_payload_parse(payload->data + 2,
1892 payload->len - 2, argc);
1894 silc_parse_inviteban_list(client, conn, server, channel,
1896 silc_argument_payload_free(ban_list);
1902 case SILC_COMMAND_GETKEY:
1906 SilcPublicKey public_key;
1909 GetkeyContext getkey;
1915 id_type = va_arg(vp, SilcUInt32);
1916 entry = va_arg(vp, void *);
1917 public_key = va_arg(vp, SilcPublicKey);
1920 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1922 getkey = silc_calloc(1, sizeof(*getkey));
1923 getkey->entry = entry;
1924 getkey->id_type = id_type;
1925 getkey->client = client;
1926 getkey->conn = conn;
1927 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1929 name = (id_type == SILC_ID_CLIENT ?
1930 ((SilcClientEntry)entry)->nickname :
1931 ((SilcServerEntry)entry)->server_name);
1933 silc_verify_public_key_internal(client, conn, name,
1934 (id_type == SILC_ID_CLIENT ?
1935 SILC_SOCKET_TYPE_CLIENT :
1936 SILC_SOCKET_TYPE_SERVER),
1937 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1938 silc_getkey_cb, getkey);
1941 printformat_module("fe-common/silc", server, NULL,
1942 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1947 case SILC_COMMAND_INFO:
1949 SilcServerEntry server_entry;
1956 server_entry = va_arg(vp, SilcServerEntry);
1957 server_name = va_arg(vp, char *);
1958 server_info = va_arg(vp, char *);
1960 if (server_name && server_info )
1962 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1963 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1968 case SILC_COMMAND_TOPIC:
1970 SilcChannelEntry channel;
1972 char tmp[256], *cp, *dm = NULL;
1977 channel = va_arg(vp, SilcChannelEntry);
1978 topic = va_arg(vp, char *);
1980 if (topic && !silc_term_utf8() &&
1981 silc_utf8_valid(topic, strlen(topic))) {
1982 memset(tmp, 0, sizeof(tmp));
1984 if (strlen(topic) > sizeof(tmp) - 1) {
1985 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1989 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1995 chanrec = silc_channel_find_entry(server, channel);
1997 g_free_not_null(chanrec->topic);
1998 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1999 signal_emit("channel topic changed", 1, chanrec);
2001 printformat_module("fe-common/silc", server, channel->channel_name,
2002 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2003 channel->channel_name, topic);
2005 printformat_module("fe-common/silc", server, channel->channel_name,
2006 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2007 channel->channel_name);
2013 case SILC_COMMAND_WATCH:
2016 case SILC_COMMAND_STATS:
2018 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2019 my_router_ops, cell_clients, cell_channels, cell_servers,
2020 clients, channels, servers, routers, server_ops, router_ops;
2022 SilcBufferStruct buf;
2023 unsigned char *tmp_buf;
2025 const char *tmptime;
2026 int days, hours, mins, secs;
2031 tmp_buf = va_arg(vp, unsigned char *);
2032 buf_len = va_arg(vp, SilcUInt32);
2034 if (!tmp_buf || !buf_len) {
2035 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2039 /* Get statistics structure */
2040 silc_buffer_set(&buf, tmp_buf, buf_len);
2041 silc_buffer_unformat(&buf,
2042 SILC_STR_UI_INT(&starttime),
2043 SILC_STR_UI_INT(&uptime),
2044 SILC_STR_UI_INT(&my_clients),
2045 SILC_STR_UI_INT(&my_channels),
2046 SILC_STR_UI_INT(&my_server_ops),
2047 SILC_STR_UI_INT(&my_router_ops),
2048 SILC_STR_UI_INT(&cell_clients),
2049 SILC_STR_UI_INT(&cell_channels),
2050 SILC_STR_UI_INT(&cell_servers),
2051 SILC_STR_UI_INT(&clients),
2052 SILC_STR_UI_INT(&channels),
2053 SILC_STR_UI_INT(&servers),
2054 SILC_STR_UI_INT(&routers),
2055 SILC_STR_UI_INT(&server_ops),
2056 SILC_STR_UI_INT(&router_ops),
2059 tmptime = silc_get_time(starttime);
2060 printformat_module("fe-common/silc", server, NULL,
2061 MSGLEVEL_CRAP, SILCTXT_STATS,
2062 "Local server start time", tmptime);
2064 days = uptime / (24 * 60 * 60);
2065 uptime -= days * (24 * 60 * 60);
2066 hours = uptime / (60 * 60);
2067 uptime -= hours * (60 * 60);
2069 uptime -= mins * 60;
2071 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2072 days, hours, mins, secs);
2073 printformat_module("fe-common/silc", server, NULL,
2074 MSGLEVEL_CRAP, SILCTXT_STATS,
2075 "Local server uptime", tmp);
2077 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2078 printformat_module("fe-common/silc", server, NULL,
2079 MSGLEVEL_CRAP, SILCTXT_STATS,
2080 "Local server clients", tmp);
2082 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2083 printformat_module("fe-common/silc", server, NULL,
2084 MSGLEVEL_CRAP, SILCTXT_STATS,
2085 "Local server channels", tmp);
2087 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2088 printformat_module("fe-common/silc", server, NULL,
2089 MSGLEVEL_CRAP, SILCTXT_STATS,
2090 "Local server operators", tmp);
2092 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2093 printformat_module("fe-common/silc", server, NULL,
2094 MSGLEVEL_CRAP, SILCTXT_STATS,
2095 "Local router operators", tmp);
2097 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2098 printformat_module("fe-common/silc", server, NULL,
2099 MSGLEVEL_CRAP, SILCTXT_STATS,
2100 "Local cell clients", tmp);
2102 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2103 printformat_module("fe-common/silc", server, NULL,
2104 MSGLEVEL_CRAP, SILCTXT_STATS,
2105 "Local cell channels", tmp);
2107 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2108 printformat_module("fe-common/silc", server, NULL,
2109 MSGLEVEL_CRAP, SILCTXT_STATS,
2110 "Local cell servers", tmp);
2112 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2113 printformat_module("fe-common/silc", server, NULL,
2114 MSGLEVEL_CRAP, SILCTXT_STATS,
2115 "Total clients", tmp);
2117 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2118 printformat_module("fe-common/silc", server, NULL,
2119 MSGLEVEL_CRAP, SILCTXT_STATS,
2120 "Total channels", tmp);
2122 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2123 printformat_module("fe-common/silc", server, NULL,
2124 MSGLEVEL_CRAP, SILCTXT_STATS,
2125 "Total servers", tmp);
2127 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2128 printformat_module("fe-common/silc", server, NULL,
2129 MSGLEVEL_CRAP, SILCTXT_STATS,
2130 "Total routers", tmp);
2132 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2133 printformat_module("fe-common/silc", server, NULL,
2134 MSGLEVEL_CRAP, SILCTXT_STATS,
2135 "Total server operators", tmp);
2137 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2138 printformat_module("fe-common/silc", server, NULL,
2139 MSGLEVEL_CRAP, SILCTXT_STATS,
2140 "Total router operators", tmp);
2151 SilcClientConnection conn;
2157 SilcSKEPKType pk_type;
2158 SilcVerifyPublicKey completion;
2162 static void verify_public_key_completion(const char *line, void *context)
2164 PublicKeyVerify verify = (PublicKeyVerify)context;
2166 if (line[0] == 'Y' || line[0] == 'y') {
2167 /* Call the completion */
2168 if (verify->completion)
2169 verify->completion(TRUE, verify->context);
2171 /* Save the key for future checking */
2172 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2173 verify->pk_len, SILC_PKCS_FILE_PEM);
2175 /* Call the completion */
2176 if (verify->completion)
2177 verify->completion(FALSE, verify->context);
2179 printformat_module("fe-common/silc", NULL, NULL,
2180 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2181 verify->entity_name ? verify->entity_name :
2185 silc_free(verify->filename);
2186 silc_free(verify->entity);
2187 silc_free(verify->entity_name);
2188 silc_free(verify->pk);
2192 /* Internal routine to verify public key. If the `completion' is provided
2193 it will be called to indicate whether public was verified or not. For
2194 server/router public key this will check for filename that includes the
2195 remote host's IP address and remote host's hostname. */
2198 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2199 const char *name, SilcSocketType conn_type,
2200 unsigned char *pk, SilcUInt32 pk_len,
2201 SilcSKEPKType pk_type,
2202 SilcVerifyPublicKey completion, void *context)
2205 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2206 char *fingerprint, *babbleprint, *format;
2209 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2210 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2211 "server" : "client");
2212 PublicKeyVerify verify;
2214 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2215 printformat_module("fe-common/silc", NULL, NULL,
2216 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2219 completion(FALSE, context);
2223 pw = getpwuid(getuid());
2226 completion(FALSE, context);
2230 memset(filename, 0, sizeof(filename));
2231 memset(filename2, 0, sizeof(filename2));
2232 memset(file, 0, sizeof(file));
2234 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2235 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2237 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2238 conn->sock->ip, conn->sock->port);
2239 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2240 get_irssi_dir(), entity, file);
2242 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2243 conn->sock->hostname, conn->sock->port);
2244 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2245 get_irssi_dir(), entity, file);
2250 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2251 name, conn->sock->port);
2252 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2253 get_irssi_dir(), entity, file);
2258 /* Replace all whitespaces with `_'. */
2259 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2260 for (i = 0; i < strlen(fingerprint); i++)
2261 if (fingerprint[i] == ' ')
2262 fingerprint[i] = '_';
2264 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2265 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2266 get_irssi_dir(), entity, file);
2267 silc_free(fingerprint);
2272 /* Take fingerprint of the public key */
2273 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2274 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2276 verify = silc_calloc(1, sizeof(*verify));
2277 verify->client = client;
2278 verify->conn = conn;
2279 verify->filename = strdup(ipf);
2280 verify->entity = strdup(entity);
2281 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2282 (name ? strdup(name) : strdup(conn->sock->hostname))
2284 verify->pk = silc_memdup(pk, pk_len);
2285 verify->pk_len = pk_len;
2286 verify->pk_type = pk_type;
2287 verify->completion = completion;
2288 verify->context = context;
2290 /* Check whether this key already exists */
2291 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2292 /* Key does not exist, ask user to verify the key and save it */
2294 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2295 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2296 verify->entity_name : entity);
2297 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2298 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2299 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2300 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2301 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2302 SILCTXT_PUBKEY_ACCEPT);
2303 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2306 silc_free(fingerprint);
2309 /* The key already exists, verify it. */
2310 SilcPublicKey public_key;
2311 unsigned char *encpk;
2312 SilcUInt32 encpk_len;
2314 /* Load the key file, try for both IP filename and hostname filename */
2315 if (!silc_pkcs_load_public_key(ipf, &public_key,
2316 SILC_PKCS_FILE_PEM) &&
2317 !silc_pkcs_load_public_key(ipf, &public_key,
2318 SILC_PKCS_FILE_BIN) &&
2319 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2320 SILC_PKCS_FILE_PEM) &&
2321 !silc_pkcs_load_public_key(hostf, &public_key,
2322 SILC_PKCS_FILE_BIN)))) {
2323 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2324 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2325 verify->entity_name : entity);
2326 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2327 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2328 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2329 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2330 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2331 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2332 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2333 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2334 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2337 silc_free(fingerprint);
2341 /* Encode the key data */
2342 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2344 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2345 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2346 verify->entity_name : entity);
2347 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2348 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2349 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2350 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2351 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2352 SILCTXT_PUBKEY_MALFORMED, entity);
2353 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2354 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2355 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2358 silc_free(fingerprint);
2362 /* Compare the keys */
2363 if (memcmp(encpk, pk, encpk_len)) {
2364 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2365 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2366 verify->entity_name : entity);
2367 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2368 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2369 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2370 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2371 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2372 SILCTXT_PUBKEY_NO_MATCH, entity);
2373 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2374 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2375 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2376 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2378 /* Ask user to verify the key and save it */
2379 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2380 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2381 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2384 silc_free(fingerprint);
2388 /* Local copy matched */
2390 completion(TRUE, context);
2391 silc_free(fingerprint);
2392 silc_free(verify->filename);
2393 silc_free(verify->entity);
2394 silc_free(verify->entity_name);
2395 silc_free(verify->pk);
2400 /* Verifies received public key. The `conn_type' indicates which entity
2401 (server, client etc.) has sent the public key. If user decides to trust
2402 the key may be saved as trusted public key for later use. The
2403 `completion' must be called after the public key has been verified. */
2406 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2407 SilcSocketType conn_type, unsigned char *pk,
2408 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2409 SilcVerifyPublicKey completion, void *context)
2411 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2413 completion, context);
2416 /* Asks passphrase from user on the input line. */
2419 SilcAskPassphrase completion;
2423 void ask_passphrase_completion(const char *passphrase, void *context)
2425 AskPassphrase p = (AskPassphrase)context;
2426 if (passphrase && passphrase[0] == '\0')
2428 p->completion((unsigned char *)passphrase,
2429 passphrase ? strlen(passphrase) : 0, p->context);
2433 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2434 SilcAskPassphrase completion, void *context)
2436 AskPassphrase p = silc_calloc(1, sizeof(*p));
2437 p->completion = completion;
2438 p->context = context;
2440 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2441 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2445 SilcGetAuthMeth completion;
2447 } *InternalGetAuthMethod;
2449 /* Callback called when we've received the authentication method information
2450 from the server after we've requested it. This will get the authentication
2451 data from the user if needed. */
2453 static void silc_get_auth_method_callback(SilcClient client,
2454 SilcClientConnection conn,
2455 SilcAuthMethod auth_meth,
2458 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2460 SILC_LOG_DEBUG(("Start"));
2462 switch (auth_meth) {
2463 case SILC_AUTH_NONE:
2464 /* No authentication required. */
2465 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2467 case SILC_AUTH_PASSWORD:
2469 /* Check whether we find the password for this server in our
2470 configuration. If not, then don't provide so library will ask
2471 it from the user. */
2472 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2474 if (!setup || !setup->password) {
2475 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2479 (*internal->completion)(TRUE, auth_meth, setup->password,
2480 strlen(setup->password), internal->context);
2483 case SILC_AUTH_PUBLIC_KEY:
2484 /* Do not get the authentication data now, the library will generate
2485 it using our default key, if we do not provide it here. */
2486 /* XXX In the future when we support multiple local keys and multiple
2487 local certificates we will need to ask from user which one to use. */
2488 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2492 silc_free(internal);
2495 /* Find authentication method and authentication data by hostname and
2496 port. The hostname may be IP address as well. The found authentication
2497 method and authentication data is returned to `auth_meth', `auth_data'
2498 and `auth_data_len'. The function returns TRUE if authentication method
2499 is found and FALSE if not. `conn' may be NULL. */
2501 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2502 char *hostname, SilcUInt16 port,
2503 SilcGetAuthMeth completion, void *context)
2505 InternalGetAuthMethod internal;
2507 SILC_LOG_DEBUG(("Start"));
2509 /* If we do not have this connection configured by the user in a
2510 configuration file then resolve the authentication method from the
2511 server for this session. */
2512 internal = silc_calloc(1, sizeof(*internal));
2513 internal->completion = completion;
2514 internal->context = context;
2516 silc_client_request_authentication_method(client, conn,
2517 silc_get_auth_method_callback,
2521 /* Notifies application that failure packet was received. This is called
2522 if there is some protocol active in the client. The `protocol' is the
2523 protocol context. The `failure' is opaque pointer to the failure
2524 indication. Note, that the `failure' is protocol dependant and application
2525 must explicitly cast it to correct type. Usually `failure' is 32 bit
2526 failure type (see protocol specs for all protocol failure types). */
2528 void silc_failure(SilcClient client, SilcClientConnection conn,
2529 SilcProtocol protocol, void *failure)
2531 SILC_LOG_DEBUG(("Start"));
2533 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2534 SilcSKEStatus status = (SilcSKEStatus)failure;
2536 if (status == SILC_SKE_STATUS_BAD_VERSION)
2537 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2538 SILCTXT_KE_BAD_VERSION);
2539 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2540 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2541 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2542 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2543 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2544 SILCTXT_KE_UNKNOWN_GROUP);
2545 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2546 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2547 SILCTXT_KE_UNKNOWN_CIPHER);
2548 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2550 SILCTXT_KE_UNKNOWN_PKCS);
2551 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2552 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2553 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2554 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2555 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2556 SILCTXT_KE_UNKNOWN_HMAC);
2557 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2558 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2559 SILCTXT_KE_INCORRECT_SIGNATURE);
2560 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2561 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2562 SILCTXT_KE_INVALID_COOKIE);
2565 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2566 SilcUInt32 err = (SilcUInt32)failure;
2568 if (err == SILC_AUTH_FAILED)
2569 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2570 SILCTXT_AUTH_FAILED);
2574 /* Asks whether the user would like to perform the key agreement protocol.
2575 This is called after we have received an key agreement packet or an
2576 reply to our key agreement packet. This returns TRUE if the user wants
2577 the library to perform the key agreement protocol and FALSE if it is not
2578 desired (application may start it later by calling the function
2579 silc_client_perform_key_agreement). */
2581 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2582 SilcClientEntry client_entry, const char *hostname,
2583 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2588 SILC_LOG_DEBUG(("Start"));
2590 /* We will just display the info on the screen and return FALSE and user
2591 will have to start the key agreement with a command. */
2594 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2597 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2598 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2600 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2601 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2602 client_entry->nickname, hostname, portstr);
2610 /* Notifies application that file transfer protocol session is being
2611 requested by the remote client indicated by the `client_entry' from
2612 the `hostname' and `port'. The `session_id' is the file transfer
2613 session and it can be used to either accept or reject the file
2614 transfer request, by calling the silc_client_file_receive or
2615 silc_client_file_close, respectively. */
2617 void silc_ftp(SilcClient client, SilcClientConnection conn,
2618 SilcClientEntry client_entry, SilcUInt32 session_id,
2619 const char *hostname, SilcUInt16 port)
2621 SILC_SERVER_REC *server;
2623 FtpSession ftp = NULL;
2625 SILC_LOG_DEBUG(("Start"));
2627 server = conn->context;
2629 silc_dlist_start(server->ftp_sessions);
2630 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2631 if (ftp->client_entry == client_entry &&
2632 ftp->session_id == session_id) {
2633 server->current_session = ftp;
2637 if (ftp == SILC_LIST_END) {
2638 ftp = silc_calloc(1, sizeof(*ftp));
2639 ftp->client_entry = client_entry;
2640 ftp->session_id = session_id;
2643 silc_dlist_add(server->ftp_sessions, ftp);
2644 server->current_session = ftp;
2648 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2651 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2652 SILCTXT_FILE_REQUEST, client_entry->nickname);
2654 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2655 SILCTXT_FILE_REQUEST_HOST,
2656 client_entry->nickname, hostname, portstr);
2659 /* Delivers SILC session detachment data indicated by `detach_data' to the
2660 application. If application has issued SILC_COMMAND_DETACH command
2661 the client session in the SILC network is not quit. The client remains
2662 in the network but is detached. The detachment data may be used later
2663 to resume the session in the SILC Network. The appliation is
2664 responsible of saving the `detach_data', to for example in a file.
2666 The detachment data can be given as argument to the functions
2667 silc_client_connect_to_server, or silc_client_add_connection when
2668 creating connection to remote server, inside SilcClientConnectionParams
2669 structure. If it is provided the client library will attempt to resume
2670 the session in the network. After the connection is created
2671 successfully, the application is responsible of setting the user
2672 interface for user into the same state it was before detaching (showing
2673 same channels, channel modes, etc). It can do this by fetching the
2674 information (like joined channels) from the client library. */
2677 silc_detach(SilcClient client, SilcClientConnection conn,
2678 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2682 /* Save the detachment data to file. */
2684 memset(file, 0, sizeof(file));
2685 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2686 silc_file_writefile(file, detach_data, detach_data_len);
2690 /* SILC client operations */
2691 SilcClientOperations ops = {
2693 silc_channel_message,
2694 silc_private_message,
2700 silc_get_auth_method,
2701 silc_verify_public_key,
2702 silc_ask_passphrase,