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           status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
411         char *tmp;
412         tmp = 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       }
419       
420       if (!success)
421         return;
422       
423       client_entry = va_arg(vp, SilcClientEntry);
424       nickname = va_arg(vp, char *);
425       username = va_arg(vp, char *);
426       realname = va_arg(vp, char *);
427       channels = va_arg(vp, SilcBuffer);
428       mode = va_arg(vp, uint32);
429       idle = va_arg(vp, uint32);
430       fingerprint = va_arg(vp, unsigned char *);
431       
432       silc_parse_userfqdn(nickname, &nick, NULL);
433       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
434                          SILCTXT_WHOIS_USERINFO, nickname, 
435                          client_entry->username, client_entry->hostname,
436                          nick, client_entry->nickname);
437       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
438                          SILCTXT_WHOIS_REALNAME, realname);
439       silc_free(nick);
440
441       if (channels) {
442         SilcDList list = silc_channel_payload_parse_list(channels);
443         if (list) {
444           SilcChannelPayload entry;
445           memset(buf, 0, sizeof(buf));
446           silc_dlist_start(list);
447           while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
448             char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
449             uint32 name_len;
450             char *name = silc_channel_get_name(entry, &name_len);
451             
452             if (m)
453               strncat(buf, m, strlen(m));
454             strncat(buf, name, name_len);
455             strncat(buf, " ", 1);
456             silc_free(m);
457           }
458
459           printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
460                              SILCTXT_WHOIS_CHANNELS, buf);
461           silc_channel_payload_list_free(list);
462         }
463       }
464       
465       if (mode) {
466         memset(buf, 0, sizeof(buf));
467
468         if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
469             (mode & SILC_UMODE_ROUTER_OPERATOR)) {
470           strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
471                  "Server Operator " :
472                  (mode & SILC_UMODE_ROUTER_OPERATOR) ?
473                  "SILC Operator " : "[Unknown mode] ");
474         }
475         if (mode & SILC_UMODE_GONE)
476           strcat(buf, "away");
477
478         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
479                            SILCTXT_WHOIS_MODES, buf);
480       }
481       
482       if (idle && nickname) {
483         memset(buf, 0, sizeof(buf));
484         snprintf(buf, sizeof(buf) - 1, "%lu %s",
485                  idle > 60 ? (idle / 60) : idle,
486                  idle > 60 ? "minutes" : "seconds");
487
488         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
489                            SILCTXT_WHOIS_IDLE, buf);
490       }
491
492       if (fingerprint) {
493         fingerprint = silc_fingerprint(fingerprint, 20);
494         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
495                            SILCTXT_WHOIS_FINGERPRINT, fingerprint);
496         silc_free(fingerprint);
497       }
498     }
499     break;
500     
501   case SILC_COMMAND_WHOWAS:
502     {
503       char *nickname, *username, *realname;
504       
505       if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
506           status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
507         char *tmp;
508         tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
509                                          3, NULL);
510         if (tmp)
511           silc_say_error("%s: %s", tmp, 
512                          silc_client_command_status_message(status));
513         break;
514       }
515       
516       if (!success)
517         return;
518       
519       (void)va_arg(vp, SilcClientEntry);
520       nickname = va_arg(vp, char *);
521       username = va_arg(vp, char *);
522       realname = va_arg(vp, char *);
523       
524       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
525                          SILCTXT_WHOWAS_USERINFO, nickname, username, 
526                          realname ? realname : "");
527     }
528     break;
529     
530   case SILC_COMMAND_INVITE:
531     {
532       SilcChannelEntry channel;
533       char *invite_list;
534       SilcArgumentPayload args;
535       int argc = 0;
536       
537       if (!success)
538         return;
539       
540       channel = va_arg(vp, SilcChannelEntry);
541       invite_list = va_arg(vp, char *);
542
543       args = silc_command_get_args(cmd_payload);
544       if (args)
545         argc = silc_argument_get_arg_num(args);
546
547       if (invite_list)
548         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
549                            SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
550                            invite_list);
551       else if (argc == 3)
552         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
553                            SILCTXT_CHANNEL_NO_INVITE_LIST, 
554                            channel->channel_name);
555     }
556     break;
557
558   case SILC_COMMAND_JOIN: 
559     {
560       char *channel, *mode, *topic;
561       uint32 modei;
562       SilcChannelEntry channel_entry;
563       SilcBuffer client_id_list;
564       uint32 list_count;
565
566       if (!success)
567         return;
568
569       channel = va_arg(vp, char *);
570       channel_entry = va_arg(vp, SilcChannelEntry);
571       modei = va_arg(vp, uint32);
572       (void)va_arg(vp, uint32);
573       (void)va_arg(vp, unsigned char *);
574       (void)va_arg(vp, unsigned char *);
575       (void)va_arg(vp, unsigned char *);
576       topic = va_arg(vp, char *);
577       (void)va_arg(vp, unsigned char *);
578       list_count = va_arg(vp, uint32);
579       client_id_list = va_arg(vp, SilcBuffer);
580
581       chanrec = silc_channel_find(server, channel);
582       if (!chanrec)
583         chanrec = silc_channel_create(server, channel, TRUE);
584
585       if (topic) {
586         g_free_not_null(chanrec->topic);
587         chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
588         signal_emit("channel topic changed", 1, chanrec);
589       }
590
591       mode = silc_client_chmode(modei, 
592                                 channel_entry->channel_key ? 
593                                 channel_entry->channel_key->cipher->name : "",
594                                 channel_entry->hmac ? 
595                                 silc_hmac_get_name(channel_entry->hmac) : "");
596       g_free_not_null(chanrec->mode);
597       chanrec->mode = g_strdup(mode == NULL ? "" : mode);
598       signal_emit("channel mode changed", 1, chanrec);
599
600       /* Resolve the client information */
601       silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
602                                       silc_client_join_get_users, 
603                                       channel_entry);
604       break;
605     }
606
607   case SILC_COMMAND_NICK: 
608     {
609       SilcClientEntry client = va_arg(vp, SilcClientEntry);
610       char *old;
611       
612       if (!success)
613         return;
614
615       old = g_strdup(server->nick);
616       server_change_nick(SERVER(server), client->nickname);
617       nicklist_rename_unique(SERVER(server),
618                              server->conn->local_entry, server->nick,
619                              client, client->nickname);
620       
621       signal_emit("message own_nick", 4, server, server->nick, old, "");
622       g_free(old);
623       break;
624     }
625     
626   case SILC_COMMAND_LIST:
627     {
628       char *topic, *name;
629       int usercount;
630       char users[20];
631       
632       if (!success)
633         return;
634       
635       (void)va_arg(vp, SilcChannelEntry);
636       name = va_arg(vp, char *);
637       topic = va_arg(vp, char *);
638       usercount = va_arg(vp, int);
639       
640       if (status == SILC_STATUS_LIST_START ||
641           status == SILC_STATUS_OK)
642         printformat_module("fe-common/silc", server, NULL,
643                            MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
644
645       if (!usercount)
646         snprintf(users, sizeof(users) - 1, "N/A");
647       else
648         snprintf(users, sizeof(users) - 1, "%d", usercount);
649       printformat_module("fe-common/silc", server, NULL,
650                          MSGLEVEL_CRAP, SILCTXT_LIST,
651                          name, users, topic ? topic : "");
652     }
653     break;
654     
655   case SILC_COMMAND_UMODE:
656     {
657       uint32 mode;
658       
659       if (!success)
660         return;
661       
662       mode = va_arg(vp, uint32);
663       
664       if (mode & SILC_UMODE_SERVER_OPERATOR)
665         printformat_module("fe-common/silc", server, NULL,
666                            MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
667
668       if (mode & SILC_UMODE_ROUTER_OPERATOR)
669         printformat_module("fe-common/silc", server, NULL,
670                            MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
671     }
672     break;
673     
674   case SILC_COMMAND_OPER:
675     if (!success)
676       return;
677
678     printformat_module("fe-common/silc", server, NULL,
679                        MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
680     break;
681     
682   case SILC_COMMAND_SILCOPER:
683     if (!success)
684       return;
685
686     printformat_module("fe-common/silc", server, NULL,
687                        MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
688     break;
689     
690   case SILC_COMMAND_USERS: 
691     {
692       SilcChannelEntry channel;
693       SilcChannelUser chu;
694       
695       if (!success)
696         return;
697       
698       channel = va_arg(vp, SilcChannelEntry);
699       
700       printformat_module("fe-common/silc", server, channel->channel_name,
701                          MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
702                          channel->channel_name);
703
704       silc_list_start(channel->clients);
705       while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
706         SilcClientEntry e = chu->client;
707         char stat[5], *mode;
708
709         if (!e->nickname)
710           continue;
711         
712         memset(stat, 0, sizeof(stat));
713         mode = silc_client_chumode_char(chu->mode);
714         if (e->mode & SILC_UMODE_GONE)
715           strcat(stat, "G");
716         else
717           strcat(stat, "H");
718         if (mode)
719           strcat(stat, mode);
720
721         printformat_module("fe-common/silc", server, channel->channel_name,
722                            MSGLEVEL_CRAP, SILCTXT_USERS,
723                            e->nickname, stat, 
724                            e->username ? e->username : "",
725                            e->hostname ? e->hostname : "",
726                            e->realname ? e->realname : "");
727         if (mode)
728           silc_free(mode);
729       }
730     }
731     break;
732
733   case SILC_COMMAND_BAN:
734     {
735       SilcChannelEntry channel;
736       char *ban_list;
737       
738       if (!success)
739         return;
740       
741       channel = va_arg(vp, SilcChannelEntry);
742       ban_list = va_arg(vp, char *);
743       
744       if (ban_list)
745         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
746                            SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
747                            ban_list);
748       else
749         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
750                            SILCTXT_CHANNEL_NO_BAN_LIST, 
751                            channel->channel_name);
752     }
753     break;
754     
755   case SILC_COMMAND_GETKEY:
756     {
757       SilcIdType id_type;
758       void *entry;
759       SilcPublicKey public_key;
760       unsigned char *pk;
761       uint32 pk_len;
762       GetkeyContext getkey;
763       
764       if (!success)
765         return;
766       
767       id_type = va_arg(vp, uint32);
768       entry = va_arg(vp, void *);
769       public_key = va_arg(vp, SilcPublicKey);
770
771       if (public_key) {
772         pk = silc_pkcs_public_key_encode(public_key, &pk_len);
773
774         getkey = silc_calloc(1, sizeof(*getkey));
775         getkey->entry = entry;
776         getkey->id_type = id_type;
777         getkey->client = client;
778         getkey->conn = conn;
779         getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
780         
781         silc_verify_public_key_internal(client, conn, 
782                                         (id_type == SILC_ID_CLIENT ?
783                                          SILC_SOCKET_TYPE_CLIENT :
784                                          SILC_SOCKET_TYPE_SERVER),
785                                         pk, pk_len, SILC_SKE_PK_TYPE_SILC,
786                                         silc_getkey_cb, getkey);
787         silc_free(pk);
788       } else {
789         printformat_module("fe-common/silc", server, NULL,
790                            MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
791       }
792     }
793     break;
794     
795   case SILC_COMMAND_TOPIC:
796     {
797       SilcChannelEntry channel;
798       char *topic;
799       
800       if (!success)
801         return;
802       
803       channel = va_arg(vp, SilcChannelEntry);
804       topic = va_arg(vp, char *);
805       
806       if (topic) {
807         chanrec = silc_channel_find_entry(server, channel);
808         if (chanrec) {
809           g_free_not_null(chanrec->topic);
810           chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
811           signal_emit("channel topic changed", 1, chanrec);
812         }
813         printformat_module("fe-common/silc", server, channel->channel_name,
814                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
815                            channel->channel_name, topic);
816       } else {
817         printformat_module("fe-common/silc", server, channel->channel_name,
818                            MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
819                            channel->channel_name);
820       }
821     }
822     break;
823
824   }
825
826   va_end(vp);
827 }
828
829 /* Internal routine to verify public key. If the `completion' is provided
830    it will be called to indicate whether public was verified or not. */
831
832 typedef struct {
833   SilcClient client;
834   SilcClientConnection conn;
835   char *filename;
836   char *entity;
837   unsigned char *pk;
838   uint32 pk_len;
839   SilcSKEPKType pk_type;
840   SilcVerifyPublicKey completion;
841   void *context;
842 } *PublicKeyVerify;
843
844 static void verify_public_key_completion(const char *line, void *context)
845 {
846   PublicKeyVerify verify = (PublicKeyVerify)context;
847
848   if (line[0] == 'Y' || line[0] == 'y') {
849     /* Call the completion */
850     if (verify->completion)
851       verify->completion(TRUE, verify->context);
852
853     /* Save the key for future checking */
854     silc_pkcs_save_public_key_data(verify->filename, verify->pk, 
855                                    verify->pk_len, SILC_PKCS_FILE_PEM);
856   } else {
857     /* Call the completion */
858     if (verify->completion)
859       verify->completion(FALSE, verify->context);
860
861     printformat_module("fe-common/silc", NULL, NULL,
862                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
863   }
864
865   silc_free(verify->filename);
866   silc_free(verify->entity);
867   silc_free(verify->pk);
868   silc_free(verify);
869 }
870
871 static void 
872 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
873                                 SilcSocketType conn_type, unsigned char *pk, 
874                                 uint32 pk_len, SilcSKEPKType pk_type,
875                                 SilcVerifyPublicKey completion, void *context)
876 {
877   int i;
878   char file[256], filename[256], *fingerprint, *babbleprint, *format;
879   struct passwd *pw;
880   struct stat st;
881   char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
882                    conn_type == SILC_SOCKET_TYPE_ROUTER) ? 
883                   "server" : "client");
884   PublicKeyVerify verify;
885
886   if (pk_type != SILC_SKE_PK_TYPE_SILC) {
887     printformat_module("fe-common/silc", NULL, NULL,
888                        MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED, 
889                        entity, pk_type);
890     if (completion)
891       completion(FALSE, context);
892     return;
893   }
894
895   pw = getpwuid(getuid());
896   if (!pw) {
897     if (completion)
898       completion(FALSE, context);
899     return;
900   }
901
902   memset(filename, 0, sizeof(filename));
903   memset(file, 0, sizeof(file));
904
905   if (conn_type == SILC_SOCKET_TYPE_SERVER ||
906       conn_type == SILC_SOCKET_TYPE_ROUTER) {
907     snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
908              conn->sock->hostname, conn->sock->port);
909     snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
910              pw->pw_dir, entity, file);
911   } else {
912     /* Replace all whitespaces with `_'. */
913     fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
914     for (i = 0; i < strlen(fingerprint); i++)
915       if (fingerprint[i] == ' ')
916         fingerprint[i] = '_';
917     
918     snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
919     snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
920              pw->pw_dir, entity, file);
921     silc_free(fingerprint);
922   }
923
924   /* Take fingerprint of the public key */
925   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
926   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
927
928   verify = silc_calloc(1, sizeof(*verify));
929   verify->client = client;
930   verify->conn = conn;
931   verify->filename = strdup(filename);
932   verify->entity = strdup(entity);
933   verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
934   memcpy(verify->pk, pk, pk_len);
935   verify->pk_len = pk_len;
936   verify->pk_type = pk_type;
937   verify->completion = completion;
938   verify->context = context;
939
940   /* Check whether this key already exists */
941   if (stat(filename, &st) < 0) {
942     /* Key does not exist, ask user to verify the key and save it */
943
944     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
945                        SILCTXT_PUBKEY_RECEIVED, entity);
946     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
947                        SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
948     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
949                        SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
950     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
951                              SILCTXT_PUBKEY_ACCEPT);
952     keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
953                             format, 0, verify);
954     g_free(format);
955     silc_free(fingerprint);
956     return;
957   } else {
958     /* The key already exists, verify it. */
959     SilcPublicKey public_key;
960     unsigned char *encpk;
961     uint32 encpk_len;
962
963     /* Load the key file */
964     if (!silc_pkcs_load_public_key(filename, &public_key, 
965                                    SILC_PKCS_FILE_PEM))
966       if (!silc_pkcs_load_public_key(filename, &public_key, 
967                                      SILC_PKCS_FILE_BIN)) {
968         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
969                            SILCTXT_PUBKEY_RECEIVED, entity);
970         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
971                            SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
972         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
973                            SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
974         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
975                            SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
976         format = format_get_text("fe-common/silc", NULL, NULL, NULL,
977                                  SILCTXT_PUBKEY_ACCEPT_ANYWAY);
978         keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
979                                 format, 0, verify);
980         g_free(format);
981         silc_free(fingerprint);
982         return;
983       }
984   
985     /* Encode the key data */
986     encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
987     if (!encpk) {
988       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
989                          SILCTXT_PUBKEY_RECEIVED, entity);
990       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
991                          SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
992       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
993                          SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
994       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
995                          SILCTXT_PUBKEY_MALFORMED, entity);
996       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
997                                SILCTXT_PUBKEY_ACCEPT_ANYWAY);
998       keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
999                               format, 0, verify);
1000       g_free(format);
1001       silc_free(fingerprint);
1002       return;
1003     }
1004
1005     /* Compare the keys */
1006     if (memcmp(encpk, pk, encpk_len)) {
1007       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1008                          SILCTXT_PUBKEY_RECEIVED, entity);
1009       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1010                          SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1011       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1012                          SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1013       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1014                          SILCTXT_PUBKEY_NO_MATCH, entity);
1015       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1016                          SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1017       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1018                          SILCTXT_PUBKEY_MITM_ATTACK, entity);
1019
1020       /* Ask user to verify the key and save it */
1021       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1022                                SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1023       keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1024                               format, 0, verify);
1025       g_free(format);
1026       silc_free(fingerprint);
1027       return;
1028     }
1029
1030     /* Local copy matched */
1031     if (completion)
1032       completion(TRUE, context);
1033     silc_free(fingerprint);
1034   }
1035 }
1036
1037 /* Verifies received public key. The `conn_type' indicates which entity
1038    (server, client etc.) has sent the public key. If user decides to trust
1039    the key may be saved as trusted public key for later use. The 
1040    `completion' must be called after the public key has been verified. */
1041
1042 void 
1043 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1044                        SilcSocketType conn_type, unsigned char *pk, 
1045                        uint32 pk_len, SilcSKEPKType pk_type,
1046                        SilcVerifyPublicKey completion, void *context)
1047 {
1048   silc_verify_public_key_internal(client, conn, conn_type, pk,
1049                                   pk_len, pk_type,
1050                                   completion, context);
1051 }
1052
1053 /* Asks passphrase from user on the input line. */
1054
1055 typedef struct {
1056   SilcAskPassphrase completion;
1057   void *context;
1058 } *AskPassphrase;
1059
1060 void ask_passphrase_completion(const char *passphrase, void *context)
1061 {
1062   AskPassphrase p = (AskPassphrase)context;
1063   p->completion((unsigned char *)passphrase, 
1064                 passphrase ? strlen(passphrase) : 0, p->context);
1065   silc_free(p);
1066 }
1067
1068 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1069                          SilcAskPassphrase completion, void *context)
1070 {
1071   AskPassphrase p = silc_calloc(1, sizeof(*p));
1072   p->completion = completion;
1073   p->context = context;
1074
1075   keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1076                           "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1077 }
1078
1079 typedef struct {
1080   SilcGetAuthMeth completion;
1081   void *context;
1082 } *InternalGetAuthMethod;
1083
1084 /* Callback called when we've received the authentication method information
1085    from the server after we've requested it. This will get the authentication
1086    data from the user if needed. */
1087
1088 static void silc_get_auth_method_callback(SilcClient client,
1089                                           SilcClientConnection conn,
1090                                           SilcAuthMethod auth_meth,
1091                                           void *context)
1092 {
1093   InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1094
1095   SILC_LOG_DEBUG(("Start"));
1096
1097   switch (auth_meth) {
1098   case SILC_AUTH_NONE:
1099     /* No authentication required. */
1100     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1101     break;
1102   case SILC_AUTH_PASSWORD:
1103     /* Do not ask the passphrase from user, the library will ask it if
1104        we do not provide it here. */
1105     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1106     break;
1107   case SILC_AUTH_PUBLIC_KEY:
1108     /* Do not get the authentication data now, the library will generate
1109        it using our default key, if we do not provide it here. */
1110     /* XXX In the future when we support multiple local keys and multiple
1111        local certificates we will need to ask from user which one to use. */
1112     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1113     break;
1114   }
1115
1116   silc_free(internal);
1117 }
1118
1119 /* Find authentication method and authentication data by hostname and
1120    port. The hostname may be IP address as well. The found authentication
1121    method and authentication data is returned to `auth_meth', `auth_data'
1122    and `auth_data_len'. The function returns TRUE if authentication method
1123    is found and FALSE if not. `conn' may be NULL. */
1124
1125 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1126                           char *hostname, uint16 port,
1127                           SilcGetAuthMeth completion, void *context)
1128 {
1129   InternalGetAuthMethod internal;
1130
1131   SILC_LOG_DEBUG(("Start"));
1132
1133   /* XXX must resolve from configuration whether this connection has
1134      any specific authentication data */
1135
1136   /* If we do not have this connection configured by the user in a
1137      configuration file then resolve the authentication method from the
1138      server for this session. */
1139   internal = silc_calloc(1, sizeof(*internal));
1140   internal->completion = completion;
1141   internal->context = context;
1142
1143   silc_client_request_authentication_method(client, conn, 
1144                                             silc_get_auth_method_callback,
1145                                             internal);
1146 }
1147
1148 /* Notifies application that failure packet was received.  This is called
1149    if there is some protocol active in the client.  The `protocol' is the
1150    protocol context.  The `failure' is opaque pointer to the failure
1151    indication.  Note, that the `failure' is protocol dependant and application
1152    must explicitly cast it to correct type.  Usually `failure' is 32 bit
1153    failure type (see protocol specs for all protocol failure types). */
1154
1155 void silc_failure(SilcClient client, SilcClientConnection conn, 
1156                   SilcProtocol protocol, void *failure)
1157 {
1158   SILC_LOG_DEBUG(("Start"));
1159
1160   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1161     SilcSKEStatus status = (SilcSKEStatus)failure;
1162     
1163     if (status == SILC_SKE_STATUS_BAD_VERSION)
1164       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1165                          SILCTXT_KE_BAD_VERSION);
1166     if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1167       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1168                          SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1169     if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1170       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1171                          SILCTXT_KE_UNKNOWN_GROUP);
1172     if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1173       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1174                          SILCTXT_KE_UNKNOWN_CIPHER);
1175     if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1176       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1177                          SILCTXT_KE_UNKNOWN_PKCS);
1178     if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1179       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1180                          SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1181     if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1182       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1183                          SILCTXT_KE_UNKNOWN_HMAC);
1184     if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1185       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1186                          SILCTXT_KE_INCORRECT_SIGNATURE);
1187     if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1188       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1189                          SILCTXT_KE_INVALID_COOKIE);
1190   }
1191
1192   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1193     uint32 err = (uint32)failure;
1194
1195     if (err == SILC_AUTH_FAILED)
1196       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
1197                          SILCTXT_AUTH_FAILED);
1198   }
1199 }
1200
1201 /* Asks whether the user would like to perform the key agreement protocol.
1202    This is called after we have received an key agreement packet or an
1203    reply to our key agreement packet. This returns TRUE if the user wants
1204    the library to perform the key agreement protocol and FALSE if it is not
1205    desired (application may start it later by calling the function
1206    silc_client_perform_key_agreement). */
1207
1208 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1209                        SilcClientEntry client_entry, const char *hostname,
1210                        uint16 port, SilcKeyAgreementCallback *completion,
1211                        void **context)
1212 {
1213   char portstr[12];
1214
1215   SILC_LOG_DEBUG(("Start"));
1216
1217   /* We will just display the info on the screen and return FALSE and user
1218      will have to start the key agreement with a command. */
1219
1220   if (hostname) 
1221     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1222
1223   if (!hostname)
1224     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1225                        SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1226   else
1227     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1228                        SILCTXT_KEY_AGREEMENT_REQUEST_HOST, 
1229                        client_entry->nickname, hostname, portstr);
1230
1231   *completion = NULL;
1232   *context = NULL;
1233
1234   return FALSE;
1235 }
1236
1237 void silc_ftp(SilcClient client, SilcClientConnection conn,
1238               SilcClientEntry client_entry, uint32 session_id,
1239               const char *hostname, uint16 port)
1240 {
1241   SILC_SERVER_REC *server;
1242   char portstr[12];
1243   FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1244
1245   SILC_LOG_DEBUG(("Start"));
1246
1247   server = conn->context;
1248
1249   ftp->client_entry = client_entry;
1250   ftp->session_id = session_id;
1251   ftp->send = FALSE;
1252   ftp->conn = conn;
1253   silc_dlist_add(server->ftp_sessions, ftp);
1254   server->current_session = ftp;
1255
1256   if (hostname) 
1257     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1258
1259   if (!hostname)
1260     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1261                        SILCTXT_FILE_REQUEST, client_entry->nickname);
1262   else
1263     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1264                        SILCTXT_FILE_REQUEST_HOST, 
1265                        client_entry->nickname, hostname, portstr);
1266 }
1267
1268 /* SILC client operations */
1269 SilcClientOperations ops = {
1270   silc_say,
1271   silc_channel_message,
1272   silc_private_message,
1273   silc_notify,
1274   silc_command,
1275   silc_command_reply,
1276   silc_connect,
1277   silc_disconnect,
1278   silc_get_auth_method,
1279   silc_verify_public_key,
1280   silc_ask_passphrase,
1281   silc_failure,
1282   silc_key_agreement,
1283   silc_ftp,
1284 };