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 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
128 SilcChannelEntry channel_entry,
129 SilcBuffer channel_pubkeys)
132 SilcArgumentPayload chpks;
134 SilcUInt32 pk_len, type;
136 char *fingerprint, *babbleprint;
137 SilcPublicKey pubkey;
138 SilcPublicKeyIdentifier ident;
140 printformat_module("fe-common/silc", server, NULL,
141 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
142 channel_entry->channel_name);
144 SILC_GET16_MSB(argc, channel_pubkeys->data);
145 chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
146 channel_pubkeys->len - 2, argc);
150 pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
152 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
153 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
154 silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
155 ident = silc_pkcs_decode_identifier(pubkey->identifier);
157 printformat_module("fe-common/silc", server, NULL,
158 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
159 c++, channel_entry->channel_name,
160 type == 0x00 ? "Added" : "Removed",
161 ident->realname ? ident->realname : "",
162 fingerprint, babbleprint);
164 silc_free(fingerprint);
165 silc_free(babbleprint);
166 silc_pkcs_public_key_free(pubkey);
167 silc_pkcs_free_identifier(ident);
168 pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
171 silc_argument_payload_free(chpks);
174 void silc_say(SilcClient client, SilcClientConnection conn,
175 SilcClientMessageType type, char *msg, ...)
177 SILC_SERVER_REC *server;
181 server = conn == NULL ? NULL : conn->context;
184 str = g_strdup_vprintf(msg, va);
185 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
190 void silc_say_error(char *msg, ...)
196 str = g_strdup_vprintf(msg, va);
197 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
203 /* try to verify a message using locally stored public key data */
204 int verify_message_signature(SilcClientEntry sender,
205 SilcMessageSignedPayload sig,
206 SilcMessagePayload message)
209 char file[256], filename[256];
210 char *fingerprint, *fingerprint2;
211 unsigned char *pk_data;
212 SilcUInt32 pk_datalen;
214 int ret = SILC_MSG_SIGNED_VERIFIED, i;
217 return SILC_MSG_SIGNED_UNKNOWN;
219 /* get public key from the signature payload and compare it with the
220 one stored in the client entry */
221 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
224 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
226 if (sender->fingerprint) {
227 fingerprint2 = silc_fingerprint(sender->fingerprint,
228 sender->fingerprint_len);
229 if (strcmp(fingerprint, fingerprint2)) {
230 /* since the public key differs from the senders public key, the
231 verification _failed_ */
232 silc_pkcs_public_key_free(pk);
233 silc_free(fingerprint);
234 ret = SILC_MSG_SIGNED_UNKNOWN;
236 silc_free(fingerprint2);
238 } else if (sender->fingerprint)
239 fingerprint = silc_fingerprint(sender->fingerprint,
240 sender->fingerprint_len);
242 /* no idea, who or what signed that message ... */
243 return SILC_MSG_SIGNED_UNKNOWN;
245 /* search our local client key cache */
246 for (i = 0; i < strlen(fingerprint); i++)
247 if (fingerprint[i] == ' ')
248 fingerprint[i] = '_';
250 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
251 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
252 get_irssi_dir(), file);
253 silc_free(fingerprint);
255 if (stat(filename, &st) < 0)
256 /* we don't have the public key cached ... use the one from the sig */
257 ret = SILC_MSG_SIGNED_UNKNOWN;
259 SilcPublicKey cached_pk=NULL;
261 /* try to load the file */
262 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
263 !silc_pkcs_load_public_key(filename, &cached_pk,
264 SILC_PKCS_FILE_BIN)) {
265 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
266 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
268 return SILC_MSG_SIGNED_UNKNOWN;
270 ret = SILC_MSG_SIGNED_UNKNOWN;
275 silc_pkcs_public_key_free(pk);
280 /* the public key is now in pk, our "level of trust" in ret */
281 if ((pk) && silc_message_signed_verify(sig, message, pk,
282 silc_client->sha1hash)!= SILC_AUTH_OK)
283 ret = SILC_MSG_SIGNED_FAILED;
286 silc_pkcs_public_key_free(pk);
291 char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
294 int i = 0, j = 0, len = strlen(escaped_data);
296 data = silc_calloc(len, sizeof(char));
299 ptr = memchr(escaped_data + i, 1, len - i);
301 int inc = (ptr - escaped_data) - i;
302 memcpy(data + j, escaped_data + i, inc);
305 data[j++] = *(ptr + 1) - 1;
307 memcpy(data + j, escaped_data + i, len - i);
317 char * silc_escape_data(const char *data, SilcUInt32 len)
319 char *escaped_data, *ptr, *ptr0, *ptr1;
322 escaped_data = silc_calloc(2 * len, sizeof(char));
325 ptr0 = memchr(data + i, 0, len - i);
326 ptr1 = memchr(data + i, 1, len - i);
328 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
331 int inc = (ptr - data) - i;
333 memcpy(escaped_data + j, data + i, inc);
336 escaped_data[j++] = 1;
337 escaped_data[j++] = *(data + i++) + 1;
339 memcpy(escaped_data + j, data + i, len - i);
348 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
349 const char *data, SilcUInt32 data_len, const char *nick,
354 escaped_data = silc_escape_data(data, data_len);
356 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
358 silc_free(escaped_data);
362 /* Message for a channel. The `sender' is the nickname of the sender
363 received in the packet. The `channel_name' is the name of the channel. */
365 void silc_channel_message(SilcClient client, SilcClientConnection conn,
366 SilcClientEntry sender, SilcChannelEntry channel,
367 SilcMessagePayload payload,
368 SilcMessageFlags flags, const unsigned char *message,
369 SilcUInt32 message_len)
371 SILC_SERVER_REC *server;
373 SILC_CHANNEL_REC *chanrec;
376 SILC_LOG_DEBUG(("Start"));
381 server = conn == NULL ? NULL : conn->context;
382 chanrec = silc_channel_find_entry(server, channel);
386 nick = silc_nicklist_find(chanrec, sender);
388 /* We didn't find client but it clearly exists, add it. */
389 SilcChannelUser chu = silc_client_on_channel(channel, sender);
391 nick = silc_nicklist_insert(chanrec, chu, FALSE);
394 /* If the messages is digitally signed, verify it, if possible. */
395 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
396 if (!settings_get_bool("ignore_message_signatures")) {
397 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
398 verified = verify_message_signature(sender, sig, payload);
400 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
404 if (flags & SILC_MESSAGE_FLAG_DATA) {
405 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
406 nick == NULL ? NULL : nick->nick,
407 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
414 /* FIXME: replace those printformat calls with signals and add signature
415 information to them (if present) */
416 if (flags & SILC_MESSAGE_FLAG_ACTION)
417 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
418 char tmp[256], *cp, *dm = NULL;
419 memset(tmp, 0, sizeof(tmp));
421 if(message_len > sizeof(tmp) - 1) {
422 dm = silc_calloc(message_len + 1, sizeof(*dm));
425 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
427 printformat_module("fe-common/silc", server, channel->channel_name,
428 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
429 nick == NULL ? "[<unknown>]" : nick->nick, cp);
432 printformat_module("fe-common/silc", server, channel->channel_name,
433 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
434 nick == NULL ? "[<unknown>]" : nick->nick,
437 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
438 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
439 char tmp[256], *cp, *dm = NULL;
440 memset(tmp, 0, sizeof(tmp));
442 if(message_len > sizeof(tmp) - 1) {
443 dm = silc_calloc(message_len + 1, sizeof(*dm));
446 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
448 printformat_module("fe-common/silc", server, channel->channel_name,
449 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
450 nick == NULL ? "[<unknown>]" : nick->nick, cp);
453 printformat_module("fe-common/silc", server, channel->channel_name,
454 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
455 nick == NULL ? "[<unknown>]" : nick->nick,
459 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
460 char tmp[256], *cp, *dm = NULL;
462 memset(tmp, 0, sizeof(tmp));
464 if (message_len > sizeof(tmp) - 1) {
465 dm = silc_calloc(message_len + 1, sizeof(*dm));
469 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
471 if (flags & SILC_MESSAGE_FLAG_SIGNED)
472 signal_emit("message signed_public", 6, server, cp,
473 nick == NULL ? "[<unknown>]" : nick->nick,
474 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
475 chanrec->name, verified);
477 signal_emit("message public", 6, server, cp,
478 nick == NULL ? "[<unknown>]" : nick->nick,
479 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
480 chanrec->name, nick);
485 if (flags & SILC_MESSAGE_FLAG_SIGNED)
486 signal_emit("message signed_public", 6, server, message,
487 nick == NULL ? "[<unknown>]" : nick->nick,
488 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
489 chanrec->name, verified);
491 signal_emit("message public", 6, server, message,
492 nick == NULL ? "[<unknown>]" : nick->nick,
493 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
494 chanrec->name, nick);
498 /* Private message to the client. The `sender' is the nickname of the
499 sender received in the packet. */
501 void silc_private_message(SilcClient client, SilcClientConnection conn,
502 SilcClientEntry sender, SilcMessagePayload payload,
503 SilcMessageFlags flags,
504 const unsigned char *message,
505 SilcUInt32 message_len)
507 SILC_SERVER_REC *server;
511 SILC_LOG_DEBUG(("Start"));
513 server = conn == NULL ? NULL : conn->context;
514 memset(userhost, 0, sizeof(userhost));
515 if (sender->username)
516 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
517 sender->username, sender->hostname);
519 /* If the messages is digitally signed, verify it, if possible. */
520 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
521 if (!settings_get_bool("ignore_message_signatures")) {
522 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
523 verified = verify_message_signature(sender, sig, payload);
525 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
529 if (flags & SILC_MESSAGE_FLAG_DATA) {
530 silc_emit_mime_sig(server,
532 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
534 message, message_len,
535 sender->nickname ? sender->nickname : "[<unknown>]",
536 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
543 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
544 char tmp[256], *cp, *dm = NULL;
546 memset(tmp, 0, sizeof(tmp));
548 if (message_len > sizeof(tmp) - 1) {
549 dm = silc_calloc(message_len + 1, sizeof(*dm));
553 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
555 if (flags & SILC_MESSAGE_FLAG_SIGNED)
556 signal_emit("message signed_private", 5, server, cp,
557 sender->nickname ? sender->nickname : "[<unknown>]",
558 sender->username ? userhost : NULL, verified);
560 signal_emit("message private", 4, server, cp,
561 sender->nickname ? sender->nickname : "[<unknown>]",
562 sender->username ? userhost : NULL);
567 if (flags & SILC_MESSAGE_FLAG_SIGNED)
568 signal_emit("message signed_private", 5, server, message,
569 sender->nickname ? sender->nickname : "[<unknown>]",
570 sender->username ? userhost : NULL, verified);
572 signal_emit("message private", 4, server, message,
573 sender->nickname ? sender->nickname : "[<unknown>]",
574 sender->username ? userhost : NULL);
577 /* Notify message to the client. The notify arguments are sent in the
578 same order as servers sends them. The arguments are same as received
579 from the server except for ID's. If ID is received application receives
580 the corresponding entry to the ID. For example, if Client ID is received
581 application receives SilcClientEntry. Also, if the notify type is
582 for channel the channel entry is sent to application (even if server
583 does not send it). */
585 void silc_notify(SilcClient client, SilcClientConnection conn,
586 SilcNotifyType type, ...)
589 SILC_SERVER_REC *server;
590 SILC_CHANNEL_REC *chanrec;
591 SILC_NICK_REC *nickrec;
592 SilcClientEntry client_entry, client_entry2;
593 SilcChannelEntry channel, channel2;
594 SilcServerEntry server_entry;
600 GSList *list1, *list_tmp;
603 SILC_LOG_DEBUG(("Start"));
607 server = conn == NULL ? NULL : conn->context;
610 case SILC_NOTIFY_TYPE_NONE:
611 /* Some generic notice from server */
612 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
615 case SILC_NOTIFY_TYPE_INVITE:
617 * Invited or modified invite list.
620 SILC_LOG_DEBUG(("Notify: INVITE"));
622 channel = va_arg(va, SilcChannelEntry);
623 name = va_arg(va, char *);
624 client_entry = va_arg(va, SilcClientEntry);
626 memset(buf, 0, sizeof(buf));
627 snprintf(buf, sizeof(buf) - 1, "%s@%s",
628 client_entry->username, client_entry->hostname);
629 signal_emit("message invite", 4, server, channel ? channel->channel_name :
630 name, client_entry->nickname, buf);
633 case SILC_NOTIFY_TYPE_JOIN:
638 SILC_LOG_DEBUG(("Notify: JOIN"));
640 client_entry = va_arg(va, SilcClientEntry);
641 channel = va_arg(va, SilcChannelEntry);
643 if (client_entry == server->conn->local_entry) {
644 /* You joined to channel */
645 chanrec = silc_channel_find(server, channel->channel_name);
646 if (chanrec != NULL && !chanrec->joined)
647 chanrec->entry = channel;
649 chanrec = silc_channel_find_entry(server, channel);
650 if (chanrec != NULL) {
651 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
653 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
657 memset(buf, 0, sizeof(buf));
658 if (client_entry->username)
659 snprintf(buf, sizeof(buf) - 1, "%s@%s",
660 client_entry->username, client_entry->hostname);
661 signal_emit("message join", 4, server, channel->channel_name,
662 client_entry->nickname,
663 client_entry->username == NULL ? "" : buf);
666 case SILC_NOTIFY_TYPE_LEAVE:
671 SILC_LOG_DEBUG(("Notify: LEAVE"));
673 client_entry = va_arg(va, SilcClientEntry);
674 channel = va_arg(va, SilcChannelEntry);
676 memset(buf, 0, sizeof(buf));
677 if (client_entry->username)
678 snprintf(buf, sizeof(buf) - 1, "%s@%s",
679 client_entry->username, client_entry->hostname);
680 signal_emit("message part", 5, server, channel->channel_name,
681 client_entry->nickname, client_entry->username ?
682 buf : "", client_entry->nickname);
684 chanrec = silc_channel_find_entry(server, channel);
685 if (chanrec != NULL) {
686 nickrec = silc_nicklist_find(chanrec, client_entry);
688 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
692 case SILC_NOTIFY_TYPE_SIGNOFF:
697 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
699 client_entry = va_arg(va, SilcClientEntry);
700 tmp = va_arg(va, char *);
702 silc_server_free_ftp(server, client_entry);
704 /* Print only if we have the nickname. If this cliente has just quit
705 when we were only resolving it, it is possible we don't have the
707 if (client_entry->nickname) {
708 memset(buf, 0, sizeof(buf));
709 if (client_entry->username)
710 snprintf(buf, sizeof(buf) - 1, "%s@%s",
711 client_entry->username, client_entry->hostname);
712 signal_emit("message quit", 4, server, client_entry->nickname,
713 client_entry->username ? buf : "",
717 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
718 for (list_tmp = list1; list_tmp != NULL; list_tmp =
719 list_tmp->next->next) {
720 CHANNEL_REC *channel = list_tmp->data;
721 NICK_REC *nickrec = list_tmp->next->data;
723 nicklist_remove(channel, nickrec);
727 case SILC_NOTIFY_TYPE_TOPIC_SET:
732 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
734 idtype = va_arg(va, int);
735 entry = va_arg(va, void *);
736 tmp = va_arg(va, char *);
737 channel = va_arg(va, SilcChannelEntry);
739 chanrec = silc_channel_find_entry(server, channel);
740 if (chanrec != NULL) {
741 char tmp2[256], *cp, *dm = NULL;
743 g_free_not_null(chanrec->topic);
744 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
745 memset(tmp2, 0, sizeof(tmp2));
747 if (strlen(tmp) > sizeof(tmp2) - 1) {
748 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
752 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
757 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
758 signal_emit("channel topic changed", 1, chanrec);
763 if (idtype == SILC_ID_CLIENT) {
764 client_entry = (SilcClientEntry)entry;
765 memset(buf, 0, sizeof(buf));
766 snprintf(buf, sizeof(buf) - 1, "%s@%s",
767 client_entry->username, client_entry->hostname);
768 signal_emit("message topic", 5, server, channel->channel_name,
769 tmp, client_entry->nickname, buf);
770 } else if (idtype == SILC_ID_SERVER) {
771 server_entry = (SilcServerEntry)entry;
772 signal_emit("message topic", 5, server, channel->channel_name,
773 tmp, server_entry->server_name,
774 server_entry->server_name);
775 } else if (idtype == SILC_ID_CHANNEL) {
776 channel = (SilcChannelEntry)entry;
777 signal_emit("message topic", 5, server, channel->channel_name,
778 tmp, channel->channel_name, channel->channel_name);
782 case SILC_NOTIFY_TYPE_NICK_CHANGE:
787 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
789 client_entry = va_arg(va, SilcClientEntry);
790 client_entry2 = va_arg(va, SilcClientEntry);
792 if (!strcmp(client_entry->nickname, client_entry2->nickname))
795 memset(buf, 0, sizeof(buf));
796 snprintf(buf, sizeof(buf) - 1, "%s@%s",
797 client_entry2->username, client_entry2->hostname);
798 nicklist_rename_unique(SERVER(server),
799 client_entry, client_entry->nickname,
800 client_entry2, client_entry2->nickname);
801 signal_emit("message nick", 4, server, client_entry2->nickname,
802 client_entry->nickname, buf);
805 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
807 * Changed channel mode.
810 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
812 idtype = va_arg(va, int);
813 entry = va_arg(va, void *);
814 mode = va_arg(va, SilcUInt32);
815 (void)va_arg(va, char *); /* cipher */
816 (void)va_arg(va, char *); /* hmac */
817 (void)va_arg(va, char *); /* passphrase */
818 (void)va_arg(va, SilcPublicKey); /* founder key */
819 buffer = va_arg(va, SilcBuffer); /* channel public keys */
820 channel = va_arg(va, SilcChannelEntry);
822 tmp = silc_client_chmode(mode,
823 channel->channel_key ?
824 silc_cipher_get_name(channel->channel_key) : "",
826 silc_hmac_get_name(channel->hmac) : "");
828 chanrec = silc_channel_find_entry(server, channel);
829 if (chanrec != NULL) {
830 g_free_not_null(chanrec->mode);
831 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
832 signal_emit("channel mode changed", 1, chanrec);
835 if (idtype == SILC_ID_CLIENT) {
836 client_entry = (SilcClientEntry)entry;
837 printformat_module("fe-common/silc", server, channel->channel_name,
838 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
839 channel->channel_name, tmp ? tmp : "removed all",
840 client_entry->nickname);
841 } else if (idtype == SILC_ID_SERVER) {
842 server_entry = (SilcServerEntry)entry;
843 printformat_module("fe-common/silc", server, channel->channel_name,
844 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
845 channel->channel_name, tmp ? tmp : "removed all",
846 server_entry->server_name);
847 } else if (idtype == SILC_ID_CHANNEL) {
848 channel2 = (SilcChannelEntry)entry;
849 printformat_module("fe-common/silc", server, channel->channel_name,
850 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
851 channel->channel_name, tmp ? tmp : "removed all",
852 channel2->channel_name);
855 /* Print the channel public key list */
857 silc_parse_channel_public_keys(server, channel, buffer);
862 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
864 * Changed user's mode on channel.
867 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
869 idtype = va_arg(va, int);
870 entry = va_arg(va, void *);
871 mode = va_arg(va, SilcUInt32);
872 client_entry2 = va_arg(va, SilcClientEntry);
873 channel = va_arg(va, SilcChannelEntry);
875 tmp = silc_client_chumode(mode);
876 chanrec = silc_channel_find_entry(server, channel);
877 if (chanrec != NULL) {
880 if (client_entry2 == server->conn->local_entry)
881 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
883 nick = silc_nicklist_find(chanrec, client_entry2);
885 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
886 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
887 signal_emit("nick mode changed", 2, chanrec, nick);
891 if (idtype == SILC_ID_CLIENT) {
892 client_entry = (SilcClientEntry)entry;
893 printformat_module("fe-common/silc", server, channel->channel_name,
894 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
895 channel->channel_name, client_entry2->nickname,
896 tmp ? tmp : "removed all",
897 client_entry->nickname);
898 } else if (idtype == SILC_ID_SERVER) {
899 server_entry = (SilcServerEntry)entry;
900 printformat_module("fe-common/silc", server, channel->channel_name,
901 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
902 channel->channel_name, client_entry2->nickname,
903 tmp ? tmp : "removed all",
904 server_entry->server_name);
905 } else if (idtype == SILC_ID_CHANNEL) {
906 channel2 = (SilcChannelEntry)entry;
907 printformat_module("fe-common/silc", server, channel->channel_name,
908 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
909 channel->channel_name, client_entry2->nickname,
910 tmp ? tmp : "removed all",
911 channel2->channel_name);
914 if (mode & SILC_CHANNEL_UMODE_CHANFO)
915 printformat_module("fe-common/silc",
916 server, channel->channel_name, MSGLEVEL_CRAP,
917 SILCTXT_CHANNEL_FOUNDER,
918 channel->channel_name, client_entry2->nickname);
920 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
921 printformat_module("fe-common/silc",
922 server, channel->channel_name, MSGLEVEL_CRAP,
923 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
928 case SILC_NOTIFY_TYPE_MOTD:
933 SILC_LOG_DEBUG(("Notify: MOTD"));
935 tmp = va_arg(va, char *);
937 if (!settings_get_bool("skip_motd"))
938 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
941 case SILC_NOTIFY_TYPE_KICKED:
943 * Someone was kicked from channel.
946 SILC_LOG_DEBUG(("Notify: KICKED"));
948 client_entry = va_arg(va, SilcClientEntry);
949 tmp = va_arg(va, char *);
950 client_entry2 = va_arg(va, SilcClientEntry);
951 channel = va_arg(va, SilcChannelEntry);
953 chanrec = silc_channel_find_entry(server, channel);
955 if (client_entry == conn->local_entry) {
956 printformat_module("fe-common/silc", server, channel->channel_name,
957 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
958 channel->channel_name,
959 client_entry ? client_entry2->nickname : "",
962 chanrec->kicked = TRUE;
963 channel_destroy((CHANNEL_REC *)chanrec);
966 printformat_module("fe-common/silc", server, channel->channel_name,
967 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
968 client_entry->nickname, channel->channel_name,
969 client_entry2 ? client_entry2->nickname : "",
973 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
975 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
980 case SILC_NOTIFY_TYPE_KILLED:
982 * Someone was killed from the network.
985 SILC_LOG_DEBUG(("Notify: KILLED"));
987 client_entry = va_arg(va, SilcClientEntry);
988 tmp = va_arg(va, char *);
989 idtype = va_arg(va, int);
990 entry = va_arg(va, SilcClientEntry);
992 if (client_entry == conn->local_entry) {
993 if (idtype == SILC_ID_CLIENT) {
994 client_entry2 = (SilcClientEntry)entry;
995 printformat_module("fe-common/silc", server, NULL,
996 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
997 client_entry2 ? client_entry2->nickname : "",
999 } else if (idtype == SILC_ID_SERVER) {
1000 server_entry = (SilcServerEntry)entry;
1001 printformat_module("fe-common/silc", server, NULL,
1002 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1003 server_entry->server_name, tmp ? tmp : "");
1004 } else if (idtype == SILC_ID_CHANNEL) {
1005 channel = (SilcChannelEntry)entry;
1006 printformat_module("fe-common/silc", server, NULL,
1007 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1008 channel->channel_name, tmp ? tmp : "");
1011 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1012 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1013 list_tmp->next->next) {
1014 CHANNEL_REC *channel = list_tmp->data;
1015 NICK_REC *nickrec = list_tmp->next->data;
1016 nicklist_remove(channel, nickrec);
1019 if (idtype == SILC_ID_CLIENT) {
1020 client_entry2 = (SilcClientEntry)entry;
1021 printformat_module("fe-common/silc", server, NULL,
1022 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1023 client_entry->nickname,
1024 client_entry2 ? client_entry2->nickname : "",
1026 } else if (idtype == SILC_ID_SERVER) {
1027 server_entry = (SilcServerEntry)entry;
1028 printformat_module("fe-common/silc", server, NULL,
1029 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1030 client_entry->nickname,
1031 server_entry->server_name, tmp ? tmp : "");
1032 } else if (idtype == SILC_ID_CHANNEL) {
1033 channel = (SilcChannelEntry)entry;
1034 printformat_module("fe-common/silc", server, NULL,
1035 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1036 client_entry->nickname,
1037 channel->channel_name, tmp ? tmp : "");
1042 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1045 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1048 * Server has quit the network.
1051 SilcClientEntry *clients;
1052 SilcUInt32 clients_count;
1054 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1056 (void)va_arg(va, void *);
1057 clients = va_arg(va, SilcClientEntry *);
1058 clients_count = va_arg(va, SilcUInt32);
1060 for (i = 0; i < clients_count; i++) {
1061 memset(buf, 0, sizeof(buf));
1063 /* Print only if we have the nickname. If this client has just quit
1064 when we were only resolving it, it is possible we don't have the
1066 if (clients[i]->nickname) {
1067 if (clients[i]->username)
1068 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1069 clients[i]->username, clients[i]->hostname);
1070 signal_emit("message quit", 4, server, clients[i]->nickname,
1071 clients[i]->username ? buf : "",
1075 silc_server_free_ftp(server, clients[i]);
1077 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1078 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1079 list_tmp->next->next) {
1080 CHANNEL_REC *channel = list_tmp->data;
1081 NICK_REC *nickrec = list_tmp->next->data;
1082 nicklist_remove(channel, nickrec);
1088 case SILC_NOTIFY_TYPE_ERROR:
1090 SilcStatus error = va_arg(va, int);
1092 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1093 "%s", silc_get_status_message(error));
1097 case SILC_NOTIFY_TYPE_WATCH:
1099 SilcNotifyType notify;
1101 client_entry = va_arg(va, SilcClientEntry);
1102 name = va_arg(va, char *); /* Maybe NULL */
1103 mode = va_arg(va, SilcUInt32);
1104 notify = va_arg(va, int);
1106 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1108 printformat_module("fe-common/silc", server, NULL,
1109 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1110 client_entry->nickname, name);
1112 printformat_module("fe-common/silc", server, NULL,
1113 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1114 client_entry->nickname);
1115 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1116 /* See if client was away and is now present */
1117 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1118 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1119 SILC_UMODE_DETACHED)) &&
1120 (client_entry->mode & SILC_UMODE_GONE ||
1121 client_entry->mode & SILC_UMODE_INDISPOSED ||
1122 client_entry->mode & SILC_UMODE_BUSY ||
1123 client_entry->mode & SILC_UMODE_PAGE ||
1124 client_entry->mode & SILC_UMODE_DETACHED)) {
1125 printformat_module("fe-common/silc", server, NULL,
1126 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1127 client_entry->nickname);
1131 memset(buf, 0, sizeof(buf));
1132 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1133 printformat_module("fe-common/silc", server, NULL,
1134 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1135 client_entry->nickname, buf);
1137 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1138 printformat_module("fe-common/silc", server, NULL,
1139 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1140 client_entry->nickname);
1141 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1142 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1143 printformat_module("fe-common/silc", server, NULL,
1144 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1145 client_entry->nickname);
1146 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1147 /* Client logged in to the network */
1148 printformat_module("fe-common/silc", server, NULL,
1149 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1150 client_entry->nickname);
1156 /* Unknown notify */
1157 printformat_module("fe-common/silc", server, NULL,
1158 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1165 /* Called to indicate that connection was either successfully established
1166 or connecting failed. This is also the first time application receives
1167 the SilcClientConnection object which it should save somewhere. */
1169 void silc_connect(SilcClient client, SilcClientConnection conn,
1170 SilcClientConnectionStatus status)
1172 SILC_SERVER_REC *server = conn->context;
1174 if (!server || server->disconnected) {
1175 silc_client_close_connection(client, conn);
1180 case SILC_CLIENT_CONN_SUCCESS:
1181 /* We have successfully connected to server */
1182 server->connected = TRUE;
1183 signal_emit("event connected", 1, server);
1186 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1187 /* We have successfully resumed old detached session */
1188 server->connected = TRUE;
1189 signal_emit("event connected", 1, server);
1191 /* If we resumed old session check whether we need to update
1193 if (strcmp(server->nick, conn->local_entry->nickname)) {
1195 old = g_strdup(server->nick);
1196 server_change_nick(SERVER(server), conn->local_entry->nickname);
1197 nicklist_rename_unique(SERVER(server),
1198 conn->local_entry, server->nick,
1199 conn->local_entry, conn->local_entry->nickname);
1200 signal_emit("message own_nick", 4, server, server->nick, old, "");
1206 server->connection_lost = TRUE;
1208 server->conn->context = NULL;
1209 server_disconnect(SERVER(server));
1214 /* Called to indicate that connection was disconnected to the server. */
1216 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1217 SilcStatus status, const char *message)
1219 SILC_SERVER_REC *server = conn->context;
1221 SILC_LOG_DEBUG(("Start"));
1223 if (!server || server->connection_lost)
1226 if (server->conn && server->conn->local_entry) {
1227 nicklist_rename_unique(SERVER(server),
1228 server->conn->local_entry, server->nick,
1229 server->conn->local_entry,
1230 silc_client->username);
1231 silc_change_nick(server, silc_client->username);
1235 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1236 "Server closed connection: %s (%d) %s",
1237 silc_get_status_message(status), status,
1238 message ? message : "");
1241 server->conn->context = NULL;
1242 server->conn = NULL;
1243 server->connection_lost = TRUE;
1244 server_disconnect(SERVER(server));
1247 /* Command handler. This function is called always in the command function.
1248 If error occurs it will be called as well. `conn' is the associated
1249 client connection. `cmd_context' is the command context that was
1250 originally sent to the command. `success' is FALSE if error occured
1251 during command. `command' is the command being processed. It must be
1252 noted that this is not reply from server. This is merely called just
1253 after application has called the command. Just to tell application
1254 that the command really was processed. */
1256 static bool cmode_list_chpks = FALSE;
1258 void silc_command(SilcClient client, SilcClientConnection conn,
1259 SilcClientCommandContext cmd_context, bool success,
1260 SilcCommand command, SilcStatus status)
1262 SILC_SERVER_REC *server = conn->context;
1264 SILC_LOG_DEBUG(("Start"));
1267 silc_say_error("%s", silc_get_status_message(status));
1273 case SILC_COMMAND_INVITE:
1274 if (cmd_context->argc > 2)
1275 printformat_module("fe-common/silc", server, NULL,
1276 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1277 cmd_context->argv[2],
1278 (cmd_context->argv[1][0] == '*' ?
1279 (char *)conn->current_channel->channel_name :
1280 (char *)cmd_context->argv[1]));
1283 case SILC_COMMAND_DETACH:
1284 server->no_reconnect = TRUE;
1287 case SILC_COMMAND_CMODE:
1288 if (cmd_context->argc == 3 &&
1289 !strcmp(cmd_context->argv[2], "+C"))
1290 cmode_list_chpks = TRUE;
1292 cmode_list_chpks = FALSE;
1301 SilcChannelEntry channel;
1305 /* Client info resolving callback when JOIN command reply is received.
1306 This will cache all users on the channel. */
1308 static void silc_client_join_get_users(SilcClient client,
1309 SilcClientConnection conn,
1310 SilcClientEntry *clients,
1311 SilcUInt32 clients_count,
1314 SilcJoinResolve r = context;
1315 SilcChannelEntry channel = r->channel;
1316 SilcHashTableList htl;
1317 SilcChannelUser chu;
1318 SILC_SERVER_REC *server = conn->context;
1319 SILC_CHANNEL_REC *chanrec;
1320 SilcClientEntry founder = NULL;
1323 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1324 silc_hash_table_count(channel->user_list)));
1326 if (!clients && r->retry < 1) {
1327 /* Retry to resolve */
1329 silc_client_get_clients_by_channel(client, conn, channel,
1330 silc_client_join_get_users, context);
1334 chanrec = silc_channel_find(server, channel->channel_name);
1335 if (chanrec == NULL)
1338 silc_hash_table_list(channel->user_list, &htl);
1339 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1340 if (!chu->client->nickname)
1342 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1343 founder = chu->client;
1344 silc_nicklist_insert(chanrec, chu, FALSE);
1346 silc_hash_table_list_reset(&htl);
1348 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1349 nicklist_set_own(CHANNEL(chanrec), ownnick);
1350 signal_emit("channel joined", 1, chanrec);
1351 chanrec->entry = channel;
1354 printformat_module("fe-common/silc", server, channel->channel_name,
1355 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1356 channel->channel_name, chanrec->topic);
1359 if (founder == conn->local_entry) {
1360 printformat_module("fe-common/silc",
1361 server, channel->channel_name, MSGLEVEL_CRAP,
1362 SILCTXT_CHANNEL_FOUNDER_YOU,
1363 channel->channel_name);
1364 signal_emit("nick mode changed", 2, chanrec, ownnick);
1366 printformat_module("fe-common/silc",
1367 server, channel->channel_name, MSGLEVEL_CRAP,
1368 SILCTXT_CHANNEL_FOUNDER,
1369 channel->channel_name, founder->nickname);
1375 SilcClientConnection conn;
1381 void silc_getkey_cb(bool success, void *context)
1383 GetkeyContext getkey = (GetkeyContext)context;
1384 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1385 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1386 ((SilcClientEntry)getkey->entry)->nickname :
1387 ((SilcServerEntry)getkey->entry)->server_name);
1390 printformat_module("fe-common/silc", NULL, NULL,
1391 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1393 printformat_module("fe-common/silc", NULL, NULL,
1394 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1398 silc_free(getkey->fingerprint);
1402 /* Parse an invite or ban list */
1403 void silc_parse_inviteban_list(SilcClient client,
1404 SilcClientConnection conn,
1405 SILC_SERVER_REC *server,
1406 SilcChannelEntry channel,
1407 const char *list_type,
1408 SilcArgumentPayload list)
1411 SilcUInt32 type, len;
1412 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1413 int counter=0, resolving = FALSE;
1415 if (!silc_argument_get_arg_num(list)) {
1416 printformat_module("fe-common/silc", server,
1417 (chanrec ? chanrec->visible_name : NULL),
1418 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1419 channel->channel_name, list_type);
1423 printformat_module("fe-common/silc", server,
1424 (chanrec ? chanrec->visible_name : NULL),
1425 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1426 channel->channel_name, list_type);
1428 /* parse the list */
1429 tmp = silc_argument_get_first_arg(list, &type, &len);
1434 /* an invite string */
1438 if (tmp[len-1] == ',')
1441 list = g_strsplit(tmp, ",", -1);
1443 printformat_module("fe-common/silc", server,
1444 (chanrec ? chanrec->visible_name : NULL),
1445 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1446 ++counter, channel->channel_name, list_type,
1455 char *fingerprint, *babbleprint;
1457 /* tmp is Public Key Payload, take public key from it. */
1458 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1459 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1461 printformat_module("fe-common/silc", server,
1462 (chanrec ? chanrec->visible_name : NULL),
1463 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1464 ++counter, channel->channel_name, list_type,
1465 fingerprint, babbleprint);
1472 SilcClientID *client_id;
1473 SilcClientEntry client_entry;
1475 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1477 if (client_id == NULL) {
1478 silc_say_error("Invalid data in %s list encountered", list_type);
1482 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1485 printformat_module("fe-common/silc", server,
1486 (chanrec ? chanrec->visible_name : NULL),
1487 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1488 ++counter, channel->channel_name, list_type,
1489 client_entry->nickname);
1492 silc_client_get_client_by_id_resolve(client, conn, client_id,
1496 silc_free(client_id);
1502 silc_say_error("Unkown type in %s list: %u (len %u)",
1503 list_type, type, len);
1505 tmp = silc_argument_get_next_arg(list, &type, &len);
1509 printformat_module("fe-common/silc", server,
1510 (chanrec ? chanrec->visible_name : NULL),
1511 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1512 list_type, channel->channel_name);
1515 /* Command reply handler. This function is called always in the command reply
1516 function. If error occurs it will be called as well. Normal scenario
1517 is that it will be called after the received command data has been parsed
1518 and processed. The function is used to pass the received command data to
1521 `conn' is the associated client connection. `cmd_payload' is the command
1522 payload data received from server and it can be ignored. It is provided
1523 if the application would like to re-parse the received command data,
1524 however, it must be noted that the data is parsed already by the library
1525 thus the payload can be ignored. `success' is FALSE if error occured.
1526 In this case arguments are not sent to the application. `command' is the
1527 command reply being processed. The function has variable argument list
1528 and each command defines the number and type of arguments it passes to the
1529 application (on error they are not sent). */
1532 silc_command_reply(SilcClient client, SilcClientConnection conn,
1533 SilcCommandPayload cmd_payload, bool success,
1534 SilcCommand command, SilcStatus status, ...)
1537 SILC_SERVER_REC *server = conn->context;
1538 SILC_CHANNEL_REC *chanrec;
1541 va_start(vp, status);
1543 SILC_LOG_DEBUG(("Start"));
1546 case SILC_COMMAND_WHOIS:
1548 char buf[1024], *nickname, *username, *realname, *nick;
1549 unsigned char *fingerprint;
1550 SilcUInt32 idle, mode;
1551 SilcBuffer channels, user_modes;
1552 SilcClientEntry client_entry;
1555 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1556 /* Print the unknown nick for user */
1557 unsigned char *tmp =
1558 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1561 silc_say_error("%s: %s", tmp,
1562 silc_get_status_message(status));
1564 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1565 /* Try to find the entry for the unknown client ID, since we
1566 might have, and print the nickname of it for user. */
1568 unsigned char *tmp =
1569 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1572 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1575 client_entry = silc_client_get_client_by_id(client, conn,
1577 if (client_entry && client_entry->nickname)
1578 silc_say_error("%s: %s", client_entry->nickname,
1579 silc_get_status_message(status));
1580 silc_free(client_id);
1584 } else if (!success) {
1585 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1589 client_entry = va_arg(vp, SilcClientEntry);
1590 nickname = va_arg(vp, char *);
1591 username = va_arg(vp, char *);
1592 realname = va_arg(vp, char *);
1593 channels = va_arg(vp, SilcBuffer);
1594 mode = va_arg(vp, SilcUInt32);
1595 idle = va_arg(vp, SilcUInt32);
1596 fingerprint = va_arg(vp, unsigned char *);
1597 user_modes = va_arg(vp, SilcBuffer);
1598 attrs = va_arg(vp, SilcDList);
1600 silc_parse_userfqdn(nickname, &nick, NULL);
1601 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1602 SILCTXT_WHOIS_USERINFO, nickname,
1603 client_entry->username, client_entry->hostname,
1604 nick, client_entry->nickname);
1605 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1606 SILCTXT_WHOIS_REALNAME, realname);
1609 if (channels && user_modes) {
1611 SilcDList list = silc_channel_payload_parse_list(channels->data,
1613 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1615 SilcChannelPayload entry;
1618 memset(buf, 0, sizeof(buf));
1619 silc_dlist_start(list);
1620 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1621 SilcUInt32 name_len;
1622 char *m = silc_client_chumode_char(umodes[i++]);
1623 char *name = silc_channel_get_name(entry, &name_len);
1626 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1627 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1628 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1632 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1633 SILCTXT_WHOIS_CHANNELS, buf);
1634 silc_channel_payload_list_free(list);
1640 memset(buf, 0, sizeof(buf));
1641 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1642 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1643 SILCTXT_WHOIS_MODES, buf);
1646 if (idle && nickname) {
1647 memset(buf, 0, sizeof(buf));
1648 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1649 idle > 60 ? (idle / 60) : idle,
1650 idle > 60 ? "minutes" : "seconds");
1652 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1653 SILCTXT_WHOIS_IDLE, buf);
1657 fingerprint = silc_fingerprint(fingerprint, 20);
1658 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1659 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1660 silc_free(fingerprint);
1664 silc_query_attributes_print(server, silc_client, conn, attrs,
1669 case SILC_COMMAND_IDENTIFY:
1671 SilcClientEntry client_entry;
1673 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1674 /* Print the unknown nick for user */
1675 unsigned char *tmp =
1676 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1679 silc_say_error("%s: %s", tmp,
1680 silc_get_status_message(status));
1682 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1683 /* Try to find the entry for the unknown client ID, since we
1684 might have, and print the nickname of it for user. */
1686 unsigned char *tmp =
1687 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1690 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1693 client_entry = silc_client_get_client_by_id(client, conn,
1695 if (client_entry && client_entry->nickname)
1696 silc_say_error("%s: %s", client_entry->nickname,
1697 silc_get_status_message(status));
1698 silc_free(client_id);
1707 case SILC_COMMAND_WHOWAS:
1709 char *nickname, *username, *realname;
1711 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1712 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1714 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1717 silc_say_error("%s: %s", tmp,
1718 silc_get_status_message(status));
1720 } else if (!success) {
1721 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1725 (void)va_arg(vp, SilcClientEntry);
1726 nickname = va_arg(vp, char *);
1727 username = va_arg(vp, char *);
1728 realname = va_arg(vp, char *);
1730 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1731 SILCTXT_WHOWAS_USERINFO, nickname, username,
1732 realname ? realname : "");
1736 case SILC_COMMAND_INVITE:
1738 SilcChannelEntry channel;
1740 SilcArgumentPayload invite_list;
1746 channel = va_arg(vp, SilcChannelEntry);
1747 payload = va_arg(vp, SilcBuffer);
1750 SILC_GET16_MSB(argc, payload->data);
1751 invite_list = silc_argument_payload_parse(payload->data + 2,
1752 payload->len - 2, argc);
1754 silc_parse_inviteban_list(client, conn, server, channel,
1755 "invite", invite_list);
1756 silc_argument_payload_free(invite_list);
1762 case SILC_COMMAND_JOIN:
1764 char *channel, *mode, *topic;
1766 SilcChannelEntry channel_entry;
1767 SilcBuffer client_id_list;
1768 SilcUInt32 list_count;
1773 channel = va_arg(vp, char *);
1774 channel_entry = va_arg(vp, SilcChannelEntry);
1775 modei = va_arg(vp, SilcUInt32);
1776 (void)va_arg(vp, SilcUInt32);
1777 (void)va_arg(vp, unsigned char *);
1778 (void)va_arg(vp, unsigned char *);
1779 (void)va_arg(vp, unsigned char *);
1780 topic = va_arg(vp, char *);
1781 (void)va_arg(vp, unsigned char *);
1782 list_count = va_arg(vp, SilcUInt32);
1783 client_id_list = va_arg(vp, SilcBuffer);
1785 chanrec = silc_channel_find(server, channel);
1787 chanrec = silc_channel_create(server, channel, channel, TRUE);
1790 char tmp[256], *cp, *dm = NULL;
1791 g_free_not_null(chanrec->topic);
1793 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1794 memset(tmp, 0, sizeof(tmp));
1796 if (strlen(topic) > sizeof(tmp) - 1) {
1797 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1801 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1806 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1807 signal_emit("channel topic changed", 1, chanrec);
1812 mode = silc_client_chmode(modei,
1813 channel_entry->channel_key ?
1814 silc_cipher_get_name(channel_entry->
1816 channel_entry->hmac ?
1817 silc_hmac_get_name(channel_entry->hmac) : "");
1818 g_free_not_null(chanrec->mode);
1819 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1820 signal_emit("channel mode changed", 1, chanrec);
1822 /* Resolve the client information */
1824 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1825 r->channel = channel_entry;
1826 silc_client_get_clients_by_list(client, conn, list_count,
1828 silc_client_join_get_users, r);
1834 case SILC_COMMAND_NICK:
1837 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1843 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1844 if ((nicks != NULL) &&
1845 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1847 SilcClientEntry collider, old;
1849 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1850 collider = silc_client_get_client_by_id(client, conn,
1853 memset(buf, 0, sizeof(buf));
1854 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1855 collider->username, collider->hostname);
1856 nicklist_rename_unique(SERVER(server),
1858 collider, collider->nickname);
1859 silc_print_nick_change(server, collider->nickname,
1860 client_entry->nickname, buf);
1861 g_slist_free(nicks);
1864 old = g_strdup(server->nick);
1865 server_change_nick(SERVER(server), client_entry->nickname);
1866 nicklist_rename_unique(SERVER(server),
1867 server->conn->local_entry, server->nick,
1868 client_entry, client_entry->nickname);
1869 signal_emit("message own_nick", 4, server, server->nick, old, "");
1874 case SILC_COMMAND_LIST:
1879 char tmp[256], *cp, *dm = NULL;
1884 (void)va_arg(vp, SilcChannelEntry);
1885 name = va_arg(vp, char *);
1886 topic = va_arg(vp, char *);
1887 usercount = va_arg(vp, int);
1889 if (topic && !silc_term_utf8() &&
1890 silc_utf8_valid(topic, strlen(topic))) {
1891 memset(tmp, 0, sizeof(tmp));
1893 if (strlen(topic) > sizeof(tmp) - 1) {
1894 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1898 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1903 if (status == SILC_STATUS_LIST_START ||
1904 status == SILC_STATUS_OK)
1905 printformat_module("fe-common/silc", server, NULL,
1906 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1909 snprintf(users, sizeof(users) - 1, "N/A");
1911 snprintf(users, sizeof(users) - 1, "%d", usercount);
1912 printformat_module("fe-common/silc", server, NULL,
1913 MSGLEVEL_CRAP, SILCTXT_LIST,
1914 name, users, topic ? topic : "");
1919 case SILC_COMMAND_UMODE:
1927 mode = va_arg(vp, SilcUInt32);
1929 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1930 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1931 printformat_module("fe-common/silc", server, NULL,
1932 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1934 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1935 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1936 printformat_module("fe-common/silc", server, NULL,
1937 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1939 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1940 if (mode & SILC_UMODE_GONE) {
1941 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1942 reason = g_strdup(server->away_reason);
1944 reason = g_strdup("away");
1946 reason = g_strdup("");
1948 silc_set_away(reason, server);
1953 server->umode = mode;
1954 signal_emit("user mode changed", 2, server, NULL);
1958 case SILC_COMMAND_OPER:
1962 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1963 signal_emit("user mode changed", 2, server, NULL);
1965 printformat_module("fe-common/silc", server, NULL,
1966 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1969 case SILC_COMMAND_SILCOPER:
1973 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1974 signal_emit("user mode changed", 2, server, NULL);
1976 printformat_module("fe-common/silc", server, NULL,
1977 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1980 case SILC_COMMAND_USERS:
1982 SilcHashTableList htl;
1983 SilcChannelEntry channel;
1984 SilcChannelUser chu;
1989 channel = va_arg(vp, SilcChannelEntry);
1991 printformat_module("fe-common/silc", server, channel->channel_name,
1992 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1993 channel->channel_name);
1995 silc_hash_table_list(channel->user_list, &htl);
1996 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1997 SilcClientEntry e = chu->client;
1998 char stat[5], *mode;
2003 memset(stat, 0, sizeof(stat));
2004 mode = silc_client_chumode_char(chu->mode);
2005 if (e->mode & SILC_UMODE_GONE)
2007 else if (e->mode & SILC_UMODE_INDISPOSED)
2009 else if (e->mode & SILC_UMODE_BUSY)
2011 else if (e->mode & SILC_UMODE_PAGE)
2013 else if (e->mode & SILC_UMODE_HYPER)
2015 else if (e->mode & SILC_UMODE_ROBOT)
2017 else if (e->mode & SILC_UMODE_ANONYMOUS)
2024 printformat_module("fe-common/silc", server, channel->channel_name,
2025 MSGLEVEL_CRAP, SILCTXT_USERS,
2027 e->username ? e->username : "",
2028 e->hostname ? e->hostname : "",
2029 e->realname ? e->realname : "");
2033 silc_hash_table_list_reset(&htl);
2037 case SILC_COMMAND_BAN:
2039 SilcChannelEntry channel;
2041 SilcArgumentPayload ban_list;
2047 channel = va_arg(vp, SilcChannelEntry);
2048 payload = va_arg(vp, SilcBuffer);
2051 SILC_GET16_MSB(argc, payload->data);
2052 ban_list = silc_argument_payload_parse(payload->data + 2,
2053 payload->len - 2, argc);
2055 silc_parse_inviteban_list(client, conn, server, channel,
2057 silc_argument_payload_free(ban_list);
2063 case SILC_COMMAND_GETKEY:
2067 SilcPublicKey public_key;
2070 GetkeyContext getkey;
2076 id_type = va_arg(vp, SilcUInt32);
2077 entry = va_arg(vp, void *);
2078 public_key = va_arg(vp, SilcPublicKey);
2081 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2083 getkey = silc_calloc(1, sizeof(*getkey));
2084 getkey->entry = entry;
2085 getkey->id_type = id_type;
2086 getkey->client = client;
2087 getkey->conn = conn;
2088 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2090 name = (id_type == SILC_ID_CLIENT ?
2091 ((SilcClientEntry)entry)->nickname :
2092 ((SilcServerEntry)entry)->server_name);
2094 silc_verify_public_key_internal(client, conn, name,
2095 (id_type == SILC_ID_CLIENT ?
2096 SILC_SOCKET_TYPE_CLIENT :
2097 SILC_SOCKET_TYPE_SERVER),
2098 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2099 silc_getkey_cb, getkey);
2102 printformat_module("fe-common/silc", server, NULL,
2103 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2108 case SILC_COMMAND_INFO:
2110 SilcServerEntry server_entry;
2117 server_entry = va_arg(vp, SilcServerEntry);
2118 server_name = va_arg(vp, char *);
2119 server_info = va_arg(vp, char *);
2121 if (server_name && server_info )
2123 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2124 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2129 case SILC_COMMAND_TOPIC:
2131 SilcChannelEntry channel;
2133 char tmp[256], *cp, *dm = NULL;
2138 channel = va_arg(vp, SilcChannelEntry);
2139 topic = va_arg(vp, char *);
2141 if (topic && !silc_term_utf8() &&
2142 silc_utf8_valid(topic, strlen(topic))) {
2143 memset(tmp, 0, sizeof(tmp));
2145 if (strlen(topic) > sizeof(tmp) - 1) {
2146 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2150 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2156 chanrec = silc_channel_find_entry(server, channel);
2158 g_free_not_null(chanrec->topic);
2159 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2160 signal_emit("channel topic changed", 1, chanrec);
2162 printformat_module("fe-common/silc", server, channel->channel_name,
2163 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2164 channel->channel_name, topic);
2166 printformat_module("fe-common/silc", server, channel->channel_name,
2167 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2168 channel->channel_name);
2174 case SILC_COMMAND_WATCH:
2177 case SILC_COMMAND_STATS:
2179 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2180 my_router_ops, cell_clients, cell_channels, cell_servers,
2181 clients, channels, servers, routers, server_ops, router_ops;
2183 SilcBufferStruct buf;
2184 unsigned char *tmp_buf;
2186 const char *tmptime;
2187 int days, hours, mins, secs;
2192 tmp_buf = va_arg(vp, unsigned char *);
2193 buf_len = va_arg(vp, SilcUInt32);
2195 if (!tmp_buf || !buf_len) {
2196 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2200 /* Get statistics structure */
2201 silc_buffer_set(&buf, tmp_buf, buf_len);
2202 silc_buffer_unformat(&buf,
2203 SILC_STR_UI_INT(&starttime),
2204 SILC_STR_UI_INT(&uptime),
2205 SILC_STR_UI_INT(&my_clients),
2206 SILC_STR_UI_INT(&my_channels),
2207 SILC_STR_UI_INT(&my_server_ops),
2208 SILC_STR_UI_INT(&my_router_ops),
2209 SILC_STR_UI_INT(&cell_clients),
2210 SILC_STR_UI_INT(&cell_channels),
2211 SILC_STR_UI_INT(&cell_servers),
2212 SILC_STR_UI_INT(&clients),
2213 SILC_STR_UI_INT(&channels),
2214 SILC_STR_UI_INT(&servers),
2215 SILC_STR_UI_INT(&routers),
2216 SILC_STR_UI_INT(&server_ops),
2217 SILC_STR_UI_INT(&router_ops),
2220 tmptime = silc_get_time(starttime);
2221 printformat_module("fe-common/silc", server, NULL,
2222 MSGLEVEL_CRAP, SILCTXT_STATS,
2223 "Local server start time", tmptime);
2225 days = uptime / (24 * 60 * 60);
2226 uptime -= days * (24 * 60 * 60);
2227 hours = uptime / (60 * 60);
2228 uptime -= hours * (60 * 60);
2230 uptime -= mins * 60;
2232 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2233 days, hours, mins, secs);
2234 printformat_module("fe-common/silc", server, NULL,
2235 MSGLEVEL_CRAP, SILCTXT_STATS,
2236 "Local server uptime", tmp);
2238 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2239 printformat_module("fe-common/silc", server, NULL,
2240 MSGLEVEL_CRAP, SILCTXT_STATS,
2241 "Local server clients", tmp);
2243 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2244 printformat_module("fe-common/silc", server, NULL,
2245 MSGLEVEL_CRAP, SILCTXT_STATS,
2246 "Local server channels", tmp);
2248 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2249 printformat_module("fe-common/silc", server, NULL,
2250 MSGLEVEL_CRAP, SILCTXT_STATS,
2251 "Local server operators", tmp);
2253 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2254 printformat_module("fe-common/silc", server, NULL,
2255 MSGLEVEL_CRAP, SILCTXT_STATS,
2256 "Local router operators", tmp);
2258 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2259 printformat_module("fe-common/silc", server, NULL,
2260 MSGLEVEL_CRAP, SILCTXT_STATS,
2261 "Local cell clients", tmp);
2263 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2264 printformat_module("fe-common/silc", server, NULL,
2265 MSGLEVEL_CRAP, SILCTXT_STATS,
2266 "Local cell channels", tmp);
2268 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2269 printformat_module("fe-common/silc", server, NULL,
2270 MSGLEVEL_CRAP, SILCTXT_STATS,
2271 "Local cell servers", tmp);
2273 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2274 printformat_module("fe-common/silc", server, NULL,
2275 MSGLEVEL_CRAP, SILCTXT_STATS,
2276 "Total clients", tmp);
2278 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2279 printformat_module("fe-common/silc", server, NULL,
2280 MSGLEVEL_CRAP, SILCTXT_STATS,
2281 "Total channels", tmp);
2283 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2284 printformat_module("fe-common/silc", server, NULL,
2285 MSGLEVEL_CRAP, SILCTXT_STATS,
2286 "Total servers", tmp);
2288 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2289 printformat_module("fe-common/silc", server, NULL,
2290 MSGLEVEL_CRAP, SILCTXT_STATS,
2291 "Total routers", tmp);
2293 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2294 printformat_module("fe-common/silc", server, NULL,
2295 MSGLEVEL_CRAP, SILCTXT_STATS,
2296 "Total server operators", tmp);
2298 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2299 printformat_module("fe-common/silc", server, NULL,
2300 MSGLEVEL_CRAP, SILCTXT_STATS,
2301 "Total router operators", tmp);
2305 case SILC_COMMAND_CMODE:
2307 SilcChannelEntry channel_entry;
2308 SilcBuffer channel_pubkeys;
2310 channel_entry = va_arg(vp, SilcChannelEntry);
2311 (void)va_arg(vp, SilcUInt32);
2312 (void)va_arg(vp, SilcPublicKey);
2313 channel_pubkeys = va_arg(vp, SilcBuffer);
2315 if (!success || !cmode_list_chpks ||
2316 !channel_entry || !channel_entry->channel_name)
2319 /* Print the channel public key list */
2320 if (channel_pubkeys)
2321 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2323 printformat_module("fe-common/silc", server, NULL,
2324 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2325 channel_entry->channel_name);
2336 SilcClientConnection conn;
2342 SilcSKEPKType pk_type;
2343 SilcVerifyPublicKey completion;
2347 static void verify_public_key_completion(const char *line, void *context)
2349 PublicKeyVerify verify = (PublicKeyVerify)context;
2351 if (line[0] == 'Y' || line[0] == 'y') {
2352 /* Call the completion */
2353 if (verify->completion)
2354 verify->completion(TRUE, verify->context);
2356 /* Save the key for future checking */
2357 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2358 verify->pk_len, SILC_PKCS_FILE_PEM);
2360 /* Call the completion */
2361 if (verify->completion)
2362 verify->completion(FALSE, verify->context);
2364 printformat_module("fe-common/silc", NULL, NULL,
2365 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2366 verify->entity_name ? verify->entity_name :
2370 silc_free(verify->filename);
2371 silc_free(verify->entity);
2372 silc_free(verify->entity_name);
2373 silc_free(verify->pk);
2377 /* Internal routine to verify public key. If the `completion' is provided
2378 it will be called to indicate whether public was verified or not. For
2379 server/router public key this will check for filename that includes the
2380 remote host's IP address and remote host's hostname. */
2383 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2384 const char *name, SilcSocketType conn_type,
2385 unsigned char *pk, SilcUInt32 pk_len,
2386 SilcSKEPKType pk_type,
2387 SilcVerifyPublicKey completion, void *context)
2390 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2391 char *fingerprint, *babbleprint, *format;
2394 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2395 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2396 "server" : "client");
2397 PublicKeyVerify verify;
2399 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2400 printformat_module("fe-common/silc", NULL, NULL,
2401 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2404 completion(FALSE, context);
2408 pw = getpwuid(getuid());
2411 completion(FALSE, context);
2415 memset(filename, 0, sizeof(filename));
2416 memset(filename2, 0, sizeof(filename2));
2417 memset(file, 0, sizeof(file));
2419 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2420 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2422 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2423 conn->sock->ip, conn->sock->port);
2424 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2425 get_irssi_dir(), entity, file);
2427 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2428 conn->sock->hostname, conn->sock->port);
2429 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2430 get_irssi_dir(), entity, file);
2435 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2436 name, conn->sock->port);
2437 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2438 get_irssi_dir(), entity, file);
2443 /* Replace all whitespaces with `_'. */
2444 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2445 for (i = 0; i < strlen(fingerprint); i++)
2446 if (fingerprint[i] == ' ')
2447 fingerprint[i] = '_';
2449 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2450 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2451 get_irssi_dir(), entity, file);
2452 silc_free(fingerprint);
2457 /* Take fingerprint of the public key */
2458 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2459 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2461 verify = silc_calloc(1, sizeof(*verify));
2462 verify->client = client;
2463 verify->conn = conn;
2464 verify->filename = strdup(ipf);
2465 verify->entity = strdup(entity);
2466 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2467 (name ? strdup(name) : strdup(conn->sock->hostname))
2469 verify->pk = silc_memdup(pk, pk_len);
2470 verify->pk_len = pk_len;
2471 verify->pk_type = pk_type;
2472 verify->completion = completion;
2473 verify->context = context;
2475 /* Check whether this key already exists */
2476 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2477 /* Key does not exist, ask user to verify the key and save it */
2479 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2480 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2481 verify->entity_name : entity);
2482 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2483 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2484 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2485 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2486 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2487 SILCTXT_PUBKEY_ACCEPT);
2488 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2491 silc_free(fingerprint);
2494 /* The key already exists, verify it. */
2495 SilcPublicKey public_key;
2496 unsigned char *encpk;
2497 SilcUInt32 encpk_len;
2499 /* Load the key file, try for both IP filename and hostname filename */
2500 if (!silc_pkcs_load_public_key(ipf, &public_key,
2501 SILC_PKCS_FILE_PEM) &&
2502 !silc_pkcs_load_public_key(ipf, &public_key,
2503 SILC_PKCS_FILE_BIN) &&
2504 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2505 SILC_PKCS_FILE_PEM) &&
2506 !silc_pkcs_load_public_key(hostf, &public_key,
2507 SILC_PKCS_FILE_BIN)))) {
2508 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2509 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2510 verify->entity_name : entity);
2511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2512 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2513 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2514 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2515 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2516 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2517 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2518 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2519 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2522 silc_free(fingerprint);
2526 /* Encode the key data */
2527 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2529 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2530 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2531 verify->entity_name : entity);
2532 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2533 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2534 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2535 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2536 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2537 SILCTXT_PUBKEY_MALFORMED, entity);
2538 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2539 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2540 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2543 silc_free(fingerprint);
2547 /* Compare the keys */
2548 if (memcmp(encpk, pk, encpk_len)) {
2549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2550 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2551 verify->entity_name : entity);
2552 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2553 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2554 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2555 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2556 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2557 SILCTXT_PUBKEY_NO_MATCH, entity);
2558 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2559 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2560 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2561 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2563 /* Ask user to verify the key and save it */
2564 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2565 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2566 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2569 silc_free(fingerprint);
2573 /* Local copy matched */
2575 completion(TRUE, context);
2576 silc_free(fingerprint);
2577 silc_free(verify->filename);
2578 silc_free(verify->entity);
2579 silc_free(verify->entity_name);
2580 silc_free(verify->pk);
2585 /* Verifies received public key. The `conn_type' indicates which entity
2586 (server, client etc.) has sent the public key. If user decides to trust
2587 the key may be saved as trusted public key for later use. The
2588 `completion' must be called after the public key has been verified. */
2591 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2592 SilcSocketType conn_type, unsigned char *pk,
2593 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2594 SilcVerifyPublicKey completion, void *context)
2596 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2598 completion, context);
2601 /* Asks passphrase from user on the input line. */
2604 SilcAskPassphrase completion;
2608 void ask_passphrase_completion(const char *passphrase, void *context)
2610 AskPassphrase p = (AskPassphrase)context;
2611 if (passphrase && passphrase[0] == '\0')
2613 p->completion((unsigned char *)passphrase,
2614 passphrase ? strlen(passphrase) : 0, p->context);
2618 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2619 SilcAskPassphrase completion, void *context)
2621 AskPassphrase p = silc_calloc(1, sizeof(*p));
2622 p->completion = completion;
2623 p->context = context;
2625 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2626 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2630 SilcGetAuthMeth completion;
2632 } *InternalGetAuthMethod;
2634 /* Callback called when we've received the authentication method information
2635 from the server after we've requested it. This will get the authentication
2636 data from the user if needed. */
2638 static void silc_get_auth_method_callback(SilcClient client,
2639 SilcClientConnection conn,
2640 SilcAuthMethod auth_meth,
2643 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2645 SILC_LOG_DEBUG(("Start"));
2647 switch (auth_meth) {
2648 case SILC_AUTH_NONE:
2649 /* No authentication required. */
2650 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2652 case SILC_AUTH_PASSWORD:
2654 /* Check whether we find the password for this server in our
2655 configuration. If not, then don't provide so library will ask
2656 it from the user. */
2657 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2659 if (!setup || !setup->password) {
2660 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2664 (*internal->completion)(TRUE, auth_meth, setup->password,
2665 strlen(setup->password), internal->context);
2668 case SILC_AUTH_PUBLIC_KEY:
2669 /* Do not get the authentication data now, the library will generate
2670 it using our default key, if we do not provide it here. */
2671 /* XXX In the future when we support multiple local keys and multiple
2672 local certificates we will need to ask from user which one to use. */
2673 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2677 silc_free(internal);
2680 /* Find authentication method and authentication data by hostname and
2681 port. The hostname may be IP address as well. The found authentication
2682 method and authentication data is returned to `auth_meth', `auth_data'
2683 and `auth_data_len'. The function returns TRUE if authentication method
2684 is found and FALSE if not. `conn' may be NULL. */
2686 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2687 char *hostname, SilcUInt16 port,
2688 SilcGetAuthMeth completion, void *context)
2690 InternalGetAuthMethod internal;
2692 SILC_LOG_DEBUG(("Start"));
2694 /* If we do not have this connection configured by the user in a
2695 configuration file then resolve the authentication method from the
2696 server for this session. */
2697 internal = silc_calloc(1, sizeof(*internal));
2698 internal->completion = completion;
2699 internal->context = context;
2701 silc_client_request_authentication_method(client, conn,
2702 silc_get_auth_method_callback,
2706 /* Notifies application that failure packet was received. This is called
2707 if there is some protocol active in the client. The `protocol' is the
2708 protocol context. The `failure' is opaque pointer to the failure
2709 indication. Note, that the `failure' is protocol dependant and application
2710 must explicitly cast it to correct type. Usually `failure' is 32 bit
2711 failure type (see protocol specs for all protocol failure types). */
2713 void silc_failure(SilcClient client, SilcClientConnection conn,
2714 SilcProtocol protocol, void *failure)
2716 SILC_LOG_DEBUG(("Start"));
2718 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2719 SilcSKEStatus status = (SilcSKEStatus)failure;
2721 if (status == SILC_SKE_STATUS_BAD_VERSION)
2722 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2723 SILCTXT_KE_BAD_VERSION);
2724 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2725 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2726 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2727 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2728 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2729 SILCTXT_KE_UNKNOWN_GROUP);
2730 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2731 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2732 SILCTXT_KE_UNKNOWN_CIPHER);
2733 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2734 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2735 SILCTXT_KE_UNKNOWN_PKCS);
2736 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2737 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2738 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2739 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2740 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2741 SILCTXT_KE_UNKNOWN_HMAC);
2742 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2743 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2744 SILCTXT_KE_INCORRECT_SIGNATURE);
2745 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2746 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2747 SILCTXT_KE_INVALID_COOKIE);
2750 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2751 SilcUInt32 err = (SilcUInt32)failure;
2753 if (err == SILC_AUTH_FAILED)
2754 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2755 SILCTXT_AUTH_FAILED);
2759 /* Asks whether the user would like to perform the key agreement protocol.
2760 This is called after we have received an key agreement packet or an
2761 reply to our key agreement packet. This returns TRUE if the user wants
2762 the library to perform the key agreement protocol and FALSE if it is not
2763 desired (application may start it later by calling the function
2764 silc_client_perform_key_agreement). */
2766 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2767 SilcClientEntry client_entry, const char *hostname,
2768 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2773 SILC_LOG_DEBUG(("Start"));
2775 /* We will just display the info on the screen and return FALSE and user
2776 will have to start the key agreement with a command. */
2779 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2782 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2783 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2785 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2786 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2787 client_entry->nickname, hostname, portstr);
2795 /* Notifies application that file transfer protocol session is being
2796 requested by the remote client indicated by the `client_entry' from
2797 the `hostname' and `port'. The `session_id' is the file transfer
2798 session and it can be used to either accept or reject the file
2799 transfer request, by calling the silc_client_file_receive or
2800 silc_client_file_close, respectively. */
2802 void silc_ftp(SilcClient client, SilcClientConnection conn,
2803 SilcClientEntry client_entry, SilcUInt32 session_id,
2804 const char *hostname, SilcUInt16 port)
2806 SILC_SERVER_REC *server;
2808 FtpSession ftp = NULL;
2810 SILC_LOG_DEBUG(("Start"));
2812 server = conn->context;
2814 silc_dlist_start(server->ftp_sessions);
2815 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2816 if (ftp->client_entry == client_entry &&
2817 ftp->session_id == session_id) {
2818 server->current_session = ftp;
2822 if (ftp == SILC_LIST_END) {
2823 ftp = silc_calloc(1, sizeof(*ftp));
2824 ftp->client_entry = client_entry;
2825 ftp->session_id = session_id;
2828 silc_dlist_add(server->ftp_sessions, ftp);
2829 server->current_session = ftp;
2833 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2836 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2837 SILCTXT_FILE_REQUEST, client_entry->nickname);
2839 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2840 SILCTXT_FILE_REQUEST_HOST,
2841 client_entry->nickname, hostname, portstr);
2844 /* Delivers SILC session detachment data indicated by `detach_data' to the
2845 application. If application has issued SILC_COMMAND_DETACH command
2846 the client session in the SILC network is not quit. The client remains
2847 in the network but is detached. The detachment data may be used later
2848 to resume the session in the SILC Network. The appliation is
2849 responsible of saving the `detach_data', to for example in a file.
2851 The detachment data can be given as argument to the functions
2852 silc_client_connect_to_server, or silc_client_add_connection when
2853 creating connection to remote server, inside SilcClientConnectionParams
2854 structure. If it is provided the client library will attempt to resume
2855 the session in the network. After the connection is created
2856 successfully, the application is responsible of setting the user
2857 interface for user into the same state it was before detaching (showing
2858 same channels, channel modes, etc). It can do this by fetching the
2859 information (like joined channels) from the client library. */
2862 silc_detach(SilcClient client, SilcClientConnection conn,
2863 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2867 /* Save the detachment data to file. */
2869 memset(file, 0, sizeof(file));
2870 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2871 silc_file_writefile(file, detach_data, detach_data_len);
2875 /* SILC client operations */
2876 SilcClientOperations ops = {
2878 silc_channel_message,
2879 silc_private_message,
2885 silc_get_auth_method,
2886 silc_verify_public_key,
2887 silc_ask_passphrase,