silc_client_unref_client fixes.
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Types and definitions ***************************/
26
27 SILC_FSM_STATE(silc_client_connection_st_run);
28 SILC_FSM_STATE(silc_client_new_id);
29
30
31 /************************ Static utility functions **************************/
32
33 /* Packet engine callback to receive a packet */
34
35 static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
36                                            SilcPacketStream stream,
37                                            SilcPacket packet,
38                                            void *callback_context,
39                                            void *stream_context)
40 {
41   SilcClientConnection conn = stream_context;
42
43   /* Packets we do not handle */
44   switch (packet->type) {
45   case SILC_PACKET_HEARTBEAT:
46   case SILC_PACKET_SUCCESS:
47   case SILC_PACKET_FAILURE:
48   case SILC_PACKET_REJECT:
49   case SILC_PACKET_KEY_EXCHANGE:
50   case SILC_PACKET_KEY_EXCHANGE_1:
51   case SILC_PACKET_KEY_EXCHANGE_2:
52   case SILC_PACKET_REKEY:
53   case SILC_PACKET_REKEY_DONE:
54   case SILC_PACKET_CONNECTION_AUTH:
55   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
56     return FALSE;
57     break;
58   }
59
60   /* Signal packet processor thread for a new packet */
61   conn->internal->new_packet = TRUE;
62   silc_fsm_set_state_context(&conn->internal->packet_thread, packet);
63   silc_fsm_continue_sync(&conn->internal->packet_thread);
64
65   return TRUE;
66 }
67
68 /* Packet engine callback to indicate end of stream */
69
70 static void silc_client_packet_eos(SilcPacketEngine engine,
71                                    SilcPacketStream stream,
72                                    void *callback_context,
73                                    void *stream_context)
74 {
75   SILC_LOG_DEBUG(("End of stream received"));
76 }
77
78 /* Packet engine callback to indicate error */
79
80 static void silc_client_packet_error(SilcPacketEngine engine,
81                                      SilcPacketStream stream,
82                                      SilcPacketError error,
83                                      void *callback_context,
84                                      void *stream_context)
85 {
86
87 }
88
89 /* Packet stream callbacks */
90 static SilcPacketCallbacks silc_client_stream_cbs =
91 {
92   silc_client_packet_receive,
93   silc_client_packet_eos,
94   silc_client_packet_error
95 };
96
97 /* FSM destructor */
98
99 void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
100                                 void *destructor_context)
101 {
102   silc_fsm_free(fsm);
103 }
104
105
106 /************************** Connection's machine ****************************/
107
108 /* Start the connection's state machine.  If threads are in use the machine
109    is always executed in a real thread. */
110
111 SILC_FSM_STATE(silc_client_connection_st_start)
112 {
113   SilcClientConnection conn = fsm_context;
114
115   /* Take scheduler for connection */
116   conn->internal->schedule = silc_fsm_get_schedule(fsm);
117
118   /*** Run connection machine */
119   silc_fsm_init(&conn->internal->fsm, conn, NULL, NULL,
120                 conn->internal->schedule);
121   silc_fsm_sema_init(&conn->internal->wait_event, &conn->internal->fsm, 0);
122   silc_fsm_start_sync(&conn->internal->fsm, silc_client_connection_st_run);
123
124   /*** Run packet processor FSM thread */
125   silc_fsm_thread_init(&conn->internal->packet_thread, &conn->internal->fsm,
126                        conn, silc_client_fsm_destructor, NULL, FALSE);
127   silc_fsm_start_sync(&conn->internal->packet_thread,
128                       silc_client_connection_st_packet);
129
130   /* Schedule any events set in initialization */
131   if (conn->internal->connect)
132     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
133   if (conn->internal->key_exchange)
134     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
135
136   /* Wait until this thread is terminated */
137   return SILC_FSM_WAIT;
138 }
139
140 /* Connection machine main state. */
141
142 SILC_FSM_STATE(silc_client_connection_st_run)
143 {
144   SilcClientConnection conn = fsm_context;
145
146   /* Wait for events */
147   SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
148
149   /* Process events */
150
151   if (conn->internal->connect) {
152     SILC_LOG_DEBUG(("Event: connect"));
153     conn->internal->connect = FALSE;
154
155     /** Connect remote host */
156     silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
157                          conn, NULL, NULL, FALSE);
158     silc_fsm_start_sync(&conn->internal->event_thread, silc_client_st_connect);
159     return SILC_FSM_CONTINUE;
160   }
161
162   if (conn->internal->key_exchange) {
163     SILC_LOG_DEBUG(("Event: key exchange"));
164     conn->internal->key_exchange = FALSE;
165
166     /** Start key exchange */
167     silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
168                          conn, NULL, NULL, FALSE);
169     silc_fsm_start_sync(&conn->internal->event_thread,
170                         silc_client_st_connect_key_exchange);
171     return SILC_FSM_CONTINUE;
172   }
173
174   if (conn->internal->disconnected) {
175     SILC_LOG_DEBUG(("Event: disconnected"));
176     conn->internal->disconnected = FALSE;
177
178     return SILC_FSM_CONTINUE;
179   }
180
181   /* NOT REACHED */
182 #if defined(SILC_DEBUG)
183   assert(FALSE);
184 #endif /* SILC_DEBUG */
185   return SILC_FSM_CONTINUE;
186 }
187
188 /* Connection's packet processor main state.  Packet processor thread waits
189    here for a new packet and processes received packets. */
190
191 SILC_FSM_STATE(silc_client_connection_st_packet)
192 {
193   SilcClientConnection conn = fsm_context;
194   SilcClient client = conn->client;
195   SilcPacket packet = state_context;
196
197   /* Wait for packet to arrive */
198   if (!conn->internal->new_packet) {
199     SILC_LOG_DEBUG(("Wait for packet"));
200     return SILC_FSM_WAIT;
201   }
202   conn->internal->new_packet = FALSE;
203
204   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
205
206   switch (packet->type) {
207
208   case SILC_PACKET_PRIVATE_MESSAGE:
209     /** Private message */
210     silc_fsm_next(fsm, silc_client_private_message);
211     break;
212
213   case SILC_PACKET_CHANNEL_MESSAGE:
214     /* Channel message */
215     //    silc_client_channel_message(client, conn, packet);
216     break;
217
218   case SILC_PACKET_FTP:
219     /* File transfer packet */
220     //    silc_client_ftp(client, conn, packet);
221     break;
222
223   case SILC_PACKET_CHANNEL_KEY:
224     /* Received channel key */
225     //    silc_client_channel_key(client, conn, packet);
226     break;
227
228   case SILC_PACKET_COMMAND_REPLY:
229     /** Command reply */
230     silc_fsm_next(fsm, silc_client_command_reply);
231     break;
232
233   case SILC_PACKET_NOTIFY:
234     /* Notify */
235     //    silc_client_notify(client, conn, packet);
236     break;
237
238   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
239     /* Private message key indicator */
240     //    silc_client_private_message_key(client, conn, packet);
241     break;
242
243   case SILC_PACKET_DISCONNECT:
244     /* Server disconnects */
245     //    silc_client_disconnect(client, conn, packet);
246     break;
247
248   case SILC_PACKET_ERROR:
249     /* Error by server */
250     //    silc_client_error(client, conn, packet);
251     break;
252
253   case SILC_PACKET_KEY_AGREEMENT:
254     /* Key agreement */
255     //    silc_client_key_agreement(client, conn, packet);
256     break;
257
258   case SILC_PACKET_COMMAND:
259     /** Command packet */
260     silc_fsm_next(fsm, silc_client_command);
261     break;
262
263   case SILC_PACKET_NEW_ID:
264     /** New ID */
265     silc_fsm_next(fsm, silc_client_new_id);
266
267   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
268     /* Reply to connection authentication request to resolve authentication
269        method from server. */
270     //    silc_client_connection_auth_request(client, conn, packet);
271     break;
272
273   default:
274     silc_packet_free(packet);
275     break;
276   }
277
278   return SILC_FSM_CONTINUE;
279 }
280
281
282 /*************************** Main client machine ****************************/
283
284 /* The client's main state where we wait for various events */
285
286 SILC_FSM_STATE(silc_client_st_run)
287 {
288   SilcClient client = fsm_context;
289
290   /* Wait for events */
291   SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
292
293   /* Process events */
294
295   if (client->internal->run_callback && client->internal->ops->running) {
296     /* Call running callbcak back to application */
297     client->internal->run_callback = FALSE;
298     client->internal->ops->running(client, client->application);
299     return SILC_FSM_CONTINUE;
300   }
301
302   /* NOT REACHED */
303 #if defined(SILC_DEBUG)
304   assert(FALSE);
305 #endif /* SILC_DEBUG */
306   return SILC_FSM_CONTINUE;
307 }
308
309
310 /**************************** Packet Processing *****************************/
311
312 /* Received new ID from server during registering to SILC network */
313
314 SILC_FSM_STATE(silc_client_new_id)
315 {
316   SilcClientConnection conn = fsm_context;
317   SilcClient client = conn->client;
318   SilcPacket packet = state_context;
319   SilcID id;
320
321   if (conn->local_id)
322     goto out;
323
324   SILC_LOG_DEBUG(("New ID received from server"));
325
326   if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
327                                 silc_buffer_len(&packet->buffer), &id))
328     goto out;
329
330   /* Create local client entry */
331   conn->local_entry = silc_client_add_client(client, conn,
332                                              (client->nickname ?
333                                               client->nickname :
334                                               client->username),
335                                              client->username,
336                                              client->realname,
337                                              &id.u.client_id, 0);
338   if (!conn->local_entry)
339     goto out;
340
341   /* Save the ID */
342   conn->local_id = &conn->local_entry->id;
343   conn->local_idp = silc_buffer_copy(&packet->buffer);
344
345   /* Save cache entry */
346   silc_idcache_find_by_id_one(conn->internal->client_cache, conn->local_id,
347                               &conn->internal->local_entry);
348
349   /* Save remote ID */
350   if (packet->src_id_len) {
351     conn->remote_idp = silc_id_payload_encode_data(packet->src_id,
352                                                    packet->src_id_len,
353                                                    packet->src_id_type);
354     if (!conn->remote_idp)
355       goto out;
356     silc_id_payload_parse_id(silc_buffer_data(conn->remote_idp),
357                              silc_buffer_len(conn->remote_idp),
358                              &conn->remote_id);
359   }
360
361   /* Signal connection that new ID was received so it can continue
362      with the registering. */
363   if (conn->internal->registering)
364     silc_fsm_continue_sync(&conn->internal->event_thread);
365
366  out:
367   /** Packet processed */
368   silc_packet_free(packet);
369   silc_fsm_next(fsm, silc_client_connection_st_packet);
370   return SILC_FSM_CONTINUE;
371 }
372
373
374 /******************************* Public API *********************************/
375
376 /* Allocates and adds new connection to the client. This adds the allocated
377    connection to the connection table and returns a pointer to it. A client
378    can have multiple connections to multiple servers. Every connection must
379    be added to the client using this function. User data `context' may
380    be sent as argument. This function is normally used only if the
381    application performed the connecting outside the library. The library
382    however may use this internally. */
383
384 SilcClientConnection
385 silc_client_add_connection(SilcClient client,
386                            SilcConnectionType conn_type,
387                            SilcClientConnectionParams *params,
388                            SilcPublicKey public_key,
389                            SilcPrivateKey private_key,
390                            char *remote_host, int port,
391                            SilcClientConnectCallback callback,
392                            void *context)
393 {
394   SilcClientConnection conn;
395   SilcFSMThread thread;
396
397   if (!callback)
398     return NULL;
399
400   SILC_LOG_DEBUG(("Adding new connection to %s:%d", remote_host, port));
401
402   conn = silc_calloc(1, sizeof(*conn));
403   if (!conn)
404     return NULL;
405   conn->internal = silc_calloc(1, sizeof(*conn->internal));
406   if (!conn->internal) {
407     silc_free(conn);
408     return NULL;
409   }
410
411   conn->client = client;
412   conn->public_key = public_key;
413   conn->private_key = private_key;
414   conn->remote_host = strdup(remote_host);
415   conn->remote_port = port ? port : 706;
416   conn->type = conn_type;
417   conn->callback = callback;
418   conn->context = context;
419   conn->internal->client_cache =
420     silc_idcache_alloc(0, SILC_ID_CLIENT, NULL, NULL);
421   conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL,
422                                                      NULL);
423   conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL,
424                                                     NULL);
425   conn->internal->ftp_sessions = silc_dlist_init();
426   conn->internal->verbose = TRUE;
427   silc_list_init(conn->internal->pending_commands,
428                  struct SilcClientCommandContextStruct, next);
429
430   if (params) {
431     if (params->detach_data)
432       conn->internal->params.detach_data =
433         silc_memdup(params->detach_data,
434                     params->detach_data_len);
435     conn->internal->params.detach_data_len = params->detach_data_len;
436   }
437
438   /* Add the connection to connections list */
439   //  silc_dlist_add(client->internal->conns, conn);
440
441   /* Run the connection state machine.  If threads are in use the machine
442      is always run in a real thread. */
443   thread = silc_fsm_thread_alloc(&client->internal->fsm, conn,
444                                  silc_client_fsm_destructor, NULL,
445                                  client->internal->params->threads);
446   if (!thread) {
447     silc_client_del_connection(client, conn);
448     return NULL;
449   }
450   silc_fsm_start_sync(thread, silc_client_connection_st_start);
451
452   return conn;
453 }
454
455 /* Removes connection from client. Frees all memory. */
456
457 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
458 {
459 #if 0
460   SilcClientConnection c;
461   SilcIDCacheList list;
462   SilcIDCacheEntry entry;
463   SilcClientCommandPending *r;
464   SilcBool ret;
465
466   silc_dlist_start(client->internal->conns);
467   while ((c = silc_dlist_get(client->internal->conns)) != SILC_LIST_END) {
468     if (c != conn)
469       continue;
470
471     /* Free all cache entries */
472     if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
473       ret = silc_idcache_list_first(list, &entry);
474       while (ret) {
475         silc_client_del_client(client, conn, entry->context);
476         ret = silc_idcache_list_next(list, &entry);
477       }
478       silc_idcache_list_free(list);
479     }
480
481     if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
482       ret = silc_idcache_list_first(list, &entry);
483       while (ret) {
484         silc_client_del_channel(client, conn, entry->context);
485         ret = silc_idcache_list_next(list, &entry);
486       }
487       silc_idcache_list_free(list);
488     }
489
490     if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
491       ret = silc_idcache_list_first(list, &entry);
492       while (ret) {
493         silc_client_del_server(client, conn, entry->context);
494         ret = silc_idcache_list_next(list, &entry);
495       }
496       silc_idcache_list_free(list);
497     }
498
499     /* Clear ID caches */
500     if (conn->internal->client_cache)
501       silc_idcache_free(conn->internal->client_cache);
502     if (conn->internal->channel_cache)
503       silc_idcache_free(conn->internal->channel_cache);
504     if (conn->internal->server_cache)
505       silc_idcache_free(conn->internal->server_cache);
506
507     /* Free data (my ID is freed in above silc_client_del_client).
508        conn->nickname is freed when freeing the local_entry->nickname. */
509     silc_free(conn->remote_host);
510     silc_free(conn->local_id_data);
511     if (conn->internal->send_key)
512       silc_cipher_free(conn->internal->send_key);
513     if (conn->internal->receive_key)
514       silc_cipher_free(conn->internal->receive_key);
515     if (conn->internal->hmac_send)
516       silc_hmac_free(conn->internal->hmac_send);
517     if (conn->internal->hmac_receive)
518       silc_hmac_free(conn->internal->hmac_receive);
519     silc_free(conn->internal->rekey);
520
521     if (conn->internal->active_session) {
522       if (conn->sock)
523         conn->sock->user_data = NULL;
524       silc_client_ftp_session_free(conn->internal->active_session);
525       conn->internal->active_session = NULL;
526     }
527
528     silc_client_ftp_free_sessions(client, conn);
529
530     if (conn->internal->pending_commands) {
531       silc_dlist_start(conn->internal->pending_commands);
532       while ((r = silc_dlist_get(conn->internal->pending_commands))
533              != SILC_LIST_END)
534         silc_dlist_del(conn->internal->pending_commands, r);
535       silc_dlist_uninit(conn->internal->pending_commands);
536     }
537
538     silc_free(conn->internal);
539     memset(conn, 0, sizeof(*conn));
540     silc_free(conn);
541
542     silc_dlist_del(client->internal->conns, conn);
543   }
544 #endif /* 0 */
545 }
546
547 /* Connects to remote server. This is the main routine used to connect
548    to remote SILC server. Returns FALSE on error. */
549
550 void silc_client_connect_to_server(SilcClient client,
551                                    SilcClientConnectionParams *params,
552                                    SilcPublicKey public_key,
553                                    SilcPrivateKey private_key,
554                                    char *remote_host, int port,
555                                    SilcClientConnectCallback callback,
556                                    void *context)
557 {
558   SilcClientConnection conn;
559
560   if (!client || !remote_host)
561     return;
562
563   /* Add new connection */
564   conn = silc_client_add_connection(client, SILC_CONN_SERVER, params,
565                                     public_key, private_key, remote_host,
566                                     port, callback, context);
567   if (!conn) {
568     callback(client, NULL, SILC_CLIENT_CONN_ERROR, context);
569     return;
570   }
571
572   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
573                              "Connecting to port %d of server %s",
574                              port, remote_host);
575
576   /* Signal connection machine to start connecting */
577   conn->internal->connect = TRUE;
578 }
579
580 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
581    key material between client and server.  This function can be called
582    directly if application is performing its own connecting and does not
583    use the connecting provided by this library. This function is normally
584    used only if the application performed the connecting outside the library.
585    The library however may use this internally. */
586
587 void silc_client_start_key_exchange(SilcClient client,
588                                     SilcClientConnection conn,
589                                     SilcStream stream)
590 {
591 #if 0
592   assert(conn && stream);
593   assert(client->public_key);
594   assert(client->private_key);
595
596   conn->nickname = (client->nickname ? strdup(client->nickname) :
597                     strdup(client->username));
598 #endif /* 0 */
599
600   /* Start */
601
602 }
603
604 #if 0
605 /* Authentication method resolving callback. Application calls this function
606    after we've called the client->internal->ops->get_auth_method
607    client operation to resolve the authentication method. We will continue
608    the executiong of the protocol in this function. */
609
610 void silc_client_resolve_auth_method(SilcBool success,
611                                      SilcProtocolAuthMeth auth_meth,
612                                      const unsigned char *auth_data,
613                                      SilcUInt32 auth_data_len, void *context)
614 {
615   SilcClientConnAuthInternalContext *proto_ctx =
616     (SilcClientConnAuthInternalContext *)context;
617   SilcClient client = (SilcClient)proto_ctx->client;
618
619   if (!success)
620     auth_meth = SILC_AUTH_NONE;
621
622   proto_ctx->auth_meth = auth_meth;
623
624   if (success && auth_data && auth_data_len) {
625
626     /* Passphrase must be UTF-8 encoded, if it isn't encode it */
627     if (auth_meth == SILC_AUTH_PASSWORD &&
628         !silc_utf8_valid(auth_data, auth_data_len)) {
629       int payload_len = 0;
630       unsigned char *autf8 = NULL;
631       payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
632                                           SILC_STRING_ASCII);
633       autf8 = silc_calloc(payload_len, sizeof(*autf8));
634       auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
635                                        SILC_STRING_ASCII, autf8, payload_len);
636       auth_data = autf8;
637     }
638
639     proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
640     proto_ctx->auth_data_len = auth_data_len;
641   }
642
643   /* Allocate the authenteication protocol and execute it. */
644   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
645                       &proto_ctx->sock->protocol, (void *)proto_ctx,
646                       silc_client_connect_to_server_final);
647
648   /* Execute the protocol */
649   silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
650 }
651
652 /* Finalizes the connection to the remote SILC server. This is called
653    after authentication protocol has been completed. This send our
654    user information to the server to receive our client ID from
655    server. */
656
657 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
658 {
659   SilcProtocol protocol = (SilcProtocol)context;
660   SilcClientConnAuthInternalContext *ctx =
661     (SilcClientConnAuthInternalContext *)protocol->context;
662   SilcClient client = (SilcClient)ctx->client;
663   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
664   SilcBuffer packet;
665
666   SILC_LOG_DEBUG(("Start"));
667
668   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
669       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
670     /* Error occured during protocol */
671     SILC_LOG_DEBUG(("Error during authentication protocol"));
672     ctx->status = SILC_CLIENT_CONN_ERROR_AUTH;
673     goto err;
674   }
675
676   if (conn->internal->params.detach_data) {
677     /* Send RESUME_CLIENT packet to the server, which is used to resume
678        old detached session back. */
679     SilcBuffer auth;
680     SilcClientID *old_client_id;
681     unsigned char *old_id;
682     SilcUInt16 old_id_len;
683
684     if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len)) {
685       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
686       goto err;
687     }
688
689     old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
690     if (!old_client_id) {
691       silc_free(old_id);
692       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
693       goto err;
694     }
695
696     /* Generate authentication data that server will verify */
697     auth = silc_auth_public_key_auth_generate(client->public_key,
698                                               client->private_key,
699                                               client->rng,
700                                               conn->internal->hash,
701                                               old_client_id, SILC_ID_CLIENT);
702     if (!auth) {
703       silc_free(old_client_id);
704       silc_free(old_id);
705       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
706       goto err;
707     }
708
709     packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
710     silc_buffer_format(packet,
711                        SILC_STR_UI_SHORT(old_id_len),
712                        SILC_STR_UI_XNSTRING(old_id, old_id_len),
713                        SILC_STR_UI_XNSTRING(auth->data, auth->len),
714                        SILC_STR_END);
715
716     /* Send the packet */
717     silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
718                             NULL, 0, NULL, NULL,
719                             packet->data, packet->len, TRUE);
720     silc_buffer_free(packet);
721     silc_buffer_free(auth);
722     silc_free(old_client_id);
723     silc_free(old_id);
724   } else {
725     /* Send NEW_CLIENT packet to the server. We will become registered
726        to the SILC network after sending this packet and we will receive
727        client ID from the server. */
728     packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
729                                strlen(client->realname));
730     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
731     silc_buffer_format(packet,
732                        SILC_STR_UI_SHORT(strlen(client->username)),
733                        SILC_STR_UI_XNSTRING(client->username,
734                                             strlen(client->username)),
735                        SILC_STR_UI_SHORT(strlen(client->realname)),
736                        SILC_STR_UI_XNSTRING(client->realname,
737                                             strlen(client->realname)),
738                        SILC_STR_END);
739
740     /* Send the packet */
741     silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
742                             NULL, 0, NULL, NULL,
743                             packet->data, packet->len, TRUE);
744     silc_buffer_free(packet);
745   }
746
747   /* Save remote ID. */
748   conn->remote_id = ctx->dest_id;
749   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
750   conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
751
752   /* Register re-key timeout */
753   conn->internal->rekey->timeout = client->internal->params->rekey_secs;
754   conn->internal->rekey->context = (void *)client;
755   silc_schedule_task_add(client->schedule, conn->sock->sock,
756                          silc_client_rekey_callback,
757                          (void *)conn->sock, conn->internal->rekey->timeout, 0,
758                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
759
760   silc_protocol_free(protocol);
761   silc_free(ctx->auth_data);
762   if (ctx->ske)
763     silc_ske_free(ctx->ske);
764   silc_socket_free(ctx->sock);
765   silc_free(ctx);
766   conn->sock->protocol = NULL;
767   return;
768
769  err:
770   silc_protocol_free(protocol);
771   silc_free(ctx->auth_data);
772   silc_free(ctx->dest_id);
773   if (ctx->ske)
774     silc_ske_free(ctx->ske);
775   conn->sock->protocol = NULL;
776   silc_socket_free(ctx->sock);
777
778   /* Notify application of failure */
779   silc_schedule_task_add(client->schedule, ctx->sock->sock,
780                          silc_client_connect_failure_auth, ctx,
781                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
782 }
783
784 /* Packet processing callback. This is used to send and receive packets
785    from network. This is generic task. */
786
787 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
788 {
789   SilcClient client = (SilcClient)context;
790   SilcClientConnection conn = NULL;
791   SilcClientConnection conn;
792   int ret;
793
794   SILC_LOG_DEBUG(("Processing packet"));
795
796   SILC_CLIENT_GET_SOCK(client, fd, sock);
797   if (sock == NULL)
798     return;
799
800   conn = (SilcClientConnection)sock->user_data;
801
802   /* Packet sending */
803   if (type == SILC_TASK_WRITE) {
804     /* Do not send data to disconnected connection */
805     if (SILC_IS_DISCONNECTED(sock))
806       return;
807
808     ret = silc_packet_send(sock, TRUE);
809
810     /* If returned -2 could not write to connection now, will do
811        it later. */
812     if (ret == -2)
813       return;
814
815     /* Error */
816     if (ret == -1)
817       return;
818
819     /* The packet has been sent and now it is time to set the connection
820        back to only for input. When there is again some outgoing data
821        available for this connection it will be set for output as well.
822        This call clears the output setting and sets it only for input. */
823     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
824     SILC_UNSET_OUTBUF_PENDING(sock);
825
826     silc_buffer_clear(sock->outbuf);
827     return;
828   }
829
830   /* Packet receiving */
831   if (type == SILC_TASK_READ) {
832     /* Read data from network */
833     ret = silc_packet_receive(sock);
834     if (ret < 0)
835       return;
836
837     /* EOF */
838     if (ret == 0) {
839       SILC_LOG_DEBUG(("Read EOF"));
840
841       /* If connection is disconnecting already we will finally
842          close the connection */
843       if (SILC_IS_DISCONNECTING(sock)) {
844         if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
845           client->internal->ops->disconnected(client, conn, 0, NULL);
846         silc_client_close_connection_real(client, sock, conn);
847         return;
848       }
849
850       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
851       if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
852         client->internal->ops->disconnected(client, conn, 0, NULL);
853       silc_client_close_connection_real(client, sock, conn);
854       return;
855     }
856
857     /* Process the packet. This will call the parser that will then
858        decrypt and parse the packet. */
859     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
860       silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
861                                   conn->internal->hmac_receive,
862                                   conn->internal->psn_receive,
863                                   silc_client_packet_parse, client);
864     else
865       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
866                                   silc_client_packet_parse, client);
867   }
868 }
869
870 /* Parser callback called by silc_packet_receive_process. Thie merely
871    registers timeout that will handle the actual parsing when appropriate. */
872
873 static SilcBool silc_client_packet_parse(SilcPacketParserContext *parser_context,
874                                      void *context)
875 {
876   SilcClient client = (SilcClient)context;
877   SilcClientConnection conn = parser_context->sock;
878   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
879   SilcPacketContext *packet = parser_context->packet;
880   SilcPacketType ret;
881
882   if (conn && conn->internal->hmac_receive && conn->sock == sock)
883     conn->internal->psn_receive = parser_context->packet->sequence + 1;
884
885   /* Parse the packet immediately */
886   if (parser_context->normal)
887     ret = silc_packet_parse(packet, conn->internal->receive_key);
888   else
889     ret = silc_packet_parse_special(packet, conn->internal->receive_key);
890
891   if (ret == SILC_PACKET_NONE) {
892     silc_packet_context_free(packet);
893     silc_free(parser_context);
894     return FALSE;
895   }
896
897   /* If protocol for this connection is key exchange or rekey then we'll
898      process all packets synchronously, since there might be packets in
899      queue that we are not able to decrypt without first processing the
900      packets before them. */
901   if (sock->protocol && sock->protocol->protocol &&
902       (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
903        sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
904
905     /* Parse the incoming packet type */
906     silc_client_packet_parse_type(client, sock, packet);
907
908     /* Reprocess the buffer since we'll return FALSE. This is because
909        the `conn->internal->receive_key' might have become valid by processing
910        the previous packet */
911     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
912       silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
913                                   conn->internal->hmac_receive,
914                                   conn->internal->psn_receive,
915                                   silc_client_packet_parse, client);
916     else
917       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
918                                   silc_client_packet_parse, client);
919
920     silc_packet_context_free(packet);
921     silc_free(parser_context);
922
923     return FALSE;
924   }
925
926   /* Parse the incoming packet type */
927   silc_client_packet_parse_type(client, sock, packet);
928   silc_packet_context_free(packet);
929   silc_free(parser_context);
930   return TRUE;
931 }
932 #endif /* 0 */
933
934 /* Closes connection to remote end. Free's all allocated data except
935    for some information such as nickname etc. that are valid at all time.
936    If the `sock' is NULL then the conn->sock will be used.  If `sock' is
937    provided it will be checked whether the sock and `conn->sock' are the
938    same (they can be different, ie. a socket can use `conn' as its
939    connection but `conn->sock' might be actually a different connection
940    than the `sock'). */
941
942 #if 0
943 void silc_client_close_connection_real(SilcClient client,
944                                        SilcClientConnection conn)
945 {
946   int del = FALSE;
947
948   SILC_LOG_DEBUG(("Start"));
949
950   if (!sock && !conn)
951     return;
952
953   if (!sock || (sock && conn->sock == sock))
954     del = TRUE;
955   if (!sock)
956     sock = conn->sock;
957
958   if (!sock) {
959     if (del && conn)
960       silc_client_del_connection(client, conn);
961     return;
962   }
963
964   /* We won't listen for this connection anymore */
965   silc_schedule_unset_listen_fd(client->schedule, sock->sock);
966
967   /* Unregister all tasks */
968   silc_schedule_task_del_by_fd(client->schedule, sock->sock);
969
970   /* Close the actual connection */
971   silc_net_close_connection(sock->sock);
972
973   /* Cancel any active protocol */
974   if (sock->protocol) {
975     if (sock->protocol->protocol->type ==
976         SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
977         sock->protocol->protocol->type ==
978         SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
979       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
980       silc_protocol_execute_final(sock->protocol, client->schedule);
981       /* The application will recall this function with these protocols
982          (the ops->connected client operation). */
983       return;
984     } else {
985       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
986       silc_protocol_execute_final(sock->protocol, client->schedule);
987       sock->protocol = NULL;
988     }
989   }
990
991   /* Free everything */
992   if (del && sock->user_data)
993     silc_client_del_connection(client, conn);
994
995   silc_socket_free(sock);
996 }
997
998 /* Closes the connection to the remote end */
999
1000 void silc_client_close_connection(SilcClient client,
1001                                   SilcClientConnection conn)
1002 {
1003   //  silc_client_close_connection_real(client, NULL, conn);
1004 }
1005
1006 /* Called when we receive disconnection packet from server. This
1007    closes our end properly and displays the reason of the disconnection
1008    on the screen. */
1009
1010 void silc_client_disconnect(SilcClient client,
1011                             SilcClientConnection conn,
1012                             SilcBuffer packet)
1013 {
1014   SilcClientConnection conn;
1015   SilcStatus status;
1016   char *message = NULL;
1017
1018   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1019
1020   if (packet->len < 1)
1021     return;
1022
1023   status = (SilcStatus)packet->data[0];
1024
1025   if (packet->len > 1 &&
1026       silc_utf8_valid(packet->data + 1, packet->len - 1))
1027     message = silc_memdup(packet->data + 1, packet->len - 1);
1028
1029   conn = (SilcClientConnection)sock->user_data;
1030   if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1031     client->internal->ops->disconnected(client, conn, status, message);
1032
1033   silc_free(message);
1034
1035   SILC_SET_DISCONNECTED(sock);
1036
1037   /* Close connection through scheduler. */
1038   silc_schedule_task_add(client->schedule, sock->sock,
1039                          silc_client_disconnected_by_server_later,
1040                          client, 0, 1, SILC_TASK_TIMEOUT,
1041                          SILC_TASK_PRI_NORMAL);
1042 }
1043
1044 /* Received error message from server. Display it on the screen.
1045    We don't take any action what so ever of the error message. */
1046
1047 void silc_client_error_by_server(SilcClient client,
1048                                  SilcClientConnection conn,
1049                                  SilcBuffer message)
1050 {
1051   char *msg;
1052
1053   msg = silc_memdup(message->data, message->len);
1054   client->internal->ops->say(client, sock->user_data,
1055                              SILC_CLIENT_MESSAGE_AUDIT, msg);
1056   silc_free(msg);
1057 }
1058
1059 /* Auto-nicking callback to send NICK command to server. */
1060
1061 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1062 {
1063   SilcClientConnection conn = (SilcClientConnection)context;
1064   SilcClient client = conn->client;
1065   if (client)
1066     silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1067                              ++conn->cmd_ident, 1, 1,
1068                              client->nickname, strlen(client->nickname));
1069 }
1070
1071 /* Client session resuming callback.  If the session was resumed
1072    this callback is called after the resuming is completed.  This
1073    will call the `connect' client operation to the application
1074    since it has not been called yet. */
1075
1076 static void silc_client_resume_session_cb(SilcClient client,
1077                                           SilcClientConnection conn,
1078                                           SilcBool success,
1079                                           void *context)
1080 {
1081   SilcBuffer sidp;
1082
1083   /* Notify application that connection is created to server */
1084   client->internal->ops->connected(client, conn, success ?
1085                                    SILC_CLIENT_CONN_SUCCESS_RESUME :
1086                                    SILC_CLIENT_CONN_ERROR_RESUME);
1087
1088   if (success) {
1089     /* Issue INFO command to fetch the real server name and server
1090        information and other stuff. */
1091     silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1092                                  silc_client_command_reply_info_i, 0,
1093                                  ++conn->cmd_ident);
1094     sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1095     silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1096                              conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1097     silc_buffer_free(sidp);
1098   }
1099 }
1100
1101 /* Removes a client entry from all channels it has joined. */
1102
1103 void silc_client_remove_from_channels(SilcClient client,
1104                                       SilcClientConnection conn,
1105                                       SilcClientEntry client_entry)
1106 {
1107   SilcHashTableList htl;
1108   SilcChannelUser chu;
1109
1110   silc_hash_table_list(client_entry->channels, &htl);
1111   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1112     silc_hash_table_del(chu->client->channels, chu->channel);
1113     silc_hash_table_del(chu->channel->user_list, chu->client);
1114     silc_free(chu);
1115   }
1116
1117   silc_hash_table_list_reset(&htl);
1118 }
1119
1120 /* Replaces `old' client entries from all channels to `new' client entry.
1121    This can be called for example when nickname changes and old ID entry
1122    is replaced from ID cache with the new one. If the old ID entry is only
1123    updated, then this fucntion needs not to be called. */
1124
1125 void silc_client_replace_from_channels(SilcClient client,
1126                                        SilcClientConnection conn,
1127                                        SilcClientEntry old,
1128                                        SilcClientEntry new)
1129 {
1130   SilcHashTableList htl;
1131   SilcChannelUser chu;
1132
1133   silc_hash_table_list(old->channels, &htl);
1134   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1135     /* Replace client entry */
1136     silc_hash_table_del(chu->client->channels, chu->channel);
1137     silc_hash_table_del(chu->channel->user_list, chu->client);
1138
1139     chu->client = new;
1140     silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1141     silc_hash_table_add(chu->client->channels, chu->channel, chu);
1142   }
1143   silc_hash_table_list_reset(&htl);
1144 }
1145
1146 /* Registers failure timeout to process the received failure packet
1147    with timeout. */
1148
1149 void silc_client_process_failure(SilcClient client,
1150                                  SilcClientConnection conn,
1151                                  SilcPacketContext *packet)
1152 {
1153   SilcUInt32 failure = 0;
1154
1155   if (sock->protocol) {
1156     if (packet->buffer->len >= 4)
1157       SILC_GET32_MSB(failure, packet->buffer->data);
1158
1159     /* Notify application */
1160     client->internal->ops->failure(client, sock->user_data, sock->protocol,
1161                                    SILC_32_TO_PTR(failure));
1162   }
1163 }
1164
1165 /* A timeout callback for the re-key. We will be the initiator of the
1166    re-key protocol. */
1167
1168 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
1169 {
1170   SilcClientConnection conn = (SilcSocketConnection)context;
1171   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1172   SilcClient client = (SilcClient)conn->internal->rekey->context;
1173   SilcProtocol protocol;
1174   SilcClientRekeyInternalContext *proto_ctx;
1175
1176   SILC_LOG_DEBUG(("Start"));
1177
1178   /* If rekey protocol is active already wait for it to finish */
1179   if (sock->protocol && sock->protocol->protocol &&
1180       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
1181     return;
1182
1183   /* Allocate internal protocol context. This is sent as context
1184      to the protocol. */
1185   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1186   proto_ctx->client = (void *)client;
1187   proto_ctx->sock = silc_socket_dup(sock);
1188   proto_ctx->responder = FALSE;
1189   proto_ctx->pfs = conn->internal->rekey->pfs;
1190
1191   /* Perform rekey protocol. Will call the final callback after the
1192      protocol is over. */
1193   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1194                       &protocol, proto_ctx, silc_client_rekey_final);
1195   sock->protocol = protocol;
1196
1197   /* Run the protocol */
1198   silc_protocol_execute(protocol, client->schedule, 0, 0);
1199 }
1200
1201 /* The final callback for the REKEY protocol. This will actually take the
1202    new key material into use. */
1203
1204 SILC_TASK_CALLBACK(silc_client_rekey_final)
1205 {
1206   SilcProtocol protocol = (SilcProtocol)context;
1207   SilcClientRekeyInternalContext *ctx =
1208     (SilcClientRekeyInternalContext *)protocol->context;
1209   SilcClient client = (SilcClient)ctx->client;
1210   SilcClientConnection conn = ctx->sock;
1211   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1212
1213   SILC_LOG_DEBUG(("Start"));
1214
1215   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1216       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1217     /* Error occured during protocol */
1218     silc_protocol_cancel(protocol, client->schedule);
1219     silc_protocol_free(protocol);
1220     sock->protocol = NULL;
1221     if (ctx->packet)
1222       silc_packet_context_free(ctx->packet);
1223     if (ctx->ske)
1224       silc_ske_free(ctx->ske);
1225     silc_socket_free(ctx->sock);
1226     silc_free(ctx);
1227     return;
1228   }
1229
1230   /* Purge the outgoing data queue to assure that all rekey packets really
1231      go to the network before we quit the protocol. */
1232   silc_client_packet_queue_purge(client, sock);
1233
1234   /* Re-register re-key timeout */
1235   if (ctx->responder == FALSE)
1236     silc_schedule_task_add(client->schedule, sock->sock,
1237                            silc_client_rekey_callback,
1238                            sock, conn->internal->rekey->timeout, 0,
1239                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1240
1241   /* Cleanup */
1242   silc_protocol_free(protocol);
1243   sock->protocol = NULL;
1244   if (ctx->packet)
1245     silc_packet_context_free(ctx->packet);
1246   if (ctx->ske)
1247     silc_ske_free(ctx->ske);
1248   silc_socket_free(ctx->sock);
1249   silc_free(ctx);
1250 }
1251
1252 /* Processes incoming connection authentication method request packet.
1253    It is a reply to our previously sent request. The packet can be used
1254    to resolve the authentication method for the current session if the
1255    client does not know it beforehand. */
1256
1257 void silc_client_connection_auth_request(SilcClient client,
1258                                          SilcClientConnection conn,
1259                                          SilcPacketContext *packet)
1260 {
1261   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1262   SilcUInt16 conn_type, auth_meth;
1263   int ret;
1264
1265   /* If we haven't send our request then ignore this one. */
1266   if (!conn->internal->connauth)
1267     return;
1268
1269   /* Parse the payload */
1270   ret = silc_buffer_unformat(packet->buffer,
1271                              SILC_STR_UI_SHORT(&conn_type),
1272                              SILC_STR_UI_SHORT(&auth_meth),
1273                              SILC_STR_END);
1274   if (ret == -1)
1275     auth_meth = SILC_AUTH_NONE;
1276
1277   /* Call the request callback to notify application for received
1278      authentication method information. */
1279   if (conn->internal->connauth->callback)
1280     (*conn->internal->connauth->callback)(client, conn, auth_meth,
1281                                           conn->internal->connauth->context);
1282
1283   silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1284
1285   silc_free(conn->internal->connauth);
1286   conn->internal->connauth = NULL;
1287 }
1288
1289 /* Timeout task callback called if the server does not reply to our
1290    connection authentication method request in the specified time interval. */
1291
1292 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1293 {
1294   SilcClientConnection conn = (SilcClientConnection)context;
1295   SilcClient client = conn->client;
1296
1297   if (!conn->internal->connauth)
1298     return;
1299
1300   /* Call the request callback to notify application */
1301   if (conn->internal->connauth->callback)
1302     (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1303                                           conn->internal->connauth->context);
1304
1305   silc_free(conn->internal->connauth);
1306   conn->internal->connauth = NULL;
1307 }
1308
1309 /* This function can be used to request the current authentication method
1310    from the server. This may be called when connecting to the server
1311    and the client library requests the authentication data from the
1312    application. If the application does not know the current authentication
1313    method it can request it from the server using this function.
1314    The `callback' with `context' will be called after the server has
1315    replied back with the current authentication method. */
1316
1317 void
1318 silc_client_request_authentication_method(SilcClient client,
1319                                           SilcClientConnection conn,
1320                                           SilcConnectionAuthRequest callback,
1321                                           void *context)
1322 {
1323   SilcClientConnAuthRequest connauth;
1324   SilcBuffer packet;
1325
1326   assert(client && conn);
1327   connauth = silc_calloc(1, sizeof(*connauth));
1328   connauth->callback = callback;
1329   connauth->context = context;
1330
1331   if (conn->internal->connauth)
1332     silc_free(conn->internal->connauth);
1333
1334   conn->internal->connauth = connauth;
1335
1336   /* Assemble the request packet and send it to the server */
1337   packet = silc_buffer_alloc(4);
1338   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1339   silc_buffer_format(packet,
1340                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1341                      SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1342                      SILC_STR_END);
1343   silc_client_packet_send(client, conn->sock,
1344                           SILC_PACKET_CONNECTION_AUTH_REQUEST,
1345                           NULL, 0, NULL, NULL,
1346                           packet->data, packet->len, FALSE);
1347   silc_buffer_free(packet);
1348
1349   /* Register a timeout in case server does not reply anything back. */
1350   connauth->timeout =
1351     silc_schedule_task_add(client->schedule, conn->sock->sock,
1352                            silc_client_request_authentication_method_timeout,
1353                            conn,
1354                            client->internal->params->connauth_request_secs, 0,
1355                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1356 }
1357 #endif /* 0 */
1358
1359
1360 /******************************* Client API *********************************/
1361
1362 /* Allocates new client object. This has to be done before client may
1363    work. After calling this one must call silc_client_init to initialize
1364    the client. The `application' is application specific user data pointer
1365    and caller must free it. */
1366
1367 SilcClient silc_client_alloc(SilcClientOperations *ops,
1368                              SilcClientParams *params,
1369                              void *application,
1370                              const char *version_string)
1371 {
1372   SilcClient new_client;
1373
1374   new_client = silc_calloc(1, sizeof(*new_client));
1375   new_client->application = application;
1376
1377   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
1378   new_client->internal->ops = ops;
1379   new_client->internal->params =
1380     silc_calloc(1, sizeof(*new_client->internal->params));
1381   if (!version_string)
1382     version_string = silc_version_string;
1383   new_client->internal->silc_client_version = strdup(version_string);
1384
1385   if (params)
1386     memcpy(new_client->internal->params, params, sizeof(*params));
1387
1388   if (!new_client->internal->params->task_max)
1389     new_client->internal->params->task_max = 200;
1390
1391   if (!new_client->internal->params->rekey_secs)
1392     new_client->internal->params->rekey_secs = 3600;
1393
1394   if (!new_client->internal->params->connauth_request_secs)
1395     new_client->internal->params->connauth_request_secs = 2;
1396
1397   new_client->internal->params->
1398     nickname_format[sizeof(new_client->internal->
1399                            params->nickname_format) - 1] = 0;
1400
1401   return new_client;
1402 }
1403
1404 /* Frees client object and its internals. */
1405
1406 void silc_client_free(SilcClient client)
1407 {
1408   if (client) {
1409     if (client->rng)
1410       silc_rng_free(client->rng);
1411
1412     if (!client->internal->params->dont_register_crypto_library) {
1413       silc_cipher_unregister_all();
1414       silc_pkcs_unregister_all();
1415       silc_hash_unregister_all();
1416       silc_hmac_unregister_all();
1417     }
1418
1419     silc_hash_free(client->md5hash);
1420     silc_hash_free(client->sha1hash);
1421     silc_hmac_free(client->internal->md5hmac);
1422     silc_hmac_free(client->internal->sha1hmac);
1423     silc_free(client->internal->params);
1424     silc_free(client->internal->silc_client_version);
1425     silc_free(client->internal);
1426     silc_free(client);
1427   }
1428 }
1429
1430 /* Initializes the client. This makes all the necessary steps to make
1431    the client ready to be run. One must call silc_client_run to run the
1432    client. Returns FALSE if error occured, TRUE otherwise. */
1433
1434 SilcBool silc_client_init(SilcClient client)
1435 {
1436   SILC_LOG_DEBUG(("Initializing client"));
1437
1438   assert(client);
1439   assert(client->username);
1440   assert(client->hostname);
1441   assert(client->realname);
1442
1443   /* Validate essential strings */
1444   if (client->nickname)
1445     if (!silc_identifier_verify(client->nickname, strlen(client->nickname),
1446                                 SILC_STRING_UTF8, 128)) {
1447       SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname));
1448       return FALSE;
1449     }
1450   if (!silc_identifier_verify(client->username, strlen(client->username),
1451                               SILC_STRING_UTF8, 128)) {
1452     SILC_LOG_ERROR(("Malformed username '%s'", client->username));
1453     return FALSE;
1454   }
1455   if (!silc_identifier_verify(client->hostname, strlen(client->hostname),
1456                               SILC_STRING_UTF8, 256)) {
1457     SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname));
1458     return FALSE;
1459   }
1460   if (!silc_utf8_valid(client->realname, strlen(client->realname))) {
1461     SILC_LOG_ERROR(("Malformed realname '%s'", client->realname));
1462     return FALSE;
1463   }
1464
1465   if (!client->internal->params->dont_register_crypto_library) {
1466     /* Initialize the crypto library.  If application has done this already
1467        this has no effect.  Also, we will not be overriding something
1468        application might have registered earlier. */
1469     silc_cipher_register_default();
1470     silc_pkcs_register_default();
1471     silc_hash_register_default();
1472     silc_hmac_register_default();
1473   }
1474
1475   /* Initialize hash functions for client to use */
1476   silc_hash_alloc("md5", &client->md5hash);
1477   silc_hash_alloc("sha1", &client->sha1hash);
1478
1479   /* Initialize random number generator */
1480   client->rng = silc_rng_alloc();
1481   silc_rng_init(client->rng);
1482   silc_rng_global_init(client->rng);
1483
1484   /* Initialize the scheduler */
1485   client->schedule =
1486     silc_schedule_init(client->internal->params->task_max ?
1487                        client->internal->params->task_max : 200, client);
1488   if (!client->schedule)
1489     return FALSE;
1490
1491   /* Start packet engine */
1492   client->internal->packet_engine =
1493     silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
1494                              client);
1495   if (!client->internal->packet_engine)
1496     return FALSE;
1497
1498   /* Initialize FSM */
1499   if (!silc_fsm_init(&client->internal->fsm, client, NULL, NULL,
1500                      client->schedule))
1501     return FALSE;
1502   silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
1503
1504   /* Allocate client lock */
1505   silc_mutex_alloc(&client->internal->lock);
1506
1507   /* Register commands */
1508   silc_client_commands_register(client);
1509
1510   return TRUE;
1511 }
1512
1513 /* Stops the client. This is called to stop the client and thus to stop
1514    the program. */
1515
1516 void silc_client_stop(SilcClient client)
1517 {
1518   SILC_LOG_DEBUG(("Stopping client"));
1519
1520   silc_schedule_stop(client->schedule);
1521   silc_schedule_uninit(client->schedule);
1522
1523   silc_client_commands_unregister(client);
1524
1525   SILC_LOG_DEBUG(("Client stopped"));
1526 }
1527
1528 /* Starts the SILC client FSM machine and blocks here.  When this returns
1529    the client has ended. */
1530
1531 void silc_client_run(SilcClient client)
1532 {
1533   SILC_LOG_DEBUG(("Starting SILC client"));
1534
1535   /* Start the client */
1536   silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
1537
1538   /* Signal the application when we are running */
1539   client->internal->run_callback = TRUE;
1540   SILC_FSM_SEMA_POST(&client->internal->wait_event);
1541
1542   /* Run the scheduler */
1543   silc_schedule(client->schedule);
1544 }
1545
1546 /* Call scheduler one iteration and return.  This cannot be called if threads
1547    are in use. */
1548
1549 void silc_client_run_one(SilcClient client)
1550 {
1551   silc_schedule_one(client->schedule, -1);
1552 }