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", 4, 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, sender->nickname) : NULL,
533 message, message_len,
534 sender->nickname ? sender->nickname : "[<unknown>]",
535 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
542 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
543 char tmp[256], *cp, *dm = NULL;
545 memset(tmp, 0, sizeof(tmp));
547 if (message_len > sizeof(tmp) - 1) {
548 dm = silc_calloc(message_len + 1, sizeof(*dm));
552 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
554 if (flags & SILC_MESSAGE_FLAG_SIGNED)
555 signal_emit("message signed_private", 5, server, cp,
556 sender->nickname ? sender->nickname : "[<unknown>]",
557 sender->username ? userhost : NULL, verified);
559 signal_emit("message private", 4, server, cp,
560 sender->nickname ? sender->nickname : "[<unknown>]",
561 sender->username ? userhost : NULL);
566 if (flags & SILC_MESSAGE_FLAG_SIGNED)
567 signal_emit("message signed_private", 5, server, message,
568 sender->nickname ? sender->nickname : "[<unknown>]",
569 sender->username ? userhost : NULL, verified);
571 signal_emit("message private", 4, server, message,
572 sender->nickname ? sender->nickname : "[<unknown>]",
573 sender->username ? userhost : NULL);
576 /* Notify message to the client. The notify arguments are sent in the
577 same order as servers sends them. The arguments are same as received
578 from the server except for ID's. If ID is received application receives
579 the corresponding entry to the ID. For example, if Client ID is received
580 application receives SilcClientEntry. Also, if the notify type is
581 for channel the channel entry is sent to application (even if server
582 does not send it). */
584 void silc_notify(SilcClient client, SilcClientConnection conn,
585 SilcNotifyType type, ...)
588 SILC_SERVER_REC *server;
589 SILC_CHANNEL_REC *chanrec;
590 SILC_NICK_REC *nickrec;
591 SilcClientEntry client_entry, client_entry2;
592 SilcChannelEntry channel, channel2;
593 SilcServerEntry server_entry;
599 GSList *list1, *list_tmp;
602 SILC_LOG_DEBUG(("Start"));
606 server = conn == NULL ? NULL : conn->context;
609 case SILC_NOTIFY_TYPE_NONE:
610 /* Some generic notice from server */
611 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
614 case SILC_NOTIFY_TYPE_INVITE:
616 * Invited or modified invite list.
619 SILC_LOG_DEBUG(("Notify: INVITE"));
621 channel = va_arg(va, SilcChannelEntry);
622 name = va_arg(va, char *);
623 client_entry = va_arg(va, SilcClientEntry);
625 memset(buf, 0, sizeof(buf));
626 snprintf(buf, sizeof(buf) - 1, "%s@%s",
627 client_entry->username, client_entry->hostname);
628 signal_emit("message invite", 4, server, channel ? channel->channel_name :
629 name, client_entry->nickname, buf);
632 case SILC_NOTIFY_TYPE_JOIN:
637 SILC_LOG_DEBUG(("Notify: JOIN"));
639 client_entry = va_arg(va, SilcClientEntry);
640 channel = va_arg(va, SilcChannelEntry);
642 if (client_entry == server->conn->local_entry) {
643 /* You joined to channel */
644 chanrec = silc_channel_find(server, channel->channel_name);
645 if (chanrec != NULL && !chanrec->joined)
646 chanrec->entry = channel;
648 chanrec = silc_channel_find_entry(server, channel);
649 if (chanrec != NULL) {
650 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
652 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
656 memset(buf, 0, sizeof(buf));
657 if (client_entry->username)
658 snprintf(buf, sizeof(buf) - 1, "%s@%s",
659 client_entry->username, client_entry->hostname);
660 signal_emit("message join", 4, server, channel->channel_name,
661 client_entry->nickname,
662 client_entry->username == NULL ? "" : buf);
665 case SILC_NOTIFY_TYPE_LEAVE:
670 SILC_LOG_DEBUG(("Notify: LEAVE"));
672 client_entry = va_arg(va, SilcClientEntry);
673 channel = va_arg(va, SilcChannelEntry);
675 memset(buf, 0, sizeof(buf));
676 if (client_entry->username)
677 snprintf(buf, sizeof(buf) - 1, "%s@%s",
678 client_entry->username, client_entry->hostname);
679 signal_emit("message part", 5, server, channel->channel_name,
680 client_entry->nickname, client_entry->username ?
681 buf : "", client_entry->nickname);
683 chanrec = silc_channel_find_entry(server, channel);
684 if (chanrec != NULL) {
685 nickrec = silc_nicklist_find(chanrec, client_entry);
687 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
691 case SILC_NOTIFY_TYPE_SIGNOFF:
696 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
698 client_entry = va_arg(va, SilcClientEntry);
699 tmp = va_arg(va, char *);
701 silc_server_free_ftp(server, client_entry);
703 /* Print only if we have the nickname. If this cliente has just quit
704 when we were only resolving it, it is possible we don't have the
706 if (client_entry->nickname) {
707 memset(buf, 0, sizeof(buf));
708 if (client_entry->username)
709 snprintf(buf, sizeof(buf) - 1, "%s@%s",
710 client_entry->username, client_entry->hostname);
711 signal_emit("message quit", 4, server, client_entry->nickname,
712 client_entry->username ? buf : "",
716 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
717 for (list_tmp = list1; list_tmp != NULL; list_tmp =
718 list_tmp->next->next) {
719 CHANNEL_REC *channel = list_tmp->data;
720 NICK_REC *nickrec = list_tmp->next->data;
722 nicklist_remove(channel, nickrec);
726 case SILC_NOTIFY_TYPE_TOPIC_SET:
731 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
733 idtype = va_arg(va, int);
734 entry = va_arg(va, void *);
735 tmp = va_arg(va, char *);
736 channel = va_arg(va, SilcChannelEntry);
738 chanrec = silc_channel_find_entry(server, channel);
739 if (chanrec != NULL) {
740 char tmp2[256], *cp, *dm = NULL;
742 g_free_not_null(chanrec->topic);
743 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
744 memset(tmp2, 0, sizeof(tmp2));
746 if (strlen(tmp) > sizeof(tmp2) - 1) {
747 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
751 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
756 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
757 signal_emit("channel topic changed", 1, chanrec);
762 if (idtype == SILC_ID_CLIENT) {
763 client_entry = (SilcClientEntry)entry;
764 memset(buf, 0, sizeof(buf));
765 snprintf(buf, sizeof(buf) - 1, "%s@%s",
766 client_entry->username, client_entry->hostname);
767 signal_emit("message topic", 5, server, channel->channel_name,
768 tmp, client_entry->nickname, buf);
769 } else if (idtype == SILC_ID_SERVER) {
770 server_entry = (SilcServerEntry)entry;
771 signal_emit("message topic", 5, server, channel->channel_name,
772 tmp, server_entry->server_name,
773 server_entry->server_name);
774 } else if (idtype == SILC_ID_CHANNEL) {
775 channel = (SilcChannelEntry)entry;
776 signal_emit("message topic", 5, server, channel->channel_name,
777 tmp, channel->channel_name, channel->channel_name);
781 case SILC_NOTIFY_TYPE_NICK_CHANGE:
786 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
788 client_entry = va_arg(va, SilcClientEntry);
789 client_entry2 = va_arg(va, SilcClientEntry);
791 if (!strcmp(client_entry->nickname, client_entry2->nickname))
794 memset(buf, 0, sizeof(buf));
795 snprintf(buf, sizeof(buf) - 1, "%s@%s",
796 client_entry2->username, client_entry2->hostname);
797 nicklist_rename_unique(SERVER(server),
798 client_entry, client_entry->nickname,
799 client_entry2, client_entry2->nickname);
800 signal_emit("message nick", 4, server, client_entry2->nickname,
801 client_entry->nickname, buf);
804 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
806 * Changed channel mode.
809 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
811 idtype = va_arg(va, int);
812 entry = va_arg(va, void *);
813 mode = va_arg(va, SilcUInt32);
814 (void)va_arg(va, char *); /* cipher */
815 (void)va_arg(va, char *); /* hmac */
816 (void)va_arg(va, char *); /* passphrase */
817 (void)va_arg(va, SilcPublicKey); /* founder key */
818 buffer = va_arg(va, SilcBuffer); /* channel public keys */
819 channel = va_arg(va, SilcChannelEntry);
821 tmp = silc_client_chmode(mode,
822 channel->channel_key ?
823 silc_cipher_get_name(channel->channel_key) : "",
825 silc_hmac_get_name(channel->hmac) : "");
827 chanrec = silc_channel_find_entry(server, channel);
828 if (chanrec != NULL) {
829 g_free_not_null(chanrec->mode);
830 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
831 signal_emit("channel mode changed", 1, chanrec);
834 if (idtype == SILC_ID_CLIENT) {
835 client_entry = (SilcClientEntry)entry;
836 printformat_module("fe-common/silc", server, channel->channel_name,
837 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
838 channel->channel_name, tmp ? tmp : "removed all",
839 client_entry->nickname);
840 } else if (idtype == SILC_ID_SERVER) {
841 server_entry = (SilcServerEntry)entry;
842 printformat_module("fe-common/silc", server, channel->channel_name,
843 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
844 channel->channel_name, tmp ? tmp : "removed all",
845 server_entry->server_name);
846 } else if (idtype == SILC_ID_CHANNEL) {
847 channel2 = (SilcChannelEntry)entry;
848 printformat_module("fe-common/silc", server, channel->channel_name,
849 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
850 channel->channel_name, tmp ? tmp : "removed all",
851 channel2->channel_name);
854 /* Print the channel public key list */
856 silc_parse_channel_public_keys(server, channel, buffer);
861 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
863 * Changed user's mode on channel.
866 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
868 idtype = va_arg(va, int);
869 entry = va_arg(va, void *);
870 mode = va_arg(va, SilcUInt32);
871 client_entry2 = va_arg(va, SilcClientEntry);
872 channel = va_arg(va, SilcChannelEntry);
874 tmp = silc_client_chumode(mode);
875 chanrec = silc_channel_find_entry(server, channel);
876 if (chanrec != NULL) {
879 if (client_entry2 == server->conn->local_entry)
880 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
882 nick = silc_nicklist_find(chanrec, client_entry2);
884 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
885 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
886 signal_emit("nick mode changed", 2, chanrec, nick);
890 if (idtype == SILC_ID_CLIENT) {
891 client_entry = (SilcClientEntry)entry;
892 printformat_module("fe-common/silc", server, channel->channel_name,
893 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
894 channel->channel_name, client_entry2->nickname,
895 tmp ? tmp : "removed all",
896 client_entry->nickname);
897 } else if (idtype == SILC_ID_SERVER) {
898 server_entry = (SilcServerEntry)entry;
899 printformat_module("fe-common/silc", server, channel->channel_name,
900 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
901 channel->channel_name, client_entry2->nickname,
902 tmp ? tmp : "removed all",
903 server_entry->server_name);
904 } else if (idtype == SILC_ID_CHANNEL) {
905 channel2 = (SilcChannelEntry)entry;
906 printformat_module("fe-common/silc", server, channel->channel_name,
907 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
908 channel->channel_name, client_entry2->nickname,
909 tmp ? tmp : "removed all",
910 channel2->channel_name);
913 if (mode & SILC_CHANNEL_UMODE_CHANFO)
914 printformat_module("fe-common/silc",
915 server, channel->channel_name, MSGLEVEL_CRAP,
916 SILCTXT_CHANNEL_FOUNDER,
917 channel->channel_name, client_entry2->nickname);
919 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
920 printformat_module("fe-common/silc",
921 server, channel->channel_name, MSGLEVEL_CRAP,
922 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
927 case SILC_NOTIFY_TYPE_MOTD:
932 SILC_LOG_DEBUG(("Notify: MOTD"));
934 tmp = va_arg(va, char *);
936 if (!settings_get_bool("skip_motd"))
937 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
940 case SILC_NOTIFY_TYPE_KICKED:
942 * Someone was kicked from channel.
945 SILC_LOG_DEBUG(("Notify: KICKED"));
947 client_entry = va_arg(va, SilcClientEntry);
948 tmp = va_arg(va, char *);
949 client_entry2 = va_arg(va, SilcClientEntry);
950 channel = va_arg(va, SilcChannelEntry);
952 chanrec = silc_channel_find_entry(server, channel);
954 if (client_entry == conn->local_entry) {
955 printformat_module("fe-common/silc", server, channel->channel_name,
956 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
957 channel->channel_name,
958 client_entry ? client_entry2->nickname : "",
961 chanrec->kicked = TRUE;
962 channel_destroy((CHANNEL_REC *)chanrec);
965 printformat_module("fe-common/silc", server, channel->channel_name,
966 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
967 client_entry->nickname, channel->channel_name,
968 client_entry2 ? client_entry2->nickname : "",
972 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
974 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
979 case SILC_NOTIFY_TYPE_KILLED:
981 * Someone was killed from the network.
984 SILC_LOG_DEBUG(("Notify: KILLED"));
986 client_entry = va_arg(va, SilcClientEntry);
987 tmp = va_arg(va, char *);
988 idtype = va_arg(va, int);
989 entry = va_arg(va, SilcClientEntry);
991 if (client_entry == conn->local_entry) {
992 if (idtype == SILC_ID_CLIENT) {
993 client_entry2 = (SilcClientEntry)entry;
994 printformat_module("fe-common/silc", server, NULL,
995 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
996 client_entry2 ? client_entry2->nickname : "",
998 } else if (idtype == SILC_ID_SERVER) {
999 server_entry = (SilcServerEntry)entry;
1000 printformat_module("fe-common/silc", server, NULL,
1001 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1002 server_entry->server_name, tmp ? tmp : "");
1003 } else if (idtype == SILC_ID_CHANNEL) {
1004 channel = (SilcChannelEntry)entry;
1005 printformat_module("fe-common/silc", server, NULL,
1006 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1007 channel->channel_name, tmp ? tmp : "");
1010 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1011 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1012 list_tmp->next->next) {
1013 CHANNEL_REC *channel = list_tmp->data;
1014 NICK_REC *nickrec = list_tmp->next->data;
1015 nicklist_remove(channel, nickrec);
1018 if (idtype == SILC_ID_CLIENT) {
1019 client_entry2 = (SilcClientEntry)entry;
1020 printformat_module("fe-common/silc", server, NULL,
1021 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1022 client_entry->nickname,
1023 client_entry2 ? client_entry2->nickname : "",
1025 } else if (idtype == SILC_ID_SERVER) {
1026 server_entry = (SilcServerEntry)entry;
1027 printformat_module("fe-common/silc", server, NULL,
1028 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1029 client_entry->nickname,
1030 server_entry->server_name, tmp ? tmp : "");
1031 } else if (idtype == SILC_ID_CHANNEL) {
1032 channel = (SilcChannelEntry)entry;
1033 printformat_module("fe-common/silc", server, NULL,
1034 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1035 client_entry->nickname,
1036 channel->channel_name, tmp ? tmp : "");
1041 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1044 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1047 * Server has quit the network.
1050 SilcClientEntry *clients;
1051 SilcUInt32 clients_count;
1053 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1055 (void)va_arg(va, void *);
1056 clients = va_arg(va, SilcClientEntry *);
1057 clients_count = va_arg(va, SilcUInt32);
1059 for (i = 0; i < clients_count; i++) {
1060 memset(buf, 0, sizeof(buf));
1062 /* Print only if we have the nickname. If this client has just quit
1063 when we were only resolving it, it is possible we don't have the
1065 if (clients[i]->nickname) {
1066 if (clients[i]->username)
1067 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1068 clients[i]->username, clients[i]->hostname);
1069 signal_emit("message quit", 4, server, clients[i]->nickname,
1070 clients[i]->username ? buf : "",
1074 silc_server_free_ftp(server, clients[i]);
1076 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1077 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1078 list_tmp->next->next) {
1079 CHANNEL_REC *channel = list_tmp->data;
1080 NICK_REC *nickrec = list_tmp->next->data;
1081 nicklist_remove(channel, nickrec);
1087 case SILC_NOTIFY_TYPE_ERROR:
1089 SilcStatus error = va_arg(va, int);
1091 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1092 "%s", silc_get_status_message(error));
1096 case SILC_NOTIFY_TYPE_WATCH:
1098 SilcNotifyType notify;
1100 client_entry = va_arg(va, SilcClientEntry);
1101 name = va_arg(va, char *); /* Maybe NULL */
1102 mode = va_arg(va, SilcUInt32);
1103 notify = va_arg(va, int);
1105 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1107 printformat_module("fe-common/silc", server, NULL,
1108 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1109 client_entry->nickname, name);
1111 printformat_module("fe-common/silc", server, NULL,
1112 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1113 client_entry->nickname);
1114 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1115 /* See if client was away and is now present */
1116 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1117 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1118 SILC_UMODE_DETACHED)) &&
1119 (client_entry->mode & SILC_UMODE_GONE ||
1120 client_entry->mode & SILC_UMODE_INDISPOSED ||
1121 client_entry->mode & SILC_UMODE_BUSY ||
1122 client_entry->mode & SILC_UMODE_PAGE ||
1123 client_entry->mode & SILC_UMODE_DETACHED)) {
1124 printformat_module("fe-common/silc", server, NULL,
1125 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1126 client_entry->nickname);
1130 memset(buf, 0, sizeof(buf));
1131 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1132 printformat_module("fe-common/silc", server, NULL,
1133 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1134 client_entry->nickname, buf);
1136 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1137 printformat_module("fe-common/silc", server, NULL,
1138 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1139 client_entry->nickname);
1140 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1141 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1142 printformat_module("fe-common/silc", server, NULL,
1143 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1144 client_entry->nickname);
1145 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1146 /* Client logged in to the network */
1147 printformat_module("fe-common/silc", server, NULL,
1148 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1149 client_entry->nickname);
1155 /* Unknown notify */
1156 printformat_module("fe-common/silc", server, NULL,
1157 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1164 /* Called to indicate that connection was either successfully established
1165 or connecting failed. This is also the first time application receives
1166 the SilcClientConnection object which it should save somewhere. */
1168 void silc_connect(SilcClient client, SilcClientConnection conn,
1169 SilcClientConnectionStatus status)
1171 SILC_SERVER_REC *server = conn->context;
1173 if (!server || server->disconnected) {
1174 silc_client_close_connection(client, conn);
1179 case SILC_CLIENT_CONN_SUCCESS:
1180 /* We have successfully connected to server */
1181 server->connected = TRUE;
1182 signal_emit("event connected", 1, server);
1185 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1186 /* We have successfully resumed old detached session */
1187 server->connected = TRUE;
1188 signal_emit("event connected", 1, server);
1190 /* If we resumed old session check whether we need to update
1192 if (strcmp(server->nick, conn->local_entry->nickname)) {
1194 old = g_strdup(server->nick);
1195 server_change_nick(SERVER(server), conn->local_entry->nickname);
1196 nicklist_rename_unique(SERVER(server),
1197 conn->local_entry, server->nick,
1198 conn->local_entry, conn->local_entry->nickname);
1199 signal_emit("message own_nick", 4, server, server->nick, old, "");
1205 server->connection_lost = TRUE;
1207 server->conn->context = NULL;
1208 server_disconnect(SERVER(server));
1213 /* Called to indicate that connection was disconnected to the server. */
1215 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1216 SilcStatus status, const char *message)
1218 SILC_SERVER_REC *server = conn->context;
1220 SILC_LOG_DEBUG(("Start"));
1222 if (!server || server->connection_lost)
1225 if (server->conn && server->conn->local_entry) {
1226 nicklist_rename_unique(SERVER(server),
1227 server->conn->local_entry, server->nick,
1228 server->conn->local_entry,
1229 silc_client->username);
1230 silc_change_nick(server, silc_client->username);
1234 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1235 "Server closed connection: %s (%d) %s",
1236 silc_get_status_message(status), status,
1237 message ? message : "");
1240 server->conn->context = NULL;
1241 server->conn = NULL;
1242 server->connection_lost = TRUE;
1243 server_disconnect(SERVER(server));
1246 /* Command handler. This function is called always in the command function.
1247 If error occurs it will be called as well. `conn' is the associated
1248 client connection. `cmd_context' is the command context that was
1249 originally sent to the command. `success' is FALSE if error occured
1250 during command. `command' is the command being processed. It must be
1251 noted that this is not reply from server. This is merely called just
1252 after application has called the command. Just to tell application
1253 that the command really was processed. */
1255 static bool cmode_list_chpks = FALSE;
1257 void silc_command(SilcClient client, SilcClientConnection conn,
1258 SilcClientCommandContext cmd_context, bool success,
1259 SilcCommand command, SilcStatus status)
1261 SILC_SERVER_REC *server = conn->context;
1263 SILC_LOG_DEBUG(("Start"));
1266 silc_say_error("%s", silc_get_status_message(status));
1272 case SILC_COMMAND_INVITE:
1273 if (cmd_context->argc > 2)
1274 printformat_module("fe-common/silc", server, NULL,
1275 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1276 cmd_context->argv[2],
1277 (cmd_context->argv[1][0] == '*' ?
1278 (char *)conn->current_channel->channel_name :
1279 (char *)cmd_context->argv[1]));
1282 case SILC_COMMAND_DETACH:
1283 server->no_reconnect = TRUE;
1286 case SILC_COMMAND_CMODE:
1287 if (cmd_context->argc == 3 &&
1288 !strcmp(cmd_context->argv[2], "+C"))
1289 cmode_list_chpks = TRUE;
1291 cmode_list_chpks = FALSE;
1300 SilcChannelEntry channel;
1304 /* Client info resolving callback when JOIN command reply is received.
1305 This will cache all users on the channel. */
1307 static void silc_client_join_get_users(SilcClient client,
1308 SilcClientConnection conn,
1309 SilcClientEntry *clients,
1310 SilcUInt32 clients_count,
1313 SilcJoinResolve r = context;
1314 SilcChannelEntry channel = r->channel;
1315 SilcHashTableList htl;
1316 SilcChannelUser chu;
1317 SILC_SERVER_REC *server = conn->context;
1318 SILC_CHANNEL_REC *chanrec;
1319 SilcClientEntry founder = NULL;
1322 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1323 silc_hash_table_count(channel->user_list)));
1325 if (!clients && r->retry < 1) {
1326 /* Retry to resolve */
1328 silc_client_get_clients_by_channel(client, conn, channel,
1329 silc_client_join_get_users, context);
1333 chanrec = silc_channel_find(server, channel->channel_name);
1334 if (chanrec == NULL)
1337 silc_hash_table_list(channel->user_list, &htl);
1338 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1339 if (!chu->client->nickname)
1341 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1342 founder = chu->client;
1343 silc_nicklist_insert(chanrec, chu, FALSE);
1345 silc_hash_table_list_reset(&htl);
1347 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1348 nicklist_set_own(CHANNEL(chanrec), ownnick);
1349 signal_emit("channel joined", 1, chanrec);
1350 chanrec->entry = channel;
1353 printformat_module("fe-common/silc", server, channel->channel_name,
1354 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1355 channel->channel_name, chanrec->topic);
1358 if (founder == conn->local_entry) {
1359 printformat_module("fe-common/silc",
1360 server, channel->channel_name, MSGLEVEL_CRAP,
1361 SILCTXT_CHANNEL_FOUNDER_YOU,
1362 channel->channel_name);
1363 signal_emit("nick mode changed", 2, chanrec, ownnick);
1365 printformat_module("fe-common/silc",
1366 server, channel->channel_name, MSGLEVEL_CRAP,
1367 SILCTXT_CHANNEL_FOUNDER,
1368 channel->channel_name, founder->nickname);
1374 SilcClientConnection conn;
1380 void silc_getkey_cb(bool success, void *context)
1382 GetkeyContext getkey = (GetkeyContext)context;
1383 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1384 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1385 ((SilcClientEntry)getkey->entry)->nickname :
1386 ((SilcServerEntry)getkey->entry)->server_name);
1389 printformat_module("fe-common/silc", NULL, NULL,
1390 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1392 printformat_module("fe-common/silc", NULL, NULL,
1393 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1397 silc_free(getkey->fingerprint);
1401 /* Parse an invite or ban list */
1402 void silc_parse_inviteban_list(SilcClient client,
1403 SilcClientConnection conn,
1404 SILC_SERVER_REC *server,
1405 SilcChannelEntry channel,
1406 const char *list_type,
1407 SilcArgumentPayload list)
1410 SilcUInt32 type, len;
1411 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1412 int counter=0, resolving = FALSE;
1414 if (!silc_argument_get_arg_num(list)) {
1415 printformat_module("fe-common/silc", server,
1416 (chanrec ? chanrec->visible_name : NULL),
1417 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1418 channel->channel_name, list_type);
1422 printformat_module("fe-common/silc", server,
1423 (chanrec ? chanrec->visible_name : NULL),
1424 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1425 channel->channel_name, list_type);
1427 /* parse the list */
1428 tmp = silc_argument_get_first_arg(list, &type, &len);
1433 /* an invite string */
1437 if (tmp[len-1] == ',')
1440 list = g_strsplit(tmp, ",", -1);
1442 printformat_module("fe-common/silc", server,
1443 (chanrec ? chanrec->visible_name : NULL),
1444 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1445 ++counter, channel->channel_name, list_type,
1454 char *fingerprint, *babbleprint;
1456 /* tmp is Public Key Payload, take public key from it. */
1457 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1458 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1460 printformat_module("fe-common/silc", server,
1461 (chanrec ? chanrec->visible_name : NULL),
1462 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1463 ++counter, channel->channel_name, list_type,
1464 fingerprint, babbleprint);
1471 SilcClientID *client_id;
1472 SilcClientEntry client_entry;
1474 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1476 if (client_id == NULL) {
1477 silc_say_error("Invalid data in %s list encountered", list_type);
1481 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1484 printformat_module("fe-common/silc", server,
1485 (chanrec ? chanrec->visible_name : NULL),
1486 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1487 ++counter, channel->channel_name, list_type,
1488 client_entry->nickname);
1491 silc_client_get_client_by_id_resolve(client, conn, client_id,
1495 silc_free(client_id);
1501 silc_say_error("Unkown type in %s list: %u (len %u)",
1502 list_type, type, len);
1504 tmp = silc_argument_get_next_arg(list, &type, &len);
1508 printformat_module("fe-common/silc", server,
1509 (chanrec ? chanrec->visible_name : NULL),
1510 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1511 list_type, channel->channel_name);
1514 /* Command reply handler. This function is called always in the command reply
1515 function. If error occurs it will be called as well. Normal scenario
1516 is that it will be called after the received command data has been parsed
1517 and processed. The function is used to pass the received command data to
1520 `conn' is the associated client connection. `cmd_payload' is the command
1521 payload data received from server and it can be ignored. It is provided
1522 if the application would like to re-parse the received command data,
1523 however, it must be noted that the data is parsed already by the library
1524 thus the payload can be ignored. `success' is FALSE if error occured.
1525 In this case arguments are not sent to the application. `command' is the
1526 command reply being processed. The function has variable argument list
1527 and each command defines the number and type of arguments it passes to the
1528 application (on error they are not sent). */
1531 silc_command_reply(SilcClient client, SilcClientConnection conn,
1532 SilcCommandPayload cmd_payload, bool success,
1533 SilcCommand command, SilcStatus status, ...)
1536 SILC_SERVER_REC *server = conn->context;
1537 SILC_CHANNEL_REC *chanrec;
1540 va_start(vp, status);
1542 SILC_LOG_DEBUG(("Start"));
1545 case SILC_COMMAND_WHOIS:
1547 char buf[1024], *nickname, *username, *realname, *nick;
1548 unsigned char *fingerprint;
1549 SilcUInt32 idle, mode;
1550 SilcBuffer channels, user_modes;
1551 SilcClientEntry client_entry;
1554 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1555 /* Print the unknown nick for user */
1556 unsigned char *tmp =
1557 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1560 silc_say_error("%s: %s", tmp,
1561 silc_get_status_message(status));
1563 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1564 /* Try to find the entry for the unknown client ID, since we
1565 might have, and print the nickname of it for user. */
1567 unsigned char *tmp =
1568 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1571 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1574 client_entry = silc_client_get_client_by_id(client, conn,
1576 if (client_entry && client_entry->nickname)
1577 silc_say_error("%s: %s", client_entry->nickname,
1578 silc_get_status_message(status));
1579 silc_free(client_id);
1583 } else if (!success) {
1584 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1588 client_entry = va_arg(vp, SilcClientEntry);
1589 nickname = va_arg(vp, char *);
1590 username = va_arg(vp, char *);
1591 realname = va_arg(vp, char *);
1592 channels = va_arg(vp, SilcBuffer);
1593 mode = va_arg(vp, SilcUInt32);
1594 idle = va_arg(vp, SilcUInt32);
1595 fingerprint = va_arg(vp, unsigned char *);
1596 user_modes = va_arg(vp, SilcBuffer);
1597 attrs = va_arg(vp, SilcDList);
1599 silc_parse_userfqdn(nickname, &nick, NULL);
1600 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1601 SILCTXT_WHOIS_USERINFO, nickname,
1602 client_entry->username, client_entry->hostname,
1603 nick, client_entry->nickname);
1604 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1605 SILCTXT_WHOIS_REALNAME, realname);
1608 if (channels && user_modes) {
1610 SilcDList list = silc_channel_payload_parse_list(channels->data,
1612 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1614 SilcChannelPayload entry;
1617 memset(buf, 0, sizeof(buf));
1618 silc_dlist_start(list);
1619 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1620 SilcUInt32 name_len;
1621 char *m = silc_client_chumode_char(umodes[i++]);
1622 char *name = silc_channel_get_name(entry, &name_len);
1625 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1626 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1627 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1631 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1632 SILCTXT_WHOIS_CHANNELS, buf);
1633 silc_channel_payload_list_free(list);
1639 memset(buf, 0, sizeof(buf));
1640 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1641 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1642 SILCTXT_WHOIS_MODES, buf);
1645 if (idle && nickname) {
1646 memset(buf, 0, sizeof(buf));
1647 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1648 idle > 60 ? (idle / 60) : idle,
1649 idle > 60 ? "minutes" : "seconds");
1651 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1652 SILCTXT_WHOIS_IDLE, buf);
1656 fingerprint = silc_fingerprint(fingerprint, 20);
1657 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1658 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1659 silc_free(fingerprint);
1663 silc_query_attributes_print(server, silc_client, conn, attrs,
1668 case SILC_COMMAND_IDENTIFY:
1670 SilcClientEntry client_entry;
1672 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1673 /* Print the unknown nick for user */
1674 unsigned char *tmp =
1675 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1678 silc_say_error("%s: %s", tmp,
1679 silc_get_status_message(status));
1681 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1682 /* Try to find the entry for the unknown client ID, since we
1683 might have, and print the nickname of it for user. */
1685 unsigned char *tmp =
1686 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1689 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1692 client_entry = silc_client_get_client_by_id(client, conn,
1694 if (client_entry && client_entry->nickname)
1695 silc_say_error("%s: %s", client_entry->nickname,
1696 silc_get_status_message(status));
1697 silc_free(client_id);
1706 case SILC_COMMAND_WHOWAS:
1708 char *nickname, *username, *realname;
1710 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1711 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1713 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1716 silc_say_error("%s: %s", tmp,
1717 silc_get_status_message(status));
1719 } else if (!success) {
1720 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1724 (void)va_arg(vp, SilcClientEntry);
1725 nickname = va_arg(vp, char *);
1726 username = va_arg(vp, char *);
1727 realname = va_arg(vp, char *);
1729 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1730 SILCTXT_WHOWAS_USERINFO, nickname, username,
1731 realname ? realname : "");
1735 case SILC_COMMAND_INVITE:
1737 SilcChannelEntry channel;
1739 SilcArgumentPayload invite_list;
1745 channel = va_arg(vp, SilcChannelEntry);
1746 payload = va_arg(vp, SilcBuffer);
1749 SILC_GET16_MSB(argc, payload->data);
1750 invite_list = silc_argument_payload_parse(payload->data + 2,
1751 payload->len - 2, argc);
1753 silc_parse_inviteban_list(client, conn, server, channel,
1754 "invite", invite_list);
1755 silc_argument_payload_free(invite_list);
1761 case SILC_COMMAND_JOIN:
1763 char *channel, *mode, *topic;
1765 SilcChannelEntry channel_entry;
1766 SilcBuffer client_id_list;
1767 SilcUInt32 list_count;
1772 channel = va_arg(vp, char *);
1773 channel_entry = va_arg(vp, SilcChannelEntry);
1774 modei = va_arg(vp, SilcUInt32);
1775 (void)va_arg(vp, SilcUInt32);
1776 (void)va_arg(vp, unsigned char *);
1777 (void)va_arg(vp, unsigned char *);
1778 (void)va_arg(vp, unsigned char *);
1779 topic = va_arg(vp, char *);
1780 (void)va_arg(vp, unsigned char *);
1781 list_count = va_arg(vp, SilcUInt32);
1782 client_id_list = va_arg(vp, SilcBuffer);
1784 chanrec = silc_channel_find(server, channel);
1786 chanrec = silc_channel_create(server, channel, channel, TRUE);
1789 char tmp[256], *cp, *dm = NULL;
1790 g_free_not_null(chanrec->topic);
1792 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1793 memset(tmp, 0, sizeof(tmp));
1795 if (strlen(topic) > sizeof(tmp) - 1) {
1796 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1800 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1805 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1806 signal_emit("channel topic changed", 1, chanrec);
1811 mode = silc_client_chmode(modei,
1812 channel_entry->channel_key ?
1813 silc_cipher_get_name(channel_entry->
1815 channel_entry->hmac ?
1816 silc_hmac_get_name(channel_entry->hmac) : "");
1817 g_free_not_null(chanrec->mode);
1818 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1819 signal_emit("channel mode changed", 1, chanrec);
1821 /* Resolve the client information */
1823 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1824 r->channel = channel_entry;
1825 silc_client_get_clients_by_list(client, conn, list_count,
1827 silc_client_join_get_users, r);
1833 case SILC_COMMAND_NICK:
1836 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1842 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1843 if ((nicks != NULL) &&
1844 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1846 SilcClientEntry collider, old;
1848 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1849 collider = silc_client_get_client_by_id(client, conn,
1852 memset(buf, 0, sizeof(buf));
1853 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1854 collider->username, collider->hostname);
1855 nicklist_rename_unique(SERVER(server),
1857 collider, collider->nickname);
1858 silc_print_nick_change(server, collider->nickname,
1859 client_entry->nickname, buf);
1860 g_slist_free(nicks);
1863 old = g_strdup(server->nick);
1864 server_change_nick(SERVER(server), client_entry->nickname);
1865 nicklist_rename_unique(SERVER(server),
1866 server->conn->local_entry, server->nick,
1867 client_entry, client_entry->nickname);
1868 signal_emit("message own_nick", 4, server, server->nick, old, "");
1873 case SILC_COMMAND_LIST:
1878 char tmp[256], *cp, *dm = NULL;
1883 (void)va_arg(vp, SilcChannelEntry);
1884 name = va_arg(vp, char *);
1885 topic = va_arg(vp, char *);
1886 usercount = va_arg(vp, int);
1888 if (topic && !silc_term_utf8() &&
1889 silc_utf8_valid(topic, strlen(topic))) {
1890 memset(tmp, 0, sizeof(tmp));
1892 if (strlen(topic) > sizeof(tmp) - 1) {
1893 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1897 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1902 if (status == SILC_STATUS_LIST_START ||
1903 status == SILC_STATUS_OK)
1904 printformat_module("fe-common/silc", server, NULL,
1905 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1908 snprintf(users, sizeof(users) - 1, "N/A");
1910 snprintf(users, sizeof(users) - 1, "%d", usercount);
1911 printformat_module("fe-common/silc", server, NULL,
1912 MSGLEVEL_CRAP, SILCTXT_LIST,
1913 name, users, topic ? topic : "");
1918 case SILC_COMMAND_UMODE:
1926 mode = va_arg(vp, SilcUInt32);
1928 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1929 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1930 printformat_module("fe-common/silc", server, NULL,
1931 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1933 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1934 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1935 printformat_module("fe-common/silc", server, NULL,
1936 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1938 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1939 if (mode & SILC_UMODE_GONE) {
1940 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1941 reason = g_strdup(server->away_reason);
1943 reason = g_strdup("away");
1945 reason = g_strdup("");
1947 silc_set_away(reason, server);
1952 server->umode = mode;
1953 signal_emit("user mode changed", 2, server, NULL);
1957 case SILC_COMMAND_OPER:
1961 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1962 signal_emit("user mode changed", 2, server, NULL);
1964 printformat_module("fe-common/silc", server, NULL,
1965 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1968 case SILC_COMMAND_SILCOPER:
1972 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1973 signal_emit("user mode changed", 2, server, NULL);
1975 printformat_module("fe-common/silc", server, NULL,
1976 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1979 case SILC_COMMAND_USERS:
1981 SilcHashTableList htl;
1982 SilcChannelEntry channel;
1983 SilcChannelUser chu;
1988 channel = va_arg(vp, SilcChannelEntry);
1990 printformat_module("fe-common/silc", server, channel->channel_name,
1991 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1992 channel->channel_name);
1994 silc_hash_table_list(channel->user_list, &htl);
1995 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1996 SilcClientEntry e = chu->client;
1997 char stat[5], *mode;
2002 memset(stat, 0, sizeof(stat));
2003 mode = silc_client_chumode_char(chu->mode);
2004 if (e->mode & SILC_UMODE_GONE)
2006 else if (e->mode & SILC_UMODE_INDISPOSED)
2008 else if (e->mode & SILC_UMODE_BUSY)
2010 else if (e->mode & SILC_UMODE_PAGE)
2012 else if (e->mode & SILC_UMODE_HYPER)
2014 else if (e->mode & SILC_UMODE_ROBOT)
2016 else if (e->mode & SILC_UMODE_ANONYMOUS)
2023 printformat_module("fe-common/silc", server, channel->channel_name,
2024 MSGLEVEL_CRAP, SILCTXT_USERS,
2026 e->username ? e->username : "",
2027 e->hostname ? e->hostname : "",
2028 e->realname ? e->realname : "");
2032 silc_hash_table_list_reset(&htl);
2036 case SILC_COMMAND_BAN:
2038 SilcChannelEntry channel;
2040 SilcArgumentPayload ban_list;
2046 channel = va_arg(vp, SilcChannelEntry);
2047 payload = va_arg(vp, SilcBuffer);
2050 SILC_GET16_MSB(argc, payload->data);
2051 ban_list = silc_argument_payload_parse(payload->data + 2,
2052 payload->len - 2, argc);
2054 silc_parse_inviteban_list(client, conn, server, channel,
2056 silc_argument_payload_free(ban_list);
2062 case SILC_COMMAND_GETKEY:
2066 SilcPublicKey public_key;
2069 GetkeyContext getkey;
2075 id_type = va_arg(vp, SilcUInt32);
2076 entry = va_arg(vp, void *);
2077 public_key = va_arg(vp, SilcPublicKey);
2080 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2082 getkey = silc_calloc(1, sizeof(*getkey));
2083 getkey->entry = entry;
2084 getkey->id_type = id_type;
2085 getkey->client = client;
2086 getkey->conn = conn;
2087 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2089 name = (id_type == SILC_ID_CLIENT ?
2090 ((SilcClientEntry)entry)->nickname :
2091 ((SilcServerEntry)entry)->server_name);
2093 silc_verify_public_key_internal(client, conn, name,
2094 (id_type == SILC_ID_CLIENT ?
2095 SILC_SOCKET_TYPE_CLIENT :
2096 SILC_SOCKET_TYPE_SERVER),
2097 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2098 silc_getkey_cb, getkey);
2101 printformat_module("fe-common/silc", server, NULL,
2102 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2107 case SILC_COMMAND_INFO:
2109 SilcServerEntry server_entry;
2116 server_entry = va_arg(vp, SilcServerEntry);
2117 server_name = va_arg(vp, char *);
2118 server_info = va_arg(vp, char *);
2120 if (server_name && server_info )
2122 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2123 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2128 case SILC_COMMAND_TOPIC:
2130 SilcChannelEntry channel;
2132 char tmp[256], *cp, *dm = NULL;
2137 channel = va_arg(vp, SilcChannelEntry);
2138 topic = va_arg(vp, char *);
2140 if (topic && !silc_term_utf8() &&
2141 silc_utf8_valid(topic, strlen(topic))) {
2142 memset(tmp, 0, sizeof(tmp));
2144 if (strlen(topic) > sizeof(tmp) - 1) {
2145 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2149 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2155 chanrec = silc_channel_find_entry(server, channel);
2157 g_free_not_null(chanrec->topic);
2158 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2159 signal_emit("channel topic changed", 1, chanrec);
2161 printformat_module("fe-common/silc", server, channel->channel_name,
2162 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2163 channel->channel_name, topic);
2165 printformat_module("fe-common/silc", server, channel->channel_name,
2166 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2167 channel->channel_name);
2173 case SILC_COMMAND_WATCH:
2176 case SILC_COMMAND_STATS:
2178 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2179 my_router_ops, cell_clients, cell_channels, cell_servers,
2180 clients, channels, servers, routers, server_ops, router_ops;
2182 SilcBufferStruct buf;
2183 unsigned char *tmp_buf;
2185 const char *tmptime;
2186 int days, hours, mins, secs;
2191 tmp_buf = va_arg(vp, unsigned char *);
2192 buf_len = va_arg(vp, SilcUInt32);
2194 if (!tmp_buf || !buf_len) {
2195 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2199 /* Get statistics structure */
2200 silc_buffer_set(&buf, tmp_buf, buf_len);
2201 silc_buffer_unformat(&buf,
2202 SILC_STR_UI_INT(&starttime),
2203 SILC_STR_UI_INT(&uptime),
2204 SILC_STR_UI_INT(&my_clients),
2205 SILC_STR_UI_INT(&my_channels),
2206 SILC_STR_UI_INT(&my_server_ops),
2207 SILC_STR_UI_INT(&my_router_ops),
2208 SILC_STR_UI_INT(&cell_clients),
2209 SILC_STR_UI_INT(&cell_channels),
2210 SILC_STR_UI_INT(&cell_servers),
2211 SILC_STR_UI_INT(&clients),
2212 SILC_STR_UI_INT(&channels),
2213 SILC_STR_UI_INT(&servers),
2214 SILC_STR_UI_INT(&routers),
2215 SILC_STR_UI_INT(&server_ops),
2216 SILC_STR_UI_INT(&router_ops),
2219 tmptime = silc_get_time(starttime);
2220 printformat_module("fe-common/silc", server, NULL,
2221 MSGLEVEL_CRAP, SILCTXT_STATS,
2222 "Local server start time", tmptime);
2224 days = uptime / (24 * 60 * 60);
2225 uptime -= days * (24 * 60 * 60);
2226 hours = uptime / (60 * 60);
2227 uptime -= hours * (60 * 60);
2229 uptime -= mins * 60;
2231 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2232 days, hours, mins, secs);
2233 printformat_module("fe-common/silc", server, NULL,
2234 MSGLEVEL_CRAP, SILCTXT_STATS,
2235 "Local server uptime", tmp);
2237 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2238 printformat_module("fe-common/silc", server, NULL,
2239 MSGLEVEL_CRAP, SILCTXT_STATS,
2240 "Local server clients", tmp);
2242 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2243 printformat_module("fe-common/silc", server, NULL,
2244 MSGLEVEL_CRAP, SILCTXT_STATS,
2245 "Local server channels", tmp);
2247 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2248 printformat_module("fe-common/silc", server, NULL,
2249 MSGLEVEL_CRAP, SILCTXT_STATS,
2250 "Local server operators", tmp);
2252 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2253 printformat_module("fe-common/silc", server, NULL,
2254 MSGLEVEL_CRAP, SILCTXT_STATS,
2255 "Local router operators", tmp);
2257 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2258 printformat_module("fe-common/silc", server, NULL,
2259 MSGLEVEL_CRAP, SILCTXT_STATS,
2260 "Local cell clients", tmp);
2262 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2263 printformat_module("fe-common/silc", server, NULL,
2264 MSGLEVEL_CRAP, SILCTXT_STATS,
2265 "Local cell channels", tmp);
2267 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2268 printformat_module("fe-common/silc", server, NULL,
2269 MSGLEVEL_CRAP, SILCTXT_STATS,
2270 "Local cell servers", tmp);
2272 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2273 printformat_module("fe-common/silc", server, NULL,
2274 MSGLEVEL_CRAP, SILCTXT_STATS,
2275 "Total clients", tmp);
2277 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2278 printformat_module("fe-common/silc", server, NULL,
2279 MSGLEVEL_CRAP, SILCTXT_STATS,
2280 "Total channels", tmp);
2282 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2283 printformat_module("fe-common/silc", server, NULL,
2284 MSGLEVEL_CRAP, SILCTXT_STATS,
2285 "Total servers", tmp);
2287 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2288 printformat_module("fe-common/silc", server, NULL,
2289 MSGLEVEL_CRAP, SILCTXT_STATS,
2290 "Total routers", tmp);
2292 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2293 printformat_module("fe-common/silc", server, NULL,
2294 MSGLEVEL_CRAP, SILCTXT_STATS,
2295 "Total server operators", tmp);
2297 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2298 printformat_module("fe-common/silc", server, NULL,
2299 MSGLEVEL_CRAP, SILCTXT_STATS,
2300 "Total router operators", tmp);
2304 case SILC_COMMAND_CMODE:
2306 SilcChannelEntry channel_entry;
2307 SilcBuffer channel_pubkeys;
2309 channel_entry = va_arg(vp, SilcChannelEntry);
2310 (void)va_arg(vp, SilcUInt32);
2311 (void)va_arg(vp, SilcPublicKey);
2312 channel_pubkeys = va_arg(vp, SilcBuffer);
2314 if (!success || !cmode_list_chpks ||
2315 !channel_entry || !channel_entry->channel_name)
2318 /* Print the channel public key list */
2319 if (channel_pubkeys)
2320 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2322 printformat_module("fe-common/silc", server, NULL,
2323 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2324 channel_entry->channel_name);
2335 SilcClientConnection conn;
2341 SilcSKEPKType pk_type;
2342 SilcVerifyPublicKey completion;
2346 static void verify_public_key_completion(const char *line, void *context)
2348 PublicKeyVerify verify = (PublicKeyVerify)context;
2350 if (line[0] == 'Y' || line[0] == 'y') {
2351 /* Call the completion */
2352 if (verify->completion)
2353 verify->completion(TRUE, verify->context);
2355 /* Save the key for future checking */
2356 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2357 verify->pk_len, SILC_PKCS_FILE_PEM);
2359 /* Call the completion */
2360 if (verify->completion)
2361 verify->completion(FALSE, verify->context);
2363 printformat_module("fe-common/silc", NULL, NULL,
2364 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2365 verify->entity_name ? verify->entity_name :
2369 silc_free(verify->filename);
2370 silc_free(verify->entity);
2371 silc_free(verify->entity_name);
2372 silc_free(verify->pk);
2376 /* Internal routine to verify public key. If the `completion' is provided
2377 it will be called to indicate whether public was verified or not. For
2378 server/router public key this will check for filename that includes the
2379 remote host's IP address and remote host's hostname. */
2382 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2383 const char *name, SilcSocketType conn_type,
2384 unsigned char *pk, SilcUInt32 pk_len,
2385 SilcSKEPKType pk_type,
2386 SilcVerifyPublicKey completion, void *context)
2389 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2390 char *fingerprint, *babbleprint, *format;
2393 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2394 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2395 "server" : "client");
2396 PublicKeyVerify verify;
2398 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2399 printformat_module("fe-common/silc", NULL, NULL,
2400 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2403 completion(FALSE, context);
2407 pw = getpwuid(getuid());
2410 completion(FALSE, context);
2414 memset(filename, 0, sizeof(filename));
2415 memset(filename2, 0, sizeof(filename2));
2416 memset(file, 0, sizeof(file));
2418 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2419 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2421 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2422 conn->sock->ip, conn->sock->port);
2423 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2424 get_irssi_dir(), entity, file);
2426 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2427 conn->sock->hostname, conn->sock->port);
2428 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2429 get_irssi_dir(), entity, file);
2434 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2435 name, conn->sock->port);
2436 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2437 get_irssi_dir(), entity, file);
2442 /* Replace all whitespaces with `_'. */
2443 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2444 for (i = 0; i < strlen(fingerprint); i++)
2445 if (fingerprint[i] == ' ')
2446 fingerprint[i] = '_';
2448 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2449 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2450 get_irssi_dir(), entity, file);
2451 silc_free(fingerprint);
2456 /* Take fingerprint of the public key */
2457 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2458 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2460 verify = silc_calloc(1, sizeof(*verify));
2461 verify->client = client;
2462 verify->conn = conn;
2463 verify->filename = strdup(ipf);
2464 verify->entity = strdup(entity);
2465 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2466 (name ? strdup(name) : strdup(conn->sock->hostname))
2468 verify->pk = silc_memdup(pk, pk_len);
2469 verify->pk_len = pk_len;
2470 verify->pk_type = pk_type;
2471 verify->completion = completion;
2472 verify->context = context;
2474 /* Check whether this key already exists */
2475 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2476 /* Key does not exist, ask user to verify the key and save it */
2478 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2479 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2480 verify->entity_name : entity);
2481 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2482 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2483 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2484 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2485 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2486 SILCTXT_PUBKEY_ACCEPT);
2487 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2490 silc_free(fingerprint);
2493 /* The key already exists, verify it. */
2494 SilcPublicKey public_key;
2495 unsigned char *encpk;
2496 SilcUInt32 encpk_len;
2498 /* Load the key file, try for both IP filename and hostname filename */
2499 if (!silc_pkcs_load_public_key(ipf, &public_key,
2500 SILC_PKCS_FILE_PEM) &&
2501 !silc_pkcs_load_public_key(ipf, &public_key,
2502 SILC_PKCS_FILE_BIN) &&
2503 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2504 SILC_PKCS_FILE_PEM) &&
2505 !silc_pkcs_load_public_key(hostf, &public_key,
2506 SILC_PKCS_FILE_BIN)))) {
2507 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2508 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2509 verify->entity_name : entity);
2510 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2511 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2512 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2513 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2514 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2515 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2516 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2517 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2518 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2521 silc_free(fingerprint);
2525 /* Encode the key data */
2526 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2528 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2529 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2530 verify->entity_name : entity);
2531 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2532 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2533 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2534 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2535 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2536 SILCTXT_PUBKEY_MALFORMED, entity);
2537 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2538 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2539 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2542 silc_free(fingerprint);
2546 /* Compare the keys */
2547 if (memcmp(encpk, pk, encpk_len)) {
2548 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2549 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2550 verify->entity_name : entity);
2551 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2552 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2553 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2554 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2555 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2556 SILCTXT_PUBKEY_NO_MATCH, entity);
2557 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2558 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2559 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2560 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2562 /* Ask user to verify the key and save it */
2563 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2564 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2565 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2568 silc_free(fingerprint);
2572 /* Local copy matched */
2574 completion(TRUE, context);
2575 silc_free(fingerprint);
2576 silc_free(verify->filename);
2577 silc_free(verify->entity);
2578 silc_free(verify->entity_name);
2579 silc_free(verify->pk);
2584 /* Verifies received public key. The `conn_type' indicates which entity
2585 (server, client etc.) has sent the public key. If user decides to trust
2586 the key may be saved as trusted public key for later use. The
2587 `completion' must be called after the public key has been verified. */
2590 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2591 SilcSocketType conn_type, unsigned char *pk,
2592 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2593 SilcVerifyPublicKey completion, void *context)
2595 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2597 completion, context);
2600 /* Asks passphrase from user on the input line. */
2603 SilcAskPassphrase completion;
2607 void ask_passphrase_completion(const char *passphrase, void *context)
2609 AskPassphrase p = (AskPassphrase)context;
2610 if (passphrase && passphrase[0] == '\0')
2612 p->completion((unsigned char *)passphrase,
2613 passphrase ? strlen(passphrase) : 0, p->context);
2617 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2618 SilcAskPassphrase completion, void *context)
2620 AskPassphrase p = silc_calloc(1, sizeof(*p));
2621 p->completion = completion;
2622 p->context = context;
2624 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2625 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2629 SilcGetAuthMeth completion;
2631 } *InternalGetAuthMethod;
2633 /* Callback called when we've received the authentication method information
2634 from the server after we've requested it. This will get the authentication
2635 data from the user if needed. */
2637 static void silc_get_auth_method_callback(SilcClient client,
2638 SilcClientConnection conn,
2639 SilcAuthMethod auth_meth,
2642 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2644 SILC_LOG_DEBUG(("Start"));
2646 switch (auth_meth) {
2647 case SILC_AUTH_NONE:
2648 /* No authentication required. */
2649 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2651 case SILC_AUTH_PASSWORD:
2653 /* Check whether we find the password for this server in our
2654 configuration. If not, then don't provide so library will ask
2655 it from the user. */
2656 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2658 if (!setup || !setup->password) {
2659 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2663 (*internal->completion)(TRUE, auth_meth, setup->password,
2664 strlen(setup->password), internal->context);
2667 case SILC_AUTH_PUBLIC_KEY:
2668 /* Do not get the authentication data now, the library will generate
2669 it using our default key, if we do not provide it here. */
2670 /* XXX In the future when we support multiple local keys and multiple
2671 local certificates we will need to ask from user which one to use. */
2672 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2676 silc_free(internal);
2679 /* Find authentication method and authentication data by hostname and
2680 port. The hostname may be IP address as well. The found authentication
2681 method and authentication data is returned to `auth_meth', `auth_data'
2682 and `auth_data_len'. The function returns TRUE if authentication method
2683 is found and FALSE if not. `conn' may be NULL. */
2685 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2686 char *hostname, SilcUInt16 port,
2687 SilcGetAuthMeth completion, void *context)
2689 InternalGetAuthMethod internal;
2691 SILC_LOG_DEBUG(("Start"));
2693 /* If we do not have this connection configured by the user in a
2694 configuration file then resolve the authentication method from the
2695 server for this session. */
2696 internal = silc_calloc(1, sizeof(*internal));
2697 internal->completion = completion;
2698 internal->context = context;
2700 silc_client_request_authentication_method(client, conn,
2701 silc_get_auth_method_callback,
2705 /* Notifies application that failure packet was received. This is called
2706 if there is some protocol active in the client. The `protocol' is the
2707 protocol context. The `failure' is opaque pointer to the failure
2708 indication. Note, that the `failure' is protocol dependant and application
2709 must explicitly cast it to correct type. Usually `failure' is 32 bit
2710 failure type (see protocol specs for all protocol failure types). */
2712 void silc_failure(SilcClient client, SilcClientConnection conn,
2713 SilcProtocol protocol, void *failure)
2715 SILC_LOG_DEBUG(("Start"));
2717 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2718 SilcSKEStatus status = (SilcSKEStatus)failure;
2720 if (status == SILC_SKE_STATUS_BAD_VERSION)
2721 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2722 SILCTXT_KE_BAD_VERSION);
2723 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2724 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2725 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2726 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2727 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2728 SILCTXT_KE_UNKNOWN_GROUP);
2729 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2730 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2731 SILCTXT_KE_UNKNOWN_CIPHER);
2732 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2733 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2734 SILCTXT_KE_UNKNOWN_PKCS);
2735 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2736 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2737 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2738 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2739 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2740 SILCTXT_KE_UNKNOWN_HMAC);
2741 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2742 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2743 SILCTXT_KE_INCORRECT_SIGNATURE);
2744 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2745 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2746 SILCTXT_KE_INVALID_COOKIE);
2749 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2750 SilcUInt32 err = (SilcUInt32)failure;
2752 if (err == SILC_AUTH_FAILED)
2753 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2754 SILCTXT_AUTH_FAILED);
2758 /* Asks whether the user would like to perform the key agreement protocol.
2759 This is called after we have received an key agreement packet or an
2760 reply to our key agreement packet. This returns TRUE if the user wants
2761 the library to perform the key agreement protocol and FALSE if it is not
2762 desired (application may start it later by calling the function
2763 silc_client_perform_key_agreement). */
2765 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2766 SilcClientEntry client_entry, const char *hostname,
2767 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2772 SILC_LOG_DEBUG(("Start"));
2774 /* We will just display the info on the screen and return FALSE and user
2775 will have to start the key agreement with a command. */
2778 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2781 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2782 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2784 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2785 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2786 client_entry->nickname, hostname, portstr);
2794 /* Notifies application that file transfer protocol session is being
2795 requested by the remote client indicated by the `client_entry' from
2796 the `hostname' and `port'. The `session_id' is the file transfer
2797 session and it can be used to either accept or reject the file
2798 transfer request, by calling the silc_client_file_receive or
2799 silc_client_file_close, respectively. */
2801 void silc_ftp(SilcClient client, SilcClientConnection conn,
2802 SilcClientEntry client_entry, SilcUInt32 session_id,
2803 const char *hostname, SilcUInt16 port)
2805 SILC_SERVER_REC *server;
2807 FtpSession ftp = NULL;
2809 SILC_LOG_DEBUG(("Start"));
2811 server = conn->context;
2813 silc_dlist_start(server->ftp_sessions);
2814 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2815 if (ftp->client_entry == client_entry &&
2816 ftp->session_id == session_id) {
2817 server->current_session = ftp;
2821 if (ftp == SILC_LIST_END) {
2822 ftp = silc_calloc(1, sizeof(*ftp));
2823 ftp->client_entry = client_entry;
2824 ftp->session_id = session_id;
2827 silc_dlist_add(server->ftp_sessions, ftp);
2828 server->current_session = ftp;
2832 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2835 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2836 SILCTXT_FILE_REQUEST, client_entry->nickname);
2838 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2839 SILCTXT_FILE_REQUEST_HOST,
2840 client_entry->nickname, hostname, portstr);
2843 /* Delivers SILC session detachment data indicated by `detach_data' to the
2844 application. If application has issued SILC_COMMAND_DETACH command
2845 the client session in the SILC network is not quit. The client remains
2846 in the network but is detached. The detachment data may be used later
2847 to resume the session in the SILC Network. The appliation is
2848 responsible of saving the `detach_data', to for example in a file.
2850 The detachment data can be given as argument to the functions
2851 silc_client_connect_to_server, or silc_client_add_connection when
2852 creating connection to remote server, inside SilcClientConnectionParams
2853 structure. If it is provided the client library will attempt to resume
2854 the session in the network. After the connection is created
2855 successfully, the application is responsible of setting the user
2856 interface for user into the same state it was before detaching (showing
2857 same channels, channel modes, etc). It can do this by fetching the
2858 information (like joined channels) from the client library. */
2861 silc_detach(SilcClient client, SilcClientConnection conn,
2862 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2866 /* Save the detachment data to file. */
2868 memset(file, 0, sizeof(file));
2869 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2870 silc_file_writefile(file, detach_data, detach_data_len);
2874 /* SILC client operations */
2875 SilcClientOperations ops = {
2877 silc_channel_message,
2878 silc_private_message,
2884 silc_get_auth_method,
2885 silc_verify_public_key,
2886 silc_ask_passphrase,