5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 - 2003 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));
936 /* Print only if we have the nickname. If this client has just quit
937 when we were only resolving it, it is possible we don't have the
939 if (clients[i]->nickname) {
940 if (clients[i]->username)
941 snprintf(buf, sizeof(buf) - 1, "%s@%s",
942 clients[i]->username, clients[i]->hostname);
943 signal_emit("message quit", 4, server, clients[i]->nickname,
944 clients[i]->username ? buf : "",
948 silc_server_free_ftp(server, clients[i]);
950 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
951 for (list_tmp = list1; list_tmp != NULL; list_tmp =
952 list_tmp->next->next) {
953 CHANNEL_REC *channel = list_tmp->data;
954 NICK_REC *nickrec = list_tmp->next->data;
955 nicklist_remove(channel, nickrec);
961 case SILC_NOTIFY_TYPE_ERROR:
963 SilcStatus error = va_arg(va, int);
965 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
966 "%s", silc_get_status_message(error));
970 case SILC_NOTIFY_TYPE_WATCH:
972 SilcNotifyType notify;
974 client_entry = va_arg(va, SilcClientEntry);
975 name = va_arg(va, char *); /* Maybe NULL */
976 mode = va_arg(va, SilcUInt32);
977 notify = va_arg(va, int);
979 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
981 printformat_module("fe-common/silc", server, NULL,
982 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
983 client_entry->nickname, name);
985 printformat_module("fe-common/silc", server, NULL,
986 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
987 client_entry->nickname);
988 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
989 /* See if client was away and is now present */
990 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
991 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
992 SILC_UMODE_DETACHED)) &&
993 (client_entry->mode & SILC_UMODE_GONE ||
994 client_entry->mode & SILC_UMODE_INDISPOSED ||
995 client_entry->mode & SILC_UMODE_BUSY ||
996 client_entry->mode & SILC_UMODE_PAGE ||
997 client_entry->mode & SILC_UMODE_DETACHED)) {
998 printformat_module("fe-common/silc", server, NULL,
999 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1000 client_entry->nickname);
1004 memset(buf, 0, sizeof(buf));
1005 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1006 printformat_module("fe-common/silc", server, NULL,
1007 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1008 client_entry->nickname, buf);
1010 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1011 printformat_module("fe-common/silc", server, NULL,
1012 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1013 client_entry->nickname);
1014 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1015 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1016 printformat_module("fe-common/silc", server, NULL,
1017 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1018 client_entry->nickname);
1019 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1020 /* Client logged in to the network */
1021 printformat_module("fe-common/silc", server, NULL,
1022 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1023 client_entry->nickname);
1029 /* Unknown notify */
1030 printformat_module("fe-common/silc", server, NULL,
1031 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1038 /* Called to indicate that connection was either successfully established
1039 or connecting failed. This is also the first time application receives
1040 the SilcClientConnection object which it should save somewhere. */
1042 void silc_connect(SilcClient client, SilcClientConnection conn,
1043 SilcClientConnectionStatus status)
1045 SILC_SERVER_REC *server = conn->context;
1047 if (!server || server->disconnected) {
1048 silc_client_close_connection(client, conn);
1053 case SILC_CLIENT_CONN_SUCCESS:
1054 /* We have successfully connected to server */
1055 server->connected = TRUE;
1056 signal_emit("event connected", 1, server);
1059 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1060 /* We have successfully resumed old detached session */
1061 server->connected = TRUE;
1062 signal_emit("event connected", 1, server);
1064 /* If we resumed old session check whether we need to update
1066 if (strcmp(server->nick, conn->local_entry->nickname)) {
1068 old = g_strdup(server->nick);
1069 server_change_nick(SERVER(server), conn->local_entry->nickname);
1070 nicklist_rename_unique(SERVER(server),
1071 conn->local_entry, server->nick,
1072 conn->local_entry, conn->local_entry->nickname);
1073 signal_emit("message own_nick", 4, server, server->nick, old, "");
1079 server->connection_lost = TRUE;
1081 server->conn->context = NULL;
1082 server_disconnect(SERVER(server));
1087 /* Called to indicate that connection was disconnected to the server. */
1089 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1090 SilcStatus status, const char *message)
1092 SILC_SERVER_REC *server = conn->context;
1094 SILC_LOG_DEBUG(("Start"));
1096 if (!server || server->connection_lost)
1099 if (server->conn && server->conn->local_entry) {
1100 nicklist_rename_unique(SERVER(server),
1101 server->conn->local_entry, server->nick,
1102 server->conn->local_entry,
1103 silc_client->username);
1104 silc_change_nick(server, silc_client->username);
1108 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1109 "Server closed connection: %s (%d) %s",
1110 silc_get_status_message(status), status,
1111 message ? message : "");
1114 server->conn->context = NULL;
1115 server->conn = NULL;
1116 server->connection_lost = TRUE;
1117 server_disconnect(SERVER(server));
1120 /* Command handler. This function is called always in the command function.
1121 If error occurs it will be called as well. `conn' is the associated
1122 client connection. `cmd_context' is the command context that was
1123 originally sent to the command. `success' is FALSE if error occured
1124 during command. `command' is the command being processed. It must be
1125 noted that this is not reply from server. This is merely called just
1126 after application has called the command. Just to tell application
1127 that the command really was processed. */
1129 void silc_command(SilcClient client, SilcClientConnection conn,
1130 SilcClientCommandContext cmd_context, bool success,
1131 SilcCommand command, SilcStatus status)
1133 SILC_SERVER_REC *server = conn->context;
1135 SILC_LOG_DEBUG(("Start"));
1138 silc_say_error("%s", silc_get_status_message(status));
1144 case SILC_COMMAND_INVITE:
1145 if (cmd_context->argc > 2)
1146 printformat_module("fe-common/silc", server, NULL,
1147 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1148 cmd_context->argv[2],
1149 (cmd_context->argv[1][0] == '*' ?
1150 (char *)conn->current_channel->channel_name :
1151 (char *)cmd_context->argv[1]));
1154 case SILC_COMMAND_DETACH:
1155 server->no_reconnect = TRUE;
1164 SilcChannelEntry channel;
1168 /* Client info resolving callback when JOIN command reply is received.
1169 This will cache all users on the channel. */
1171 static void silc_client_join_get_users(SilcClient client,
1172 SilcClientConnection conn,
1173 SilcClientEntry *clients,
1174 SilcUInt32 clients_count,
1177 SilcJoinResolve r = context;
1178 SilcChannelEntry channel = r->channel;
1179 SilcHashTableList htl;
1180 SilcChannelUser chu;
1181 SILC_SERVER_REC *server = conn->context;
1182 SILC_CHANNEL_REC *chanrec;
1183 SilcClientEntry founder = NULL;
1186 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1187 silc_hash_table_count(channel->user_list)));
1189 if (!clients && r->retry < 1) {
1190 /* Retry to resolve */
1191 silc_client_get_clients_by_channel(client, conn, channel,
1192 silc_client_join_get_users, context);
1196 chanrec = silc_channel_find(server, channel->channel_name);
1197 if (chanrec == NULL)
1200 silc_hash_table_list(channel->user_list, &htl);
1201 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1202 if (!chu->client->nickname)
1204 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1205 founder = chu->client;
1206 silc_nicklist_insert(chanrec, chu, FALSE);
1208 silc_hash_table_list_reset(&htl);
1210 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1211 nicklist_set_own(CHANNEL(chanrec), ownnick);
1212 signal_emit("channel joined", 1, chanrec);
1213 chanrec->entry = channel;
1216 printformat_module("fe-common/silc", server, channel->channel_name,
1217 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1218 channel->channel_name, chanrec->topic);
1221 if (founder == conn->local_entry) {
1222 printformat_module("fe-common/silc",
1223 server, channel->channel_name, MSGLEVEL_CRAP,
1224 SILCTXT_CHANNEL_FOUNDER_YOU,
1225 channel->channel_name);
1226 signal_emit("nick mode changed", 2, chanrec, ownnick);
1228 printformat_module("fe-common/silc",
1229 server, channel->channel_name, MSGLEVEL_CRAP,
1230 SILCTXT_CHANNEL_FOUNDER,
1231 channel->channel_name, founder->nickname);
1237 SilcClientConnection conn;
1243 void silc_getkey_cb(bool success, void *context)
1245 GetkeyContext getkey = (GetkeyContext)context;
1246 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1247 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1248 ((SilcClientEntry)getkey->entry)->nickname :
1249 ((SilcServerEntry)getkey->entry)->server_name);
1252 printformat_module("fe-common/silc", NULL, NULL,
1253 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1255 printformat_module("fe-common/silc", NULL, NULL,
1256 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1260 silc_free(getkey->fingerprint);
1264 /* Parse an invite or ban list */
1265 void silc_parse_inviteban_list(SilcClient client,
1266 SilcClientConnection conn,
1267 SILC_SERVER_REC *server,
1268 SilcChannelEntry channel,
1269 const char *list_type,
1270 SilcArgumentPayload list)
1273 SilcUInt32 type, len;
1274 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1275 int counter=0, resolving = FALSE;
1277 if (!silc_argument_get_arg_num(list)) {
1278 printformat_module("fe-common/silc", server,
1279 (chanrec ? chanrec->visible_name : NULL),
1280 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1281 channel->channel_name, list_type);
1285 printformat_module("fe-common/silc", server,
1286 (chanrec ? chanrec->visible_name : NULL),
1287 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1288 channel->channel_name, list_type);
1290 /* parse the list */
1291 tmp = silc_argument_get_first_arg(list, &type, &len);
1296 /* an invite string */
1300 if (tmp[len-1] == ',')
1303 list = g_strsplit(tmp, ",", -1);
1305 printformat_module("fe-common/silc", server,
1306 (chanrec ? chanrec->visible_name : NULL),
1307 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1308 ++counter, channel->channel_name, list_type,
1317 char *fingerprint, *babbleprint;
1319 /* tmp is Public Key Payload, take public key from it. */
1320 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1321 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1323 printformat_module("fe-common/silc", server,
1324 (chanrec ? chanrec->visible_name : NULL),
1325 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1326 ++counter, channel->channel_name, list_type,
1327 fingerprint, babbleprint);
1334 SilcClientID *client_id;
1335 SilcClientEntry client_entry;
1337 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1339 if (client_id == NULL) {
1340 silc_say_error("Invalid data in %s list encountered", list_type);
1344 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1347 printformat_module("fe-common/silc", server,
1348 (chanrec ? chanrec->visible_name : NULL),
1349 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1350 ++counter, channel->channel_name, list_type,
1351 client_entry->nickname);
1354 silc_client_get_client_by_id_resolve(client, conn, client_id,
1358 silc_free(client_id);
1364 silc_say_error("Unkown type in %s list: %u (len %u)",
1365 list_type, type, len);
1367 tmp = silc_argument_get_next_arg(list, &type, &len);
1371 printformat_module("fe-common/silc", server,
1372 (chanrec ? chanrec->visible_name : NULL),
1373 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1374 list_type, channel->channel_name);
1377 /* Command reply handler. This function is called always in the command reply
1378 function. If error occurs it will be called as well. Normal scenario
1379 is that it will be called after the received command data has been parsed
1380 and processed. The function is used to pass the received command data to
1383 `conn' is the associated client connection. `cmd_payload' is the command
1384 payload data received from server and it can be ignored. It is provided
1385 if the application would like to re-parse the received command data,
1386 however, it must be noted that the data is parsed already by the library
1387 thus the payload can be ignored. `success' is FALSE if error occured.
1388 In this case arguments are not sent to the application. `command' is the
1389 command reply being processed. The function has variable argument list
1390 and each command defines the number and type of arguments it passes to the
1391 application (on error they are not sent). */
1394 silc_command_reply(SilcClient client, SilcClientConnection conn,
1395 SilcCommandPayload cmd_payload, bool success,
1396 SilcCommand command, SilcStatus status, ...)
1399 SILC_SERVER_REC *server = conn->context;
1400 SILC_CHANNEL_REC *chanrec;
1403 va_start(vp, status);
1405 SILC_LOG_DEBUG(("Start"));
1408 case SILC_COMMAND_WHOIS:
1410 char buf[1024], *nickname, *username, *realname, *nick;
1411 unsigned char *fingerprint;
1412 SilcUInt32 idle, mode;
1413 SilcBuffer channels, user_modes;
1414 SilcClientEntry client_entry;
1417 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1418 /* Print the unknown nick for user */
1419 unsigned char *tmp =
1420 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1423 silc_say_error("%s: %s", tmp,
1424 silc_get_status_message(status));
1426 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1427 /* Try to find the entry for the unknown client ID, since we
1428 might have, and print the nickname of it for user. */
1430 unsigned char *tmp =
1431 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1434 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1437 client_entry = silc_client_get_client_by_id(client, conn,
1439 if (client_entry && client_entry->nickname)
1440 silc_say_error("%s: %s", client_entry->nickname,
1441 silc_get_status_message(status));
1442 silc_free(client_id);
1446 } else if (!success) {
1447 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1451 client_entry = va_arg(vp, SilcClientEntry);
1452 nickname = va_arg(vp, char *);
1453 username = va_arg(vp, char *);
1454 realname = va_arg(vp, char *);
1455 channels = va_arg(vp, SilcBuffer);
1456 mode = va_arg(vp, SilcUInt32);
1457 idle = va_arg(vp, SilcUInt32);
1458 fingerprint = va_arg(vp, unsigned char *);
1459 user_modes = va_arg(vp, SilcBuffer);
1460 attrs = va_arg(vp, SilcDList);
1462 silc_parse_userfqdn(nickname, &nick, NULL);
1463 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1464 SILCTXT_WHOIS_USERINFO, nickname,
1465 client_entry->username, client_entry->hostname,
1466 nick, client_entry->nickname);
1467 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1468 SILCTXT_WHOIS_REALNAME, realname);
1471 if (channels && user_modes) {
1473 SilcDList list = silc_channel_payload_parse_list(channels->data,
1475 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1477 SilcChannelPayload entry;
1480 memset(buf, 0, sizeof(buf));
1481 silc_dlist_start(list);
1482 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1483 SilcUInt32 name_len;
1484 char *m = silc_client_chumode_char(umodes[i++]);
1485 char *name = silc_channel_get_name(entry, &name_len);
1488 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1489 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1490 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1494 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1495 SILCTXT_WHOIS_CHANNELS, buf);
1496 silc_channel_payload_list_free(list);
1502 memset(buf, 0, sizeof(buf));
1503 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1504 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1505 SILCTXT_WHOIS_MODES, buf);
1508 if (idle && nickname) {
1509 memset(buf, 0, sizeof(buf));
1510 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1511 idle > 60 ? (idle / 60) : idle,
1512 idle > 60 ? "minutes" : "seconds");
1514 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1515 SILCTXT_WHOIS_IDLE, buf);
1519 fingerprint = silc_fingerprint(fingerprint, 20);
1520 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1521 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1522 silc_free(fingerprint);
1526 silc_query_attributes_print(server, silc_client, conn, attrs,
1531 case SILC_COMMAND_IDENTIFY:
1533 SilcClientEntry client_entry;
1535 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1536 /* Print the unknown nick for user */
1537 unsigned char *tmp =
1538 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1541 silc_say_error("%s: %s", tmp,
1542 silc_get_status_message(status));
1544 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1545 /* Try to find the entry for the unknown client ID, since we
1546 might have, and print the nickname of it for user. */
1548 unsigned char *tmp =
1549 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1552 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1555 client_entry = silc_client_get_client_by_id(client, conn,
1557 if (client_entry && client_entry->nickname)
1558 silc_say_error("%s: %s", client_entry->nickname,
1559 silc_get_status_message(status));
1560 silc_free(client_id);
1569 case SILC_COMMAND_WHOWAS:
1571 char *nickname, *username, *realname;
1573 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1574 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1576 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1579 silc_say_error("%s: %s", tmp,
1580 silc_get_status_message(status));
1582 } else if (!success) {
1583 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1587 (void)va_arg(vp, SilcClientEntry);
1588 nickname = va_arg(vp, char *);
1589 username = va_arg(vp, char *);
1590 realname = va_arg(vp, char *);
1592 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1593 SILCTXT_WHOWAS_USERINFO, nickname, username,
1594 realname ? realname : "");
1598 case SILC_COMMAND_INVITE:
1600 SilcChannelEntry channel;
1602 SilcArgumentPayload invite_list;
1608 channel = va_arg(vp, SilcChannelEntry);
1609 payload = va_arg(vp, SilcBuffer);
1612 SILC_GET16_MSB(argc, payload->data);
1613 invite_list = silc_argument_payload_parse(payload->data + 2,
1614 payload->len - 2, argc);
1616 silc_parse_inviteban_list(client, conn, server, channel,
1617 "invite", invite_list);
1618 silc_argument_payload_free(invite_list);
1624 case SILC_COMMAND_JOIN:
1626 char *channel, *mode, *topic;
1628 SilcChannelEntry channel_entry;
1629 SilcBuffer client_id_list;
1630 SilcUInt32 list_count;
1635 channel = va_arg(vp, char *);
1636 channel_entry = va_arg(vp, SilcChannelEntry);
1637 modei = va_arg(vp, SilcUInt32);
1638 (void)va_arg(vp, SilcUInt32);
1639 (void)va_arg(vp, unsigned char *);
1640 (void)va_arg(vp, unsigned char *);
1641 (void)va_arg(vp, unsigned char *);
1642 topic = va_arg(vp, char *);
1643 (void)va_arg(vp, unsigned char *);
1644 list_count = va_arg(vp, SilcUInt32);
1645 client_id_list = va_arg(vp, SilcBuffer);
1647 chanrec = silc_channel_find(server, channel);
1649 chanrec = silc_channel_create(server, channel, channel, TRUE);
1652 char tmp[256], *cp, *dm = NULL;
1653 g_free_not_null(chanrec->topic);
1655 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1656 memset(tmp, 0, sizeof(tmp));
1658 if (strlen(topic) > sizeof(tmp) - 1) {
1659 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1663 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1668 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1669 signal_emit("channel topic changed", 1, chanrec);
1674 mode = silc_client_chmode(modei,
1675 channel_entry->channel_key ?
1676 silc_cipher_get_name(channel_entry->
1678 channel_entry->hmac ?
1679 silc_hmac_get_name(channel_entry->hmac) : "");
1680 g_free_not_null(chanrec->mode);
1681 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1682 signal_emit("channel mode changed", 1, chanrec);
1684 /* Resolve the client information */
1685 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1686 r->channel = channel_entry;
1687 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1688 silc_client_join_get_users, r);
1693 case SILC_COMMAND_NICK:
1696 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1702 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1703 if ((nicks != NULL) &&
1704 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1706 SilcClientEntry collider, old;
1708 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1709 collider = silc_client_get_client_by_id(client, conn,
1712 memset(buf, 0, sizeof(buf));
1713 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1714 collider->username, collider->hostname);
1715 nicklist_rename_unique(SERVER(server),
1717 collider, collider->nickname);
1718 silc_print_nick_change(server, collider->nickname,
1719 client_entry->nickname, buf);
1720 g_slist_free(nicks);
1723 old = g_strdup(server->nick);
1724 server_change_nick(SERVER(server), client_entry->nickname);
1725 nicklist_rename_unique(SERVER(server),
1726 server->conn->local_entry, server->nick,
1727 client_entry, client_entry->nickname);
1728 signal_emit("message own_nick", 4, server, server->nick, old, "");
1733 case SILC_COMMAND_LIST:
1738 char tmp[256], *cp, *dm = NULL;
1743 (void)va_arg(vp, SilcChannelEntry);
1744 name = va_arg(vp, char *);
1745 topic = va_arg(vp, char *);
1746 usercount = va_arg(vp, int);
1748 if (topic && !silc_term_utf8() &&
1749 silc_utf8_valid(topic, strlen(topic))) {
1750 memset(tmp, 0, sizeof(tmp));
1752 if (strlen(topic) > sizeof(tmp) - 1) {
1753 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1757 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1762 if (status == SILC_STATUS_LIST_START ||
1763 status == SILC_STATUS_OK)
1764 printformat_module("fe-common/silc", server, NULL,
1765 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1768 snprintf(users, sizeof(users) - 1, "N/A");
1770 snprintf(users, sizeof(users) - 1, "%d", usercount);
1771 printformat_module("fe-common/silc", server, NULL,
1772 MSGLEVEL_CRAP, SILCTXT_LIST,
1773 name, users, topic ? topic : "");
1778 case SILC_COMMAND_UMODE:
1786 mode = va_arg(vp, SilcUInt32);
1788 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1789 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1790 printformat_module("fe-common/silc", server, NULL,
1791 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1793 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1794 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1795 printformat_module("fe-common/silc", server, NULL,
1796 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1798 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1799 if (mode & SILC_UMODE_GONE) {
1800 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1801 reason = g_strdup(server->away_reason);
1803 reason = g_strdup("away");
1805 reason = g_strdup("");
1807 silc_set_away(reason, server);
1812 server->umode = mode;
1813 signal_emit("user mode changed", 2, server, NULL);
1817 case SILC_COMMAND_OPER:
1821 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1822 signal_emit("user mode changed", 2, server, NULL);
1824 printformat_module("fe-common/silc", server, NULL,
1825 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1828 case SILC_COMMAND_SILCOPER:
1832 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1833 signal_emit("user mode changed", 2, server, NULL);
1835 printformat_module("fe-common/silc", server, NULL,
1836 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1839 case SILC_COMMAND_USERS:
1841 SilcHashTableList htl;
1842 SilcChannelEntry channel;
1843 SilcChannelUser chu;
1848 channel = va_arg(vp, SilcChannelEntry);
1850 printformat_module("fe-common/silc", server, channel->channel_name,
1851 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1852 channel->channel_name);
1854 silc_hash_table_list(channel->user_list, &htl);
1855 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1856 SilcClientEntry e = chu->client;
1857 char stat[5], *mode;
1862 memset(stat, 0, sizeof(stat));
1863 mode = silc_client_chumode_char(chu->mode);
1864 if (e->mode & SILC_UMODE_GONE)
1866 else if (e->mode & SILC_UMODE_INDISPOSED)
1868 else if (e->mode & SILC_UMODE_BUSY)
1870 else if (e->mode & SILC_UMODE_PAGE)
1872 else if (e->mode & SILC_UMODE_HYPER)
1874 else if (e->mode & SILC_UMODE_ROBOT)
1876 else if (e->mode & SILC_UMODE_ANONYMOUS)
1883 printformat_module("fe-common/silc", server, channel->channel_name,
1884 MSGLEVEL_CRAP, SILCTXT_USERS,
1886 e->username ? e->username : "",
1887 e->hostname ? e->hostname : "",
1888 e->realname ? e->realname : "");
1892 silc_hash_table_list_reset(&htl);
1896 case SILC_COMMAND_BAN:
1898 SilcChannelEntry channel;
1900 SilcArgumentPayload ban_list;
1906 channel = va_arg(vp, SilcChannelEntry);
1907 payload = va_arg(vp, SilcBuffer);
1910 SILC_GET16_MSB(argc, payload->data);
1911 ban_list = silc_argument_payload_parse(payload->data + 2,
1912 payload->len - 2, argc);
1914 silc_parse_inviteban_list(client, conn, server, channel,
1916 silc_argument_payload_free(ban_list);
1922 case SILC_COMMAND_GETKEY:
1926 SilcPublicKey public_key;
1929 GetkeyContext getkey;
1935 id_type = va_arg(vp, SilcUInt32);
1936 entry = va_arg(vp, void *);
1937 public_key = va_arg(vp, SilcPublicKey);
1940 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1942 getkey = silc_calloc(1, sizeof(*getkey));
1943 getkey->entry = entry;
1944 getkey->id_type = id_type;
1945 getkey->client = client;
1946 getkey->conn = conn;
1947 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1949 name = (id_type == SILC_ID_CLIENT ?
1950 ((SilcClientEntry)entry)->nickname :
1951 ((SilcServerEntry)entry)->server_name);
1953 silc_verify_public_key_internal(client, conn, name,
1954 (id_type == SILC_ID_CLIENT ?
1955 SILC_SOCKET_TYPE_CLIENT :
1956 SILC_SOCKET_TYPE_SERVER),
1957 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1958 silc_getkey_cb, getkey);
1961 printformat_module("fe-common/silc", server, NULL,
1962 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1967 case SILC_COMMAND_INFO:
1969 SilcServerEntry server_entry;
1976 server_entry = va_arg(vp, SilcServerEntry);
1977 server_name = va_arg(vp, char *);
1978 server_info = va_arg(vp, char *);
1980 if (server_name && server_info )
1982 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1983 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1988 case SILC_COMMAND_TOPIC:
1990 SilcChannelEntry channel;
1992 char tmp[256], *cp, *dm = NULL;
1997 channel = va_arg(vp, SilcChannelEntry);
1998 topic = va_arg(vp, char *);
2000 if (topic && !silc_term_utf8() &&
2001 silc_utf8_valid(topic, strlen(topic))) {
2002 memset(tmp, 0, sizeof(tmp));
2004 if (strlen(topic) > sizeof(tmp) - 1) {
2005 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2009 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2015 chanrec = silc_channel_find_entry(server, channel);
2017 g_free_not_null(chanrec->topic);
2018 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2019 signal_emit("channel topic changed", 1, chanrec);
2021 printformat_module("fe-common/silc", server, channel->channel_name,
2022 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2023 channel->channel_name, topic);
2025 printformat_module("fe-common/silc", server, channel->channel_name,
2026 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2027 channel->channel_name);
2033 case SILC_COMMAND_WATCH:
2036 case SILC_COMMAND_STATS:
2038 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2039 my_router_ops, cell_clients, cell_channels, cell_servers,
2040 clients, channels, servers, routers, server_ops, router_ops;
2042 SilcBufferStruct buf;
2043 unsigned char *tmp_buf;
2045 const char *tmptime;
2046 int days, hours, mins, secs;
2051 tmp_buf = va_arg(vp, unsigned char *);
2052 buf_len = va_arg(vp, SilcUInt32);
2054 if (!tmp_buf || !buf_len) {
2055 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2059 /* Get statistics structure */
2060 silc_buffer_set(&buf, tmp_buf, buf_len);
2061 silc_buffer_unformat(&buf,
2062 SILC_STR_UI_INT(&starttime),
2063 SILC_STR_UI_INT(&uptime),
2064 SILC_STR_UI_INT(&my_clients),
2065 SILC_STR_UI_INT(&my_channels),
2066 SILC_STR_UI_INT(&my_server_ops),
2067 SILC_STR_UI_INT(&my_router_ops),
2068 SILC_STR_UI_INT(&cell_clients),
2069 SILC_STR_UI_INT(&cell_channels),
2070 SILC_STR_UI_INT(&cell_servers),
2071 SILC_STR_UI_INT(&clients),
2072 SILC_STR_UI_INT(&channels),
2073 SILC_STR_UI_INT(&servers),
2074 SILC_STR_UI_INT(&routers),
2075 SILC_STR_UI_INT(&server_ops),
2076 SILC_STR_UI_INT(&router_ops),
2079 tmptime = silc_get_time(starttime);
2080 printformat_module("fe-common/silc", server, NULL,
2081 MSGLEVEL_CRAP, SILCTXT_STATS,
2082 "Local server start time", tmptime);
2084 days = uptime / (24 * 60 * 60);
2085 uptime -= days * (24 * 60 * 60);
2086 hours = uptime / (60 * 60);
2087 uptime -= hours * (60 * 60);
2089 uptime -= mins * 60;
2091 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2092 days, hours, mins, secs);
2093 printformat_module("fe-common/silc", server, NULL,
2094 MSGLEVEL_CRAP, SILCTXT_STATS,
2095 "Local server uptime", tmp);
2097 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2098 printformat_module("fe-common/silc", server, NULL,
2099 MSGLEVEL_CRAP, SILCTXT_STATS,
2100 "Local server clients", tmp);
2102 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2103 printformat_module("fe-common/silc", server, NULL,
2104 MSGLEVEL_CRAP, SILCTXT_STATS,
2105 "Local server channels", tmp);
2107 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2108 printformat_module("fe-common/silc", server, NULL,
2109 MSGLEVEL_CRAP, SILCTXT_STATS,
2110 "Local server operators", tmp);
2112 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2113 printformat_module("fe-common/silc", server, NULL,
2114 MSGLEVEL_CRAP, SILCTXT_STATS,
2115 "Local router operators", tmp);
2117 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2118 printformat_module("fe-common/silc", server, NULL,
2119 MSGLEVEL_CRAP, SILCTXT_STATS,
2120 "Local cell clients", tmp);
2122 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2123 printformat_module("fe-common/silc", server, NULL,
2124 MSGLEVEL_CRAP, SILCTXT_STATS,
2125 "Local cell channels", tmp);
2127 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2128 printformat_module("fe-common/silc", server, NULL,
2129 MSGLEVEL_CRAP, SILCTXT_STATS,
2130 "Local cell servers", tmp);
2132 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2133 printformat_module("fe-common/silc", server, NULL,
2134 MSGLEVEL_CRAP, SILCTXT_STATS,
2135 "Total clients", tmp);
2137 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2138 printformat_module("fe-common/silc", server, NULL,
2139 MSGLEVEL_CRAP, SILCTXT_STATS,
2140 "Total channels", tmp);
2142 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2143 printformat_module("fe-common/silc", server, NULL,
2144 MSGLEVEL_CRAP, SILCTXT_STATS,
2145 "Total servers", tmp);
2147 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2148 printformat_module("fe-common/silc", server, NULL,
2149 MSGLEVEL_CRAP, SILCTXT_STATS,
2150 "Total routers", tmp);
2152 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2153 printformat_module("fe-common/silc", server, NULL,
2154 MSGLEVEL_CRAP, SILCTXT_STATS,
2155 "Total server operators", tmp);
2157 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2158 printformat_module("fe-common/silc", server, NULL,
2159 MSGLEVEL_CRAP, SILCTXT_STATS,
2160 "Total router operators", tmp);
2171 SilcClientConnection conn;
2177 SilcSKEPKType pk_type;
2178 SilcVerifyPublicKey completion;
2182 static void verify_public_key_completion(const char *line, void *context)
2184 PublicKeyVerify verify = (PublicKeyVerify)context;
2186 if (line[0] == 'Y' || line[0] == 'y') {
2187 /* Call the completion */
2188 if (verify->completion)
2189 verify->completion(TRUE, verify->context);
2191 /* Save the key for future checking */
2192 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2193 verify->pk_len, SILC_PKCS_FILE_PEM);
2195 /* Call the completion */
2196 if (verify->completion)
2197 verify->completion(FALSE, verify->context);
2199 printformat_module("fe-common/silc", NULL, NULL,
2200 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2201 verify->entity_name ? verify->entity_name :
2205 silc_free(verify->filename);
2206 silc_free(verify->entity);
2207 silc_free(verify->entity_name);
2208 silc_free(verify->pk);
2212 /* Internal routine to verify public key. If the `completion' is provided
2213 it will be called to indicate whether public was verified or not. For
2214 server/router public key this will check for filename that includes the
2215 remote host's IP address and remote host's hostname. */
2218 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2219 const char *name, SilcSocketType conn_type,
2220 unsigned char *pk, SilcUInt32 pk_len,
2221 SilcSKEPKType pk_type,
2222 SilcVerifyPublicKey completion, void *context)
2225 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2226 char *fingerprint, *babbleprint, *format;
2229 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2230 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2231 "server" : "client");
2232 PublicKeyVerify verify;
2234 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2235 printformat_module("fe-common/silc", NULL, NULL,
2236 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2239 completion(FALSE, context);
2243 pw = getpwuid(getuid());
2246 completion(FALSE, context);
2250 memset(filename, 0, sizeof(filename));
2251 memset(filename2, 0, sizeof(filename2));
2252 memset(file, 0, sizeof(file));
2254 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2255 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2257 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2258 conn->sock->ip, conn->sock->port);
2259 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2260 get_irssi_dir(), entity, file);
2262 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2263 conn->sock->hostname, conn->sock->port);
2264 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2265 get_irssi_dir(), entity, file);
2270 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2271 name, conn->sock->port);
2272 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2273 get_irssi_dir(), entity, file);
2278 /* Replace all whitespaces with `_'. */
2279 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2280 for (i = 0; i < strlen(fingerprint); i++)
2281 if (fingerprint[i] == ' ')
2282 fingerprint[i] = '_';
2284 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2285 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2286 get_irssi_dir(), entity, file);
2287 silc_free(fingerprint);
2292 /* Take fingerprint of the public key */
2293 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2294 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2296 verify = silc_calloc(1, sizeof(*verify));
2297 verify->client = client;
2298 verify->conn = conn;
2299 verify->filename = strdup(ipf);
2300 verify->entity = strdup(entity);
2301 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2302 (name ? strdup(name) : strdup(conn->sock->hostname))
2304 verify->pk = silc_memdup(pk, pk_len);
2305 verify->pk_len = pk_len;
2306 verify->pk_type = pk_type;
2307 verify->completion = completion;
2308 verify->context = context;
2310 /* Check whether this key already exists */
2311 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2312 /* Key does not exist, ask user to verify the key and save it */
2314 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2315 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2316 verify->entity_name : entity);
2317 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2318 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2319 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2320 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2321 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2322 SILCTXT_PUBKEY_ACCEPT);
2323 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2326 silc_free(fingerprint);
2329 /* The key already exists, verify it. */
2330 SilcPublicKey public_key;
2331 unsigned char *encpk;
2332 SilcUInt32 encpk_len;
2334 /* Load the key file, try for both IP filename and hostname filename */
2335 if (!silc_pkcs_load_public_key(ipf, &public_key,
2336 SILC_PKCS_FILE_PEM) &&
2337 !silc_pkcs_load_public_key(ipf, &public_key,
2338 SILC_PKCS_FILE_BIN) &&
2339 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2340 SILC_PKCS_FILE_PEM) &&
2341 !silc_pkcs_load_public_key(hostf, &public_key,
2342 SILC_PKCS_FILE_BIN)))) {
2343 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2344 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2345 verify->entity_name : entity);
2346 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2347 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2348 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2349 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2350 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2351 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2352 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2353 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2354 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2357 silc_free(fingerprint);
2361 /* Encode the key data */
2362 encpk = silc_pkcs_public_key_encode(public_key, &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_MALFORMED, entity);
2373 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2374 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2375 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2378 silc_free(fingerprint);
2382 /* Compare the keys */
2383 if (memcmp(encpk, pk, encpk_len)) {
2384 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2385 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2386 verify->entity_name : entity);
2387 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2388 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2389 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2390 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2391 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2392 SILCTXT_PUBKEY_NO_MATCH, entity);
2393 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2394 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2395 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2396 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2398 /* Ask user to verify the key and save it */
2399 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2400 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2401 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2404 silc_free(fingerprint);
2408 /* Local copy matched */
2410 completion(TRUE, context);
2411 silc_free(fingerprint);
2412 silc_free(verify->filename);
2413 silc_free(verify->entity);
2414 silc_free(verify->entity_name);
2415 silc_free(verify->pk);
2420 /* Verifies received public key. The `conn_type' indicates which entity
2421 (server, client etc.) has sent the public key. If user decides to trust
2422 the key may be saved as trusted public key for later use. The
2423 `completion' must be called after the public key has been verified. */
2426 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2427 SilcSocketType conn_type, unsigned char *pk,
2428 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2429 SilcVerifyPublicKey completion, void *context)
2431 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2433 completion, context);
2436 /* Asks passphrase from user on the input line. */
2439 SilcAskPassphrase completion;
2443 void ask_passphrase_completion(const char *passphrase, void *context)
2445 AskPassphrase p = (AskPassphrase)context;
2446 if (passphrase && passphrase[0] == '\0')
2448 p->completion((unsigned char *)passphrase,
2449 passphrase ? strlen(passphrase) : 0, p->context);
2453 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2454 SilcAskPassphrase completion, void *context)
2456 AskPassphrase p = silc_calloc(1, sizeof(*p));
2457 p->completion = completion;
2458 p->context = context;
2460 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2461 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2465 SilcGetAuthMeth completion;
2467 } *InternalGetAuthMethod;
2469 /* Callback called when we've received the authentication method information
2470 from the server after we've requested it. This will get the authentication
2471 data from the user if needed. */
2473 static void silc_get_auth_method_callback(SilcClient client,
2474 SilcClientConnection conn,
2475 SilcAuthMethod auth_meth,
2478 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2480 SILC_LOG_DEBUG(("Start"));
2482 switch (auth_meth) {
2483 case SILC_AUTH_NONE:
2484 /* No authentication required. */
2485 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2487 case SILC_AUTH_PASSWORD:
2489 /* Check whether we find the password for this server in our
2490 configuration. If not, then don't provide so library will ask
2491 it from the user. */
2492 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2494 if (!setup || !setup->password) {
2495 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2499 (*internal->completion)(TRUE, auth_meth, setup->password,
2500 strlen(setup->password), internal->context);
2503 case SILC_AUTH_PUBLIC_KEY:
2504 /* Do not get the authentication data now, the library will generate
2505 it using our default key, if we do not provide it here. */
2506 /* XXX In the future when we support multiple local keys and multiple
2507 local certificates we will need to ask from user which one to use. */
2508 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2512 silc_free(internal);
2515 /* Find authentication method and authentication data by hostname and
2516 port. The hostname may be IP address as well. The found authentication
2517 method and authentication data is returned to `auth_meth', `auth_data'
2518 and `auth_data_len'. The function returns TRUE if authentication method
2519 is found and FALSE if not. `conn' may be NULL. */
2521 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2522 char *hostname, SilcUInt16 port,
2523 SilcGetAuthMeth completion, void *context)
2525 InternalGetAuthMethod internal;
2527 SILC_LOG_DEBUG(("Start"));
2529 /* If we do not have this connection configured by the user in a
2530 configuration file then resolve the authentication method from the
2531 server for this session. */
2532 internal = silc_calloc(1, sizeof(*internal));
2533 internal->completion = completion;
2534 internal->context = context;
2536 silc_client_request_authentication_method(client, conn,
2537 silc_get_auth_method_callback,
2541 /* Notifies application that failure packet was received. This is called
2542 if there is some protocol active in the client. The `protocol' is the
2543 protocol context. The `failure' is opaque pointer to the failure
2544 indication. Note, that the `failure' is protocol dependant and application
2545 must explicitly cast it to correct type. Usually `failure' is 32 bit
2546 failure type (see protocol specs for all protocol failure types). */
2548 void silc_failure(SilcClient client, SilcClientConnection conn,
2549 SilcProtocol protocol, void *failure)
2551 SILC_LOG_DEBUG(("Start"));
2553 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2554 SilcSKEStatus status = (SilcSKEStatus)failure;
2556 if (status == SILC_SKE_STATUS_BAD_VERSION)
2557 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2558 SILCTXT_KE_BAD_VERSION);
2559 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2560 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2561 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2562 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2563 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2564 SILCTXT_KE_UNKNOWN_GROUP);
2565 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2566 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2567 SILCTXT_KE_UNKNOWN_CIPHER);
2568 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2569 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2570 SILCTXT_KE_UNKNOWN_PKCS);
2571 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2572 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2573 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2574 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2575 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2576 SILCTXT_KE_UNKNOWN_HMAC);
2577 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2578 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2579 SILCTXT_KE_INCORRECT_SIGNATURE);
2580 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2581 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2582 SILCTXT_KE_INVALID_COOKIE);
2585 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2586 SilcUInt32 err = (SilcUInt32)failure;
2588 if (err == SILC_AUTH_FAILED)
2589 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2590 SILCTXT_AUTH_FAILED);
2594 /* Asks whether the user would like to perform the key agreement protocol.
2595 This is called after we have received an key agreement packet or an
2596 reply to our key agreement packet. This returns TRUE if the user wants
2597 the library to perform the key agreement protocol and FALSE if it is not
2598 desired (application may start it later by calling the function
2599 silc_client_perform_key_agreement). */
2601 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2602 SilcClientEntry client_entry, const char *hostname,
2603 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2608 SILC_LOG_DEBUG(("Start"));
2610 /* We will just display the info on the screen and return FALSE and user
2611 will have to start the key agreement with a command. */
2614 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2617 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2618 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2620 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2621 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2622 client_entry->nickname, hostname, portstr);
2630 /* Notifies application that file transfer protocol session is being
2631 requested by the remote client indicated by the `client_entry' from
2632 the `hostname' and `port'. The `session_id' is the file transfer
2633 session and it can be used to either accept or reject the file
2634 transfer request, by calling the silc_client_file_receive or
2635 silc_client_file_close, respectively. */
2637 void silc_ftp(SilcClient client, SilcClientConnection conn,
2638 SilcClientEntry client_entry, SilcUInt32 session_id,
2639 const char *hostname, SilcUInt16 port)
2641 SILC_SERVER_REC *server;
2643 FtpSession ftp = NULL;
2645 SILC_LOG_DEBUG(("Start"));
2647 server = conn->context;
2649 silc_dlist_start(server->ftp_sessions);
2650 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2651 if (ftp->client_entry == client_entry &&
2652 ftp->session_id == session_id) {
2653 server->current_session = ftp;
2657 if (ftp == SILC_LIST_END) {
2658 ftp = silc_calloc(1, sizeof(*ftp));
2659 ftp->client_entry = client_entry;
2660 ftp->session_id = session_id;
2663 silc_dlist_add(server->ftp_sessions, ftp);
2664 server->current_session = ftp;
2668 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2671 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2672 SILCTXT_FILE_REQUEST, client_entry->nickname);
2674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2675 SILCTXT_FILE_REQUEST_HOST,
2676 client_entry->nickname, hostname, portstr);
2679 /* Delivers SILC session detachment data indicated by `detach_data' to the
2680 application. If application has issued SILC_COMMAND_DETACH command
2681 the client session in the SILC network is not quit. The client remains
2682 in the network but is detached. The detachment data may be used later
2683 to resume the session in the SILC Network. The appliation is
2684 responsible of saving the `detach_data', to for example in a file.
2686 The detachment data can be given as argument to the functions
2687 silc_client_connect_to_server, or silc_client_add_connection when
2688 creating connection to remote server, inside SilcClientConnectionParams
2689 structure. If it is provided the client library will attempt to resume
2690 the session in the network. After the connection is created
2691 successfully, the application is responsible of setting the user
2692 interface for user into the same state it was before detaching (showing
2693 same channels, channel modes, etc). It can do this by fetching the
2694 information (like joined channels) from the client library. */
2697 silc_detach(SilcClient client, SilcClientConnection conn,
2698 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2702 /* Save the detachment data to file. */
2704 memset(file, 0, sizeof(file));
2705 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2706 silc_file_writefile(file, detach_data, detach_data_len);
2710 /* SILC client operations */
2711 SilcClientOperations ops = {
2713 silc_channel_message,
2714 silc_private_message,
2720 silc_get_auth_method,
2721 silc_verify_public_key,
2722 silc_ask_passphrase,