Initial client library rewrite, connects to remote server already.
[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   SilcClient client = callback_context;
42   SilcClientConnection conn = stream_context;
43
44   /* Packets we do not handle */
45   switch (packet->type) {
46   case SILC_PACKET_HEARTBEAT:
47   case SILC_PACKET_SUCCESS:
48   case SILC_PACKET_FAILURE:
49   case SILC_PACKET_REJECT:
50   case SILC_PACKET_KEY_EXCHANGE:
51   case SILC_PACKET_KEY_EXCHANGE_1:
52   case SILC_PACKET_KEY_EXCHANGE_2:
53   case SILC_PACKET_REKEY:
54   case SILC_PACKET_REKEY_DONE:
55   case SILC_PACKET_CONNECTION_AUTH:
56   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
57     return FALSE;
58     break;
59   }
60
61   /* Signal packet processor thread for a new packet */
62   conn->internal->new_packet = TRUE;
63   silc_fsm_set_state_context(&conn->internal->packet_thread, packet);
64   silc_fsm_continue_sync(&conn->internal->packet_thread);
65
66   return TRUE;
67 }
68
69 /* Packet engine callback to indicate end of stream */
70
71 static void silc_client_packet_eos(SilcPacketEngine engine,
72                                    SilcPacketStream stream,
73                                    void *callback_context,
74                                    void *stream_context)
75 {
76   SILC_LOG_DEBUG(("End of stream received"));
77 }
78
79 /* Packet engine callback to indicate error */
80
81 static void silc_client_packet_error(SilcPacketEngine engine,
82                                      SilcPacketStream stream,
83                                      SilcPacketError error,
84                                      void *callback_context,
85                                      void *stream_context)
86 {
87
88 }
89
90 /* Packet stream callbacks */
91 static SilcPacketCallbacks silc_client_stream_cbs =
92 {
93   silc_client_packet_receive,
94   silc_client_packet_eos,
95   silc_client_packet_error
96 };
97
98 /* FSM destructor */
99
100 void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
101                                 void *destructor_context)
102 {
103   silc_fsm_free(fsm);
104 }
105
106
107 /************************** Connection's machine ****************************/
108
109 /* Start the connection's state machine.  If threads are in use the machine
110    is always executed in a real thread. */
111
112 SILC_FSM_STATE(silc_client_connection_st_start)
113 {
114   SilcClientConnection conn = fsm_context;
115
116   /* Take scheduler for connection */
117   conn->internal->schedule = silc_fsm_get_schedule(fsm);
118
119   /*** Run connection machine */
120   silc_fsm_init(&conn->internal->fsm, conn, NULL, NULL,
121                 conn->internal->schedule);
122   silc_fsm_sema_init(&conn->internal->wait_event, &conn->internal->fsm, 0);
123   silc_fsm_start_sync(&conn->internal->fsm, silc_client_connection_st_run);
124
125   /*** Run packet processor FSM thread */
126   silc_fsm_thread_init(&conn->internal->packet_thread, &conn->internal->fsm,
127                        conn, silc_client_fsm_destructor, NULL, FALSE);
128   silc_fsm_start_sync(&conn->internal->packet_thread,
129                       silc_client_connection_st_packet);
130
131   /* Schedule any events set in initialization */
132   if (conn->internal->connect)
133     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
134   if (conn->internal->key_exchange)
135     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
136
137   /* Wait until this thread is terminated */
138   return SILC_FSM_WAIT;
139 }
140
141 /* Connection machine main state. */
142
143 SILC_FSM_STATE(silc_client_connection_st_run)
144 {
145   SilcClientConnection conn = fsm_context;
146
147   /* Wait for events */
148   SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
149
150   /* Process events */
151
152   if (conn->internal->connect) {
153     SILC_LOG_DEBUG(("Event: connect"));
154     conn->internal->connect = FALSE;
155
156     /** Connect remote host */
157     silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
158                          conn, NULL, NULL, FALSE);
159     silc_fsm_start_sync(&conn->internal->event_thread, silc_client_st_connect);
160     return SILC_FSM_CONTINUE;
161   }
162
163   if (conn->internal->key_exchange) {
164     SILC_LOG_DEBUG(("Event: key exchange"));
165     conn->internal->key_exchange = FALSE;
166
167     /** Start key exchange */
168     silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
169                          conn, NULL, NULL, FALSE);
170     silc_fsm_start_sync(&conn->internal->event_thread,
171                         silc_client_st_connect_key_exchange);
172     return SILC_FSM_CONTINUE;
173   }
174
175   if (conn->internal->disconnected) {
176     SILC_LOG_DEBUG(("Event: disconnected"));
177     conn->internal->disconnected = FALSE;
178
179     return SILC_FSM_CONTINUE;
180   }
181
182   /* NOT REACHED */
183 #if defined(SILC_DEBUG)
184   assert(FALSE);
185 #endif /* SILC_DEBUG */
186   return SILC_FSM_CONTINUE;
187 }
188
189 /* Connection's packet processor main state.  Packet processor thread waits
190    here for a new packet and processes received packets. */
191
192 SILC_FSM_STATE(silc_client_connection_st_packet)
193 {
194   SilcClientConnection conn = fsm_context;
195   SilcClient client = conn->client;
196   SilcPacket packet = state_context;
197
198   /* Wait for packet to arrive */
199   if (!conn->internal->new_packet) {
200     SILC_LOG_DEBUG(("Wait for packet"));
201     return SILC_FSM_WAIT;
202   }
203   conn->internal->new_packet = FALSE;
204
205   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
206
207   switch (packet->type) {
208
209   case SILC_PACKET_PRIVATE_MESSAGE:
210     /** Private message */
211     silc_fsm_next(fsm, silc_client_private_message);
212     break;
213
214   case SILC_PACKET_CHANNEL_MESSAGE:
215     /* Channel message */
216     //    silc_client_channel_message(client, conn, packet);
217     break;
218
219   case SILC_PACKET_FTP:
220     /* File transfer packet */
221     //    silc_client_ftp(client, conn, packet);
222     break;
223
224   case SILC_PACKET_CHANNEL_KEY:
225     /* Received channel key */
226     //    silc_client_channel_key(client, conn, packet);
227     break;
228
229   case SILC_PACKET_COMMAND_REPLY:
230     /** Command reply */
231     silc_fsm_next(fsm, silc_client_command_reply);
232     break;
233
234   case SILC_PACKET_NOTIFY:
235     /* Notify */
236     //    silc_client_notify(client, conn, packet);
237     break;
238
239   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
240     /* Private message key indicator */
241     //    silc_client_private_message_key(client, conn, packet);
242     break;
243
244   case SILC_PACKET_DISCONNECT:
245     /* Server disconnects */
246     //    silc_client_disconnect(client, conn, packet);
247     break;
248
249   case SILC_PACKET_ERROR:
250     /* Error by server */
251     //    silc_client_error(client, conn, packet);
252     break;
253
254   case SILC_PACKET_KEY_AGREEMENT:
255     /* Key agreement */
256     //    silc_client_key_agreement(client, conn, packet);
257     break;
258
259   case SILC_PACKET_COMMAND:
260     /** Command packet */
261     silc_fsm_next(fsm, silc_client_command);
262     break;
263
264   case SILC_PACKET_NEW_ID:
265     /** New ID */
266     silc_fsm_next(fsm, silc_client_new_id);
267
268   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
269     /* Reply to connection authentication request to resolve authentication
270        method from server. */
271     //    silc_client_connection_auth_request(client, conn, packet);
272     break;
273
274   default:
275     silc_packet_free(packet);
276     break;
277   }
278
279   return SILC_FSM_CONTINUE;
280 }
281
282
283 /*************************** Main client machine ****************************/
284
285 /* The client's main state where we wait for various events */
286
287 SILC_FSM_STATE(silc_client_st_run)
288 {
289   SilcClient client = fsm_context;
290
291   /* Wait for events */
292   SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
293
294   /* Process events */
295
296   if (client->internal->run_callback && client->internal->ops->running) {
297     /* Call running callbcak back to application */
298     client->internal->run_callback = FALSE;
299     client->internal->ops->running(client, client->application);
300     return SILC_FSM_CONTINUE;
301   }
302
303   /* NOT REACHED */
304 #if defined(SILC_DEBUG)
305   assert(FALSE);
306 #endif /* SILC_DEBUG */
307   return SILC_FSM_CONTINUE;
308 }
309
310
311 /**************************** Packet Processing *****************************/
312
313 /* Received new ID from server during registering to SILC network */
314
315 SILC_FSM_STATE(silc_client_new_id)
316 {
317   SilcClientConnection conn = fsm_context;
318   SilcClient client = conn->client;
319   SilcPacket packet = state_context;
320   SilcID id;
321
322   if (conn->local_id)
323     goto out;
324
325   SILC_LOG_DEBUG(("New ID received from server"));
326
327   if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
328                                 silc_buffer_len(&packet->buffer), &id))
329     goto out;
330
331   /* Create local client entry */
332   conn->local_entry = silc_client_add_client(client, conn, (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 /* Processes the received new Client ID from server. Old Client ID is
1102    deleted from cache and new one is added. */
1103
1104 void silc_client_receive_new_id(SilcClient client,
1105                                 SilcClientConnection conn,
1106                                 SilcIDPayload idp)
1107 {
1108   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1109   int connecting = FALSE;
1110   SilcClientID *client_id = silc_id_payload_get_id(idp);
1111   char *nickname;
1112
1113   if (!conn->local_entry)
1114     connecting = TRUE;
1115
1116   /* Delete old ID from ID cache */
1117   if (conn->local_id) {
1118     /* Check whether they are different */
1119     if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1120       silc_free(client_id);
1121       return;
1122     }
1123
1124     silc_idcache_del_by_context(conn->internal->client_cache,
1125                                 conn->local_entry);
1126     silc_free(conn->local_id);
1127   }
1128
1129   /* Save the new ID */
1130
1131   if (conn->local_id_data)
1132     silc_free(conn->local_id_data);
1133
1134   conn->local_id = client_id;
1135   conn->local_id_data = silc_id_payload_get_data(idp);
1136   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1137
1138   if (!conn->local_entry)
1139     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1140
1141   conn->local_entry->nickname = conn->nickname;
1142   if (!conn->local_entry->username)
1143     conn->local_entry->username = strdup(client->username);
1144   if (!conn->local_entry->server)
1145     conn->local_entry->server = strdup(conn->remote_host);
1146   conn->local_entry->id = conn->local_id;
1147   conn->local_entry->valid = TRUE;
1148   if (!conn->local_entry->channels)
1149     conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1150                                                         NULL, NULL,
1151                                                         NULL, NULL, NULL,
1152                                                         TRUE);
1153
1154   /* Normalize nickname */
1155   nickname = silc_identifier_check(conn->nickname, strlen(conn->nickname),
1156                                    SILC_STRING_UTF8, 128, NULL);
1157   if (!nickname)
1158     return;
1159
1160     /* Put it to the ID cache */
1161   silc_idcache_add(conn->internal->client_cache, nickname, conn->local_id,
1162                    (void *)conn->local_entry, 0, NULL);
1163
1164 #if 0
1165   if (connecting) {
1166     SilcBuffer sidp;
1167
1168     /* Issue IDENTIFY command for itself to get resolved hostname
1169        correctly from server. */
1170     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1171                                  silc_client_command_reply_identify_i, 0,
1172                                  ++conn->cmd_ident);
1173     sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1174     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1175                              conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1176     silc_buffer_free(sidp);
1177
1178     if (!conn->internal->params.detach_data) {
1179       /* Send NICK command if the nickname was set by the application (and is
1180          not same as the username). Send this with little timeout. */
1181       if (client->nickname &&
1182           !silc_utf8_strcasecmp(client->nickname, client->username))
1183         silc_schedule_task_add(client->schedule, 0,
1184                                silc_client_send_auto_nick, conn,
1185                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1186
1187       /* Notify application of successful connection. We do it here now that
1188          we've received the Client ID and are allowed to send traffic. */
1189       client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1190
1191       /* Issue INFO command to fetch the real server name and server
1192          information and other stuff. */
1193       silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1194                                    silc_client_command_reply_info_i, 0,
1195                                    ++conn->cmd_ident);
1196       sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1197       silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1198                                conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1199       silc_buffer_free(sidp);
1200     } else {
1201       /* We are resuming session.  Start resolving informations from the
1202          server we need to set the client libary in the state before
1203          detaching the session.  The connect client operation is called
1204          after this is successfully completed */
1205       silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1206                                  NULL);
1207     }
1208   }
1209 #endif /* 0 */
1210 }
1211
1212 /* Removes a client entry from all channels it has joined. */
1213
1214 void silc_client_remove_from_channels(SilcClient client,
1215                                       SilcClientConnection conn,
1216                                       SilcClientEntry client_entry)
1217 {
1218   SilcHashTableList htl;
1219   SilcChannelUser chu;
1220
1221   silc_hash_table_list(client_entry->channels, &htl);
1222   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1223     silc_hash_table_del(chu->client->channels, chu->channel);
1224     silc_hash_table_del(chu->channel->user_list, chu->client);
1225     silc_free(chu);
1226   }
1227
1228   silc_hash_table_list_reset(&htl);
1229 }
1230
1231 /* Replaces `old' client entries from all channels to `new' client entry.
1232    This can be called for example when nickname changes and old ID entry
1233    is replaced from ID cache with the new one. If the old ID entry is only
1234    updated, then this fucntion needs not to be called. */
1235
1236 void silc_client_replace_from_channels(SilcClient client,
1237                                        SilcClientConnection conn,
1238                                        SilcClientEntry old,
1239                                        SilcClientEntry new)
1240 {
1241   SilcHashTableList htl;
1242   SilcChannelUser chu;
1243
1244   silc_hash_table_list(old->channels, &htl);
1245   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1246     /* Replace client entry */
1247     silc_hash_table_del(chu->client->channels, chu->channel);
1248     silc_hash_table_del(chu->channel->user_list, chu->client);
1249
1250     chu->client = new;
1251     silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1252     silc_hash_table_add(chu->client->channels, chu->channel, chu);
1253   }
1254   silc_hash_table_list_reset(&htl);
1255 }
1256
1257 /* Registers failure timeout to process the received failure packet
1258    with timeout. */
1259
1260 void silc_client_process_failure(SilcClient client,
1261                                  SilcClientConnection conn,
1262                                  SilcPacketContext *packet)
1263 {
1264   SilcUInt32 failure = 0;
1265
1266   if (sock->protocol) {
1267     if (packet->buffer->len >= 4)
1268       SILC_GET32_MSB(failure, packet->buffer->data);
1269
1270     /* Notify application */
1271     client->internal->ops->failure(client, sock->user_data, sock->protocol,
1272                                    SILC_32_TO_PTR(failure));
1273   }
1274 }
1275
1276 /* A timeout callback for the re-key. We will be the initiator of the
1277    re-key protocol. */
1278
1279 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
1280 {
1281   SilcClientConnection conn = (SilcSocketConnection)context;
1282   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1283   SilcClient client = (SilcClient)conn->internal->rekey->context;
1284   SilcProtocol protocol;
1285   SilcClientRekeyInternalContext *proto_ctx;
1286
1287   SILC_LOG_DEBUG(("Start"));
1288
1289   /* If rekey protocol is active already wait for it to finish */
1290   if (sock->protocol && sock->protocol->protocol &&
1291       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
1292     return;
1293
1294   /* Allocate internal protocol context. This is sent as context
1295      to the protocol. */
1296   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1297   proto_ctx->client = (void *)client;
1298   proto_ctx->sock = silc_socket_dup(sock);
1299   proto_ctx->responder = FALSE;
1300   proto_ctx->pfs = conn->internal->rekey->pfs;
1301
1302   /* Perform rekey protocol. Will call the final callback after the
1303      protocol is over. */
1304   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1305                       &protocol, proto_ctx, silc_client_rekey_final);
1306   sock->protocol = protocol;
1307
1308   /* Run the protocol */
1309   silc_protocol_execute(protocol, client->schedule, 0, 0);
1310 }
1311
1312 /* The final callback for the REKEY protocol. This will actually take the
1313    new key material into use. */
1314
1315 SILC_TASK_CALLBACK(silc_client_rekey_final)
1316 {
1317   SilcProtocol protocol = (SilcProtocol)context;
1318   SilcClientRekeyInternalContext *ctx =
1319     (SilcClientRekeyInternalContext *)protocol->context;
1320   SilcClient client = (SilcClient)ctx->client;
1321   SilcClientConnection conn = ctx->sock;
1322   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1323
1324   SILC_LOG_DEBUG(("Start"));
1325
1326   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1327       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1328     /* Error occured during protocol */
1329     silc_protocol_cancel(protocol, client->schedule);
1330     silc_protocol_free(protocol);
1331     sock->protocol = NULL;
1332     if (ctx->packet)
1333       silc_packet_context_free(ctx->packet);
1334     if (ctx->ske)
1335       silc_ske_free(ctx->ske);
1336     silc_socket_free(ctx->sock);
1337     silc_free(ctx);
1338     return;
1339   }
1340
1341   /* Purge the outgoing data queue to assure that all rekey packets really
1342      go to the network before we quit the protocol. */
1343   silc_client_packet_queue_purge(client, sock);
1344
1345   /* Re-register re-key timeout */
1346   if (ctx->responder == FALSE)
1347     silc_schedule_task_add(client->schedule, sock->sock,
1348                            silc_client_rekey_callback,
1349                            sock, conn->internal->rekey->timeout, 0,
1350                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1351
1352   /* Cleanup */
1353   silc_protocol_free(protocol);
1354   sock->protocol = NULL;
1355   if (ctx->packet)
1356     silc_packet_context_free(ctx->packet);
1357   if (ctx->ske)
1358     silc_ske_free(ctx->ske);
1359   silc_socket_free(ctx->sock);
1360   silc_free(ctx);
1361 }
1362
1363 /* Processes incoming connection authentication method request packet.
1364    It is a reply to our previously sent request. The packet can be used
1365    to resolve the authentication method for the current session if the
1366    client does not know it beforehand. */
1367
1368 void silc_client_connection_auth_request(SilcClient client,
1369                                          SilcClientConnection conn,
1370                                          SilcPacketContext *packet)
1371 {
1372   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1373   SilcUInt16 conn_type, auth_meth;
1374   int ret;
1375
1376   /* If we haven't send our request then ignore this one. */
1377   if (!conn->internal->connauth)
1378     return;
1379
1380   /* Parse the payload */
1381   ret = silc_buffer_unformat(packet->buffer,
1382                              SILC_STR_UI_SHORT(&conn_type),
1383                              SILC_STR_UI_SHORT(&auth_meth),
1384                              SILC_STR_END);
1385   if (ret == -1)
1386     auth_meth = SILC_AUTH_NONE;
1387
1388   /* Call the request callback to notify application for received
1389      authentication method information. */
1390   if (conn->internal->connauth->callback)
1391     (*conn->internal->connauth->callback)(client, conn, auth_meth,
1392                                           conn->internal->connauth->context);
1393
1394   silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1395
1396   silc_free(conn->internal->connauth);
1397   conn->internal->connauth = NULL;
1398 }
1399
1400 /* Timeout task callback called if the server does not reply to our
1401    connection authentication method request in the specified time interval. */
1402
1403 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1404 {
1405   SilcClientConnection conn = (SilcClientConnection)context;
1406   SilcClient client = conn->client;
1407
1408   if (!conn->internal->connauth)
1409     return;
1410
1411   /* Call the request callback to notify application */
1412   if (conn->internal->connauth->callback)
1413     (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1414                                           conn->internal->connauth->context);
1415
1416   silc_free(conn->internal->connauth);
1417   conn->internal->connauth = NULL;
1418 }
1419
1420 /* This function can be used to request the current authentication method
1421    from the server. This may be called when connecting to the server
1422    and the client library requests the authentication data from the
1423    application. If the application does not know the current authentication
1424    method it can request it from the server using this function.
1425    The `callback' with `context' will be called after the server has
1426    replied back with the current authentication method. */
1427
1428 void
1429 silc_client_request_authentication_method(SilcClient client,
1430                                           SilcClientConnection conn,
1431                                           SilcConnectionAuthRequest callback,
1432                                           void *context)
1433 {
1434   SilcClientConnAuthRequest connauth;
1435   SilcBuffer packet;
1436
1437   assert(client && conn);
1438   connauth = silc_calloc(1, sizeof(*connauth));
1439   connauth->callback = callback;
1440   connauth->context = context;
1441
1442   if (conn->internal->connauth)
1443     silc_free(conn->internal->connauth);
1444
1445   conn->internal->connauth = connauth;
1446
1447   /* Assemble the request packet and send it to the server */
1448   packet = silc_buffer_alloc(4);
1449   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1450   silc_buffer_format(packet,
1451                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1452                      SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1453                      SILC_STR_END);
1454   silc_client_packet_send(client, conn->sock,
1455                           SILC_PACKET_CONNECTION_AUTH_REQUEST,
1456                           NULL, 0, NULL, NULL,
1457                           packet->data, packet->len, FALSE);
1458   silc_buffer_free(packet);
1459
1460   /* Register a timeout in case server does not reply anything back. */
1461   connauth->timeout =
1462     silc_schedule_task_add(client->schedule, conn->sock->sock,
1463                            silc_client_request_authentication_method_timeout,
1464                            conn,
1465                            client->internal->params->connauth_request_secs, 0,
1466                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1467 }
1468 #endif /* 0 */
1469
1470
1471 /******************************* Client API *********************************/
1472
1473 /* Allocates new client object. This has to be done before client may
1474    work. After calling this one must call silc_client_init to initialize
1475    the client. The `application' is application specific user data pointer
1476    and caller must free it. */
1477
1478 SilcClient silc_client_alloc(SilcClientOperations *ops,
1479                              SilcClientParams *params,
1480                              void *application,
1481                              const char *version_string)
1482 {
1483   SilcClient new_client;
1484
1485   new_client = silc_calloc(1, sizeof(*new_client));
1486   new_client->application = application;
1487
1488   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
1489   new_client->internal->ops = ops;
1490   new_client->internal->params =
1491     silc_calloc(1, sizeof(*new_client->internal->params));
1492   if (!version_string)
1493     version_string = silc_version_string;
1494   new_client->internal->silc_client_version = strdup(version_string);
1495
1496   if (params)
1497     memcpy(new_client->internal->params, params, sizeof(*params));
1498
1499   if (!new_client->internal->params->task_max)
1500     new_client->internal->params->task_max = 200;
1501
1502   if (!new_client->internal->params->rekey_secs)
1503     new_client->internal->params->rekey_secs = 3600;
1504
1505   if (!new_client->internal->params->connauth_request_secs)
1506     new_client->internal->params->connauth_request_secs = 2;
1507
1508   new_client->internal->params->
1509     nickname_format[sizeof(new_client->internal->
1510                            params->nickname_format) - 1] = 0;
1511
1512   return new_client;
1513 }
1514
1515 /* Frees client object and its internals. */
1516
1517 void silc_client_free(SilcClient client)
1518 {
1519   if (client) {
1520     if (client->rng)
1521       silc_rng_free(client->rng);
1522
1523     if (!client->internal->params->dont_register_crypto_library) {
1524       silc_cipher_unregister_all();
1525       silc_pkcs_unregister_all();
1526       silc_hash_unregister_all();
1527       silc_hmac_unregister_all();
1528     }
1529
1530     silc_hash_free(client->md5hash);
1531     silc_hash_free(client->sha1hash);
1532     silc_hmac_free(client->internal->md5hmac);
1533     silc_hmac_free(client->internal->sha1hmac);
1534     silc_free(client->internal->params);
1535     silc_free(client->internal->silc_client_version);
1536     silc_free(client->internal);
1537     silc_free(client);
1538   }
1539 }
1540
1541 /* Initializes the client. This makes all the necessary steps to make
1542    the client ready to be run. One must call silc_client_run to run the
1543    client. Returns FALSE if error occured, TRUE otherwise. */
1544
1545 SilcBool silc_client_init(SilcClient client)
1546 {
1547   SILC_LOG_DEBUG(("Initializing client"));
1548
1549   assert(client);
1550   assert(client->username);
1551   assert(client->hostname);
1552   assert(client->realname);
1553
1554   /* Validate essential strings */
1555   if (client->nickname)
1556     if (!silc_identifier_verify(client->nickname, strlen(client->nickname),
1557                                 SILC_STRING_UTF8, 128)) {
1558       SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname));
1559       return FALSE;
1560     }
1561   if (!silc_identifier_verify(client->username, strlen(client->username),
1562                               SILC_STRING_UTF8, 128)) {
1563     SILC_LOG_ERROR(("Malformed username '%s'", client->username));
1564     return FALSE;
1565   }
1566   if (!silc_identifier_verify(client->hostname, strlen(client->hostname),
1567                               SILC_STRING_UTF8, 256)) {
1568     SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname));
1569     return FALSE;
1570   }
1571   if (!silc_utf8_valid(client->realname, strlen(client->realname))) {
1572     SILC_LOG_ERROR(("Malformed realname '%s'", client->realname));
1573     return FALSE;
1574   }
1575
1576   if (!client->internal->params->dont_register_crypto_library) {
1577     /* Initialize the crypto library.  If application has done this already
1578        this has no effect.  Also, we will not be overriding something
1579        application might have registered earlier. */
1580     silc_cipher_register_default();
1581     silc_pkcs_register_default();
1582     silc_hash_register_default();
1583     silc_hmac_register_default();
1584   }
1585
1586   /* Initialize hash functions for client to use */
1587   silc_hash_alloc("md5", &client->md5hash);
1588   silc_hash_alloc("sha1", &client->sha1hash);
1589
1590   /* Initialize random number generator */
1591   client->rng = silc_rng_alloc();
1592   silc_rng_init(client->rng);
1593   silc_rng_global_init(client->rng);
1594
1595   /* Initialize the scheduler */
1596   client->schedule =
1597     silc_schedule_init(client->internal->params->task_max ?
1598                        client->internal->params->task_max : 200, client);
1599   if (!client->schedule)
1600     return FALSE;
1601
1602   /* Start packet engine */
1603   client->internal->packet_engine =
1604     silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
1605                              client);
1606   if (!client->internal->packet_engine)
1607     return FALSE;
1608
1609   /* Initialize FSM */
1610   if (!silc_fsm_init(&client->internal->fsm, client, NULL, NULL,
1611                      client->schedule))
1612     return FALSE;
1613   silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
1614
1615   /* Allocate client lock */
1616   silc_mutex_alloc(&client->internal->lock);
1617
1618   /* Register commands */
1619   silc_client_commands_register(client);
1620
1621   return TRUE;
1622 }
1623
1624 /* Stops the client. This is called to stop the client and thus to stop
1625    the program. */
1626
1627 void silc_client_stop(SilcClient client)
1628 {
1629   SILC_LOG_DEBUG(("Stopping client"));
1630
1631   silc_schedule_stop(client->schedule);
1632   silc_schedule_uninit(client->schedule);
1633
1634   silc_client_commands_unregister(client);
1635
1636   SILC_LOG_DEBUG(("Client stopped"));
1637 }
1638
1639 /* Starts the SILC client FSM machine and blocks here.  When this returns
1640    the client has ended. */
1641
1642 void silc_client_run(SilcClient client)
1643 {
1644   SILC_LOG_DEBUG(("Starting SILC client"));
1645
1646   /* Start the client */
1647   silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
1648
1649   /* Signal the application when we are running */
1650   client->internal->run_callback = TRUE;
1651   SILC_FSM_SEMA_POST(&client->internal->wait_event);
1652
1653   /* Run the scheduler */
1654   silc_schedule(client->schedule);
1655 }
1656
1657 /* Call scheduler one iteration and return.  This cannot be called if threads
1658    are in use. */
1659
1660 void silc_client_run_one(SilcClient client)
1661 {
1662   silc_schedule_one(client->schedule, -1);
1663 }