Porting to new Toolkit API.
[silc.git] / apps / irssi / src / silc / core / silc-servers.c
1 /*
2   silc-server.c : irssi
3
4   Copyright (C) 2000 - 2006 Timo Sirainen
5                             Pekka Riikonen <priikone@silcnet.org>
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "module.h"
23
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
26 #include "signals.h"
27 #include "servers.h"
28 #include "commands.h"
29 #include "levels.h"
30 #include "modules.h"
31 #include "rawlog.h"
32 #include "misc.h"
33 #include "settings.h"
34
35 #include "servers-setup.h"
36
37 #include "client_ops.h"
38 #include "silc-servers.h"
39 #include "silc-channels.h"
40 #include "silc-queries.h"
41 #include "silc-nicklist.h"
42 #include "silc-cmdqueue.h"
43 #include "window-item-def.h"
44
45 #include "fe-common/core/printtext.h"
46 #include "fe-common/core/fe-channels.h"
47 #include "fe-common/core/keyboard.h"
48 #include "fe-common/silc/module-formats.h"
49
50 #include "silc-commands.h"
51
52 void silc_servers_reconnect_init(void);
53 void silc_servers_reconnect_deinit(void);
54
55 int silc_send_channel(SILC_SERVER_REC *server,
56                       char *channel, char *msg,
57                       SilcMessageFlags flags)
58 {
59   SILC_CHANNEL_REC *rec;
60
61   rec = silc_channel_find(server, channel);
62   if (rec == NULL || rec->entry == NULL) {
63     cmd_return_error_value(CMDERR_NOT_JOINED, FALSE);
64   }
65
66   return silc_client_send_channel_message(silc_client, server->conn,
67                                           rec->entry, NULL, flags, sha1hash,
68                                           msg, strlen(msg));
69 }
70
71 typedef struct {
72   char *nick;
73   char *msg;
74   int len;
75   SilcMessageFlags flags;
76   SILC_SERVER_REC *server;
77 } PRIVMSG_REC;
78
79 /* Callback function that sends the private message if the client was
80    resolved from the server. */
81
82 static void silc_send_msg_clients(SilcClient client,
83                                   SilcClientConnection conn,
84                                   SilcStatus status,
85                                   SilcDList clients,
86                                   void *context)
87 {
88   PRIVMSG_REC *rec = context;
89   SILC_SERVER_REC *server = rec->server;
90   SilcClientEntry target;
91   char nickname[128 + 1];
92   SilcDList lclients = NULL;
93
94   if (!clients) {
95     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
96               "%s: There is no such client", rec->nick);
97   } else {
98     if (silc_dlist_count(clients) > 1) {
99       silc_parse_userfqdn(rec->nick, nickname, sizeof(nickname), NULL, 0);
100
101       /* Find the correct one. The rec->nick might be a formatted nick
102          so this will find the correct one. */
103       clients = lclients =
104         silc_client_get_clients_local(silc_client, server->conn,
105                                       nickname, rec->nick);
106       if (!clients) {
107         printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
108                   "%s: There is no such client", rec->nick);
109         goto out;
110       }
111     }
112
113     target = silc_dlist_get(clients);
114
115     /* Still check for exact math for nickname, this compares the
116        real (formatted) nickname and the nick (maybe formatted) that
117        user gave. This is to assure that `nick' does not match
118        `nick@host'. */
119     if (!silc_utf8_strcasecmp(rec->nick, target->nickname)) {
120       printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
121                 "%s: There is no such client", rec->nick);
122       goto out;
123     }
124
125     /* Send the private message */
126     silc_client_send_private_message(client, conn, target,
127                                      rec->flags, sha1hash,
128                                      rec->msg, rec->len);
129   }
130
131  out:
132   silc_client_list_free(silc_client, server->conn, lclients);
133   g_free(rec->nick);
134   g_free(rec->msg);
135   g_free(rec);
136 }
137
138 int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
139                   int msg_len, SilcMessageFlags flags)
140 {
141   PRIVMSG_REC *rec;
142   char nickname[128 + 1];
143   SilcDList clients;
144   SilcClientEntry target;
145   int ret;
146
147   if (!silc_parse_userfqdn(nick, nickname, sizeof(nickname), NULL, 0)) {
148     printformat_module("fe-common/silc", server, NULL,
149                        MSGLEVEL_CRAP, SILCTXT_BAD_NICK, nick);
150     return FALSE;
151   }
152
153   /* Find client entry */
154   clients = silc_client_get_clients_local(silc_client, server->conn,
155                                           nickname, nick);
156   if (!clients) {
157     rec = g_new0(PRIVMSG_REC, 1);
158     rec->nick = g_strdup(nick);
159     rec->msg = g_strdup(msg);
160     rec->server = server;
161     rec->flags = flags;
162     rec->len = msg_len;
163
164     /* Could not find client with that nick, resolve it from server. */
165     silc_client_get_clients(silc_client, server->conn,
166                             nickname, NULL, silc_send_msg_clients, rec);
167     silc_free(nickname);
168     return TRUE;
169   }
170
171   /* Send the private message directly */
172   target = silc_dlist_get(clients);
173   ret = silc_client_send_private_message(silc_client, server->conn,
174                                          target, flags, sha1hash,
175                                          msg, msg_len);
176
177   silc_free(nickname);
178   silc_client_list_free(silc_client, server->conn, clients);
179
180   return ret;
181 }
182
183 void silc_send_mime(SILC_SERVER_REC *server, int channel, const char *to,
184                     const char *data, int sign)
185 {
186   char *unescaped_data;
187   SilcUInt32 unescaped_data_len;
188   int target_type;
189
190   if (!(IS_SILC_SERVER(server)) || (data == NULL) || (to == NULL))
191     return;
192
193   if (channel) {
194     target_type = SEND_TARGET_CHANNEL;
195   } else {
196     target_type = server_ischannel(SERVER(server), to) ?
197       SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
198   }
199
200   unescaped_data = silc_unescape_data(data, &unescaped_data_len);
201
202   if (target_type == SEND_TARGET_CHANNEL) {
203     SILC_CHANNEL_REC *rec;
204
205     rec = silc_channel_find(server, to);
206     if (rec == NULL || rec->entry == NULL) {
207       cmd_return_error(CMDERR_NOT_JOINED);
208     }
209
210     silc_client_send_channel_message(silc_client, server->conn, rec->entry,
211                                      NULL, SILC_MESSAGE_FLAG_DATA |
212                                      (sign ? SILC_MESSAGE_FLAG_SIGNED : 0),
213                                      sha1hash, unescaped_data,
214                                      unescaped_data_len);
215   } else {
216     silc_send_msg(server, (char *)to, unescaped_data, unescaped_data_len,
217                   SILC_MESSAGE_FLAG_DATA |
218                   (sign ? SILC_MESSAGE_FLAG_SIGNED : 0));
219
220   }
221
222   signal_stop();
223
224   silc_free(unescaped_data);
225 }
226
227 static int isnickflag_func(char flag)
228 {
229   return flag == '@' || flag == '+';
230 }
231
232 static int ischannel_func(SERVER_REC *server, const char *data)
233 {
234   return FALSE;
235 }
236
237 const char *get_nick_flags(void)
238 {
239   return "@\0\0";
240 }
241
242 static void send_message(SILC_SERVER_REC *server, char *target,
243                          char *msg, int target_type)
244 {
245   char *message = NULL, *t = NULL;
246   int len;
247
248   g_return_if_fail(server != NULL);
249   g_return_if_fail(target != NULL);
250   g_return_if_fail(msg != NULL);
251
252   if (!silc_term_utf8()) {
253     len = silc_utf8_encoded_len(msg, strlen(msg), SILC_STRING_LOCALE);
254     message = silc_calloc(len + 1, sizeof(*message));
255     g_return_if_fail(message != NULL);
256     silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE, message, len);
257   }
258
259   if (target_type == SEND_TARGET_CHANNEL)
260     silc_send_channel(server, target, message ? message : msg,
261                       SILC_MESSAGE_FLAG_UTF8);
262   else {
263     if (!silc_term_utf8()) {
264       len = silc_utf8_encoded_len(target, strlen(target), SILC_STRING_LOCALE);
265       t = silc_calloc(len + 1, sizeof(*t));
266       g_return_if_fail(t != NULL);
267       silc_utf8_encode(target, strlen(target), SILC_STRING_LOCALE, t, len);
268     }
269
270     silc_send_msg(server, t ? t : target, message ? message : msg,
271                   message ? strlen(message) : strlen(msg),
272                   SILC_MESSAGE_FLAG_UTF8);
273   }
274
275   silc_free(message);
276   silc_free(t);
277 }
278
279 /* Connection callback */
280
281 static void silc_connect_cb(SilcClient client,
282                             SilcClientConnection conn,
283                             SilcClientConnectionStatus status,
284                             SilcStatus error,
285                             const char *message,
286                             void *context)
287 {
288   SILC_SERVER_REC *server = context;
289   char *file;
290
291   if (server->disconnected) {
292     silc_client_close_connection(client, conn);
293     return;
294   }
295
296   switch (status) {
297   case SILC_CLIENT_CONN_SUCCESS:
298     /* We have successfully connected to server */
299
300     /* Enable queueing until we have our requested nick */
301 #if 0
302     if (settings_get_str("nick") &&
303         !strcmp(conn->local_entry->nickname, conn->local_entry->username))
304       silc_queue_enable(conn);
305 #endif
306
307     /* Put default attributes */
308     silc_query_attributes_default(silc_client, conn);
309
310     server->connected = TRUE;
311     server->conn = conn;
312     server->conn->context = server;
313     signal_emit("event connected", 1, server);
314     break;
315
316   case SILC_CLIENT_CONN_SUCCESS_RESUME:
317     /* We have successfully resumed old detached session */
318     server->connected = TRUE;
319     server->conn = conn;
320     server->conn->context = server;
321     signal_emit("event connected", 1, server);
322
323     /* Put default attributes */
324     silc_query_attributes_default(silc_client, conn);
325
326     /* If we resumed old session check whether we need to update
327        our nickname */
328     if (strcmp(server->nick, conn->local_entry->nickname)) {
329       char *old;
330       old = g_strdup(server->nick);
331       server_change_nick(SERVER(server), conn->local_entry->nickname);
332       nicklist_rename_unique(SERVER(server),
333                              conn->local_entry, server->nick,
334                              conn->local_entry, conn->local_entry->nickname);
335       signal_emit("message own_nick", 4, server, server->nick, old, "");
336       g_free(old);
337     }
338
339     /* Remove the detach data now */
340     file = silc_get_session_filename(server);
341     unlink(file);
342     silc_free(file);
343     break;
344
345   case SILC_CLIENT_CONN_DISCONNECTED:
346     /* Server disconnected */
347     if (server->conn && server->conn->local_entry) {
348       nicklist_rename_unique(SERVER(server),
349                              server->conn->local_entry, server->nick,
350                              server->conn->local_entry,
351                              silc_client->username);
352       silc_change_nick(server, silc_client->username);
353     }
354
355     if (message)
356       silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
357                "Server closed connection: %s (%d) %s",
358                silc_get_status_message(error), error,
359                message ? message : "");
360
361     if (server->conn)
362       server->conn->context = NULL;
363     server->conn = NULL;
364     server->connection_lost = TRUE;
365     server_disconnect(SERVER(server));
366     break;
367
368   default:
369     file = silc_get_session_filename(server);
370     if (silc_file_size(file) > 0)
371       printformat_module("fe-common/silc", server, NULL,
372                          MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
373
374     silc_free(file);
375
376     server->connection_lost = TRUE;
377     if (server->conn)
378       server->conn->context = NULL;
379     server_disconnect(SERVER(server));
380     break;
381   }
382 }
383
384 static void sig_connected_stream_created(SilcSocketStreamStatus status,
385                                          SilcStream stream, void *context)
386 {
387   SILC_SERVER_REC *server = context;
388   SilcClientConnectionParams params;
389   char *file;
390
391   if (!stream) {
392     server->connection_lost = TRUE;
393     server_disconnect(SERVER(server));
394     return;
395   }
396
397   if (server->disconnected) {
398     silc_stream_destroy(stream);
399     return;
400   }
401
402   /* Set connection parameters */
403   memset(&params, 0, sizeof(params));
404   params.nickname = (char *)settings_get_str("nick");
405
406   /* Try to read detached session data and use it if found. */
407   file = silc_get_session_filename(server);
408   params.detach_data = silc_file_readfile(file, &params.detach_data_len);
409   if (params.detach_data)
410     params.detach_data[params.detach_data_len] = 0;
411   if (params.detach_data)
412     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
413                         SILCTXT_REATTACH, server->tag);
414
415   /* Start key exchange */
416   silc_client_key_exchange(silc_client, &params, irssi_pubkey, irssi_privkey,
417                            stream, SILC_CONN_SERVER, silc_connect_cb, server);
418
419   server->ftp_sessions = silc_dlist_init();
420   server->isnickflag = isnickflag_func;
421   server->ischannel = ischannel_func;
422   server->get_nick_flags = get_nick_flags;
423   server->send_message = (void *) send_message;
424 }
425
426 static void sig_connected(SILC_SERVER_REC *server)
427 {
428   int fd;
429
430   if (!IS_SILC_SERVER(server))
431     return;
432
433   //  server->connrec->address,
434   //  server->connrec->port,
435
436   /* Wrap the socket to TCP stream */
437   fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
438   silc_socket_tcp_stream_create(fd, TRUE, FALSE, silc_client->schedule,
439                                 sig_connected_stream_created, server);
440 }
441
442 static void sig_disconnected(SILC_SERVER_REC *server)
443 {
444   if (!IS_SILC_SERVER(server))
445     return;
446
447   silc_dlist_uninit(server->ftp_sessions);
448
449   if (server->conn) {
450     silc_client_close_connection(silc_client, server->conn);
451
452     /* SILC closes the handle */
453     g_io_channel_unref(net_sendbuffer_handle(server->handle));
454     net_sendbuffer_destroy(server->handle, FALSE);
455     server->handle = NULL;
456   }
457 }
458
459 SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
460 {
461   SILC_SERVER_REC *server;
462
463   g_return_val_if_fail(IS_SILC_SERVER_CONNECT(conn), NULL);
464   if (conn->address == NULL || *conn->address == '\0')
465     return NULL;
466   if (conn->nick == NULL || *conn->nick == '\0') {
467     silc_say_error("Cannot connect: nickname is not set");
468     return NULL;
469   }
470
471   server = g_new0(SILC_SERVER_REC, 1);
472   server->chat_type = SILC_PROTOCOL;
473   server->connrec = (SILC_SERVER_CONNECT_REC *)conn;
474   server_connect_ref(conn);
475
476   if (server->connrec->port <= 0)
477     server->connrec->port = 706;
478
479   server_connect_init((SERVER_REC *)server);
480   return (SERVER_REC *)server;
481 }
482
483 void silc_server_connect(SERVER_REC *server)
484 {
485   if (!server_start_connect(server)) {
486     server_connect_unref(server->connrec);
487     g_free(server);
488     return;
489   }
490 }
491
492 /* Return a string of all channels in server in server->channels_join()
493    format */
494
495 char *silc_server_get_channels(SILC_SERVER_REC *server)
496 {
497   GSList *tmp;
498   GString *chans;
499   char *ret;
500
501   g_return_val_if_fail(server != NULL, FALSE);
502
503   chans = g_string_new(NULL);
504   for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
505     CHANNEL_REC *channel = tmp->data;
506
507     g_string_sprintfa(chans, "%s,", channel->name);
508   }
509
510   if (chans->len > 0)
511     g_string_truncate(chans, chans->len-1);
512
513   ret = chans->str;
514   g_string_free(chans, FALSE);
515
516   return ret;
517 }
518
519 /* Syntaxes of all SILC commands for HELP files (the help file generation
520    will snoop these from here). */
521
522 /* SYNTAX: BAN <channel> [+|-[<nickname>[@<server>[!<username>[@hostname>]]]]] */
523 /* SYNTAX: CMODE <channel> +|-<modes> [{ <arguments>}] */
524 /* SYNTAX: CUMODE <channel> +|-<modes> <nickname>[@<hostname>] */
525 /* SYNTAX: GETKEY <nickname or server name> */
526 /* SYNTAX: INVITE <channel> [<nickname>[@hostname>] */
527 /* SYNTAX: INVITE <channel> [+|-[<nickname>[@<server>[!<username>[@hostname>]]]]] */
528 /* SYNTAX: KEY MSG <nickname> set|unset|list|agreement|negotiate [<arguments>] */
529 /* SYNTAX: KEY CHANNEL <channel> set|unset|list|change [<arguments>] */
530 /* SYNTAX: KICK <channel> <nickname>[@<hostname>] [<comment>] */
531 /* SYNTAX: KILL <nickname>[@<hostname>] [<comment>] [-pubkey] */
532 /* SYNTAX: OPER <username> [-pubkey] */
533 /* SYNTAX: SILCOPER <username> [-pubkey] */
534 /* SYNTAX: TOPIC <channel> [<topic>] */
535 /* SYNTAX: UMODE +|-<modes> */
536 /* SYNTAX: WHOIS [<nickname>[@<hostname>]] [-details] [-pubkey <pubkeyfile>] [<count>] */
537 /* SYNTAX: WHOWAS <nickname>[@<hostname>] [<count>] */
538 /* SYNTAX: CLOSE <server> [<port>] */
539 /* SYNTAX: SHUTDOWN */
540 /* SYNTAX: MOTD [<server>] */
541 /* SYNTAX: LIST [<channel>] */
542 /* SYNTAX: ME <message> */
543 /* SYNTAX: ACTION [-sign] [-channel] <target> <message> */
544 /* SYNTAX: AWAY [<message>] */
545 /* SYNTAX: INFO [<server>] */
546 /* SYNTAX: NICK <nickname> */
547 /* SYNTAX: NOTICE [-sign] [-channel] <target> <message> */
548 /* SYNTAX: PART [<channel>] */
549 /* SYNTAX: PING */
550 /* SYNTAX: SCONNECT <server> [<port>] */
551 /* SYNTAX: USERS <channel> */
552 /* SYNTAX: FILE SEND <filepath> <nickname> [<local IP> [<local port>]] [-no-listener]*/
553 /* SYNTAX: FILE ACCEPT [<nickname>] */
554 /* SYNTAX: FILE CLOSE [<nickname>] */
555 /* SYNTAX: FILE */
556 /* SYNTAX: JOIN <channel> [<passphrase>] [-cipher <cipher>] [-hmac <hmac>] [-founder] [-auth [<pubkeyfile> <privkeyfile> [<privkey passphrase>]]]*/
557 /* SYNTAX: DETACH */
558 /* SYNTAX: WATCH [<-add | -del> <nickname>] [-pubkey +|-<pubkeyfile>] */
559 /* SYNTAX: STATS */
560 /* SYNTAX: ATTR [<-del> <option> [{ <value>}]] */
561 /* SYNTAX: SMSG [<-channel>] <target> <message> */
562 /* SYNTAX: LISTKEYS [-servers] [-clients] [<public key file>] */
563
564 void silc_command_exec(SILC_SERVER_REC *server,
565                        const char *command, const char *args)
566 {
567   char *data;
568   g_return_if_fail(server != NULL);
569
570   /* Call the command */
571   data = g_strconcat(command, " ", args, NULL);
572   silc_queue_command_call(silc_client, server->conn, data);
573   g_free(data);
574 }
575
576 /* Generic command function to call any SILC command directly. */
577
578 static void command_self(const char *data, SILC_SERVER_REC *server,
579                          WI_ITEM_REC *item)
580 {
581   CMD_SILC_SERVER(server);
582
583   if (!IS_SILC_SERVER(server) || !server->connected) {
584     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Not connected to server");
585     return;
586   }
587
588   if (IS_SILC_CHANNEL(item)) {
589     SILC_CHANNEL_REC *chanrec;
590     chanrec = silc_channel_find(server, item->visible_name);
591     if (chanrec)
592       server->conn->current_channel = chanrec->entry;
593   }
594
595   silc_command_exec(server, current_command, data);
596   signal_stop();
597 }
598
599 /* SCONNECT command.  Calls actually SILC's CONNECT command since Irssi
600    has CONNECT command for other purposes. */
601
602 static void command_sconnect(const char *data, SILC_SERVER_REC *server)
603 {
604   CMD_SILC_SERVER(server);
605   if (!IS_SILC_SERVER(server) || !server->connected) {
606     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Not connected to server");
607     return;
608   }
609
610   silc_command_exec(server, "CONNECT", data);
611   signal_stop();
612 }
613
614 /* SMSG command, to send digitally signed messages */
615
616 static void command_smsg(const char *data, SILC_SERVER_REC *server,
617                          WI_ITEM_REC *item)
618 {
619   GHashTable *optlist;
620   char *target, *origtarget, *msg;
621   void *free_arg;
622   int free_ret, target_type;
623
624   g_return_if_fail(data != NULL);
625   if (server == NULL || !server->connected)
626     cmd_param_error(CMDERR_NOT_CONNECTED);
627
628   if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
629                       PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
630                       "msg", &optlist, &target, &msg))
631     return;
632   if (*target == '\0' || *msg == '\0')
633     cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
634
635   origtarget = target;
636   free_ret = FALSE;
637
638   if (strcmp(target, "*") == 0) {
639     if (item == NULL)
640       cmd_param_error(CMDERR_NOT_JOINED);
641
642     target_type = IS_CHANNEL(item) ?
643       SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
644     target = (char *) window_item_get_target(item);
645   } else if (g_hash_table_lookup(optlist, "channel") != NULL) {
646     target_type = SEND_TARGET_CHANNEL;
647   } else {
648     target_type = server_ischannel(SERVER(server), target) ?
649       SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
650   }
651
652   if (target != NULL) {
653     char *message = NULL, *t = NULL;
654     int len, result;
655
656     if (!silc_term_utf8()) {
657       len = silc_utf8_encoded_len(msg, strlen(msg), SILC_STRING_LOCALE);
658       message = silc_calloc(len + 1, sizeof(*message));
659       g_return_if_fail(message != NULL);
660       silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE, message, len);
661     }
662
663     if (target_type == SEND_TARGET_CHANNEL)
664       result = silc_send_channel(server, target, message ? message : msg,
665                                  SILC_MESSAGE_FLAG_UTF8 |
666                                  SILC_MESSAGE_FLAG_SIGNED);
667     else {
668       if (!silc_term_utf8()) {
669         len = silc_utf8_encoded_len(target, strlen(target),
670                                     SILC_STRING_LOCALE);
671         t = silc_calloc(len + 1, sizeof(*t));
672         g_return_if_fail(t != NULL);
673         silc_utf8_encode(target, strlen(target), SILC_STRING_LOCALE, t, len);
674       }
675       result = silc_send_msg(server, t ? t : target, message ? message : msg,
676                              message ? strlen(message) : strlen(msg),
677                              SILC_MESSAGE_FLAG_UTF8 |
678                              SILC_MESSAGE_FLAG_SIGNED);
679     }
680     silc_free(message);
681     silc_free(t);
682     if (!result)
683       goto out;
684   }
685
686   signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
687               "message signed_own_public" : "message signed_own_private", 4,
688               server, msg, target, origtarget);
689 out:
690   if (free_ret && target != NULL) g_free(target);
691   cmd_params_free(free_arg);
692 }
693
694 #if 0
695 /* FILE command */
696
697 SILC_TASK_CALLBACK(silc_client_file_close_later)
698 {
699   FtpSession ftp = (FtpSession)context;
700
701   SILC_LOG_DEBUG(("Start"));
702
703   silc_client_file_close(silc_client, ftp->conn, ftp->session_id);
704   silc_free(ftp->filepath);
705   silc_free(ftp);
706 }
707
708 static void silc_client_file_monitor(SilcClient client,
709                                      SilcClientConnection conn,
710                                      SilcClientMonitorStatus status,
711                                      SilcClientFileError error,
712                                      SilcUInt64 offset,
713                                      SilcUInt64 filesize,
714                                      SilcClientEntry client_entry,
715                                      SilcUInt32 session_id,
716                                      const char *filepath,
717                                      void *context)
718 {
719   SILC_SERVER_REC *server = (SILC_SERVER_REC *)context;
720   FtpSession ftp;
721   char fsize[32];
722
723   if (status == SILC_CLIENT_FILE_MONITOR_CLOSED)
724     return;
725
726   snprintf(fsize, sizeof(fsize) - 1, "%llu", ((filesize + 1023) / 1024));
727
728   silc_dlist_start(server->ftp_sessions);
729   while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
730     if (ftp->session_id == session_id) {
731       if (!ftp->filepath && filepath)
732         ftp->filepath = strdup(filepath);
733       break;
734     }
735   }
736
737   if (ftp == SILC_LIST_END)
738     return;
739
740   if (status == SILC_CLIENT_FILE_MONITOR_ERROR) {
741     if (error == SILC_CLIENT_FILE_NO_SUCH_FILE)
742       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
743                          SILCTXT_FILE_ERROR_NO_SUCH_FILE,
744                          client_entry->nickname,
745                          filepath ? filepath : "[N/A]");
746     else if (error == SILC_CLIENT_FILE_PERMISSION_DENIED)
747       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
748                          SILCTXT_FILE_ERROR_PERMISSION_DENIED,
749                          client_entry->nickname);
750     else
751       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
752                          SILCTXT_FILE_ERROR, client_entry->nickname);
753     silc_schedule_task_add(silc_client->schedule, 0,
754                            silc_client_file_close_later, ftp,
755                            1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
756     silc_dlist_del(server->ftp_sessions, ftp);
757     if (ftp == server->current_session) {
758       server->current_session = NULL;
759       silc_dlist_start(server->ftp_sessions);
760       server->current_session = silc_dlist_get(server->ftp_sessions);
761     }
762   }
763
764   if (status == SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT) {
765     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
766                        SILCTXT_FILE_KEY_EXCHANGE, client_entry->nickname);
767   }
768
769   /* Save some transmission data */
770   if (offset && filesize) {
771     unsigned long delta = time(NULL) - ftp->starttime;
772
773     ftp->percent = ((double)offset / (double)filesize) * (double)100.0;
774     if (delta)
775       ftp->kps = (double)((offset / (double)delta) + 1023) / (double)1024;
776     else
777       ftp->kps = (double)(offset + 1023) / (double)1024;
778     ftp->offset = offset;
779     ftp->filesize = filesize;
780   }
781
782   if (status == SILC_CLIENT_FILE_MONITOR_SEND) {
783     if (offset == 0) {
784       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
785                          SILCTXT_FILE_TRANSMIT, filepath, fsize,
786                          client_entry->nickname);
787       ftp->starttime = time(NULL);
788     }
789     if (offset == filesize) {
790       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
791                          SILCTXT_FILE_TRANSMITTED, filepath, fsize,
792                          client_entry->nickname, ftp->kps);
793       silc_schedule_task_add(silc_client->schedule, 0,
794                              silc_client_file_close_later, ftp,
795                              1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
796       silc_dlist_del(server->ftp_sessions, ftp);
797       if (ftp == server->current_session) {
798         server->current_session = NULL;
799         silc_dlist_start(server->ftp_sessions);
800         server->current_session = silc_dlist_get(server->ftp_sessions);
801       }
802
803     }
804   }
805
806   if (status == SILC_CLIENT_FILE_MONITOR_RECEIVE) {
807     if (offset == 0) {
808       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
809                          SILCTXT_FILE_RECEIVE, filepath, fsize,
810                          client_entry->nickname);
811       ftp->starttime = time(NULL);
812     }
813
814     if (offset == filesize) {
815       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
816                          SILCTXT_FILE_RECEIVED, filepath, fsize,
817                          client_entry->nickname, ftp->kps);
818       silc_schedule_task_add(silc_client->schedule, 0,
819                              silc_client_file_close_later, ftp,
820                              1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
821       silc_dlist_del(server->ftp_sessions, ftp);
822       if (ftp == server->current_session) {
823         server->current_session = NULL;
824         silc_dlist_start(server->ftp_sessions);
825         server->current_session = silc_dlist_get(server->ftp_sessions);
826       }
827
828     }
829   }
830 }
831
832 typedef struct {
833   SILC_SERVER_REC *server;
834   char *data;
835   char *nick;
836   WI_ITEM_REC *item;
837 } *FileGetClients;
838
839 static void silc_client_command_file_get_clients(SilcClient client,
840                                                  SilcClientConnection conn,
841                                                  SilcClientEntry *clients,
842                                                  SilcUInt32 clients_count,
843                                                  void *context)
844 {
845   FileGetClients internal = (FileGetClients)context;
846
847   if (!clients) {
848     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
849               internal->nick);
850     silc_free(internal->data);
851     silc_free(internal->nick);
852     silc_free(internal);
853     return;
854   }
855
856   signal_emit("command file", 3, internal->data, internal->server,
857               internal->item);
858
859   silc_free(internal->data);
860   silc_free(internal->nick);
861   silc_free(internal);
862 }
863
864 static void command_file(const char *data, SILC_SERVER_REC *server,
865                          WI_ITEM_REC *item)
866 {
867   SilcClientConnection conn;
868   SilcClientEntry *entrys, client_entry;
869   SilcClientFileError ret;
870   SilcUInt32 entry_count;
871   char *nickname = NULL, *tmp;
872   unsigned char **argv;
873   SilcUInt32 argc;
874   SilcUInt32 *argv_lens, *argv_types;
875   int type = 0;
876   FtpSession ftp;
877   char *local_ip = NULL;
878   SilcUInt32 local_port = 0;
879   SilcUInt32 session_id;
880   bool do_not_bind = FALSE;
881
882   CMD_SILC_SERVER(server);
883   if (!server || !IS_SILC_SERVER(server) || !server->connected)
884     cmd_return_error(CMDERR_NOT_CONNECTED);
885
886   conn = server->conn;
887
888   /* Now parse all arguments */
889   tmp = g_strconcat("FILE", " ", data, NULL);
890   silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
891   g_free(tmp);
892
893   if (argc == 1)
894     type = 4;
895
896   if (argc >= 2) {
897     if (!strcasecmp(argv[1], "send"))
898       type = 1;
899     if (!strcasecmp(argv[1], "accept"))
900       type = 2;
901     if (!strcasecmp(argv[1], "close"))
902       type = 3;
903   }
904
905   if (type == 0)
906     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
907
908   switch (type) {
909   case 1:
910     if (argc < 4)
911       cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
912
913     /* Parse the typed nickname. */
914     if (!silc_parse_userfqdn(argv[3], &nickname, NULL)) {
915       printformat_module("fe-common/silc", server, NULL,
916                          MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[3]);
917       goto out;
918     }
919
920     /* Find client entry */
921     entrys = silc_client_get_clients_local(silc_client, conn, nickname,
922                                            argv[3], &entry_count);
923     if (!entrys) {
924       FileGetClients inter = silc_calloc(1, sizeof(*inter));
925       inter->server = server;
926       inter->data = strdup(data);
927       inter->nick = strdup(nickname);
928       inter->item = item;
929       silc_client_get_clients(silc_client, conn, nickname, argv[3],
930                               silc_client_command_file_get_clients, inter);
931       goto out;
932     }
933     client_entry = entrys[0];
934     silc_free(entrys);
935
936     if (argc >= 5) {
937       if (!strcasecmp(argv[4], "-no-listener"))
938         do_not_bind = TRUE;
939       else
940         local_ip = argv[4];
941     }
942     if (argc >= 6) {
943       if (!strcasecmp(argv[5], "-no-listener"))
944         do_not_bind = TRUE;
945       else
946         local_port = atoi(argv[5]);
947     }
948     if (argc >= 7) {
949       if (!strcasecmp(argv[6], "-no-listener"))
950         do_not_bind = TRUE;
951     }
952
953     ret =
954       silc_client_file_send(silc_client, conn, silc_client_file_monitor,
955                             server, local_ip, local_port, do_not_bind,
956                             client_entry, argv[2], &session_id);
957     if (ret == SILC_CLIENT_FILE_OK) {
958       ftp = silc_calloc(1, sizeof(*ftp));
959       ftp->session_id = session_id;
960
961       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
962                          SILCTXT_FILE_SEND, client_entry->nickname,
963                          argv[2]);
964
965       ftp->client_entry = client_entry;
966       ftp->filepath = strdup(argv[2]);
967       ftp->conn = conn;
968       ftp->send = TRUE;
969       silc_dlist_add(server->ftp_sessions, ftp);
970       server->current_session = ftp;
971     } else {
972       if (ret == SILC_CLIENT_FILE_ALREADY_STARTED)
973         printformat_module("fe-common/silc", server, NULL,
974                            MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED,
975                            client_entry->nickname);
976       if (ret == SILC_CLIENT_FILE_NO_SUCH_FILE)
977         printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
978                            SILCTXT_FILE_ERROR_NO_SUCH_FILE,
979                            client_entry->nickname, argv[2]);
980     }
981
982     break;
983
984   case 2:
985     /* Parse the typed nickname. */
986     if (argc >= 3) {
987       if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
988         printformat_module("fe-common/silc", server, NULL,
989                            MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
990         goto out;
991       }
992
993       /* Find client entry */
994       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
995                                              argv[2], &entry_count);
996       if (!entrys) {
997         FileGetClients inter = silc_calloc(1, sizeof(*inter));
998         inter->server = server;
999         inter->data = strdup(data);
1000         inter->nick = strdup(nickname);
1001         inter->item = item;
1002         silc_client_get_clients(silc_client, conn, nickname, argv[2],
1003                                 silc_client_command_file_get_clients, inter);
1004         goto out;
1005       }
1006       client_entry = entrys[0];
1007       silc_free(entrys);
1008     } else {
1009       if (!server->current_session) {
1010         printformat_module("fe-common/silc", server, NULL,
1011                            MSGLEVEL_CRAP, SILCTXT_FILE_NA);
1012         goto out;
1013       }
1014
1015       ret = silc_client_file_receive(silc_client, conn,
1016                                      silc_client_file_monitor, server, NULL,
1017                                      server->current_session->session_id,
1018                                      NULL, NULL);
1019       if (ret != SILC_CLIENT_FILE_OK) {
1020         if (ret == SILC_CLIENT_FILE_ALREADY_STARTED)
1021           printformat_module("fe-common/silc", server, NULL,
1022                              MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED,
1023                              server->current_session->client_entry->nickname);
1024         else {
1025           printformat_module("fe-common/silc", server, NULL,
1026                              MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA,
1027                              server->current_session->client_entry->nickname);
1028
1029           silc_client_file_close(silc_client, conn,
1030                                  server->current_session->session_id);
1031           silc_dlist_del(server->ftp_sessions, server->current_session);
1032           silc_free(server->current_session->filepath);
1033           silc_free(server->current_session);
1034           server->current_session = NULL;
1035
1036           silc_dlist_start(server->ftp_sessions);
1037           server->current_session = silc_dlist_get(server->ftp_sessions);
1038         }
1039       }
1040
1041       goto out;
1042     }
1043
1044     silc_dlist_start(server->ftp_sessions);
1045     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
1046       if (ftp->client_entry == client_entry && !ftp->filepath) {
1047         ret = silc_client_file_receive(silc_client, conn,
1048                                        silc_client_file_monitor, server,
1049                                        NULL, ftp->session_id, NULL, NULL);
1050         if (ret != SILC_CLIENT_FILE_OK) {
1051           if (ret == SILC_CLIENT_FILE_ALREADY_STARTED)
1052             printformat_module("fe-common/silc", server, NULL,
1053                                MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED,
1054                                client_entry->nickname);
1055           else {
1056             printformat_module("fe-common/silc", server, NULL,
1057                                MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA,
1058                                client_entry->nickname);
1059             silc_client_file_close(silc_client, conn, ftp->session_id);
1060             silc_dlist_del(server->ftp_sessions, ftp);
1061             if (ftp == server->current_session) {
1062               server->current_session = NULL;
1063               silc_dlist_start(server->ftp_sessions);
1064               server->current_session = silc_dlist_get(server->ftp_sessions);
1065             }
1066             silc_free(ftp->filepath);
1067             silc_free(ftp);
1068           }
1069         }
1070         break;
1071       }
1072     }
1073
1074     if (ftp == SILC_LIST_END) {
1075       printformat_module("fe-common/silc", server, NULL,
1076                          MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA,
1077                          client_entry->nickname);
1078       goto out;
1079     }
1080     break;
1081
1082   case 3:
1083     /* Parse the typed nickname. */
1084     if (argc >= 3) {
1085       if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
1086         printformat_module("fe-common/silc", server, NULL,
1087                            MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
1088         goto out;
1089       }
1090
1091       /* Find client entry */
1092       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
1093                                              argv[2], &entry_count);
1094       if (!entrys) {
1095         FileGetClients inter = silc_calloc(1, sizeof(*inter));
1096         inter->server = server;
1097         inter->data = strdup(data);
1098         inter->nick = strdup(nickname);
1099         inter->item = item;
1100         silc_client_get_clients(silc_client, conn, nickname, argv[2],
1101                                 silc_client_command_file_get_clients, inter);
1102         goto out;
1103       }
1104       client_entry = entrys[0];
1105       silc_free(entrys);
1106     } else {
1107       if (!server->current_session) {
1108         printformat_module("fe-common/silc", server, NULL,
1109                            MSGLEVEL_CRAP, SILCTXT_FILE_NA);
1110         goto out;
1111       }
1112
1113       silc_client_file_close(silc_client, conn,
1114                              server->current_session->session_id);
1115       printformat_module("fe-common/silc", server, NULL,
1116                          MSGLEVEL_CRAP, SILCTXT_FILE_CLOSED,
1117                          server->current_session->client_entry->nickname,
1118                          server->current_session->filepath ?
1119                          server->current_session->filepath : "[N/A]");
1120       silc_dlist_del(server->ftp_sessions, server->current_session);
1121       silc_free(server->current_session->filepath);
1122       silc_free(server->current_session);
1123       server->current_session = NULL;
1124
1125       silc_dlist_start(server->ftp_sessions);
1126       server->current_session = silc_dlist_get(server->ftp_sessions);
1127       goto out;
1128     }
1129
1130     silc_dlist_start(server->ftp_sessions);
1131     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
1132       if (ftp->client_entry == client_entry) {
1133         silc_client_file_close(silc_client, conn, ftp->session_id);
1134         printformat_module("fe-common/silc", server, NULL,
1135                            MSGLEVEL_CRAP, SILCTXT_FILE_CLOSED,
1136                            client_entry->nickname,
1137                            ftp->filepath ? ftp->filepath : "[N/A]");
1138         silc_dlist_del(server->ftp_sessions, ftp);
1139         if (ftp == server->current_session) {
1140           server->current_session = NULL;
1141           silc_dlist_start(server->ftp_sessions);
1142           server->current_session = silc_dlist_get(server->ftp_sessions);
1143         }
1144         silc_free(ftp->filepath);
1145         silc_free(ftp);
1146         break;
1147       }
1148     }
1149
1150     if (ftp == SILC_LIST_END) {
1151       printformat_module("fe-common/silc", server, NULL,
1152                          MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA,
1153                          client_entry->nickname);
1154       goto out;
1155     }
1156     break;
1157
1158   case 4:
1159
1160     if (!silc_dlist_count(server->ftp_sessions)) {
1161       printformat_module("fe-common/silc", server, NULL,
1162                          MSGLEVEL_CRAP, SILCTXT_FILE_NA);
1163       goto out;
1164     }
1165
1166     printformat_module("fe-common/silc", server, NULL,
1167                        MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_HEADER);
1168
1169     silc_dlist_start(server->ftp_sessions);
1170     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
1171       printformat_module("fe-common/silc", server, NULL,
1172                          MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_LINE,
1173                          ftp->client_entry->nickname,
1174                          ftp->session_id,
1175                          ftp->send ? "send" : "receive",
1176                          (SilcUInt32)(ftp->offset + 1023) / 1024,
1177                          (SilcUInt32)(ftp->filesize + 1023) / 1024,
1178                          ftp->percent, ftp->kps,
1179                          ftp->filepath ? ftp->filepath : "[N/A]");
1180     }
1181
1182     break;
1183
1184   default:
1185     break;
1186   }
1187
1188  out:
1189   silc_free(nickname);
1190 }
1191 #endif /* 0 */
1192
1193 void silc_server_init(void)
1194 {
1195   silc_servers_reconnect_init();
1196
1197   signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
1198   signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
1199   signal_add("mime-send", (SIGNAL_FUNC)silc_send_mime);
1200   command_bind_silc("whois", MODULE_NAME, (SIGNAL_FUNC) command_self);
1201   command_bind_silc("whowas", MODULE_NAME, (SIGNAL_FUNC) command_self);
1202   command_bind_silc("nick", MODULE_NAME, (SIGNAL_FUNC) command_self);
1203   command_bind_silc("topic", MODULE_NAME, (SIGNAL_FUNC) command_self);
1204   command_bind_silc("cmode", MODULE_NAME, (SIGNAL_FUNC) command_self);
1205   command_bind_silc("cumode", MODULE_NAME, (SIGNAL_FUNC) command_self);
1206   command_bind_silc("users", MODULE_NAME, (SIGNAL_FUNC) command_self);
1207   command_bind_silc("list", MODULE_NAME, (SIGNAL_FUNC) command_self);
1208   command_bind_silc("ban", MODULE_NAME, (SIGNAL_FUNC) command_self);
1209   command_bind_silc("oper", MODULE_NAME, (SIGNAL_FUNC) command_self);
1210   command_bind_silc("silcoper", MODULE_NAME, (SIGNAL_FUNC) command_self);
1211   command_bind_silc("umode", MODULE_NAME, (SIGNAL_FUNC) command_self);
1212   command_bind_silc("invite", MODULE_NAME, (SIGNAL_FUNC) command_self);
1213   command_bind_silc("kill", MODULE_NAME, (SIGNAL_FUNC) command_self);
1214   command_bind_silc("kick", MODULE_NAME, (SIGNAL_FUNC) command_self);
1215   command_bind_silc("info", MODULE_NAME, (SIGNAL_FUNC) command_self);
1216   command_bind_silc("ping", MODULE_NAME, (SIGNAL_FUNC) command_self);
1217   command_bind_silc("motd", MODULE_NAME, (SIGNAL_FUNC) command_self);
1218   command_bind_silc("close", MODULE_NAME, (SIGNAL_FUNC) command_self);
1219   command_bind_silc("shutdown", MODULE_NAME, (SIGNAL_FUNC) command_self);
1220   command_bind_silc("getkey", MODULE_NAME, (SIGNAL_FUNC) command_self);
1221   command_bind_silc("sconnect", MODULE_NAME, (SIGNAL_FUNC) command_sconnect);
1222 //  command_bind_silc("file", MODULE_NAME, (SIGNAL_FUNC) command_file);
1223   command_bind_silc("detach", MODULE_NAME, (SIGNAL_FUNC) command_self);
1224   command_bind_silc("watch", MODULE_NAME, (SIGNAL_FUNC) command_self);
1225   command_bind_silc("stats", MODULE_NAME, (SIGNAL_FUNC) command_self);
1226   command_bind_silc("attr", MODULE_NAME, (SIGNAL_FUNC) command_attr);
1227   command_bind_silc("smsg", MODULE_NAME, (SIGNAL_FUNC) command_smsg);
1228
1229   command_set_options("connect", "+silcnet");
1230 }
1231
1232 void silc_server_deinit(void)
1233 {
1234   silc_servers_reconnect_deinit();
1235
1236   signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1237   signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
1238   signal_remove("mime-send", (SIGNAL_FUNC)silc_send_mime);
1239   command_unbind("whois", (SIGNAL_FUNC) command_self);
1240   command_unbind("whowas", (SIGNAL_FUNC) command_self);
1241   command_unbind("nick", (SIGNAL_FUNC) command_self);
1242   command_unbind("topic", (SIGNAL_FUNC) command_self);
1243   command_unbind("cmode", (SIGNAL_FUNC) command_self);
1244   command_unbind("cumode", (SIGNAL_FUNC) command_self);
1245   command_unbind("users", (SIGNAL_FUNC) command_self);
1246   command_unbind("list", (SIGNAL_FUNC) command_self);
1247   command_unbind("oper", (SIGNAL_FUNC) command_self);
1248   command_unbind("silcoper", (SIGNAL_FUNC) command_self);
1249   command_unbind("umode", (SIGNAL_FUNC) command_self);
1250   command_unbind("invite", (SIGNAL_FUNC) command_self);
1251   command_unbind("kill", (SIGNAL_FUNC) command_self);
1252   command_unbind("kick", (SIGNAL_FUNC) command_self);
1253   command_unbind("info", (SIGNAL_FUNC) command_self);
1254   command_unbind("ping", (SIGNAL_FUNC) command_self);
1255   command_unbind("motd", (SIGNAL_FUNC) command_self);
1256   command_unbind("ban", (SIGNAL_FUNC) command_self);
1257   command_unbind("close", (SIGNAL_FUNC) command_self);
1258   command_unbind("shutdown", (SIGNAL_FUNC) command_self);
1259   command_unbind("getkey", (SIGNAL_FUNC) command_self);
1260   command_unbind("sconnect", (SIGNAL_FUNC) command_sconnect);
1261 //  command_unbind("file", (SIGNAL_FUNC) command_file);
1262   command_unbind("detach", (SIGNAL_FUNC) command_self);
1263   command_unbind("watch", (SIGNAL_FUNC) command_self);
1264   command_unbind("stats", (SIGNAL_FUNC) command_self);
1265   command_unbind("attr", (SIGNAL_FUNC) command_attr);
1266   command_unbind("smsg", (SIGNAL_FUNC) command_smsg);
1267 }
1268
1269 #if 0
1270 void silc_server_free_ftp(SILC_SERVER_REC *server,
1271                           SilcClientEntry client_entry)
1272 {
1273   FtpSession ftp;
1274
1275   silc_dlist_start(server->ftp_sessions);
1276   while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
1277     if (ftp->client_entry == client_entry) {
1278       silc_dlist_del(server->ftp_sessions, ftp);
1279       silc_free(ftp->filepath);
1280       silc_free(ftp);
1281     }
1282   }
1283 }
1284 #endif /* 0 */
1285
1286 bool silc_term_utf8(void)
1287 {
1288   const char *str;
1289   str = settings_get_str("term_type");
1290   if (str)
1291     if (g_strcasecmp(str, "utf-8") == 0)
1292       return TRUE;
1293   return FALSE;
1294 }