updates.
[silc.git] / apps / irssi / src / silc / core / client_ops.c
1 /*
2
3   client_ops.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2001 Pekka Riikonen
8
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.
13   
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.
18
19 */
20
21 #include "module.h"
22 #include "chat-protocols.h"
23 #include "args.h"
24
25 #include "chatnets.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"
32
33 #include "signals.h"
34 #include "levels.h"
35 #include "settings.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
40
41 static void 
42 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
43                                 SilcSocketType conn_type, unsigned char *pk, 
44                                 uint32 pk_len, SilcSKEPKType pk_type,
45                                 SilcVerifyPublicKey completion, void *context);
46
47 void silc_say(SilcClient client, SilcClientConnection conn,
48               SilcClientMessageType type, char *msg, ...)
49 {
50   SILC_SERVER_REC *server;
51   va_list va;
52   char *str;
53
54   server = conn == NULL ? NULL : conn->context;
55   
56   va_start(va, msg);
57   str = g_strdup_vprintf(msg, va);
58   printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
59   g_free(str);
60   va_end(va);
61 }
62
63 void silc_say_error(char *msg, ...)
64 {
65   va_list va;
66   char *str;
67
68   va_start(va, msg);
69   str = g_strdup_vprintf(msg, va);
70   printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
71
72   g_free(str);
73   va_end(va);
74 }
75
76 /* Message for a channel. The `sender' is the nickname of the sender 
77    received in the packet. The `channel_name' is the name of the channel. */
78
79 void silc_channel_message(SilcClient client, SilcClientConnection conn,
80                           SilcClientEntry sender, SilcChannelEntry channel,
81                           SilcMessageFlags flags, char *msg)
82 {
83   SILC_SERVER_REC *server;
84   SILC_NICK_REC *nick;
85   SILC_CHANNEL_REC *chanrec;
86   
87   SILC_LOG_DEBUG(("Start"));
88
89   server = conn == NULL ? NULL : conn->context;
90   chanrec = silc_channel_find_entry(server, channel);
91   if (!chanrec)
92     return;
93   
94   nick = silc_nicklist_find(chanrec, sender);
95   if (!nick) {
96     /* We didn't find client but it clearly exists, add it. */
97     SilcChannelUser chu;
98
99     silc_list_start(channel->clients);
100     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
101       if (chu->client == sender) {
102         nick = silc_nicklist_insert(chanrec, chu, FALSE);
103         break;
104       }
105     }
106   }
107
108   if (flags & SILC_MESSAGE_FLAG_ACTION)
109     printformat_module("fe-common/silc", server, channel->channel_name,
110                        MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, 
111                        nick == NULL ? "[<unknown>]" : nick->nick, msg);
112   else if (flags & SILC_MESSAGE_FLAG_NOTICE)
113     printformat_module("fe-common/silc", server, channel->channel_name,
114                        MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, 
115                        nick == NULL ? "[<unknown>]" : nick->nick, msg);
116   else
117     signal_emit("message public", 6, server, msg,
118                 nick == NULL ? "[<unknown>]" : nick->nick,
119                 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
120                 chanrec->name, nick);
121 }
122
123 /* Private message to the client. The `sender' is the nickname of the
124    sender received in the packet. */
125
126 void silc_private_message(SilcClient client, SilcClientConnection conn,
127                           SilcClientEntry sender, SilcMessageFlags flags,
128                           char *msg)
129 {
130   SILC_SERVER_REC *server;
131   char userhost[256];
132   
133   SILC_LOG_DEBUG(("Start"));
134
135   server = conn == NULL ? NULL : conn->context;
136   memset(userhost, 0, sizeof(userhost));
137   if (sender->username)
138     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
139              sender->username, sender->hostname);
140   signal_emit("message private", 4, server, msg,
141               sender->nickname ? sender->nickname : "[<unknown>]",
142               sender->username ? userhost : NULL);
143 }
144
145 /* Notify message to the client. The notify arguments are sent in the
146    same order as servers sends them. The arguments are same as received
147    from the server except for ID's.  If ID is received application receives
148    the corresponding entry to the ID. For example, if Client ID is received
149    application receives SilcClientEntry.  Also, if the notify type is
150    for channel the channel entry is sent to application (even if server
151    does not send it). */
152
153 typedef struct {
154   int type;
155   const char *name;
156 } NOTIFY_REC;
157
158 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
159 static NOTIFY_REC notifies[] = {
160   { SILC_NOTIFY_TYPE_NONE,              NULL },
161   { SILC_NOTIFY_TYPE_INVITE,            "invite" },
162   { SILC_NOTIFY_TYPE_JOIN,              "join" },
163   { SILC_NOTIFY_TYPE_LEAVE,             "leave" },
164   { SILC_NOTIFY_TYPE_SIGNOFF,           "signoff" },
165   { SILC_NOTIFY_TYPE_TOPIC_SET,         "topic" },
166   { SILC_NOTIFY_TYPE_NICK_CHANGE,       "nick" },
167   { SILC_NOTIFY_TYPE_CMODE_CHANGE,      "cmode" },
168   { SILC_NOTIFY_TYPE_CUMODE_CHANGE,     "cumode" },
169   { SILC_NOTIFY_TYPE_MOTD,              "motd" },
170   { SILC_NOTIFY_TYPE_CHANNEL_CHANGE,    "channel_change" },
171   { SILC_NOTIFY_TYPE_SERVER_SIGNOFF,    "server_signoff" },
172   { SILC_NOTIFY_TYPE_KICKED,            "kick" },
173   { SILC_NOTIFY_TYPE_KILLED,            "kill" },
174   { SILC_NOTIFY_TYPE_UMODE_CHANGE,      "umode" },
175   { SILC_NOTIFY_TYPE_BAN,               "ban" },
176 };
177
178 void silc_notify(SilcClient client, SilcClientConnection conn,
179                  SilcNotifyType type, ...)
180 {
181   SILC_SERVER_REC *server;
182   va_list va;
183   
184   SILC_LOG_DEBUG(("Start"));
185
186   server = conn == NULL ? NULL : conn->context;
187   va_start(va, type);
188   
189   if (type == SILC_NOTIFY_TYPE_NONE) {
190     /* Some generic notice from server */
191     printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
192   } else if (type < MAX_NOTIFY) {
193     /* Send signal about the notify event */
194     char signal[50];
195     g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
196     signal_emit(signal, 2, server, va);
197   } else {
198     /* Unknown notify */
199     printformat_module("fe-common/silc", server, NULL,
200                        MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
201   }
202
203   va_end(va);
204 }
205
206 /* Called to indicate that connection was either successfully established
207    or connecting failed.  This is also the first time application receives
208    the SilcClientConnection object which it should save somewhere. */
209
210 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
211 {
212   SILC_SERVER_REC *server = conn->context;
213
214   if (!server && !success) {
215     silc_client_close_connection(client, NULL, conn);
216     return;
217   }
218
219   if (success) {
220     server->connected = TRUE;
221     signal_emit("event connected", 1, server);
222   } else {
223     server->connection_lost = TRUE;
224     server->conn->context = NULL;
225     server_disconnect(SERVER(server));
226   }
227 }
228
229 /* Called to indicate that connection was disconnected to the server. */
230
231 void silc_disconnect(SilcClient client, SilcClientConnection conn)
232 {
233   SILC_SERVER_REC *server = conn->context;
234
235   SILC_LOG_DEBUG(("Start"));
236
237   if (server->conn) {
238     nicklist_rename_unique(SERVER(server),
239                            server->conn->local_entry, server->nick,
240                            server->conn->local_entry, 
241                            silc_client->username);
242     silc_change_nick(server, silc_client->username);
243   }
244
245   server->conn->context = NULL;
246   server->conn = NULL;
247   server->connection_lost = TRUE;
248   server_disconnect(SERVER(server));
249 }
250
251 /* Command handler. This function is called always in the command function.
252    If error occurs it will be called as well. `conn' is the associated
253    client connection. `cmd_context' is the command context that was
254    originally sent to the command. `success' is FALSE if error occured
255    during command. `command' is the command being processed. It must be
256    noted that this is not reply from server. This is merely called just
257    after application has called the command. Just to tell application
258    that the command really was processed. */
259
260 void silc_command(SilcClient client, SilcClientConnection conn, 
261                   SilcClientCommandContext cmd_context, int success,
262                   SilcCommand command)
263 {
264   SILC_SERVER_REC *server = conn->context;
265
266   SILC_LOG_DEBUG(("Start"));
267
268   if (!success)
269     return;
270
271   switch(command) {
272   case SILC_COMMAND_INVITE:
273     printformat_module("fe-common/silc", server, NULL,
274                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
275                        cmd_context->argv[2], 
276                        (cmd_context->argv[1][0] == '*' ?
277                         (char *)conn->current_channel->channel_name :
278                         (char *)cmd_context->argv[1]));
279     break;
280   default:
281     break;
282   }
283 }
284
285 /* Client info resolving callback when JOIN command reply is received.
286    This will cache all users on the channel. */
287
288 static void silc_client_join_get_users(SilcClient client,
289                                        SilcClientConnection conn,
290                                        SilcClientEntry *clients,
291                                        uint32 clients_count,
292                                        void *context)
293 {
294   SilcChannelEntry channel = (SilcChannelEntry)context;
295   SilcChannelUser chu;
296   SILC_SERVER_REC *server = conn->context;
297   SILC_CHANNEL_REC *chanrec;
298   SilcClientEntry founder = NULL;
299   NICK_REC *ownnick;
300
301   if (!clients)
302     return;
303
304   chanrec = silc_channel_find(server, channel->channel_name);
305   if (chanrec == NULL)
306     return;
307
308   silc_list_start(channel->clients);
309   while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
310     if (!chu->client->nickname)
311       continue;
312     if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
313       founder = chu->client;
314     silc_nicklist_insert(chanrec, chu, FALSE);
315   }
316
317   ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
318   nicklist_set_own(CHANNEL(chanrec), ownnick);
319   signal_emit("channel joined", 1, chanrec);
320
321   if (chanrec->topic)
322     printformat_module("fe-common/silc", server, channel->channel_name,
323                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
324                        channel->channel_name, chanrec->topic);
325
326   fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
327
328   if (founder) {
329     if (founder == conn->local_entry)
330       printformat_module("fe-common/silc", 
331                          server, channel->channel_name, MSGLEVEL_CRAP,
332                          SILCTXT_CHANNEL_FOUNDER_YOU,
333                          channel->channel_name);
334     else
335       printformat_module("fe-common/silc", 
336                          server, channel->channel_name, MSGLEVEL_CRAP,
337                          SILCTXT_CHANNEL_FOUNDER,
338                          channel->channel_name, founder->nickname);
339   }
340 }
341
342 typedef struct {
343   SilcClient client;
344   SilcClientConnection conn;
345   void *entry;
346   SilcIdType id_type;
347   char *fingerprint;
348 } *GetkeyContext;
349
350 void silc_getkey_cb(bool success, void *context)
351 {
352   GetkeyContext getkey = (GetkeyContext)context;
353   char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
354   char *name = (getkey->id_type == SILC_ID_CLIENT ? 
355                 ((SilcClientEntry)getkey->entry)->nickname :
356                 ((SilcServerEntry)getkey->entry)->server_name);
357
358   if (success) {
359     printformat_module("fe-common/silc", NULL, NULL,
360                        MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
361   } else {
362     printformat_module("fe-common/silc", NULL, NULL,
363                        MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
364   }
365
366   silc_free(getkey->fingerprint);
367   silc_free(getkey);
368 }
369
370 /* Command reply handler. This function is called always in the command reply
371    function. If error occurs it will be called as well. Normal scenario
372    is that it will be called after the received command data has been parsed
373    and processed. The function is used to pass the received command data to
374    the application. 
375
376    `conn' is the associated client connection. `cmd_payload' is the command
377    payload data received from server and it can be ignored. It is provided
378    if the application would like to re-parse the received command data,
379    however, it must be noted that the data is parsed already by the library
380    thus the payload can be ignored. `success' is FALSE if error occured.
381    In this case arguments are not sent to the application. `command' is the
382    command reply being processed. The function has variable argument list
383    and each command defines the number and type of arguments it passes to the
384    application (on error they are not sent). */
385
386 void 
387 silc_command_reply(SilcClient client, SilcClientConnection conn,
388                    SilcCommandPayload cmd_payload, int success,
389                    SilcCommand command, SilcCommandStatus status, ...)
390
391 {
392   SILC_SERVER_REC *server = conn->context;
393   SILC_CHANNEL_REC *chanrec;
394   va_list vp;
395
396   va_start(vp, status);
397
398   SILC_LOG_DEBUG(("Start"));
399
400   switch(command) {
401   case SILC_COMMAND_WHOIS:
402     {
403       char buf[1024], *nickname, *username, *realname, *nick;
404       unsigned char *fingerprint;
405       uint32 idle, mode;
406       SilcBuffer channels;
407       SilcClientEntry client_entry;
408       
409       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
410         /* Print the unknown nick for user */
411         unsigned char *tmp =
412           silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
413                                      3, NULL);
414         if (tmp)
415           silc_say_error("%s: %s", tmp, 
416                          silc_client_command_status_message(status));
417         break;
418       } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
419         /* Try to find the entry for the unknown client ID, since we
420            might have, and print the nickname of it for user. */
421         uint32 tmp_len;
422         unsigned char *tmp =
423           silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
424                                      2, &tmp_len);
425         if (tmp) {
426           SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
427           if (client_id) {
428             client_entry = silc_client_get_client_by_id(client, conn,
429                                                         client_id);
430             if (client_entry && client_entry->nickname)
431               silc_say_error("%s: %s", client_entry->nickname,
432                              silc_client_command_status_message(status));
433             silc_free(client_id);
434           }
435         }
436         break;
437       }
438       
439       if (!success)
440         return;
441       
442       client_entry = va_arg(vp, SilcClientEntry);
443       nickname = va_arg(vp, char *);
444       username = va_arg(vp, char *);
445       realname = va_arg(vp, char *);
446       channels = va_arg(vp, SilcBuffer);
447       mode = va_arg(vp, uint32);
448       idle = va_arg(vp, uint32);
449       fingerprint = va_arg(vp, unsigned char *);
450       
451       silc_parse_userfqdn(nickname, &nick, NULL);
452       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
453                          SILCTXT_WHOIS_USERINFO, nickname, 
454                          client_entry->username, client_entry->hostname,
455                          nick, client_entry->nickname);
456       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
457                          SILCTXT_WHOIS_REALNAME, realname);
458       silc_free(nick);
459
460       if (channels) {
461         SilcDList list = silc_channel_payload_parse_list(channels->data,
462                                                          channels->len);
463         if (list) {
464           SilcChannelPayload entry;
465           memset(buf, 0, sizeof(buf));
466           silc_dlist_start(list);
467           while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
468             char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
469             uint32 name_len;
470             char *name = silc_channel_get_name(entry, &name_len);
471             
472             if (m)
473               strncat(buf, m, strlen(m));
474             strncat(buf, name, name_len);
475             strncat(buf, " ", 1);
476             silc_free(m);
477           }
478
479           printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
480                              SILCTXT_WHOIS_CHANNELS, buf);
481           silc_channel_payload_list_free(list);
482         }
483       }
484       
485       if (mode) {
486         memset(buf, 0, sizeof(buf));
487
488         if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
489             (mode & SILC_UMODE_ROUTER_OPERATOR)) {
490           strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
491                  "Server Operator " :
492                  (mode & SILC_UMODE_ROUTER_OPERATOR) ?
493                  "SILC Operator " : "[Unknown mode] ");
494         }
495         if (mode & SILC_UMODE_GONE)
496           strcat(buf, "away");
497
498         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
499                            SILCTXT_WHOIS_MODES, buf);
500       }
501       
502       if (idle && nickname) {
503         memset(buf, 0, sizeof(buf));
504         snprintf(buf, sizeof(buf) - 1, "%lu %s",
505                  idle > 60 ? (idle / 60) : idle,
506                  idle > 60 ? "minutes" : "seconds");
507
508         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
509                            SILCTXT_WHOIS_IDLE, buf);
510       }
511
512       if (fingerprint) {
513         fingerprint = silc_fingerprint(fingerprint, 20);
514         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
515                            SILCTXT_WHOIS_FINGERPRINT, fingerprint);
516         silc_free(fingerprint);
517       }
518     }
519     break;
520     
521   case SILC_COMMAND_IDENTIFY:
522     {
523       SilcClientEntry client_entry;
524       
525       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
526         /* Print the unknown nick for user */
527         unsigned char *tmp =
528           silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
529                                      3, NULL);
530         if (tmp)
531           silc_say_error("%s: %s", tmp, 
532                          silc_client_command_status_message(status));
533         break;
534       } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
535         /* Try to find the entry for the unknown client ID, since we
536            might have, and print the nickname of it for user. */
537         uint32 tmp_len;
538         unsigned char *tmp =
539           silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
540                                      2, &tmp_len);
541         if (tmp) {
542           SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
543           if (client_id) {
544             client_entry = silc_client_get_client_by_id(client, conn,
545                                                         client_id);
546             if (client_entry && client_entry->nickname)
547               silc_say_error("%s: %s", client_entry->nickname,
548                              silc_client_command_status_message(status));
549             silc_free(client_id);
550           }
551         }
552         break;
553       }
554
555       break;
556     }
557
558   case SILC_COMMAND_WHOWAS:
559     {
560       char *nickname, *username, *realname;
561       
562       if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
563           status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
564         char *tmp;
565         tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
566                                          3, NULL);
567         if (tmp)
568           silc_say_error("%s: %s", tmp, 
569                          silc_client_command_status_message(status));
570         break;
571       }
572       
573       if (!success)
574         return;
575       
576       (void)va_arg(vp, SilcClientEntry);
577       nickname = va_arg(vp, char *);
578       username = va_arg(vp, char *);
579       realname = va_arg(vp, char *);
580       
581       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
582                          SILCTXT_WHOWAS_USERINFO, nickname, username, 
583                          realname ? realname : "");
584     }
585     break;
586     
587   case SILC_COMMAND_INVITE:
588     {
589       SilcChannelEntry channel;
590       char *invite_list;
591       SilcArgumentPayload args;
592       int argc = 0;
593       
594       if (!success)
595         return;
596       
597       channel = va_arg(vp, SilcChannelEntry);
598       invite_list = va_arg(vp, char *);
599
600       args = silc_command_get_args(cmd_payload);
601       if (args)
602         argc = silc_argument_get_arg_num(args);
603
604       if (invite_list)
605         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
606                            SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
607                            invite_list);
608       else if (argc == 3)
609         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
610                            SILCTXT_CHANNEL_NO_INVITE_LIST, 
611                            channel->channel_name);
612     }
613     break;
614
615   case SILC_COMMAND_JOIN: 
616     {
617       char *channel, *mode, *topic;
618       uint32 modei;
619       SilcChannelEntry channel_entry;
620       SilcBuffer client_id_list;
621       uint32 list_count;
622
623       if (!success)
624         return;
625
626       channel = va_arg(vp, char *);
627       channel_entry = va_arg(vp, SilcChannelEntry);
628       modei = va_arg(vp, uint32);
629       (void)va_arg(vp, uint32);
630       (void)va_arg(vp, unsigned char *);
631       (void)va_arg(vp, unsigned char *);
632       (void)va_arg(vp, unsigned char *);
633       topic = va_arg(vp, char *);
634       (void)va_arg(vp, unsigned char *);
635       list_count = va_arg(vp, uint32);
636       client_id_list = va_arg(vp, SilcBuffer);
637
638       chanrec = silc_channel_find(server, channel);
639       if (!chanrec)
640         chanrec = silc_channel_create(server, channel, TRUE);
641
642       if (topic) {
643         g_free_not_null(chanrec->topic);
644         chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
645         signal_emit("channel topic changed", 1, chanrec);
646       }
647
648       mode = silc_client_chmode(modei, 
649                                 channel_entry->channel_key ? 
650                                 channel_entry->channel_key->cipher->name : "",
651                                 channel_entry->hmac ? 
652                                 silc_hmac_get_name(channel_entry->hmac) : "");
653       g_free_not_null(chanrec->mode);
654       chanrec->mode = g_strdup(mode == NULL ? "" : mode);
655       signal_emit("channel mode changed", 1, chanrec);
656
657       /* Resolve the client information */
658       silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
659                                       silc_client_join_get_users, 
660                                       channel_entry);
661       break;
662     }
663
664   case SILC_COMMAND_NICK: 
665     {
666       SilcClientEntry client = va_arg(vp, SilcClientEntry);
667       char *old;
668       
669       if (!success)
670         return;
671
672       old = g_strdup(server->nick);
673       server_change_nick(SERVER(server), client->nickname);
674       nicklist_rename_unique(SERVER(server),
675                              server->conn->local_entry, server->nick,
676                              client, client->nickname);
677       
678       signal_emit("message own_nick", 4, server, server->nick, old, "");
679       g_free(old);
680       break;
681     }
682     
683   case SILC_COMMAND_LIST:
684     {
685       char *topic, *name;
686       int usercount;
687       char users[20];
688       
689       if (!success)
690         return;
691       
692       (void)va_arg(vp, SilcChannelEntry);
693       name = va_arg(vp, char *);
694       topic = va_arg(vp, char *);
695       usercount = va_arg(vp, int);
696       
697       if (status == SILC_STATUS_LIST_START ||
698           status == SILC_STATUS_OK)
699         printformat_module("fe-common/silc", server, NULL,
700                            MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
701
702       if (!usercount)
703         snprintf(users, sizeof(users) - 1, "N/A");
704       else
705         snprintf(users, sizeof(users) - 1, "%d", usercount);
706       printformat_module("fe-common/silc", server, NULL,
707                          MSGLEVEL_CRAP, SILCTXT_LIST,
708                          name, users, topic ? topic : "");
709     }
710     break;
711     
712   case SILC_COMMAND_UMODE:
713     {
714       uint32 mode;
715       
716       if (!success)
717         return;
718       
719       mode = va_arg(vp, uint32);
720       
721       if (mode & SILC_UMODE_SERVER_OPERATOR &&
722           !(server->umode & SILC_UMODE_SERVER_OPERATOR))
723         printformat_module("fe-common/silc", server, NULL,
724                            MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
725
726       if (mode & SILC_UMODE_ROUTER_OPERATOR &&
727           !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
728         printformat_module("fe-common/silc", server, NULL,
729                            MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
730
731       server->umode = mode;
732     }
733     break;
734     
735   case SILC_COMMAND_OPER:
736     if (!success)
737       return;
738
739     printformat_module("fe-common/silc", server, NULL,
740                        MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
741     break;
742     
743   case SILC_COMMAND_SILCOPER:
744     if (!success)
745       return;
746
747     printformat_module("fe-common/silc", server, NULL,
748                        MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
749     break;
750     
751   case SILC_COMMAND_USERS: 
752     {
753       SilcChannelEntry channel;
754       SilcChannelUser chu;
755       
756       if (!success)
757         return;
758       
759       channel = va_arg(vp, SilcChannelEntry);
760       
761       printformat_module("fe-common/silc", server, channel->channel_name,
762                          MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
763                          channel->channel_name);
764
765       silc_list_start(channel->clients);
766       while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
767         SilcClientEntry e = chu->client;
768         char stat[5], *mode;
769
770         if (!e->nickname)
771           continue;
772         
773         memset(stat, 0, sizeof(stat));
774         mode = silc_client_chumode_char(chu->mode);
775         if (e->mode & SILC_UMODE_GONE)
776           strcat(stat, "G");
777         else
778           strcat(stat, "H");
779         if (mode)
780           strcat(stat, mode);
781
782         printformat_module("fe-common/silc", server, channel->channel_name,
783                            MSGLEVEL_CRAP, SILCTXT_USERS,
784                            e->nickname, stat, 
785                            e->username ? e->username : "",
786                            e->hostname ? e->hostname : "",
787                            e->realname ? e->realname : "");
788         if (mode)
789           silc_free(mode);
790       }
791     }
792     break;
793
794   case SILC_COMMAND_BAN:
795     {
796       SilcChannelEntry channel;
797       char *ban_list;
798       
799       if (!success)
800         return;
801       
802       channel = va_arg(vp, SilcChannelEntry);
803       ban_list = va_arg(vp, char *);
804       
805       if (ban_list)
806         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
807                            SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
808                            ban_list);
809       else
810         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
811                            SILCTXT_CHANNEL_NO_BAN_LIST, 
812                            channel->channel_name);
813     }
814     break;
815     
816   case SILC_COMMAND_GETKEY:
817     {
818       SilcIdType id_type;
819       void *entry;
820       SilcPublicKey public_key;
821       unsigned char *pk;
822       uint32 pk_len;
823       GetkeyContext getkey;
824       
825       if (!success)
826         return;
827       
828       id_type = va_arg(vp, uint32);
829       entry = va_arg(vp, void *);
830       public_key = va_arg(vp, SilcPublicKey);
831
832       if (public_key) {
833         pk = silc_pkcs_public_key_encode(public_key, &pk_len);
834
835         getkey = silc_calloc(1, sizeof(*getkey));
836         getkey->entry = entry;
837         getkey->id_type = id_type;
838         getkey->client = client;
839         getkey->conn = conn;
840         getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
841         
842         silc_verify_public_key_internal(client, conn, 
843                                         (id_type == SILC_ID_CLIENT ?
844                                          SILC_SOCKET_TYPE_CLIENT :
845                                          SILC_SOCKET_TYPE_SERVER),
846                                         pk, pk_len, SILC_SKE_PK_TYPE_SILC,
847                                         silc_getkey_cb, getkey);
848         silc_free(pk);
849       } else {
850         printformat_module("fe-common/silc", server, NULL,
851                            MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
852       }
853     }
854     break;
855
856   case SILC_COMMAND_INFO:
857     {
858       SilcServerEntry server_entry;
859       char *server_name;
860       char *server_info;
861
862       if (!success)
863         return;
864       
865       server_entry = va_arg(vp, SilcServerEntry);
866       server_name = va_arg(vp, char *);
867       server_info = va_arg(vp, char *);
868
869       if (server_name && server_info )
870         {
871           printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
872           printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
873         }
874     }
875     break;
876     
877   case SILC_COMMAND_TOPIC:
878     {
879       SilcChannelEntry channel;
880       char *topic;
881       
882       if (!success)
883         return;
884       
885       channel = va_arg(vp, SilcChannelEntry);
886       topic = va_arg(vp, char *);
887       
888       if (topic) {
889         chanrec = silc_channel_find_entry(server, channel);
890         if (chanrec) {
891           g_free_not_null(chanrec->topic);
892           chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
893           signal_emit("channel topic changed", 1, chanrec);
894         }
895         printformat_module("fe-common/silc", server, channel->channel_name,
896                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
897                            channel->channel_name, topic);
898       } else {
899         printformat_module("fe-common/silc", server, channel->channel_name,
900                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
901                            channel->channel_name);
902       }
903     }
904     break;
905
906   }
907
908   va_end(vp);
909 }
910
911 /* Internal routine to verify public key. If the `completion' is provided
912    it will be called to indicate whether public was verified or not. */
913
914 typedef struct {
915   SilcClient client;
916   SilcClientConnection conn;
917   char *filename;
918   char *entity;
919   unsigned char *pk;
920   uint32 pk_len;
921   SilcSKEPKType pk_type;
922   SilcVerifyPublicKey completion;
923   void *context;
924 } *PublicKeyVerify;
925
926 static void verify_public_key_completion(const char *line, void *context)
927 {
928   PublicKeyVerify verify = (PublicKeyVerify)context;
929
930   if (line[0] == 'Y' || line[0] == 'y') {
931     /* Call the completion */
932     if (verify->completion)
933       verify->completion(TRUE, verify->context);
934
935     /* Save the key for future checking */
936     silc_pkcs_save_public_key_data(verify->filename, verify->pk, 
937                                    verify->pk_len, SILC_PKCS_FILE_PEM);
938   } else {
939     /* Call the completion */
940     if (verify->completion)
941       verify->completion(FALSE, verify->context);
942
943     printformat_module("fe-common/silc", NULL, NULL,
944                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
945   }
946
947   silc_free(verify->filename);
948   silc_free(verify->entity);
949   silc_free(verify->pk);
950   silc_free(verify);
951 }
952
953 static void 
954 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
955                                 SilcSocketType conn_type, unsigned char *pk, 
956                                 uint32 pk_len, SilcSKEPKType pk_type,
957                                 SilcVerifyPublicKey completion, void *context)
958 {
959   int i;
960   char file[256], filename[256], *fingerprint, *babbleprint, *format;
961   struct passwd *pw;
962   struct stat st;
963   char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
964                    conn_type == SILC_SOCKET_TYPE_ROUTER) ? 
965                   "server" : "client");
966   PublicKeyVerify verify;
967
968   if (pk_type != SILC_SKE_PK_TYPE_SILC) {
969     printformat_module("fe-common/silc", NULL, NULL,
970                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED, 
971                        entity, pk_type);
972     if (completion)
973       completion(FALSE, context);
974     return;
975   }
976
977   pw = getpwuid(getuid());
978   if (!pw) {
979     if (completion)
980       completion(FALSE, context);
981     return;
982   }
983
984   memset(filename, 0, sizeof(filename));
985   memset(file, 0, sizeof(file));
986
987   if (conn_type == SILC_SOCKET_TYPE_SERVER ||
988       conn_type == SILC_SOCKET_TYPE_ROUTER) {
989     snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
990              conn->sock->ip, conn->sock->port);
991     snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
992              pw->pw_dir, entity, file);
993   } else {
994     /* Replace all whitespaces with `_'. */
995     fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
996     for (i = 0; i < strlen(fingerprint); i++)
997       if (fingerprint[i] == ' ')
998         fingerprint[i] = '_';
999     
1000     snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1001     snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
1002              pw->pw_dir, entity, file);
1003     silc_free(fingerprint);
1004   }
1005
1006   /* Take fingerprint of the public key */
1007   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1008   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1009
1010   verify = silc_calloc(1, sizeof(*verify));
1011   verify->client = client;
1012   verify->conn = conn;
1013   verify->filename = strdup(filename);
1014   verify->entity = strdup(entity);
1015   verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1016   memcpy(verify->pk, pk, pk_len);
1017   verify->pk_len = pk_len;
1018   verify->pk_type = pk_type;
1019   verify->completion = completion;
1020   verify->context = context;
1021
1022   /* Check whether this key already exists */
1023   if (stat(filename, &st) < 0) {
1024     /* Key does not exist, ask user to verify the key and save it */
1025
1026     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1027                        SILCTXT_PUBKEY_RECEIVED, entity);
1028     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1029                        SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1030     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1031                        SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1032     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1033                              SILCTXT_PUBKEY_ACCEPT);
1034     keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1035                             format, 0, verify);
1036     g_free(format);
1037     silc_free(fingerprint);
1038     return;
1039   } else {
1040     /* The key already exists, verify it. */
1041     SilcPublicKey public_key;
1042     unsigned char *encpk;
1043     uint32 encpk_len;
1044
1045     /* Load the key file */
1046     if (!silc_pkcs_load_public_key(filename, &public_key, 
1047                                    SILC_PKCS_FILE_PEM))
1048       if (!silc_pkcs_load_public_key(filename, &public_key, 
1049                                      SILC_PKCS_FILE_BIN)) {
1050         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1051                            SILCTXT_PUBKEY_RECEIVED, entity);
1052         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1053                            SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1054         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1055                            SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1056         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1057                            SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1058         format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1059                                  SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1060         keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1061                                 format, 0, verify);
1062         g_free(format);
1063         silc_free(fingerprint);
1064         return;
1065       }
1066   
1067     /* Encode the key data */
1068     encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1069     if (!encpk) {
1070       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1071                          SILCTXT_PUBKEY_RECEIVED, entity);
1072       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1073                          SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1074       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1075                          SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1076       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1077                          SILCTXT_PUBKEY_MALFORMED, entity);
1078       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1079                                SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1080       keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1081                               format, 0, verify);
1082       g_free(format);
1083       silc_free(fingerprint);
1084       return;
1085     }
1086
1087     /* Compare the keys */
1088     if (memcmp(encpk, pk, encpk_len)) {
1089       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1090                          SILCTXT_PUBKEY_RECEIVED, entity);
1091       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1092                          SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1093       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1094                          SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1095       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1096                          SILCTXT_PUBKEY_NO_MATCH, entity);
1097       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1098                          SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1099       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1100                          SILCTXT_PUBKEY_MITM_ATTACK, entity);
1101
1102       /* Ask user to verify the key and save it */
1103       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1104                                SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1105       keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1106                               format, 0, verify);
1107       g_free(format);
1108       silc_free(fingerprint);
1109       return;
1110     }
1111
1112     /* Local copy matched */
1113     if (completion)
1114       completion(TRUE, context);
1115     silc_free(fingerprint);
1116   }
1117 }
1118
1119 /* Verifies received public key. The `conn_type' indicates which entity
1120    (server, client etc.) has sent the public key. If user decides to trust
1121    the key may be saved as trusted public key for later use. The 
1122    `completion' must be called after the public key has been verified. */
1123
1124 void 
1125 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1126                        SilcSocketType conn_type, unsigned char *pk, 
1127                        uint32 pk_len, SilcSKEPKType pk_type,
1128                        SilcVerifyPublicKey completion, void *context)
1129 {
1130   silc_verify_public_key_internal(client, conn, conn_type, pk,
1131                                   pk_len, pk_type,
1132                                   completion, context);
1133 }
1134
1135 /* Asks passphrase from user on the input line. */
1136
1137 typedef struct {
1138   SilcAskPassphrase completion;
1139   void *context;
1140 } *AskPassphrase;
1141
1142 void ask_passphrase_completion(const char *passphrase, void *context)
1143 {
1144   AskPassphrase p = (AskPassphrase)context;
1145   p->completion((unsigned char *)passphrase, 
1146                 passphrase ? strlen(passphrase) : 0, p->context);
1147   silc_free(p);
1148 }
1149
1150 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1151                          SilcAskPassphrase completion, void *context)
1152 {
1153   AskPassphrase p = silc_calloc(1, sizeof(*p));
1154   p->completion = completion;
1155   p->context = context;
1156
1157   keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1158                           "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1159 }
1160
1161 typedef struct {
1162   SilcGetAuthMeth completion;
1163   void *context;
1164 } *InternalGetAuthMethod;
1165
1166 /* Callback called when we've received the authentication method information
1167    from the server after we've requested it. This will get the authentication
1168    data from the user if needed. */
1169
1170 static void silc_get_auth_method_callback(SilcClient client,
1171                                           SilcClientConnection conn,
1172                                           SilcAuthMethod auth_meth,
1173                                           void *context)
1174 {
1175   InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1176
1177   SILC_LOG_DEBUG(("Start"));
1178
1179   switch (auth_meth) {
1180   case SILC_AUTH_NONE:
1181     /* No authentication required. */
1182     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1183     break;
1184   case SILC_AUTH_PASSWORD:
1185     /* Do not ask the passphrase from user, the library will ask it if
1186        we do not provide it here. */
1187     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1188     break;
1189   case SILC_AUTH_PUBLIC_KEY:
1190     /* Do not get the authentication data now, the library will generate
1191        it using our default key, if we do not provide it here. */
1192     /* XXX In the future when we support multiple local keys and multiple
1193        local certificates we will need to ask from user which one to use. */
1194     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1195     break;
1196   }
1197
1198   silc_free(internal);
1199 }
1200
1201 /* Find authentication method and authentication data by hostname and
1202    port. The hostname may be IP address as well. The found authentication
1203    method and authentication data is returned to `auth_meth', `auth_data'
1204    and `auth_data_len'. The function returns TRUE if authentication method
1205    is found and FALSE if not. `conn' may be NULL. */
1206
1207 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1208                           char *hostname, uint16 port,
1209                           SilcGetAuthMeth completion, void *context)
1210 {
1211   InternalGetAuthMethod internal;
1212
1213   SILC_LOG_DEBUG(("Start"));
1214
1215   /* XXX must resolve from configuration whether this connection has
1216      any specific authentication data */
1217
1218   /* If we do not have this connection configured by the user in a
1219      configuration file then resolve the authentication method from the
1220      server for this session. */
1221   internal = silc_calloc(1, sizeof(*internal));
1222   internal->completion = completion;
1223   internal->context = context;
1224
1225   silc_client_request_authentication_method(client, conn, 
1226                                             silc_get_auth_method_callback,
1227                                             internal);
1228 }
1229
1230 /* Notifies application that failure packet was received.  This is called
1231    if there is some protocol active in the client.  The `protocol' is the
1232    protocol context.  The `failure' is opaque pointer to the failure
1233    indication.  Note, that the `failure' is protocol dependant and application
1234    must explicitly cast it to correct type.  Usually `failure' is 32 bit
1235    failure type (see protocol specs for all protocol failure types). */
1236
1237 void silc_failure(SilcClient client, SilcClientConnection conn, 
1238                   SilcProtocol protocol, void *failure)
1239 {
1240   SILC_LOG_DEBUG(("Start"));
1241
1242   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1243     SilcSKEStatus status = (SilcSKEStatus)failure;
1244     
1245     if (status == SILC_SKE_STATUS_BAD_VERSION)
1246       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1247                          SILCTXT_KE_BAD_VERSION);
1248     if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1249       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1250                          SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1251     if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1252       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1253                          SILCTXT_KE_UNKNOWN_GROUP);
1254     if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1255       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1256                          SILCTXT_KE_UNKNOWN_CIPHER);
1257     if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1258       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1259                          SILCTXT_KE_UNKNOWN_PKCS);
1260     if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1261       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1262                          SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1263     if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1264       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1265                          SILCTXT_KE_UNKNOWN_HMAC);
1266     if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1267       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1268                          SILCTXT_KE_INCORRECT_SIGNATURE);
1269     if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1270       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1271                          SILCTXT_KE_INVALID_COOKIE);
1272   }
1273
1274   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1275     uint32 err = (uint32)failure;
1276
1277     if (err == SILC_AUTH_FAILED)
1278       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1279                          SILCTXT_AUTH_FAILED);
1280   }
1281 }
1282
1283 /* Asks whether the user would like to perform the key agreement protocol.
1284    This is called after we have received an key agreement packet or an
1285    reply to our key agreement packet. This returns TRUE if the user wants
1286    the library to perform the key agreement protocol and FALSE if it is not
1287    desired (application may start it later by calling the function
1288    silc_client_perform_key_agreement). */
1289
1290 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1291                        SilcClientEntry client_entry, const char *hostname,
1292                        uint16 port, SilcKeyAgreementCallback *completion,
1293                        void **context)
1294 {
1295   char portstr[12];
1296
1297   SILC_LOG_DEBUG(("Start"));
1298
1299   /* We will just display the info on the screen and return FALSE and user
1300      will have to start the key agreement with a command. */
1301
1302   if (hostname) 
1303     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1304
1305   if (!hostname)
1306     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1307                        SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1308   else
1309     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1310                        SILCTXT_KEY_AGREEMENT_REQUEST_HOST, 
1311                        client_entry->nickname, hostname, portstr);
1312
1313   *completion = NULL;
1314   *context = NULL;
1315
1316   return FALSE;
1317 }
1318
1319 void silc_ftp(SilcClient client, SilcClientConnection conn,
1320               SilcClientEntry client_entry, uint32 session_id,
1321               const char *hostname, uint16 port)
1322 {
1323   SILC_SERVER_REC *server;
1324   char portstr[12];
1325   FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1326
1327   SILC_LOG_DEBUG(("Start"));
1328
1329   server = conn->context;
1330
1331   ftp->client_entry = client_entry;
1332   ftp->session_id = session_id;
1333   ftp->send = FALSE;
1334   ftp->conn = conn;
1335   silc_dlist_add(server->ftp_sessions, ftp);
1336   server->current_session = ftp;
1337
1338   if (hostname) 
1339     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1340
1341   if (!hostname)
1342     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1343                        SILCTXT_FILE_REQUEST, client_entry->nickname);
1344   else
1345     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1346                        SILCTXT_FILE_REQUEST_HOST, 
1347                        client_entry->nickname, hostname, portstr);
1348 }
1349
1350 /* SILC client operations */
1351 SilcClientOperations ops = {
1352   silc_say,
1353   silc_channel_message,
1354   silc_private_message,
1355   silc_notify,
1356   silc_command,
1357   silc_command_reply,
1358   silc_connect,
1359   silc_disconnect,
1360   silc_get_auth_method,
1361   silc_verify_public_key,
1362   silc_ask_passphrase,
1363   silc_failure,
1364   silc_key_agreement,
1365   silc_ftp,
1366 };