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 memset(buf, 0, sizeof(buf));
585 if (client_entry->username)
586 snprintf(buf, sizeof(buf) - 1, "%s@%s",
587 client_entry->username, client_entry->hostname);
588 signal_emit("message quit", 4, server, client_entry->nickname,
589 client_entry->username ? buf : "",
592 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
593 for (list_tmp = list1; list_tmp != NULL; list_tmp =
594 list_tmp->next->next) {
595 CHANNEL_REC *channel = list_tmp->data;
596 NICK_REC *nickrec = list_tmp->next->data;
598 nicklist_remove(channel, nickrec);
602 case SILC_NOTIFY_TYPE_TOPIC_SET:
607 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
609 idtype = va_arg(va, int);
610 entry = va_arg(va, void *);
611 tmp = va_arg(va, char *);
612 channel = va_arg(va, SilcChannelEntry);
614 chanrec = silc_channel_find_entry(server, channel);
615 if (chanrec != NULL) {
616 char tmp2[256], *cp, *dm = NULL;
618 g_free_not_null(chanrec->topic);
619 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
620 memset(tmp2, 0, sizeof(tmp2));
622 if (strlen(tmp) > sizeof(tmp2) - 1) {
623 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
627 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
632 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
633 signal_emit("channel topic changed", 1, chanrec);
638 if (idtype == SILC_ID_CLIENT) {
639 client_entry = (SilcClientEntry)entry;
640 memset(buf, 0, sizeof(buf));
641 snprintf(buf, sizeof(buf) - 1, "%s@%s",
642 client_entry->username, client_entry->hostname);
643 signal_emit("message topic", 5, server, channel->channel_name,
644 tmp, client_entry->nickname, buf);
645 } else if (idtype == SILC_ID_SERVER) {
646 server_entry = (SilcServerEntry)entry;
647 signal_emit("message topic", 5, server, channel->channel_name,
648 tmp, server_entry->server_name,
649 server_entry->server_name);
650 } else if (idtype == SILC_ID_CHANNEL) {
651 channel = (SilcChannelEntry)entry;
652 signal_emit("message topic", 5, server, channel->channel_name,
653 tmp, channel->channel_name, channel->channel_name);
657 case SILC_NOTIFY_TYPE_NICK_CHANGE:
662 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
664 client_entry = va_arg(va, SilcClientEntry);
665 client_entry2 = va_arg(va, SilcClientEntry);
667 if (!strcmp(client_entry->nickname, client_entry2->nickname))
670 memset(buf, 0, sizeof(buf));
671 snprintf(buf, sizeof(buf) - 1, "%s@%s",
672 client_entry2->username, client_entry2->hostname);
673 nicklist_rename_unique(SERVER(server),
674 client_entry, client_entry->nickname,
675 client_entry2, client_entry2->nickname);
676 signal_emit("message nick", 4, server, client_entry2->nickname,
677 client_entry->nickname, buf);
680 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
682 * Changed channel mode.
685 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
687 idtype = va_arg(va, int);
688 entry = va_arg(va, void *);
689 mode = va_arg(va, SilcUInt32);
690 (void)va_arg(va, char *);
691 (void)va_arg(va, char *);
692 channel = va_arg(va, SilcChannelEntry);
694 tmp = silc_client_chmode(mode,
695 channel->channel_key ?
696 silc_cipher_get_name(channel->channel_key) : "",
698 silc_hmac_get_name(channel->hmac) : "");
700 chanrec = silc_channel_find_entry(server, channel);
701 if (chanrec != NULL) {
702 g_free_not_null(chanrec->mode);
703 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
704 signal_emit("channel mode changed", 1, chanrec);
707 if (idtype == SILC_ID_CLIENT) {
708 client_entry = (SilcClientEntry)entry;
709 printformat_module("fe-common/silc", server, channel->channel_name,
710 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
711 channel->channel_name, tmp ? tmp : "removed all",
712 client_entry->nickname);
713 } else if (idtype == SILC_ID_SERVER) {
714 server_entry = (SilcServerEntry)entry;
715 printformat_module("fe-common/silc", server, channel->channel_name,
716 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
717 channel->channel_name, tmp ? tmp : "removed all",
718 server_entry->server_name);
719 } else if (idtype == SILC_ID_CHANNEL) {
720 channel2 = (SilcChannelEntry)entry;
721 printformat_module("fe-common/silc", server, channel->channel_name,
722 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
723 channel->channel_name, tmp ? tmp : "removed all",
724 channel2->channel_name);
730 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
732 * Changed user's mode on channel.
735 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
737 idtype = va_arg(va, int);
738 entry = va_arg(va, void *);
739 mode = va_arg(va, SilcUInt32);
740 client_entry2 = va_arg(va, SilcClientEntry);
741 channel = va_arg(va, SilcChannelEntry);
743 tmp = silc_client_chumode(mode);
744 chanrec = silc_channel_find_entry(server, channel);
745 if (chanrec != NULL) {
748 if (client_entry2 == server->conn->local_entry)
749 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
751 nick = silc_nicklist_find(chanrec, client_entry2);
753 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
754 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
755 signal_emit("nick mode changed", 2, chanrec, nick);
759 if (idtype == SILC_ID_CLIENT) {
760 client_entry = (SilcClientEntry)entry;
761 printformat_module("fe-common/silc", server, channel->channel_name,
762 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
763 channel->channel_name, client_entry2->nickname,
764 tmp ? tmp : "removed all",
765 client_entry->nickname);
766 } else if (idtype == SILC_ID_SERVER) {
767 server_entry = (SilcServerEntry)entry;
768 printformat_module("fe-common/silc", server, channel->channel_name,
769 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
770 channel->channel_name, client_entry2->nickname,
771 tmp ? tmp : "removed all",
772 server_entry->server_name);
773 } else if (idtype == SILC_ID_CHANNEL) {
774 channel2 = (SilcChannelEntry)entry;
775 printformat_module("fe-common/silc", server, channel->channel_name,
776 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
777 channel->channel_name, client_entry2->nickname,
778 tmp ? tmp : "removed all",
779 channel2->channel_name);
782 if (mode & SILC_CHANNEL_UMODE_CHANFO)
783 printformat_module("fe-common/silc",
784 server, channel->channel_name, MSGLEVEL_CRAP,
785 SILCTXT_CHANNEL_FOUNDER,
786 channel->channel_name, client_entry2->nickname);
788 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
789 printformat_module("fe-common/silc",
790 server, channel->channel_name, MSGLEVEL_CRAP,
791 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
796 case SILC_NOTIFY_TYPE_MOTD:
801 SILC_LOG_DEBUG(("Notify: MOTD"));
803 tmp = va_arg(va, char *);
805 if (!settings_get_bool("skip_motd"))
806 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
809 case SILC_NOTIFY_TYPE_KICKED:
811 * Someone was kicked from channel.
814 SILC_LOG_DEBUG(("Notify: KICKED"));
816 client_entry = va_arg(va, SilcClientEntry);
817 tmp = va_arg(va, char *);
818 client_entry2 = va_arg(va, SilcClientEntry);
819 channel = va_arg(va, SilcChannelEntry);
821 chanrec = silc_channel_find_entry(server, channel);
823 if (client_entry == conn->local_entry) {
824 printformat_module("fe-common/silc", server, channel->channel_name,
825 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
826 channel->channel_name,
827 client_entry ? client_entry2->nickname : "",
830 chanrec->kicked = TRUE;
831 channel_destroy((CHANNEL_REC *)chanrec);
834 printformat_module("fe-common/silc", server, channel->channel_name,
835 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
836 client_entry->nickname, channel->channel_name,
837 client_entry2 ? client_entry2->nickname : "",
841 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
843 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
848 case SILC_NOTIFY_TYPE_KILLED:
850 * Someone was killed from the network.
853 SILC_LOG_DEBUG(("Notify: KILLED"));
855 client_entry = va_arg(va, SilcClientEntry);
856 tmp = va_arg(va, char *);
857 idtype = va_arg(va, int);
858 entry = va_arg(va, SilcClientEntry);
860 if (client_entry == conn->local_entry) {
861 if (idtype == SILC_ID_CLIENT) {
862 client_entry2 = (SilcClientEntry)entry;
863 printformat_module("fe-common/silc", server, NULL,
864 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
865 client_entry2 ? client_entry2->nickname : "",
867 } else if (idtype == SILC_ID_SERVER) {
868 server_entry = (SilcServerEntry)entry;
869 printformat_module("fe-common/silc", server, NULL,
870 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
871 server_entry->server_name, tmp ? tmp : "");
872 } else if (idtype == SILC_ID_CHANNEL) {
873 channel = (SilcChannelEntry)entry;
874 printformat_module("fe-common/silc", server, NULL,
875 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
876 channel->channel_name, tmp ? tmp : "");
879 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
880 for (list_tmp = list1; list_tmp != NULL; list_tmp =
881 list_tmp->next->next) {
882 CHANNEL_REC *channel = list_tmp->data;
883 NICK_REC *nickrec = list_tmp->next->data;
884 nicklist_remove(channel, nickrec);
887 if (idtype == SILC_ID_CLIENT) {
888 client_entry2 = (SilcClientEntry)entry;
889 printformat_module("fe-common/silc", server, NULL,
890 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
891 client_entry->nickname,
892 client_entry2 ? client_entry2->nickname : "",
894 } else if (idtype == SILC_ID_SERVER) {
895 server_entry = (SilcServerEntry)entry;
896 printformat_module("fe-common/silc", server, NULL,
897 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
898 client_entry->nickname,
899 server_entry->server_name, tmp ? tmp : "");
900 } else if (idtype == SILC_ID_CHANNEL) {
901 channel = (SilcChannelEntry)entry;
902 printformat_module("fe-common/silc", server, NULL,
903 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
904 client_entry->nickname,
905 channel->channel_name, tmp ? tmp : "");
910 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
913 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
916 * Server has quit the network.
919 SilcClientEntry *clients;
920 SilcUInt32 clients_count;
922 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
924 (void)va_arg(va, void *);
925 clients = va_arg(va, SilcClientEntry *);
926 clients_count = va_arg(va, SilcUInt32);
928 for (i = 0; i < clients_count; i++) {
929 memset(buf, 0, sizeof(buf));
930 if (clients[i]->username)
931 snprintf(buf, sizeof(buf) - 1, "%s@%s",
932 clients[i]->username, clients[i]->hostname);
933 signal_emit("message quit", 4, server, clients[i]->nickname,
934 clients[i]->username ? buf : "",
937 silc_server_free_ftp(server, clients[i]);
939 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
940 for (list_tmp = list1; list_tmp != NULL; list_tmp =
941 list_tmp->next->next) {
942 CHANNEL_REC *channel = list_tmp->data;
943 NICK_REC *nickrec = list_tmp->next->data;
944 nicklist_remove(channel, nickrec);
950 case SILC_NOTIFY_TYPE_ERROR:
952 SilcStatus error = va_arg(va, int);
954 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
955 "%s", silc_get_status_message(error));
959 case SILC_NOTIFY_TYPE_WATCH:
961 SilcNotifyType notify;
963 client_entry = va_arg(va, SilcClientEntry);
964 name = va_arg(va, char *); /* Maybe NULL */
965 mode = va_arg(va, SilcUInt32);
966 notify = va_arg(va, int);
968 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
970 printformat_module("fe-common/silc", server, NULL,
971 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
972 client_entry->nickname, name);
974 printformat_module("fe-common/silc", server, NULL,
975 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
976 client_entry->nickname);
977 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
978 /* See if client was away and is now present */
979 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
980 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
981 SILC_UMODE_DETACHED)) &&
982 (client_entry->mode & SILC_UMODE_GONE ||
983 client_entry->mode & SILC_UMODE_INDISPOSED ||
984 client_entry->mode & SILC_UMODE_BUSY ||
985 client_entry->mode & SILC_UMODE_PAGE ||
986 client_entry->mode & SILC_UMODE_DETACHED)) {
987 printformat_module("fe-common/silc", server, NULL,
988 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
989 client_entry->nickname);
993 memset(buf, 0, sizeof(buf));
994 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
995 printformat_module("fe-common/silc", server, NULL,
996 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
997 client_entry->nickname, buf);
999 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1000 printformat_module("fe-common/silc", server, NULL,
1001 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1002 client_entry->nickname);
1003 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1004 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1005 printformat_module("fe-common/silc", server, NULL,
1006 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1007 client_entry->nickname);
1008 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1009 /* Client logged in to the network */
1010 printformat_module("fe-common/silc", server, NULL,
1011 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1012 client_entry->nickname);
1018 /* Unknown notify */
1019 printformat_module("fe-common/silc", server, NULL,
1020 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1027 /* Called to indicate that connection was either successfully established
1028 or connecting failed. This is also the first time application receives
1029 the SilcClientConnection object which it should save somewhere. */
1031 void silc_connect(SilcClient client, SilcClientConnection conn,
1032 SilcClientConnectionStatus status)
1034 SILC_SERVER_REC *server = conn->context;
1036 if (!server || server->disconnected) {
1037 silc_client_close_connection(client, conn);
1042 case SILC_CLIENT_CONN_SUCCESS:
1043 /* We have successfully connected to server */
1044 server->connected = TRUE;
1045 signal_emit("event connected", 1, server);
1048 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1049 /* We have successfully resumed old detached session */
1050 server->connected = TRUE;
1051 signal_emit("event connected", 1, server);
1053 /* If we resumed old session check whether we need to update
1055 if (strcmp(server->nick, conn->local_entry->nickname)) {
1057 old = g_strdup(server->nick);
1058 server_change_nick(SERVER(server), conn->local_entry->nickname);
1059 nicklist_rename_unique(SERVER(server),
1060 conn->local_entry, server->nick,
1061 conn->local_entry, conn->local_entry->nickname);
1062 signal_emit("message own_nick", 4, server, server->nick, old, "");
1068 server->connection_lost = TRUE;
1070 server->conn->context = NULL;
1071 server_disconnect(SERVER(server));
1076 /* Called to indicate that connection was disconnected to the server. */
1078 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1079 SilcStatus status, const char *message)
1081 SILC_SERVER_REC *server = conn->context;
1083 SILC_LOG_DEBUG(("Start"));
1085 if (!server || server->connection_lost)
1088 if (server->conn && server->conn->local_entry) {
1089 nicklist_rename_unique(SERVER(server),
1090 server->conn->local_entry, server->nick,
1091 server->conn->local_entry,
1092 silc_client->username);
1093 silc_change_nick(server, silc_client->username);
1097 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1098 "Server closed connection: %s (%d) %s",
1099 silc_get_status_message(status), status,
1100 message ? message : "");
1102 server->conn->context = NULL;
1103 server->conn = NULL;
1104 server->connection_lost = TRUE;
1105 server_disconnect(SERVER(server));
1108 /* Command handler. This function is called always in the command function.
1109 If error occurs it will be called as well. `conn' is the associated
1110 client connection. `cmd_context' is the command context that was
1111 originally sent to the command. `success' is FALSE if error occured
1112 during command. `command' is the command being processed. It must be
1113 noted that this is not reply from server. This is merely called just
1114 after application has called the command. Just to tell application
1115 that the command really was processed. */
1117 void silc_command(SilcClient client, SilcClientConnection conn,
1118 SilcClientCommandContext cmd_context, bool success,
1119 SilcCommand command, SilcStatus status)
1121 SILC_SERVER_REC *server = conn->context;
1123 SILC_LOG_DEBUG(("Start"));
1126 silc_say_error("%s", silc_get_status_message(status));
1132 case SILC_COMMAND_INVITE:
1133 if (cmd_context->argc > 2)
1134 printformat_module("fe-common/silc", server, NULL,
1135 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1136 cmd_context->argv[2],
1137 (cmd_context->argv[1][0] == '*' ?
1138 (char *)conn->current_channel->channel_name :
1139 (char *)cmd_context->argv[1]));
1142 case SILC_COMMAND_DETACH:
1143 server->no_reconnect = TRUE;
1151 /* Client info resolving callback when JOIN command reply is received.
1152 This will cache all users on the channel. */
1154 static void silc_client_join_get_users(SilcClient client,
1155 SilcClientConnection conn,
1156 SilcClientEntry *clients,
1157 SilcUInt32 clients_count,
1160 SilcChannelEntry channel = (SilcChannelEntry)context;
1161 SilcHashTableList htl;
1162 SilcChannelUser chu;
1163 SILC_SERVER_REC *server = conn->context;
1164 SILC_CHANNEL_REC *chanrec;
1165 SilcClientEntry founder = NULL;
1168 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1169 silc_hash_table_count(channel->user_list)));
1174 chanrec = silc_channel_find(server, channel->channel_name);
1175 if (chanrec == NULL)
1178 silc_hash_table_list(channel->user_list, &htl);
1179 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1180 if (!chu->client->nickname)
1182 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1183 founder = chu->client;
1184 silc_nicklist_insert(chanrec, chu, FALSE);
1186 silc_hash_table_list_reset(&htl);
1188 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1189 nicklist_set_own(CHANNEL(chanrec), ownnick);
1190 signal_emit("channel joined", 1, chanrec);
1191 chanrec->entry = channel;
1194 printformat_module("fe-common/silc", server, channel->channel_name,
1195 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1196 channel->channel_name, chanrec->topic);
1199 if (founder == conn->local_entry)
1200 printformat_module("fe-common/silc",
1201 server, channel->channel_name, MSGLEVEL_CRAP,
1202 SILCTXT_CHANNEL_FOUNDER_YOU,
1203 channel->channel_name);
1205 printformat_module("fe-common/silc",
1206 server, channel->channel_name, MSGLEVEL_CRAP,
1207 SILCTXT_CHANNEL_FOUNDER,
1208 channel->channel_name, founder->nickname);
1214 SilcClientConnection conn;
1220 void silc_getkey_cb(bool success, void *context)
1222 GetkeyContext getkey = (GetkeyContext)context;
1223 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1224 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1225 ((SilcClientEntry)getkey->entry)->nickname :
1226 ((SilcServerEntry)getkey->entry)->server_name);
1229 printformat_module("fe-common/silc", NULL, NULL,
1230 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1232 printformat_module("fe-common/silc", NULL, NULL,
1233 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1237 silc_free(getkey->fingerprint);
1241 /* Parse an invite or ban list */
1242 void silc_parse_inviteban_list(SilcClient client,
1243 SilcClientConnection conn,
1244 SILC_SERVER_REC *server,
1245 SilcChannelEntry channel,
1246 const char *list_type,
1247 SilcArgumentPayload list)
1250 SilcUInt32 type, len;
1251 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1252 int counter=0, resolving = FALSE;
1254 if (!silc_argument_get_arg_num(list)) {
1255 printformat_module("fe-common/silc", server,
1256 (chanrec ? chanrec->visible_name : NULL),
1257 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1258 channel->channel_name, list_type);
1262 printformat_module("fe-common/silc", server,
1263 (chanrec ? chanrec->visible_name : NULL),
1264 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1265 channel->channel_name, list_type);
1267 /* parse the list */
1268 tmp = silc_argument_get_first_arg(list, &type, &len);
1273 /* an invite string */
1277 if (tmp[len-1] == ',')
1280 list = g_strsplit(tmp, ",", -1);
1282 printformat_module("fe-common/silc", server,
1283 (chanrec ? chanrec->visible_name : NULL),
1284 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1285 ++counter, channel->channel_name, list_type,
1294 char *fingerprint, *babbleprint;
1296 /* tmp is Public Key Payload, take public key from it. */
1297 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1298 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1300 printformat_module("fe-common/silc", server,
1301 (chanrec ? chanrec->visible_name : NULL),
1302 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1303 ++counter, channel->channel_name, list_type,
1304 fingerprint, babbleprint);
1311 SilcClientID *client_id;
1312 SilcClientEntry client_entry;
1314 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1316 if (client_id == NULL) {
1317 silc_say_error("Invalid data in %s list encountered", list_type);
1321 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1324 printformat_module("fe-common/silc", server,
1325 (chanrec ? chanrec->visible_name : NULL),
1326 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1327 ++counter, channel->channel_name, list_type,
1328 client_entry->nickname);
1331 silc_client_get_client_by_id_resolve(client, conn, client_id,
1335 silc_free(client_id);
1341 silc_say_error("Unkown type in %s list: %u (len %u)",
1342 list_type, type, len);
1344 tmp = silc_argument_get_next_arg(list, &type, &len);
1348 printformat_module("fe-common/silc", server,
1349 (chanrec ? chanrec->visible_name : NULL),
1350 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1351 list_type, channel->channel_name);
1354 /* Command reply handler. This function is called always in the command reply
1355 function. If error occurs it will be called as well. Normal scenario
1356 is that it will be called after the received command data has been parsed
1357 and processed. The function is used to pass the received command data to
1360 `conn' is the associated client connection. `cmd_payload' is the command
1361 payload data received from server and it can be ignored. It is provided
1362 if the application would like to re-parse the received command data,
1363 however, it must be noted that the data is parsed already by the library
1364 thus the payload can be ignored. `success' is FALSE if error occured.
1365 In this case arguments are not sent to the application. `command' is the
1366 command reply being processed. The function has variable argument list
1367 and each command defines the number and type of arguments it passes to the
1368 application (on error they are not sent). */
1371 silc_command_reply(SilcClient client, SilcClientConnection conn,
1372 SilcCommandPayload cmd_payload, bool success,
1373 SilcCommand command, SilcStatus status, ...)
1376 SILC_SERVER_REC *server = conn->context;
1377 SILC_CHANNEL_REC *chanrec;
1380 va_start(vp, status);
1382 SILC_LOG_DEBUG(("Start"));
1385 case SILC_COMMAND_WHOIS:
1387 char buf[1024], *nickname, *username, *realname, *nick;
1388 unsigned char *fingerprint;
1389 SilcUInt32 idle, mode;
1390 SilcBuffer channels, user_modes;
1391 SilcClientEntry client_entry;
1394 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1395 /* Print the unknown nick for user */
1396 unsigned char *tmp =
1397 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1400 silc_say_error("%s: %s", tmp,
1401 silc_get_status_message(status));
1403 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1404 /* Try to find the entry for the unknown client ID, since we
1405 might have, and print the nickname of it for user. */
1407 unsigned char *tmp =
1408 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1411 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1414 client_entry = silc_client_get_client_by_id(client, conn,
1416 if (client_entry && client_entry->nickname)
1417 silc_say_error("%s: %s", client_entry->nickname,
1418 silc_get_status_message(status));
1419 silc_free(client_id);
1423 } else if (!success) {
1424 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1428 client_entry = va_arg(vp, SilcClientEntry);
1429 nickname = va_arg(vp, char *);
1430 username = va_arg(vp, char *);
1431 realname = va_arg(vp, char *);
1432 channels = va_arg(vp, SilcBuffer);
1433 mode = va_arg(vp, SilcUInt32);
1434 idle = va_arg(vp, SilcUInt32);
1435 fingerprint = va_arg(vp, unsigned char *);
1436 user_modes = va_arg(vp, SilcBuffer);
1437 attrs = va_arg(vp, SilcDList);
1439 silc_parse_userfqdn(nickname, &nick, NULL);
1440 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1441 SILCTXT_WHOIS_USERINFO, nickname,
1442 client_entry->username, client_entry->hostname,
1443 nick, client_entry->nickname);
1444 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1445 SILCTXT_WHOIS_REALNAME, realname);
1448 if (channels && user_modes) {
1450 SilcDList list = silc_channel_payload_parse_list(channels->data,
1452 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1454 SilcChannelPayload entry;
1457 memset(buf, 0, sizeof(buf));
1458 silc_dlist_start(list);
1459 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1460 SilcUInt32 name_len;
1461 char *m = silc_client_chumode_char(umodes[i++]);
1462 char *name = silc_channel_get_name(entry, &name_len);
1465 strncat(buf, m, strlen(m));
1466 strncat(buf, name, name_len);
1467 strncat(buf, " ", 1);
1471 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1472 SILCTXT_WHOIS_CHANNELS, buf);
1473 silc_channel_payload_list_free(list);
1479 memset(buf, 0, sizeof(buf));
1480 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1481 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1482 SILCTXT_WHOIS_MODES, buf);
1485 if (idle && nickname) {
1486 memset(buf, 0, sizeof(buf));
1487 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1488 idle > 60 ? (idle / 60) : idle,
1489 idle > 60 ? "minutes" : "seconds");
1491 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1492 SILCTXT_WHOIS_IDLE, buf);
1496 fingerprint = silc_fingerprint(fingerprint, 20);
1497 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1498 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1499 silc_free(fingerprint);
1503 silc_query_attributes_print(server, silc_client, conn, attrs,
1508 case SILC_COMMAND_IDENTIFY:
1510 SilcClientEntry client_entry;
1512 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1513 /* Print the unknown nick for user */
1514 unsigned char *tmp =
1515 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1518 silc_say_error("%s: %s", tmp,
1519 silc_get_status_message(status));
1521 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1522 /* Try to find the entry for the unknown client ID, since we
1523 might have, and print the nickname of it for user. */
1525 unsigned char *tmp =
1526 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1529 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1532 client_entry = silc_client_get_client_by_id(client, conn,
1534 if (client_entry && client_entry->nickname)
1535 silc_say_error("%s: %s", client_entry->nickname,
1536 silc_get_status_message(status));
1537 silc_free(client_id);
1546 case SILC_COMMAND_WHOWAS:
1548 char *nickname, *username, *realname;
1550 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1551 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1553 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1556 silc_say_error("%s: %s", tmp,
1557 silc_get_status_message(status));
1559 } else if (!success) {
1560 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1564 (void)va_arg(vp, SilcClientEntry);
1565 nickname = va_arg(vp, char *);
1566 username = va_arg(vp, char *);
1567 realname = va_arg(vp, char *);
1569 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1570 SILCTXT_WHOWAS_USERINFO, nickname, username,
1571 realname ? realname : "");
1575 case SILC_COMMAND_INVITE:
1577 SilcChannelEntry channel;
1579 SilcArgumentPayload invite_list;
1585 channel = va_arg(vp, SilcChannelEntry);
1586 payload = va_arg(vp, SilcBuffer);
1589 SILC_GET16_MSB(argc, payload->data);
1590 invite_list = silc_argument_payload_parse(payload->data + 2,
1591 payload->len - 2, argc);
1593 silc_parse_inviteban_list(client, conn, server, channel,
1594 "invite", invite_list);
1595 silc_argument_payload_free(invite_list);
1601 case SILC_COMMAND_JOIN:
1603 char *channel, *mode, *topic;
1605 SilcChannelEntry channel_entry;
1606 SilcBuffer client_id_list;
1607 SilcUInt32 list_count;
1612 channel = va_arg(vp, char *);
1613 channel_entry = va_arg(vp, SilcChannelEntry);
1614 modei = va_arg(vp, SilcUInt32);
1615 (void)va_arg(vp, SilcUInt32);
1616 (void)va_arg(vp, unsigned char *);
1617 (void)va_arg(vp, unsigned char *);
1618 (void)va_arg(vp, unsigned char *);
1619 topic = va_arg(vp, char *);
1620 (void)va_arg(vp, unsigned char *);
1621 list_count = va_arg(vp, SilcUInt32);
1622 client_id_list = va_arg(vp, SilcBuffer);
1624 chanrec = silc_channel_find(server, channel);
1626 chanrec = silc_channel_create(server, channel, channel, TRUE);
1629 char tmp[256], *cp, *dm = NULL;
1630 g_free_not_null(chanrec->topic);
1632 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1633 memset(tmp, 0, sizeof(tmp));
1635 if (strlen(topic) > sizeof(tmp) - 1) {
1636 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1640 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1645 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1646 signal_emit("channel topic changed", 1, chanrec);
1651 mode = silc_client_chmode(modei,
1652 channel_entry->channel_key ?
1653 silc_cipher_get_name(channel_entry->
1655 channel_entry->hmac ?
1656 silc_hmac_get_name(channel_entry->hmac) : "");
1657 g_free_not_null(chanrec->mode);
1658 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1659 signal_emit("channel mode changed", 1, chanrec);
1661 /* Resolve the client information */
1662 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1663 silc_client_join_get_users,
1669 case SILC_COMMAND_NICK:
1672 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1678 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1679 if (nicks != NULL) {
1681 SilcClientEntry collider, old;
1683 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1684 collider = silc_client_get_client_by_id(client, conn,
1687 memset(buf, 0, sizeof(buf));
1688 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1689 collider->username, collider->hostname);
1690 nicklist_rename_unique(SERVER(server),
1692 collider, collider->nickname);
1693 silc_print_nick_change(server, collider->nickname,
1694 client_entry->nickname, buf);
1695 g_slist_free(nicks);
1698 old = g_strdup(server->nick);
1699 server_change_nick(SERVER(server), client_entry->nickname);
1700 nicklist_rename_unique(SERVER(server),
1701 server->conn->local_entry, server->nick,
1702 client_entry, client_entry->nickname);
1703 signal_emit("message own_nick", 4, server, server->nick, old, "");
1708 case SILC_COMMAND_LIST:
1713 char tmp[256], *cp, *dm = NULL;
1718 (void)va_arg(vp, SilcChannelEntry);
1719 name = va_arg(vp, char *);
1720 topic = va_arg(vp, char *);
1721 usercount = va_arg(vp, int);
1723 if (topic && !silc_term_utf8() &&
1724 silc_utf8_valid(topic, strlen(topic))) {
1725 memset(tmp, 0, sizeof(tmp));
1727 if (strlen(topic) > sizeof(tmp) - 1) {
1728 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1732 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1737 if (status == SILC_STATUS_LIST_START ||
1738 status == SILC_STATUS_OK)
1739 printformat_module("fe-common/silc", server, NULL,
1740 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1743 snprintf(users, sizeof(users) - 1, "N/A");
1745 snprintf(users, sizeof(users) - 1, "%d", usercount);
1746 printformat_module("fe-common/silc", server, NULL,
1747 MSGLEVEL_CRAP, SILCTXT_LIST,
1748 name, users, topic ? topic : "");
1753 case SILC_COMMAND_UMODE:
1761 mode = va_arg(vp, SilcUInt32);
1763 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1764 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1765 printformat_module("fe-common/silc", server, NULL,
1766 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1768 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1769 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1770 printformat_module("fe-common/silc", server, NULL,
1771 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1773 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1774 if (mode & SILC_UMODE_GONE) {
1775 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1776 reason = g_strdup(server->away_reason);
1778 reason = g_strdup("away");
1780 reason = g_strdup("");
1782 silc_set_away(reason, server);
1787 server->umode = mode;
1788 signal_emit("user mode changed", 2, server, NULL);
1792 case SILC_COMMAND_OPER:
1796 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1797 signal_emit("user mode changed", 2, server, NULL);
1799 printformat_module("fe-common/silc", server, NULL,
1800 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1803 case SILC_COMMAND_SILCOPER:
1807 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1808 signal_emit("user mode changed", 2, server, NULL);
1810 printformat_module("fe-common/silc", server, NULL,
1811 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1814 case SILC_COMMAND_USERS:
1816 SilcHashTableList htl;
1817 SilcChannelEntry channel;
1818 SilcChannelUser chu;
1823 channel = va_arg(vp, SilcChannelEntry);
1825 printformat_module("fe-common/silc", server, channel->channel_name,
1826 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1827 channel->channel_name);
1829 silc_hash_table_list(channel->user_list, &htl);
1830 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1831 SilcClientEntry e = chu->client;
1832 char stat[5], *mode;
1837 memset(stat, 0, sizeof(stat));
1838 mode = silc_client_chumode_char(chu->mode);
1839 if (e->mode & SILC_UMODE_GONE)
1841 else if (e->mode & SILC_UMODE_INDISPOSED)
1843 else if (e->mode & SILC_UMODE_BUSY)
1845 else if (e->mode & SILC_UMODE_PAGE)
1847 else if (e->mode & SILC_UMODE_HYPER)
1849 else if (e->mode & SILC_UMODE_ROBOT)
1851 else if (e->mode & SILC_UMODE_ANONYMOUS)
1858 printformat_module("fe-common/silc", server, channel->channel_name,
1859 MSGLEVEL_CRAP, SILCTXT_USERS,
1861 e->username ? e->username : "",
1862 e->hostname ? e->hostname : "",
1863 e->realname ? e->realname : "");
1867 silc_hash_table_list_reset(&htl);
1871 case SILC_COMMAND_BAN:
1873 SilcChannelEntry channel;
1875 SilcArgumentPayload ban_list;
1881 channel = va_arg(vp, SilcChannelEntry);
1882 payload = va_arg(vp, SilcBuffer);
1885 SILC_GET16_MSB(argc, payload->data);
1886 ban_list = silc_argument_payload_parse(payload->data + 2,
1887 payload->len - 2, argc);
1889 silc_parse_inviteban_list(client, conn, server, channel,
1891 silc_argument_payload_free(ban_list);
1897 case SILC_COMMAND_GETKEY:
1901 SilcPublicKey public_key;
1904 GetkeyContext getkey;
1910 id_type = va_arg(vp, SilcUInt32);
1911 entry = va_arg(vp, void *);
1912 public_key = va_arg(vp, SilcPublicKey);
1915 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1917 getkey = silc_calloc(1, sizeof(*getkey));
1918 getkey->entry = entry;
1919 getkey->id_type = id_type;
1920 getkey->client = client;
1921 getkey->conn = conn;
1922 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1924 name = (id_type == SILC_ID_CLIENT ?
1925 ((SilcClientEntry)entry)->nickname :
1926 ((SilcServerEntry)entry)->server_name);
1928 silc_verify_public_key_internal(client, conn, name,
1929 (id_type == SILC_ID_CLIENT ?
1930 SILC_SOCKET_TYPE_CLIENT :
1931 SILC_SOCKET_TYPE_SERVER),
1932 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1933 silc_getkey_cb, getkey);
1936 printformat_module("fe-common/silc", server, NULL,
1937 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1942 case SILC_COMMAND_INFO:
1944 SilcServerEntry server_entry;
1951 server_entry = va_arg(vp, SilcServerEntry);
1952 server_name = va_arg(vp, char *);
1953 server_info = va_arg(vp, char *);
1955 if (server_name && server_info )
1957 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1958 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1963 case SILC_COMMAND_TOPIC:
1965 SilcChannelEntry channel;
1967 char tmp[256], *cp, *dm = NULL;
1972 channel = va_arg(vp, SilcChannelEntry);
1973 topic = va_arg(vp, char *);
1975 if (topic && !silc_term_utf8() &&
1976 silc_utf8_valid(topic, strlen(topic))) {
1977 memset(tmp, 0, sizeof(tmp));
1979 if (strlen(topic) > sizeof(tmp) - 1) {
1980 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1984 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1990 chanrec = silc_channel_find_entry(server, channel);
1992 g_free_not_null(chanrec->topic);
1993 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1994 signal_emit("channel topic changed", 1, chanrec);
1996 printformat_module("fe-common/silc", server, channel->channel_name,
1997 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1998 channel->channel_name, topic);
2000 printformat_module("fe-common/silc", server, channel->channel_name,
2001 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2002 channel->channel_name);
2008 case SILC_COMMAND_WATCH:
2011 case SILC_COMMAND_STATS:
2013 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2014 my_router_ops, cell_clients, cell_channels, cell_servers,
2015 clients, channels, servers, routers, server_ops, router_ops;
2017 SilcBufferStruct buf;
2018 unsigned char *tmp_buf;
2020 const char *tmptime;
2021 int days, hours, mins, secs;
2026 tmp_buf = va_arg(vp, unsigned char *);
2027 buf_len = va_arg(vp, SilcUInt32);
2029 if (!tmp_buf || !buf_len) {
2030 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2034 /* Get statistics structure */
2035 silc_buffer_set(&buf, tmp_buf, buf_len);
2036 silc_buffer_unformat(&buf,
2037 SILC_STR_UI_INT(&starttime),
2038 SILC_STR_UI_INT(&uptime),
2039 SILC_STR_UI_INT(&my_clients),
2040 SILC_STR_UI_INT(&my_channels),
2041 SILC_STR_UI_INT(&my_server_ops),
2042 SILC_STR_UI_INT(&my_router_ops),
2043 SILC_STR_UI_INT(&cell_clients),
2044 SILC_STR_UI_INT(&cell_channels),
2045 SILC_STR_UI_INT(&cell_servers),
2046 SILC_STR_UI_INT(&clients),
2047 SILC_STR_UI_INT(&channels),
2048 SILC_STR_UI_INT(&servers),
2049 SILC_STR_UI_INT(&routers),
2050 SILC_STR_UI_INT(&server_ops),
2051 SILC_STR_UI_INT(&router_ops),
2054 tmptime = silc_get_time(starttime);
2055 printformat_module("fe-common/silc", server, NULL,
2056 MSGLEVEL_CRAP, SILCTXT_STATS,
2057 "Local server start time", tmptime);
2059 days = uptime / (24 * 60 * 60);
2060 uptime -= days * (24 * 60 * 60);
2061 hours = uptime / (60 * 60);
2062 uptime -= hours * (60 * 60);
2064 uptime -= mins * 60;
2066 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2067 days, hours, mins, secs);
2068 printformat_module("fe-common/silc", server, NULL,
2069 MSGLEVEL_CRAP, SILCTXT_STATS,
2070 "Local server uptime", tmp);
2072 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2073 printformat_module("fe-common/silc", server, NULL,
2074 MSGLEVEL_CRAP, SILCTXT_STATS,
2075 "Local server clients", tmp);
2077 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2078 printformat_module("fe-common/silc", server, NULL,
2079 MSGLEVEL_CRAP, SILCTXT_STATS,
2080 "Local server channels", tmp);
2082 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2083 printformat_module("fe-common/silc", server, NULL,
2084 MSGLEVEL_CRAP, SILCTXT_STATS,
2085 "Local server operators", tmp);
2087 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2088 printformat_module("fe-common/silc", server, NULL,
2089 MSGLEVEL_CRAP, SILCTXT_STATS,
2090 "Local router operators", tmp);
2092 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2093 printformat_module("fe-common/silc", server, NULL,
2094 MSGLEVEL_CRAP, SILCTXT_STATS,
2095 "Local cell clients", tmp);
2097 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2098 printformat_module("fe-common/silc", server, NULL,
2099 MSGLEVEL_CRAP, SILCTXT_STATS,
2100 "Local cell channels", tmp);
2102 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2103 printformat_module("fe-common/silc", server, NULL,
2104 MSGLEVEL_CRAP, SILCTXT_STATS,
2105 "Local cell servers", tmp);
2107 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2108 printformat_module("fe-common/silc", server, NULL,
2109 MSGLEVEL_CRAP, SILCTXT_STATS,
2110 "Total clients", tmp);
2112 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2113 printformat_module("fe-common/silc", server, NULL,
2114 MSGLEVEL_CRAP, SILCTXT_STATS,
2115 "Total channels", tmp);
2117 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2118 printformat_module("fe-common/silc", server, NULL,
2119 MSGLEVEL_CRAP, SILCTXT_STATS,
2120 "Total servers", tmp);
2122 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2123 printformat_module("fe-common/silc", server, NULL,
2124 MSGLEVEL_CRAP, SILCTXT_STATS,
2125 "Total routers", tmp);
2127 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2128 printformat_module("fe-common/silc", server, NULL,
2129 MSGLEVEL_CRAP, SILCTXT_STATS,
2130 "Total server operators", tmp);
2132 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2133 printformat_module("fe-common/silc", server, NULL,
2134 MSGLEVEL_CRAP, SILCTXT_STATS,
2135 "Total router operators", tmp);
2146 SilcClientConnection conn;
2152 SilcSKEPKType pk_type;
2153 SilcVerifyPublicKey completion;
2157 static void verify_public_key_completion(const char *line, void *context)
2159 PublicKeyVerify verify = (PublicKeyVerify)context;
2161 if (line[0] == 'Y' || line[0] == 'y') {
2162 /* Call the completion */
2163 if (verify->completion)
2164 verify->completion(TRUE, verify->context);
2166 /* Save the key for future checking */
2167 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2168 verify->pk_len, SILC_PKCS_FILE_PEM);
2170 /* Call the completion */
2171 if (verify->completion)
2172 verify->completion(FALSE, verify->context);
2174 printformat_module("fe-common/silc", NULL, NULL,
2175 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2176 verify->entity_name ? verify->entity_name :
2180 silc_free(verify->filename);
2181 silc_free(verify->entity);
2182 silc_free(verify->entity_name);
2183 silc_free(verify->pk);
2187 /* Internal routine to verify public key. If the `completion' is provided
2188 it will be called to indicate whether public was verified or not. For
2189 server/router public key this will check for filename that includes the
2190 remote host's IP address and remote host's hostname. */
2193 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2194 const char *name, SilcSocketType conn_type,
2195 unsigned char *pk, SilcUInt32 pk_len,
2196 SilcSKEPKType pk_type,
2197 SilcVerifyPublicKey completion, void *context)
2200 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2201 char *fingerprint, *babbleprint, *format;
2204 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2205 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2206 "server" : "client");
2207 PublicKeyVerify verify;
2209 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2210 printformat_module("fe-common/silc", NULL, NULL,
2211 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2214 completion(FALSE, context);
2218 pw = getpwuid(getuid());
2221 completion(FALSE, context);
2225 memset(filename, 0, sizeof(filename));
2226 memset(filename2, 0, sizeof(filename2));
2227 memset(file, 0, sizeof(file));
2229 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2230 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2232 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2233 conn->sock->ip, conn->sock->port);
2234 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2235 get_irssi_dir(), entity, file);
2237 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2238 conn->sock->hostname, conn->sock->port);
2239 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2240 get_irssi_dir(), entity, file);
2245 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2246 name, conn->sock->port);
2247 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2248 get_irssi_dir(), entity, file);
2253 /* Replace all whitespaces with `_'. */
2254 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2255 for (i = 0; i < strlen(fingerprint); i++)
2256 if (fingerprint[i] == ' ')
2257 fingerprint[i] = '_';
2259 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2260 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2261 get_irssi_dir(), entity, file);
2262 silc_free(fingerprint);
2267 /* Take fingerprint of the public key */
2268 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2269 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2271 verify = silc_calloc(1, sizeof(*verify));
2272 verify->client = client;
2273 verify->conn = conn;
2274 verify->filename = strdup(ipf);
2275 verify->entity = strdup(entity);
2276 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2277 (name ? strdup(name) : strdup(conn->sock->hostname))
2279 verify->pk = silc_memdup(pk, pk_len);
2280 verify->pk_len = pk_len;
2281 verify->pk_type = pk_type;
2282 verify->completion = completion;
2283 verify->context = context;
2285 /* Check whether this key already exists */
2286 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2287 /* Key does not exist, ask user to verify the key and save it */
2289 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2290 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2291 verify->entity_name : entity);
2292 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2293 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2294 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2295 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2296 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2297 SILCTXT_PUBKEY_ACCEPT);
2298 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2301 silc_free(fingerprint);
2304 /* The key already exists, verify it. */
2305 SilcPublicKey public_key;
2306 unsigned char *encpk;
2307 SilcUInt32 encpk_len;
2309 /* Load the key file, try for both IP filename and hostname filename */
2310 if (!silc_pkcs_load_public_key(ipf, &public_key,
2311 SILC_PKCS_FILE_PEM) &&
2312 !silc_pkcs_load_public_key(ipf, &public_key,
2313 SILC_PKCS_FILE_BIN) &&
2314 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2315 SILC_PKCS_FILE_PEM) &&
2316 !silc_pkcs_load_public_key(hostf, &public_key,
2317 SILC_PKCS_FILE_BIN)))) {
2318 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2319 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2320 verify->entity_name : entity);
2321 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2322 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2323 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2324 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2325 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2326 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2327 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2328 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2329 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2332 silc_free(fingerprint);
2336 /* Encode the key data */
2337 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2339 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2340 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2341 verify->entity_name : entity);
2342 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2343 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2344 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2345 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2346 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2347 SILCTXT_PUBKEY_MALFORMED, entity);
2348 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2349 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2350 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2353 silc_free(fingerprint);
2357 /* Compare the keys */
2358 if (memcmp(encpk, pk, encpk_len)) {
2359 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2360 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2361 verify->entity_name : entity);
2362 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2363 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2364 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2365 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2366 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2367 SILCTXT_PUBKEY_NO_MATCH, entity);
2368 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2369 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2370 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2371 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2373 /* Ask user to verify the key and save it */
2374 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2375 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2376 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2379 silc_free(fingerprint);
2383 /* Local copy matched */
2385 completion(TRUE, context);
2386 silc_free(fingerprint);
2387 silc_free(verify->filename);
2388 silc_free(verify->entity);
2389 silc_free(verify->entity_name);
2390 silc_free(verify->pk);
2395 /* Verifies received public key. The `conn_type' indicates which entity
2396 (server, client etc.) has sent the public key. If user decides to trust
2397 the key may be saved as trusted public key for later use. The
2398 `completion' must be called after the public key has been verified. */
2401 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2402 SilcSocketType conn_type, unsigned char *pk,
2403 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2404 SilcVerifyPublicKey completion, void *context)
2406 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2408 completion, context);
2411 /* Asks passphrase from user on the input line. */
2414 SilcAskPassphrase completion;
2418 void ask_passphrase_completion(const char *passphrase, void *context)
2420 AskPassphrase p = (AskPassphrase)context;
2421 if (passphrase && passphrase[0] == '\0')
2423 p->completion((unsigned char *)passphrase,
2424 passphrase ? strlen(passphrase) : 0, p->context);
2428 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2429 SilcAskPassphrase completion, void *context)
2431 AskPassphrase p = silc_calloc(1, sizeof(*p));
2432 p->completion = completion;
2433 p->context = context;
2435 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2436 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2440 SilcGetAuthMeth completion;
2442 } *InternalGetAuthMethod;
2444 /* Callback called when we've received the authentication method information
2445 from the server after we've requested it. This will get the authentication
2446 data from the user if needed. */
2448 static void silc_get_auth_method_callback(SilcClient client,
2449 SilcClientConnection conn,
2450 SilcAuthMethod auth_meth,
2453 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2455 SILC_LOG_DEBUG(("Start"));
2457 switch (auth_meth) {
2458 case SILC_AUTH_NONE:
2459 /* No authentication required. */
2460 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2462 case SILC_AUTH_PASSWORD:
2464 /* Check whether we find the password for this server in our
2465 configuration. If not, then don't provide so library will ask
2466 it from the user. */
2467 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2469 if (!setup || !setup->password) {
2470 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2474 (*internal->completion)(TRUE, auth_meth, setup->password,
2475 strlen(setup->password), internal->context);
2478 case SILC_AUTH_PUBLIC_KEY:
2479 /* Do not get the authentication data now, the library will generate
2480 it using our default key, if we do not provide it here. */
2481 /* XXX In the future when we support multiple local keys and multiple
2482 local certificates we will need to ask from user which one to use. */
2483 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2487 silc_free(internal);
2490 /* Find authentication method and authentication data by hostname and
2491 port. The hostname may be IP address as well. The found authentication
2492 method and authentication data is returned to `auth_meth', `auth_data'
2493 and `auth_data_len'. The function returns TRUE if authentication method
2494 is found and FALSE if not. `conn' may be NULL. */
2496 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2497 char *hostname, SilcUInt16 port,
2498 SilcGetAuthMeth completion, void *context)
2500 InternalGetAuthMethod internal;
2502 SILC_LOG_DEBUG(("Start"));
2504 /* If we do not have this connection configured by the user in a
2505 configuration file then resolve the authentication method from the
2506 server for this session. */
2507 internal = silc_calloc(1, sizeof(*internal));
2508 internal->completion = completion;
2509 internal->context = context;
2511 silc_client_request_authentication_method(client, conn,
2512 silc_get_auth_method_callback,
2516 /* Notifies application that failure packet was received. This is called
2517 if there is some protocol active in the client. The `protocol' is the
2518 protocol context. The `failure' is opaque pointer to the failure
2519 indication. Note, that the `failure' is protocol dependant and application
2520 must explicitly cast it to correct type. Usually `failure' is 32 bit
2521 failure type (see protocol specs for all protocol failure types). */
2523 void silc_failure(SilcClient client, SilcClientConnection conn,
2524 SilcProtocol protocol, void *failure)
2526 SILC_LOG_DEBUG(("Start"));
2528 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2529 SilcSKEStatus status = (SilcSKEStatus)failure;
2531 if (status == SILC_SKE_STATUS_BAD_VERSION)
2532 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2533 SILCTXT_KE_BAD_VERSION);
2534 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2535 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2536 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2537 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2538 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2539 SILCTXT_KE_UNKNOWN_GROUP);
2540 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2541 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2542 SILCTXT_KE_UNKNOWN_CIPHER);
2543 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2544 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2545 SILCTXT_KE_UNKNOWN_PKCS);
2546 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2547 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2548 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2549 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2550 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2551 SILCTXT_KE_UNKNOWN_HMAC);
2552 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2553 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2554 SILCTXT_KE_INCORRECT_SIGNATURE);
2555 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2556 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2557 SILCTXT_KE_INVALID_COOKIE);
2560 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2561 SilcUInt32 err = (SilcUInt32)failure;
2563 if (err == SILC_AUTH_FAILED)
2564 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2565 SILCTXT_AUTH_FAILED);
2569 /* Asks whether the user would like to perform the key agreement protocol.
2570 This is called after we have received an key agreement packet or an
2571 reply to our key agreement packet. This returns TRUE if the user wants
2572 the library to perform the key agreement protocol and FALSE if it is not
2573 desired (application may start it later by calling the function
2574 silc_client_perform_key_agreement). */
2576 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2577 SilcClientEntry client_entry, const char *hostname,
2578 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2583 SILC_LOG_DEBUG(("Start"));
2585 /* We will just display the info on the screen and return FALSE and user
2586 will have to start the key agreement with a command. */
2589 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2592 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2593 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2595 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2596 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2597 client_entry->nickname, hostname, portstr);
2605 /* Notifies application that file transfer protocol session is being
2606 requested by the remote client indicated by the `client_entry' from
2607 the `hostname' and `port'. The `session_id' is the file transfer
2608 session and it can be used to either accept or reject the file
2609 transfer request, by calling the silc_client_file_receive or
2610 silc_client_file_close, respectively. */
2612 void silc_ftp(SilcClient client, SilcClientConnection conn,
2613 SilcClientEntry client_entry, SilcUInt32 session_id,
2614 const char *hostname, SilcUInt16 port)
2616 SILC_SERVER_REC *server;
2618 FtpSession ftp = NULL;
2620 SILC_LOG_DEBUG(("Start"));
2622 server = conn->context;
2624 silc_dlist_start(server->ftp_sessions);
2625 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2626 if (ftp->client_entry == client_entry &&
2627 ftp->session_id == session_id) {
2628 server->current_session = ftp;
2632 if (ftp == SILC_LIST_END) {
2633 ftp = silc_calloc(1, sizeof(*ftp));
2634 ftp->client_entry = client_entry;
2635 ftp->session_id = session_id;
2638 silc_dlist_add(server->ftp_sessions, ftp);
2639 server->current_session = ftp;
2643 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2646 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2647 SILCTXT_FILE_REQUEST, client_entry->nickname);
2649 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2650 SILCTXT_FILE_REQUEST_HOST,
2651 client_entry->nickname, hostname, portstr);
2654 /* Delivers SILC session detachment data indicated by `detach_data' to the
2655 application. If application has issued SILC_COMMAND_DETACH command
2656 the client session in the SILC network is not quit. The client remains
2657 in the network but is detached. The detachment data may be used later
2658 to resume the session in the SILC Network. The appliation is
2659 responsible of saving the `detach_data', to for example in a file.
2661 The detachment data can be given as argument to the functions
2662 silc_client_connect_to_server, or silc_client_add_connection when
2663 creating connection to remote server, inside SilcClientConnectionParams
2664 structure. If it is provided the client library will attempt to resume
2665 the session in the network. After the connection is created
2666 successfully, the application is responsible of setting the user
2667 interface for user into the same state it was before detaching (showing
2668 same channels, channel modes, etc). It can do this by fetching the
2669 information (like joined channels) from the client library. */
2672 silc_detach(SilcClient client, SilcClientConnection conn,
2673 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2677 /* Save the detachment data to file. */
2679 memset(file, 0, sizeof(file));
2680 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2681 silc_file_writefile(file, detach_data, detach_data_len);
2685 /* SILC client operations */
2686 SilcClientOperations ops = {
2688 silc_channel_message,
2689 silc_private_message,
2695 silc_get_auth_method,
2696 silc_verify_public_key,
2697 silc_ask_passphrase,