updates.
[silc.git] / apps / irssi / src / silc / core / silc-core.c
1 /*
2
3   silc-core.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 #include "version_internal.h"
33 #include "version.h"
34
35 #include "signals.h"
36 #include "levels.h"
37 #include "settings.h"
38 #include "fe-common/core/printtext.h"
39 #include "fe-common/core/fe-channels.h"
40
41 /* Command line option variables */
42 static char *opt_server = NULL;
43 static int opt_port = 0;
44 static char *opt_nickname = NULL;
45 static char *opt_channel = NULL;
46 static char *opt_cipher = NULL;
47 static char *opt_public_key = NULL;
48 static char *opt_private_key = NULL;
49 static char *opt_config_file = NULL;
50 static bool opt_no_silcrc = FALSE;
51
52 static bool opt_create_keypair = FALSE;
53 static char *opt_pkcs = NULL;
54 static char *opt_keyfile = NULL;
55 static int opt_bits = 0;
56
57 static int idletag;
58
59 SilcClient silc_client = NULL;
60 SilcClientConfig silc_config = NULL;
61 extern SilcClientOperations ops;
62 #ifdef SILC_SIM
63 /* SIM (SILC Module) table */
64 SilcSimContext **sims = NULL;
65 uint32 sims_count = 0;
66 #endif
67
68 static void silc_say(SilcClient client, SilcClientConnection conn,
69                      char *msg, ...)
70 {
71   SILC_SERVER_REC *server;
72   va_list va;
73   char *str;
74
75   server = conn == NULL ? NULL : conn->context;
76   
77   va_start(va, msg);
78   str = g_strdup_vprintf(msg, va);
79   printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str);
80   g_free(str);
81   va_end(va);
82 }
83
84 /* Message for a channel. The `sender' is the nickname of the sender 
85    received in the packet. The `channel_name' is the name of the channel. */
86
87 static void 
88 silc_channel_message(SilcClient client, SilcClientConnection conn,
89                      SilcClientEntry sender, SilcChannelEntry channel,
90                      SilcMessageFlags flags, char *msg)
91 {
92   SILC_SERVER_REC *server;
93   SILC_NICK_REC *nick;
94   SILC_CHANNEL_REC *chanrec;
95   
96   server = conn == NULL ? NULL : conn->context;
97   chanrec = silc_channel_find_entry(server, channel);
98   
99   nick = silc_nicklist_find(chanrec, sender);
100   signal_emit("message public", 6, server, msg,
101               nick == NULL ? "[<unknown>]" : nick->nick,
102               nick == NULL ? NULL : nick->host,
103               chanrec->name, nick);
104 }
105
106 /* Private message to the client. The `sender' is the nickname of the
107    sender received in the packet. */
108
109 static void 
110 silc_private_message(SilcClient client, SilcClientConnection conn,
111                      SilcClientEntry sender, SilcMessageFlags flags,
112                           char *msg)
113 {
114   SILC_SERVER_REC *server;
115   
116   server = conn == NULL ? NULL : conn->context;
117   signal_emit("message private", 4, server, msg,
118               sender->nickname ? sender->nickname : "[<unknown>]",
119               sender->username ? sender->username : NULL);
120 }
121
122 /* Notify message to the client. The notify arguments are sent in the
123    same order as servers sends them. The arguments are same as received
124    from the server except for ID's.  If ID is received application receives
125    the corresponding entry to the ID. For example, if Client ID is received
126    application receives SilcClientEntry.  Also, if the notify type is
127    for channel the channel entry is sent to application (even if server
128    does not send it). */
129
130 typedef struct {
131   int type;
132   const char *name;
133 } NOTIFY_REC;
134
135 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
136 static NOTIFY_REC notifies[] = {
137   { SILC_NOTIFY_TYPE_NONE,              NULL },
138   { SILC_NOTIFY_TYPE_INVITE,            "invite" },
139   { SILC_NOTIFY_TYPE_JOIN,              "join" },
140   { SILC_NOTIFY_TYPE_LEAVE,             "leave" },
141   { SILC_NOTIFY_TYPE_SIGNOFF,           "signoff" },
142   { SILC_NOTIFY_TYPE_TOPIC_SET,         "topic" },
143   { SILC_NOTIFY_TYPE_NICK_CHANGE,       "nick" },
144   { SILC_NOTIFY_TYPE_CMODE_CHANGE,      "cmode" },
145   { SILC_NOTIFY_TYPE_CUMODE_CHANGE,     "cumode" },
146   { SILC_NOTIFY_TYPE_MOTD,              "motd" },
147   { SILC_NOTIFY_TYPE_CHANNEL_CHANGE,    "channel_change" },
148   { SILC_NOTIFY_TYPE_SERVER_SIGNOFF,    "server_signoff" },
149   { SILC_NOTIFY_TYPE_KICKED,            "kick" },
150   { SILC_NOTIFY_TYPE_KILLED,            "kill" },
151   { SILC_NOTIFY_TYPE_UMODE_CHANGE,      "umode" },
152   { SILC_NOTIFY_TYPE_BAN,               "ban" },
153 };
154
155 static void silc_notify(SilcClient client, SilcClientConnection conn,
156                         SilcNotifyType type, ...)
157 {
158   SILC_SERVER_REC *server;
159   va_list va;
160   
161   server = conn == NULL ? NULL : conn->context;
162   va_start(va, type);
163   
164   if (type == SILC_NOTIFY_TYPE_NONE) {
165     /* Some generic notice from server */
166     printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
167   } else if (type < MAX_NOTIFY) {
168     /* Send signal about the notify event */
169     char signal[50];
170     g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
171     signal_emit(signal, 2, server, va);
172   } else {
173     /* Unknown notify */
174     printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type);
175   }
176
177   va_end(va);
178 }
179
180 /* Called to indicate that connection was either successfully established
181    or connecting failed.  This is also the first time application receives
182    the SilcClientConnection objecet which it should save somewhere. */
183
184 static void 
185 silc_connect(SilcClient client, SilcClientConnection conn, int success)
186 {
187   SILC_SERVER_REC *server = conn->context;
188
189   if (success) {
190     server->connected = TRUE;
191     signal_emit("event connected", 1, server);
192   } else {
193     server->connection_lost = TRUE;
194     server->conn->context = NULL;
195     server_disconnect(SERVER(server));
196   }
197 }
198
199 /* Called to indicate that connection was disconnected to the server. */
200
201 static void 
202 silc_disconnect(SilcClient client, SilcClientConnection conn)
203 {
204   SILC_SERVER_REC *server = conn->context;
205
206   server->conn->context = NULL;
207   server->conn = NULL;
208   server->connection_lost = TRUE;
209   server_disconnect(SERVER(server));
210 }
211
212 /* Command handler. This function is called always in the command function.
213    If error occurs it will be called as well. `conn' is the associated
214    client connection. `cmd_context' is the command context that was
215    originally sent to the command. `success' is FALSE if error occured
216    during command. `command' is the command being processed. It must be
217    noted that this is not reply from server. This is merely called just
218    after application has called the command. Just to tell application
219    that the command really was processed. */
220
221 static void 
222 silc_command(SilcClient client, SilcClientConnection conn, 
223              SilcClientCommandContext cmd_context, int success,
224              SilcCommand command)
225 {
226 }
227
228 /* Command reply handler. This function is called always in the command reply
229    function. If error occurs it will be called as well. Normal scenario
230    is that it will be called after the received command data has been parsed
231    and processed. The function is used to pass the received command data to
232    the application. 
233
234    `conn' is the associated client connection. `cmd_payload' is the command
235    payload data received from server and it can be ignored. It is provided
236    if the application would like to re-parse the received command data,
237    however, it must be noted that the data is parsed already by the library
238    thus the payload can be ignored. `success' is FALSE if error occured.
239    In this case arguments are not sent to the application. `command' is the
240    command reply being processed. The function has variable argument list
241    and each command defines the number and type of arguments it passes to the
242    application (on error they are not sent). */
243
244 static void 
245 silc_command_reply(SilcClient client, SilcClientConnection conn,
246                    SilcCommandPayload cmd_payload, int success,
247                    SilcCommand command, SilcCommandStatus status, ...)
248
249 {
250   SILC_SERVER_REC *server = conn->context;
251   SILC_CHANNEL_REC *chanrec;
252   va_list vp;
253
254   va_start(vp, status);
255
256   switch(command) {
257     case SILC_COMMAND_WHOIS:
258       {
259         char buf[1024], *nickname, *username, *realname;
260         int len;
261         uint32 idle, mode;
262         SilcBuffer channels;
263
264         if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
265             status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
266           char *tmp;
267           tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
268                                            3, NULL);
269           if (tmp)
270             client->ops->say(client, conn, "%s: %s", tmp,
271                              silc_client_command_status_message(status));
272           else
273             client->ops->say(client, conn, "%s",
274                              silc_client_command_status_message(status));
275           break;
276         }
277
278         if (!success)
279           return;
280
281         (void)va_arg(vp, SilcClientEntry);
282         nickname = va_arg(vp, char *);
283         username = va_arg(vp, char *);
284         realname = va_arg(vp, char *);
285         channels = va_arg(vp, SilcBuffer);
286         mode = va_arg(vp, uint32);
287         idle = va_arg(vp, uint32);
288
289         memset(buf, 0, sizeof(buf));
290
291         if (nickname) {
292           len = strlen(nickname);
293           strncat(buf, nickname, len);
294           strncat(buf, " is ", 4);
295         }
296         
297         if (username) {
298           strncat(buf, username, strlen(username));
299         }
300         
301         if (realname) {
302           strncat(buf, " (", 2);
303           strncat(buf, realname, strlen(realname));
304           strncat(buf, ")", 1);
305         }
306
307         client->ops->say(client, conn, "%s", buf);
308
309         if (channels) {
310           SilcDList list = silc_channel_payload_parse_list(channels);
311           if (list) {
312             SilcChannelPayload entry;
313
314             memset(buf, 0, sizeof(buf));
315             strcat(buf, "on channels: ");
316
317             silc_dlist_start(list);
318             while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
319               char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
320               uint32 name_len;
321               char *name = silc_channel_get_name(entry, &name_len);
322
323               if (m)
324                 strncat(buf, m, strlen(m));
325               strncat(buf, name, name_len);
326               strncat(buf, " ", 1);
327               silc_free(m);
328             }
329
330             client->ops->say(client, conn, "%s", buf);
331             silc_channel_payload_list_free(list);
332           }
333         }
334
335         if (mode) {
336           if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
337               (mode & SILC_UMODE_ROUTER_OPERATOR))
338             client->ops->say(client, conn, "%s is %s", nickname,
339                              (mode & SILC_UMODE_SERVER_OPERATOR) ?
340                              "Server Operator" :
341                              (mode & SILC_UMODE_ROUTER_OPERATOR) ?
342                              "SILC Operator" : "[Unknown mode]");
343
344           if (mode & SILC_UMODE_GONE)
345             client->ops->say(client, conn, "%s is gone", nickname);
346         }
347
348         if (idle && nickname)
349           client->ops->say(client, conn, "%s has been idle %d %s",
350                            nickname,
351                            idle > 60 ? (idle / 60) : idle,
352                            idle > 60 ? "minutes" : "seconds");
353       }
354       break;
355
356     case SILC_COMMAND_WHOWAS:
357       {
358         char buf[1024], *nickname, *username, *realname;
359         int len;
360
361         if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
362             status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
363           char *tmp;
364           tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
365                                            3, NULL);
366           if (tmp)
367             client->ops->say(client, conn, "%s: %s", tmp,
368                              silc_client_command_status_message(status));
369           else
370             client->ops->say(client, conn, "%s",
371                              silc_client_command_status_message(status));
372           break;
373         }
374
375         if (!success)
376           return;
377
378         (void)va_arg(vp, SilcClientEntry);
379         nickname = va_arg(vp, char *);
380         username = va_arg(vp, char *);
381         realname = va_arg(vp, char *);
382
383         memset(buf, 0, sizeof(buf));
384
385         if (nickname) {
386           len = strlen(nickname);
387           strncat(buf, nickname, len);
388           strncat(buf, " was ", 5);
389         }
390         
391         if (username) {
392           strncat(buf, username, strlen(nickname));
393         }
394         
395         if (realname) {
396           strncat(buf, " (", 2);
397           strncat(buf, realname, strlen(realname));
398           strncat(buf, ")", 1);
399         }
400
401         client->ops->say(client, conn, "%s", buf);
402       }
403       break;
404
405     case SILC_COMMAND_INVITE:
406       {
407         SilcChannelEntry channel;
408         char *invite_list;
409
410         if (!success)
411           return;
412         
413         channel = va_arg(vp, SilcChannelEntry);
414         invite_list = va_arg(vp, char *);
415
416         if (invite_list)
417           silc_say(client, conn, "%s invite list: %s", channel->channel_name,
418                    invite_list);
419         else
420           silc_say(client, conn, "%s invite list not set", 
421                    channel->channel_name);
422       }
423       break;
424
425   case SILC_COMMAND_JOIN: 
426     {
427       char *channel, *mode;
428       uint32 modei;
429       SilcChannelEntry channel_entry;
430       
431       channel = va_arg(vp, char *);
432       channel_entry = va_arg(vp, SilcChannelEntry);
433       modei = va_arg(vp, uint32);
434       mode = silc_client_chmode(modei, channel_entry);
435       
436       chanrec = silc_channel_find(server, channel);
437       if (chanrec != NULL && !success)
438         channel_destroy(CHANNEL(chanrec));
439       else if (chanrec == NULL && success)
440         chanrec = silc_channel_create(server, channel, TRUE);
441       
442       g_free_not_null(chanrec->mode);
443       chanrec->mode = g_strdup(mode == NULL ? "" : mode);
444       signal_emit("channel mode changed", 1, chanrec);
445       break;
446     }
447
448   case SILC_COMMAND_NICK: 
449     {
450       SilcClientEntry client = va_arg(vp, SilcClientEntry);
451       char *old;
452       
453       old = g_strdup(server->nick);
454       server_change_nick(SERVER(server), client->nickname);
455       nicklist_rename_unique(SERVER(server),
456                              server->conn->local_entry, server->nick,
457                              client, client->nickname);
458       
459       signal_emit("message own_nick", 4,
460                   server, server->nick, old, "");
461       g_free(old);
462       break;
463     }
464
465   case SILC_COMMAND_USERS: 
466     {
467       SilcChannelEntry channel;
468       SilcChannelUser user;
469       NICK_REC *ownnick;
470       
471       channel = va_arg(vp, SilcChannelEntry);
472       chanrec = silc_channel_find_entry(server, channel);
473       if (chanrec == NULL)
474         break;
475       
476       silc_list_start(channel->clients);
477       while ((user = silc_list_get(channel->clients)) != NULL)
478         silc_nicklist_insert(chanrec, user, FALSE);
479       
480       ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
481       nicklist_set_own(CHANNEL(chanrec), ownnick);
482       signal_emit("channel joined", 1, chanrec);
483       fe_channels_nicklist(CHANNEL(chanrec),
484                            CHANNEL_NICKLIST_FLAG_ALL);
485       break;
486     }
487   }
488   
489   va_end(vp);
490 }
491
492 /* Verifies received public key. If user decides to trust the key it is
493    saved as public server key for later use. If user does not trust the
494    key this returns FALSE. */
495
496 static int silc_verify_public_key(SilcClient client,
497                                   SilcClientConnection conn, 
498                                   SilcSocketType conn_type,
499                                   unsigned char *pk, uint32 pk_len,
500                                   SilcSKEPKType pk_type)
501 {
502   return TRUE;
503 }
504
505 /* Asks passphrase from user on the input line. */
506
507 static unsigned char *silc_ask_passphrase(SilcClient client,
508                                           SilcClientConnection conn)
509 {
510   return NULL;
511 }
512
513 /* Find authentication method and authentication data by hostname and
514    port. The hostname may be IP address as well. The found authentication
515    method and authentication data is returned to `auth_meth', `auth_data'
516    and `auth_data_len'. The function returns TRUE if authentication method
517    is found and FALSE if not. `conn' may be NULL. */
518
519 static int 
520 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
521                      char *hostname, uint16 port,
522                      SilcProtocolAuthMeth *auth_meth,
523                      unsigned char **auth_data,
524                      uint32 *auth_data_len)
525 {
526   return FALSE;
527 }
528
529 /* Notifies application that failure packet was received.  This is called
530    if there is some protocol active in the client.  The `protocol' is the
531    protocol context.  The `failure' is opaque pointer to the failure
532    indication.  Note, that the `failure' is protocol dependant and application
533    must explicitly cast it to correct type.  Usually `failure' is 32 bit
534    failure type (see protocol specs for all protocol failure types). */
535
536 static void 
537 silc_failure(SilcClient client, SilcClientConnection conn, 
538              SilcProtocol protocol, void *failure)
539 {
540   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
541     SilcSKEStatus status = (SilcSKEStatus)failure;
542     
543     if (status == SILC_SKE_STATUS_BAD_VERSION)
544       silc_say(client, conn, 
545                "You are running incompatible client version (it may be "
546                "too old or too new)");
547     if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
548       silc_say(client, conn, "Server does not support your public key type");
549     if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
550       silc_say(client, conn, 
551                "Server does not support one of your proposed KE group");
552     if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
553       silc_say(client, conn, 
554                "Server does not support one of your proposed cipher");
555     if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
556       silc_say(client, conn, 
557                "Server does not support one of your proposed PKCS");
558     if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
559       silc_say(client, conn, 
560                "Server does not support one of your proposed hash function");
561     if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
562       silc_say(client, conn, 
563                "Server does not support one of your proposed HMAC");
564     if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
565       silc_say(client, conn, "Incorrect signature");
566   }
567
568   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
569     uint32 err = (uint32)failure;
570
571     if (err == SILC_AUTH_FAILED)
572       silc_say(client, conn, "Authentication failed");
573   }
574 }
575
576 /* Asks whether the user would like to perform the key agreement protocol.
577    This is called after we have received an key agreement packet or an
578    reply to our key agreement packet. This returns TRUE if the user wants
579    the library to perform the key agreement protocol and FALSE if it is not
580    desired (application may start it later by calling the function
581    silc_client_perform_key_agreement). */
582
583 static int 
584 silc_key_agreement(SilcClient client, SilcClientConnection conn,
585                    SilcClientEntry client_entry, char *hostname,
586                    int port,
587                    SilcKeyAgreementCallback *completion,
588                    void **context)
589 {
590   char host[256];
591
592   /* We will just display the info on the screen and return FALSE and user
593      will have to start the key agreement with a command. */
594
595   if (hostname) {
596     memset(host, 0, sizeof(host));
597     snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port); 
598   }
599
600   silc_say(client, conn, "%s wants to perform key agreement %s",
601            client_entry->nickname, hostname ? host : "");
602
603   *completion = NULL;
604   *context = NULL;
605
606   return FALSE;
607 }
608
609 /* SILC client operations */
610 SilcClientOperations ops = {
611   silc_say,
612   silc_channel_message,
613   silc_private_message,
614   silc_notify,
615   silc_command,
616   silc_command_reply,
617   silc_connect,
618   silc_disconnect,
619   silc_get_auth_method,
620   silc_verify_public_key,
621   silc_ask_passphrase,
622   silc_failure,
623   silc_key_agreement,
624 };
625
626 static int my_silc_scheduler(void)
627 {
628   silc_schedule_one(0);
629   return 1;
630 }
631
632 static CHATNET_REC *create_chatnet(void)
633 {
634   return g_malloc0(sizeof(CHATNET_REC));
635 }
636
637 static SERVER_SETUP_REC *create_server_setup(void)
638 {
639   return g_malloc0(sizeof(SERVER_SETUP_REC));
640 }
641
642 static CHANNEL_SETUP_REC *create_channel_setup(void)
643 {
644   return g_malloc0(sizeof(CHANNEL_SETUP_REC));
645 }
646
647 static SERVER_CONNECT_REC *create_server_connect(void)
648 {
649   return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
650 }
651
652 /* Checks user information and saves them to the config file it they
653    do not exist there already. */
654
655 static void silc_init_userinfo(void)
656 {
657   const char *set, *nick, *user_name;
658   char *str;   
659         
660   /* check if nick/username/realname wasn't read from setup.. */
661   set = settings_get_str("real_name");
662   if (set == NULL || *set == '\0') {
663     str = g_getenv("SILCNAME");
664     if (!str)
665       str = g_getenv("IRCNAME");
666     settings_set_str("real_name",
667                      str != NULL ? str : g_get_real_name());
668   }
669  
670   /* username */
671   user_name = settings_get_str("user_name");
672   if (user_name == NULL || *user_name == '\0') {
673     str = g_getenv("SILCUSER");
674     if (!str)
675       str = g_getenv("IRCUSER");
676     settings_set_str("user_name",
677                      str != NULL ? str : g_get_user_name());
678     
679     user_name = settings_get_str("user_name");
680   }
681          
682   /* nick */
683   nick = settings_get_str("nick");
684   if (nick == NULL || *nick == '\0') {
685     str = g_getenv("SILCNICK");
686     if (!str)
687       str = g_getenv("IRCNICK");
688     settings_set_str("nick", str != NULL ? str : user_name);
689     
690     nick = settings_get_str("nick");
691   }
692                 
693   /* alternate nick */
694   set = settings_get_str("alternate_nick");
695   if (set == NULL || *set == '\0') {
696     if (strlen(nick) < 9)
697       str = g_strconcat(nick, "_", NULL);
698     else { 
699       str = g_strdup(nick);
700       str[strlen(str)-1] = '_';
701     }
702     settings_set_str("alternate_nick", str);
703     g_free(str);
704   }
705
706   /* host name */
707   set = settings_get_str("hostname");
708   if (set == NULL || *set == '\0') {
709     str = g_getenv("SILCHOST");
710     if (!str)
711       str = g_getenv("IRCHOST");
712     if (str != NULL)
713       settings_set_str("hostname", str);
714   }
715 }
716
717 /* Init SILC. Called from src/fe-text/silc.c */
718
719 void silc_core_init(void)
720 {
721   static struct poptOption options[] = {
722     { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0, 
723       "Create new public key pair", NULL },
724     { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0, 
725       "Set the PKCS of the public key pair", "PKCS" },
726     { "bits", 0, POPT_ARG_INT, &opt_bits, 0, 
727       "Set the length of the public key pair", "VALUE" },
728     { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0, 
729       "Show the contents of the public key", "FILE" },
730     { NULL, '\0', 0, NULL }
731   };
732
733   args_register(options);
734 }
735
736 /* Finalize init. Called from src/fe-text/silc.c */
737
738 void silc_core_init_finish(void)
739 {
740   CHAT_PROTOCOL_REC *rec;
741
742   if (opt_create_keypair == TRUE) {
743     /* Create new key pair and exit */
744     silc_cipher_register_default();
745     silc_pkcs_register_default();
746     silc_hash_register_default();
747     silc_hmac_register_default();
748     silc_client_create_key_pair(opt_pkcs, opt_bits, 
749                                 NULL, NULL, NULL, NULL, NULL);
750     exit(0);
751   }
752
753   if (opt_keyfile) {
754     /* Dump the key */
755     silc_cipher_register_default();
756     silc_pkcs_register_default();
757     silc_hash_register_default();
758     silc_hmac_register_default();
759     silc_client_show_key(opt_keyfile);
760     exit(0);
761   }
762
763   /* Allocate SILC client */
764   silc_client = silc_client_alloc(&ops, NULL);
765
766   /* Load local config file */
767   silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE);
768
769   /* Get user information */
770   silc_client->username = g_strdup(settings_get_str("user_name"));
771   silc_client->hostname = silc_net_localhost();
772   silc_client->realname = g_strdup(settings_get_str("real_name"));
773
774   /* Register all configured ciphers, PKCS and hash functions. */
775   if (silc_config) {
776     silc_config->client = silc_client;
777     if (!silc_client_config_register_ciphers(silc_config))
778       silc_cipher_register_default();
779     if (!silc_client_config_register_pkcs(silc_config))
780       silc_pkcs_register_default();
781     if (!silc_client_config_register_hashfuncs(silc_config))
782       silc_hash_register_default();
783     if (!silc_client_config_register_hmacs(silc_config))
784       silc_hmac_register_default();
785   } else {
786     /* Register default ciphers, pkcs, hash funtions and hmacs. */
787     silc_cipher_register_default();
788     silc_pkcs_register_default();
789     silc_hash_register_default();
790     silc_hmac_register_default();
791   }
792
793   /* Check ~/.silc directory and public and private keys */
794   if (silc_client_check_silc_dir() == FALSE) {
795     idletag = -1;
796     return;
797   }
798
799   /* Load public and private key */
800   if (silc_client_load_keys(silc_client) == FALSE) {
801     idletag = -1;
802     return;
803   }
804
805   /* Initialize the SILC client */
806   if (!silc_client_init(silc_client)) {
807     idletag = -1;
808     return;
809   }
810
811   /* Register SILC to the irssi */
812   rec = g_new0(CHAT_PROTOCOL_REC, 1);
813   rec->name = "SILC";
814   rec->fullname = "Secure Internet Live Conferencing";
815   rec->chatnet = "silcnet";
816   rec->create_chatnet = create_chatnet;
817   rec->create_server_setup = create_server_setup;
818   rec->create_channel_setup = create_channel_setup;
819   rec->create_server_connect = create_server_connect;
820   rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
821     silc_server_connect; 
822   rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
823     silc_channel_create;
824   rec->query_create = (QUERY_REC *(*) (const char *, const char *, int))
825     silc_query_create;
826   
827   chat_protocol_register(rec);
828   g_free(rec);
829
830   silc_init_userinfo();
831   silc_server_init();
832   silc_channels_init();
833   silc_queries_init();
834
835   idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL);
836 }
837
838 /* Deinit SILC. Called from src/fe-text/silc.c */
839
840 void silc_core_deinit(void)
841 {
842   if (idletag != -1) {
843     signal_emit("chat protocol deinit", 1,
844                 chat_protocol_find("SILC"));
845     
846     silc_server_deinit();
847     silc_channels_deinit();
848     silc_queries_deinit();
849     
850     chat_protocol_unregister("SILC");
851     
852     g_source_remove(idletag);
853   }
854   
855   g_free(silc_client->username);
856   g_free(silc_client->realname);
857   silc_client_free(silc_client);
858 }