Protocol version 1.2 integrations
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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 "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /* Static task callback prototypes */
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
28 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
29 SILC_TASK_CALLBACK(silc_client_rekey_final);
30
31 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
32                                      void *context);
33 static void silc_client_packet_parse_type(SilcClient client, 
34                                           SilcSocketConnection sock,
35                                           SilcPacketContext *packet);
36 void silc_client_resolve_auth_method(bool success,
37                                      SilcProtocolAuthMeth auth_meth,
38                                      const unsigned char *auth_data,
39                                      SilcUInt32 auth_data_len, void *context);
40
41 /* Allocates new client object. This has to be done before client may
42    work. After calling this one must call silc_client_init to initialize
43    the client. The `application' is application specific user data pointer
44    and caller must free it. */
45
46 SilcClient silc_client_alloc(SilcClientOperations *ops, 
47                              SilcClientParams *params,
48                              void *application,
49                              const char *version_string)
50 {
51   SilcClient new_client;
52
53   new_client = silc_calloc(1, sizeof(*new_client));
54   new_client->application = application;
55
56   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
57   new_client->internal->ops = ops;
58   new_client->internal->params = 
59     silc_calloc(1, sizeof(*new_client->internal->params));
60   if (!version_string)
61     version_string = silc_version_string;
62   new_client->internal->silc_client_version = strdup(version_string);
63
64   if (params)
65     memcpy(new_client->internal->params, params, sizeof(*params));
66
67   if (!new_client->internal->params->task_max)
68     new_client->internal->params->task_max = 200;
69
70   if (!new_client->internal->params->rekey_secs)
71     new_client->internal->params->rekey_secs = 3600;
72
73   if (!new_client->internal->params->connauth_request_secs)
74     new_client->internal->params->connauth_request_secs = 2;
75
76   new_client->internal->params->
77     nickname_format[sizeof(new_client->internal->
78                            params->nickname_format) - 1] = 0;
79
80   return new_client;
81 }
82
83 /* Frees client object and its internals. */
84
85 void silc_client_free(SilcClient client)
86 {
87   if (client) {
88     if (client->rng)
89       silc_rng_free(client->rng);
90
91     silc_free(client->internal->params);
92     silc_free(client->internal->silc_client_version);
93     silc_free(client->internal);
94     silc_free(client);
95   }
96 }
97
98 /* Initializes the client. This makes all the necessary steps to make
99    the client ready to be run. One must call silc_client_run to run the
100    client. Returns FALSE if error occured, TRUE otherwise. */
101
102 bool silc_client_init(SilcClient client)
103 {
104   SILC_LOG_DEBUG(("Initializing client"));
105
106   assert(client);
107   assert(client->username);
108   assert(client->hostname);
109   assert(client->realname);
110
111   /* Initialize the crypto library.  If application has done this already
112      this has no effect.  Also, we will not be overriding something
113      application might have registered earlier. */
114   silc_cipher_register_default();
115   silc_pkcs_register_default();
116   silc_hash_register_default();
117   silc_hmac_register_default();
118
119   /* Initialize hash functions for client to use */
120   silc_hash_alloc("md5", &client->md5hash);
121   silc_hash_alloc("sha1", &client->sha1hash);
122
123   /* Initialize none cipher */
124   silc_cipher_alloc("none", &client->internal->none_cipher);
125
126   /* Initialize random number generator */
127   client->rng = silc_rng_alloc();
128   silc_rng_init(client->rng);
129   silc_rng_global_init(client->rng);
130
131   /* Register protocols */
132   silc_client_protocols_register();
133
134   /* Initialize the scheduler */
135   client->schedule = 
136     silc_schedule_init(client->internal->params->task_max ?
137                        client->internal->params->task_max : 200, client);
138   if (!client->schedule)
139     return FALSE;
140
141   /* Register commands */
142   silc_client_commands_register(client);
143
144   return TRUE;
145 }
146
147 /* Stops the client. This is called to stop the client and thus to stop
148    the program. */
149
150 void silc_client_stop(SilcClient client)
151 {
152   SILC_LOG_DEBUG(("Stopping client"));
153
154   silc_schedule_stop(client->schedule);
155   silc_schedule_uninit(client->schedule);
156
157   silc_client_protocols_unregister();
158   silc_client_commands_unregister(client);
159
160   SILC_LOG_DEBUG(("Client stopped"));
161 }
162
163 /* Runs the client. This starts the scheduler from the utility library.
164    When this functions returns the execution of the appliation is over. */
165
166 void silc_client_run(SilcClient client)
167 {
168   SILC_LOG_DEBUG(("Running client"));
169
170   assert(client);
171   assert(client->pkcs);
172   assert(client->public_key);
173   assert(client->private_key);
174
175   /* Start the scheduler, the heart of the SILC client. When this returns
176      the program will be terminated. */
177   silc_schedule(client->schedule);
178 }
179
180 /* Runs the client and returns immeadiately. This function is used when
181    the SILC Client object indicated by the `client' is run under some
182    other scheduler, or event loop or main loop.  On GUI applications,
183    for example this may be desired to use to run the client under the
184    GUI application's main loop.  Typically the GUI application would
185    register an idle task that calls this function multiple times in
186    a second to quickly process the SILC specific data. */
187
188 void silc_client_run_one(SilcClient client)
189 {
190   /* Run the scheduler once. */
191   silc_schedule_one(client->schedule, 0);
192 }
193
194 static void silc_client_entry_destructor(SilcIDCache cache,
195                                          SilcIDCacheEntry entry)
196 {
197   silc_free(entry->name);
198 }
199
200 /* Allocates and adds new connection to the client. This adds the allocated
201    connection to the connection table and returns a pointer to it. A client
202    can have multiple connections to multiple servers. Every connection must
203    be added to the client using this function. User data `context' may
204    be sent as argument. This function is normally used only if the 
205    application performed the connecting outside the library. The library
206    however may use this internally. */
207
208 SilcClientConnection
209 silc_client_add_connection(SilcClient client,
210                            SilcClientConnectionParams *params,
211                            char *hostname, int port, void *context)
212 {
213   SilcClientConnection conn;
214   int i;
215
216   SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
217
218   conn = silc_calloc(1, sizeof(*conn));
219   conn->internal = silc_calloc(1, sizeof(*conn->internal));
220
221   /* Initialize ID caches */
222   conn->client = client;
223   conn->remote_host = strdup(hostname);
224   conn->remote_port = port;
225   conn->context = context;
226   conn->internal->client_cache =
227     silc_idcache_alloc(0, SILC_ID_CLIENT, silc_client_entry_destructor);
228   conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
229   conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
230   conn->internal->pending_commands = silc_dlist_init();
231   conn->internal->ftp_sessions = silc_dlist_init();
232
233   if (params) {
234     if (params->detach_data)
235       conn->internal->params.detach_data =
236         silc_memdup(params->detach_data,
237                     params->detach_data_len);
238     conn->internal->params.detach_data_len = params->detach_data_len;
239   }
240
241   /* Add the connection to connections table */
242   for (i = 0; i < client->internal->conns_count; i++)
243     if (client->internal->conns && !client->internal->conns[i]) {
244       client->internal->conns[i] = conn;
245       return conn;
246     }
247
248   client->internal->conns = 
249     silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
250                  * (client->internal->conns_count + 1));
251   client->internal->conns[client->internal->conns_count] = conn;
252   client->internal->conns_count++;
253
254   return conn;
255 }
256
257 /* Removes connection from client. Frees all memory. */
258
259 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
260 {
261   int i;
262
263   for (i = 0; i < client->internal->conns_count; i++)
264     if (client->internal->conns[i] == conn) {
265       /* Free all cache entries */
266       SilcIDCacheList list;
267       SilcIDCacheEntry entry;
268       SilcClientCommandPending *r;
269       bool ret;
270
271       if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
272         ret = silc_idcache_list_first(list, &entry);
273         while (ret) {
274           silc_client_del_client(client, conn, entry->context);
275           ret = silc_idcache_list_next(list, &entry);
276         }
277         silc_idcache_list_free(list);
278       }
279
280       if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
281         ret = silc_idcache_list_first(list, &entry);
282         while (ret) {
283           silc_client_del_channel(client, conn, entry->context);
284           ret = silc_idcache_list_next(list, &entry);
285         }
286         silc_idcache_list_free(list);
287       }
288
289       if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
290         ret = silc_idcache_list_first(list, &entry);
291         while (ret) {
292           silc_client_del_server(client, conn, entry->context);
293           ret = silc_idcache_list_next(list, &entry);
294         }
295         silc_idcache_list_free(list);
296       }
297
298       /* Clear ID caches */
299       if (conn->internal->client_cache)
300         silc_idcache_free(conn->internal->client_cache);
301       if (conn->internal->channel_cache)
302         silc_idcache_free(conn->internal->channel_cache);
303       if (conn->internal->server_cache)
304         silc_idcache_free(conn->internal->server_cache);
305
306       /* Free data (my ID is freed in above silc_client_del_client).
307          conn->nickname is freed when freeing the local_entry->nickname. */
308       silc_free(conn->remote_host);
309       silc_free(conn->local_id_data);
310       if (conn->internal->send_key)
311         silc_cipher_free(conn->internal->send_key);
312       if (conn->internal->receive_key)
313         silc_cipher_free(conn->internal->receive_key);
314       if (conn->internal->hmac_send)
315         silc_hmac_free(conn->internal->hmac_send);
316       if (conn->internal->hmac_receive)
317         silc_hmac_free(conn->internal->hmac_receive);
318       silc_free(conn->internal->rekey);
319
320       if (conn->internal->active_session) {
321         conn->sock->user_data = NULL;
322         silc_client_ftp_session_free(conn->internal->active_session);
323         conn->internal->active_session = NULL;
324       }
325
326       silc_client_ftp_free_sessions(client, conn);
327
328       if (conn->internal->pending_commands) {
329         silc_dlist_start(conn->internal->pending_commands);
330         while ((r = silc_dlist_get(conn->internal->pending_commands))
331                != SILC_LIST_END)
332           silc_dlist_del(conn->internal->pending_commands, r);
333         silc_dlist_uninit(conn->internal->pending_commands);
334       }
335
336       silc_free(conn->internal);
337       memset(conn, 0, sizeof(*conn));
338       silc_free(conn);
339
340       client->internal->conns[i] = NULL;
341     }
342 }
343
344 /* Adds listener socket to the listener sockets table. This function is
345    used to add socket objects that are listeners to the client.  This should
346    not be used to add other connection objects. */
347
348 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
349 {
350   int i;
351
352   if (!client->internal->sockets) {
353     client->internal->sockets = 
354       silc_calloc(1, sizeof(*client->internal->sockets));
355     client->internal->sockets[0] = silc_socket_dup(sock);
356     client->internal->sockets_count = 1;
357     return;
358   }
359
360   for (i = 0; i < client->internal->sockets_count; i++) {
361     if (client->internal->sockets[i] == NULL) {
362       client->internal->sockets[i] = silc_socket_dup(sock);
363       return;
364     }
365   }
366
367   client->internal->sockets = 
368     silc_realloc(client->internal->sockets, 
369                  sizeof(*client->internal->sockets) *
370                  (client->internal->sockets_count + 1));
371   client->internal->sockets[client->internal->sockets_count] = 
372     silc_socket_dup(sock);
373   client->internal->sockets_count++;
374 }
375
376 /* Deletes listener socket from the listener sockets table. */
377
378 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
379 {
380   int i;
381
382   if (!client->internal->sockets)
383     return;
384
385   for (i = 0; i < client->internal->sockets_count; i++) {
386     if (client->internal->sockets[i] == sock) {
387       silc_socket_free(sock);
388       client->internal->sockets[i] = NULL;
389       return;
390     }
391   }
392 }
393
394 static int 
395 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
396 {
397   int sock;
398
399   /* XXX In the future we should give up this non-blocking connect all
400      together and use threads instead. */
401   /* Create connection to server asynchronously */
402   sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
403   if (sock < 0)
404     return -1;
405
406   /* Register task that will receive the async connect and will
407      read the result. */
408   ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, 
409                                      silc_client_connect_to_server_start,
410                                      (void *)ctx, 0, 0, 
411                                      SILC_TASK_FD,
412                                      SILC_TASK_PRI_NORMAL);
413   silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
414                               FALSE);
415
416   ctx->sock = sock;
417
418   return sock;
419 }
420
421 /* Connects to remote server. This is the main routine used to connect
422    to SILC server. Returns -1 on error and the created socket otherwise. 
423    The `context' is user context that is saved into the SilcClientConnection
424    that is created after the connection is created. Note that application
425    may handle the connecting process outside the library. If this is the
426    case then this function is not used at all. When the connecting is
427    done the `connect' client operation is called. */
428
429 bool silc_client_connect_to_server(SilcClient client,
430                                   SilcClientConnectionParams *params,
431                                   int port, char *host, void *context)
432 {
433   SilcClientInternalConnectContext *ctx;
434   SilcClientConnection conn;
435   int sock;
436
437   SILC_LOG_DEBUG(("Connecting to port %d of server %s",
438                   port, host));
439
440   conn = silc_client_add_connection(client, params, host, port, context);
441
442   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
443                              "Connecting to port %d of server %s", port, host);
444
445   /* Allocate internal context for connection process. This is
446      needed as we are doing async connecting. */
447   ctx = silc_calloc(1, sizeof(*ctx));
448   ctx->client = client;
449   ctx->conn = conn;
450   ctx->host = strdup(host);
451   ctx->port = port ? port : 706;
452   ctx->tries = 0;
453
454   /* Do the actual connecting process */
455   sock = silc_client_connect_to_server_internal(ctx);
456   if (sock == -1)
457     silc_client_del_connection(client, conn);
458   return sock;
459 }
460
461 /* Socket hostname and IP lookup callback that is called before actually
462    starting the key exchange.  The lookup is called from the function
463    silc_client_start_key_exchange. */
464
465 static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
466                                               void *context)
467 {
468   SilcClientConnection conn = (SilcClientConnection)context;
469   SilcClient client = conn->client;
470   SilcProtocol protocol;
471   SilcClientKEInternalContext *proto_ctx;
472
473   SILC_LOG_DEBUG(("Start"));
474
475   if (conn->sock->hostname) {
476     silc_free(conn->remote_host);
477     conn->remote_host = strdup(conn->sock->hostname);
478   } else {
479     conn->sock->hostname = strdup(conn->remote_host);
480   }
481   if (!conn->sock->ip)
482     conn->sock->ip = strdup(conn->sock->hostname);
483   conn->sock->port = conn->remote_port;
484
485   /* Allocate internal Key Exchange context. This is sent to the
486      protocol as context. */
487   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
488   proto_ctx->client = (void *)client;
489   proto_ctx->sock = silc_socket_dup(conn->sock);
490   proto_ctx->rng = client->rng;
491   proto_ctx->responder = FALSE;
492   proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
493   proto_ctx->verify = silc_client_protocol_ke_verify_key;
494
495   /* Perform key exchange protocol. silc_client_connect_to_server_final
496      will be called after the protocol is finished. */
497   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
498                       &protocol, (void *)proto_ctx,
499                       silc_client_connect_to_server_second);
500   if (!protocol) {
501     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
502                                "Error: Could not start key exchange protocol");
503     silc_net_close_connection(conn->sock->sock);
504     client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
505     return;
506   }
507   conn->sock->protocol = protocol;
508
509   /* Register the connection for network input and output. This sets
510      that scheduler will listen for incoming packets for this connection 
511      and sets that outgoing packets may be sent to this connection as well.
512      However, this doesn't set the scheduler for outgoing traffic, it will 
513      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
514      later when outgoing data is available. */
515   context = (void *)client;
516   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
517
518   /* Execute the protocol */
519   silc_protocol_execute(protocol, client->schedule, 0, 0);
520 }
521
522 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
523    key material between client and server.  This function can be called
524    directly if application is performing its own connecting and does not
525    use the connecting provided by this library. This function is normally
526    used only if the application performed the connecting outside the library.
527    The library however may use this internally. */
528
529 void silc_client_start_key_exchange(SilcClient client,
530                                     SilcClientConnection conn,
531                                     int fd)
532 {
533   assert(client->pkcs);
534   assert(client->public_key);
535   assert(client->private_key);
536
537   /* Allocate new socket connection object */
538   silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
539
540   /* Sometimes when doing quick reconnects the new socket may be same as
541      the old one and there might be pending stuff for the old socket. 
542      If new one is same then those pending sutff might cause problems.
543      Make sure they do not do that. */
544   silc_schedule_task_del_by_fd(client->schedule, fd);
545
546   conn->nickname = (client->nickname ? strdup(client->nickname) :
547                     strdup(client->username));
548
549   /* Resolve the remote hostname and IP address for our socket connection */
550   silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
551                           conn, client->schedule);
552 }
553
554 /* Callback called when error has occurred during connecting (KE) to
555    the server.  The `connect' client operation will be called. */
556
557 SILC_TASK_CALLBACK(silc_client_connect_failure)
558 {
559   SilcClientKEInternalContext *ctx = 
560     (SilcClientKEInternalContext *)context;
561   SilcClient client = (SilcClient)ctx->client;
562
563   client->internal->ops->connected(client, ctx->sock->user_data, 
564                                    SILC_CLIENT_CONN_ERROR);
565   if (ctx->packet)
566     silc_packet_context_free(ctx->packet);
567   silc_free(ctx);
568 }
569
570 /* Callback called when error has occurred during connecting (auth) to
571    the server.  The `connect' client operation will be called. */
572
573 SILC_TASK_CALLBACK(silc_client_connect_failure_auth)
574 {
575   SilcClientConnAuthInternalContext *ctx =
576     (SilcClientConnAuthInternalContext *)context;
577   SilcClient client = (SilcClient)ctx->client;
578
579   client->internal->ops->connected(client, ctx->sock->user_data, 
580                                    SILC_CLIENT_CONN_ERROR);
581   silc_free(ctx);
582 }
583
584 /* Start of the connection to the remote server. This is called after
585    succesful TCP/IP connection has been established to the remote host. */
586
587 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
588 {
589   SilcClientInternalConnectContext *ctx =
590     (SilcClientInternalConnectContext *)context;
591   SilcClient client = ctx->client;
592   SilcClientConnection conn = ctx->conn;
593   int opt, opt_len = sizeof(opt);
594
595   SILC_LOG_DEBUG(("Start"));
596
597   /* Check the socket status as it might be in error */
598   silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
599   if (opt != 0) {
600     if (ctx->tries < 2) {
601       /* Connection failed but lets try again */
602       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
603                                  "Could not connect to server %s: %s",
604                                  ctx->host, strerror(opt));
605       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
606                                  "Connecting to port %d of server %s resumed", 
607                                  ctx->port, ctx->host);
608
609       /* Unregister old connection try */
610       silc_schedule_unset_listen_fd(client->schedule, fd);
611       silc_net_close_connection(fd);
612       silc_schedule_task_del(client->schedule, ctx->task);
613
614       /* Try again */
615       silc_client_connect_to_server_internal(ctx);
616       ctx->tries++;
617     } else {
618       /* Connection failed and we won't try anymore */
619       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
620                                  "Could not connect to server %s: %s",
621                                  ctx->host, strerror(opt));
622       silc_schedule_unset_listen_fd(client->schedule, fd);
623       silc_net_close_connection(fd);
624       silc_schedule_task_del(client->schedule, ctx->task);
625       silc_free(ctx);
626
627       /* Notify application of failure */
628       client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
629       silc_client_del_connection(client, conn);
630     }
631     return;
632   }
633
634   silc_schedule_unset_listen_fd(client->schedule, fd);
635   silc_schedule_task_del(client->schedule, ctx->task);
636   silc_free(ctx);
637
638   silc_client_start_key_exchange(client, conn, fd);
639 }
640
641 /* Second part of the connecting to the server. This executed 
642    authentication protocol. */
643
644 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
645 {
646   SilcProtocol protocol = (SilcProtocol)context;
647   SilcClientKEInternalContext *ctx = 
648     (SilcClientKEInternalContext *)protocol->context;
649   SilcClient client = (SilcClient)ctx->client;
650   SilcSocketConnection sock = NULL;
651   SilcClientConnAuthInternalContext *proto_ctx;
652
653   SILC_LOG_DEBUG(("Start"));
654
655   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
656       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
657     /* Error occured during protocol */
658     SILC_LOG_DEBUG(("Error during KE protocol"));
659     silc_protocol_free(protocol);
660     silc_ske_free_key_material(ctx->keymat);
661     if (ctx->ske)
662       silc_ske_free(ctx->ske);
663     if (ctx->dest_id)
664       silc_free(ctx->dest_id);
665     ctx->sock->protocol = NULL;
666     silc_socket_free(ctx->sock);
667
668     /* Notify application of failure */
669     silc_schedule_task_add(client->schedule, ctx->sock->sock,
670                            silc_client_connect_failure, ctx,
671                            0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
672     return;
673   }
674
675   /* We now have the key material as the result of the key exchange
676      protocol. Take the key material into use. Free the raw key material
677      as soon as we've set them into use. */
678   silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
679                                    ctx->ske->prop->cipher,
680                                    ctx->ske->prop->pkcs,
681                                    ctx->ske->prop->hash,
682                                    ctx->ske->prop->hmac,
683                                    ctx->ske->prop->group,
684                                    ctx->responder);
685   silc_ske_free_key_material(ctx->keymat);
686
687   /* Allocate internal context for the authentication protocol. This
688      is sent as context for the protocol. */
689   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
690   proto_ctx->client = (void *)client;
691   proto_ctx->sock = sock = ctx->sock;
692   proto_ctx->ske = ctx->ske;    /* Save SKE object from previous protocol */
693   proto_ctx->dest_id_type = ctx->dest_id_type;
694   proto_ctx->dest_id = ctx->dest_id;
695
696   /* Free old protocol as it is finished now */
697   silc_protocol_free(protocol);
698   if (ctx->packet)
699     silc_packet_context_free(ctx->packet);
700   ctx->packet = NULL;
701   silc_free(ctx);
702   sock->protocol = NULL;
703
704   /* Resolve the authentication method to be used in this connection. The
705      completion callback is called after the application has resolved
706      the authentication method. */
707   client->internal->ops->get_auth_method(client, sock->user_data, 
708                                          sock->hostname,
709                                          sock->port, 
710                                          silc_client_resolve_auth_method,
711                                          proto_ctx);
712 }
713
714 /* Authentication method resolving callback. Application calls this function
715    after we've called the client->internal->ops->get_auth_method 
716    client operation to resolve the authentication method. We will continue
717    the executiong of the protocol in this function. */
718
719 void silc_client_resolve_auth_method(bool success,
720                                      SilcProtocolAuthMeth auth_meth,
721                                      const unsigned char *auth_data,
722                                      SilcUInt32 auth_data_len, void *context)
723 {
724   SilcClientConnAuthInternalContext *proto_ctx =
725     (SilcClientConnAuthInternalContext *)context;
726   SilcClient client = (SilcClient)proto_ctx->client;
727
728   if (!success)
729     auth_meth = SILC_AUTH_NONE;
730
731   proto_ctx->auth_meth = auth_meth;
732
733   if (success && auth_data && auth_data_len) {
734
735     /* Passphrase must be UTF-8 encoded, if it isn't encode it */
736     if (auth_meth == SILC_AUTH_PASSWORD && 
737         !silc_utf8_valid(auth_data, auth_data_len)) {
738       int payload_len = 0;
739       unsigned char *autf8 = NULL;
740       payload_len = silc_utf8_encoded_len(auth_data, auth_data_len, 
741                                           SILC_STRING_ASCII);
742       autf8 = silc_calloc(payload_len, sizeof(*autf8));
743       auth_data_len = silc_utf8_encode(auth_data, auth_data_len, 
744                                        SILC_STRING_ASCII, autf8, payload_len);
745       auth_data = autf8;
746     }
747
748     proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
749     proto_ctx->auth_data_len = auth_data_len;
750   }
751
752   /* Allocate the authenteication protocol and execute it. */
753   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
754                       &proto_ctx->sock->protocol, (void *)proto_ctx, 
755                       silc_client_connect_to_server_final);
756
757   /* Execute the protocol */
758   silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
759 }
760
761 /* Finalizes the connection to the remote SILC server. This is called
762    after authentication protocol has been completed. This send our
763    user information to the server to receive our client ID from
764    server. */
765
766 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
767 {
768   SilcProtocol protocol = (SilcProtocol)context;
769   SilcClientConnAuthInternalContext *ctx = 
770     (SilcClientConnAuthInternalContext *)protocol->context;
771   SilcClient client = (SilcClient)ctx->client;
772   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
773   SilcBuffer packet;
774
775   SILC_LOG_DEBUG(("Start"));
776
777   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
778       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
779     /* Error occured during protocol */
780     SILC_LOG_DEBUG(("Error during authentication protocol"));
781     goto err;
782   }
783
784   if (conn->internal->params.detach_data) {
785     /* Send RESUME_CLIENT packet to the server, which is used to resume
786        old detached session back. */
787     SilcBuffer auth;
788     SilcClientID *old_client_id;
789     unsigned char *old_id;
790     SilcUInt16 old_id_len;
791
792     if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len))
793       goto err;
794
795     old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
796     if (!old_client_id) {
797       silc_free(old_id);
798       goto err;
799     }
800
801     /* Generate authentication data that server will verify */
802     auth = silc_auth_public_key_auth_generate(client->public_key,
803                                               client->private_key,
804                                               client->rng,
805                                               conn->internal->hash,
806                                               old_client_id, SILC_ID_CLIENT);
807     if (!auth) {
808       silc_free(old_client_id);
809       silc_free(old_id);
810       goto err;
811     }
812
813     packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
814     silc_buffer_format(packet,
815                        SILC_STR_UI_SHORT(old_id_len),
816                        SILC_STR_UI_XNSTRING(old_id, old_id_len),
817                        SILC_STR_UI_XNSTRING(auth->data, auth->len),
818                        SILC_STR_END);
819
820     /* Send the packet */
821     silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
822                             NULL, 0, NULL, NULL, 
823                             packet->data, packet->len, TRUE);
824     silc_buffer_free(packet);
825     silc_buffer_free(auth);
826     silc_free(old_client_id);
827     silc_free(old_id);
828   } else {
829     /* Send NEW_CLIENT packet to the server. We will become registered
830        to the SILC network after sending this packet and we will receive
831        client ID from the server. */
832     packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
833                                strlen(client->realname));
834     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
835     silc_buffer_format(packet,
836                        SILC_STR_UI_SHORT(strlen(client->username)),
837                        SILC_STR_UI_XNSTRING(client->username,
838                                             strlen(client->username)),
839                        SILC_STR_UI_SHORT(strlen(client->realname)),
840                        SILC_STR_UI_XNSTRING(client->realname,
841                                             strlen(client->realname)),
842                        SILC_STR_END);
843
844     /* Send the packet */
845     silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
846                             NULL, 0, NULL, NULL, 
847                             packet->data, packet->len, TRUE);
848     silc_buffer_free(packet);
849   }
850
851   /* Save remote ID. */
852   conn->remote_id = ctx->dest_id;
853   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
854   conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
855
856   /* Register re-key timeout */
857   conn->internal->rekey->timeout = client->internal->params->rekey_secs;
858   conn->internal->rekey->context = (void *)client;
859   silc_schedule_task_add(client->schedule, conn->sock->sock, 
860                          silc_client_rekey_callback,
861                          (void *)conn->sock, conn->internal->rekey->timeout, 0,
862                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
863
864   silc_protocol_free(protocol);
865   silc_free(ctx->auth_data);
866   if (ctx->ske)
867     silc_ske_free(ctx->ske);
868   silc_socket_free(ctx->sock);
869   silc_free(ctx);
870   conn->sock->protocol = NULL;
871   return;
872
873  err:
874   silc_protocol_free(protocol);
875   silc_free(ctx->auth_data);
876   silc_free(ctx->dest_id);
877   if (ctx->ske)
878     silc_ske_free(ctx->ske);
879   conn->sock->protocol = NULL;
880   silc_socket_free(ctx->sock);
881
882   /* Notify application of failure */
883   silc_schedule_task_add(client->schedule, ctx->sock->sock,
884                          silc_client_connect_failure_auth, ctx,
885                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
886 }
887
888 /* Internal routine that sends packet or marks packet to be sent. This
889    is used directly only in special cases. Normal cases should use
890    silc_server_packet_send. Returns < 0 on error. */
891
892 bool silc_client_packet_send_real(SilcClient client,
893                                  SilcSocketConnection sock,
894                                  bool force_send)
895 {
896   int ret;
897
898   /* If rekey protocol is active we must assure that all packets are
899      sent through packet queue. */
900   if (SILC_CLIENT_IS_REKEY(sock))
901     force_send = FALSE;
902
903   /* If outbound data is already pending do not force send */
904   if (SILC_IS_OUTBUF_PENDING(sock))
905     force_send = FALSE;
906
907   /* Send the packet */
908   ret = silc_packet_send(sock, force_send);
909   if (ret != -2)
910     return ret;
911
912   /* Mark that there is some outgoing data available for this connection. 
913      This call sets the connection both for input and output (the input
914      is set always and this call keeps the input setting, actually). 
915      Actual data sending is performed by silc_client_packet_process. */
916   SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
917
918   /* Mark to socket that data is pending in outgoing buffer. This flag
919      is needed if new data is added to the buffer before the earlier
920      put data is sent to the network. */
921   SILC_SET_OUTBUF_PENDING(sock);
922
923   return 0;
924 }
925
926 /* Packet processing callback. This is used to send and receive packets
927    from network. This is generic task. */
928
929 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
930 {
931   SilcClient client = (SilcClient)context;
932   SilcSocketConnection sock = NULL;
933   SilcClientConnection conn;
934   int ret;
935
936   SILC_LOG_DEBUG(("Processing packet"));
937
938   SILC_CLIENT_GET_SOCK(client, fd, sock);
939   if (sock == NULL)
940     return;
941
942   conn = (SilcClientConnection)sock->user_data;
943
944   /* Packet sending */
945   if (type == SILC_TASK_WRITE) {
946     /* Do not send data to disconnected connection */
947     if (SILC_IS_DISCONNECTED(sock))
948       return;
949
950     ret = silc_packet_send(sock, TRUE);
951
952     /* If returned -2 could not write to connection now, will do
953        it later. */
954     if (ret == -2)
955       return;
956
957     /* Error */
958     if (ret == -1)
959       return;
960     
961     /* The packet has been sent and now it is time to set the connection
962        back to only for input. When there is again some outgoing data 
963        available for this connection it will be set for output as well. 
964        This call clears the output setting and sets it only for input. */
965     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
966     SILC_UNSET_OUTBUF_PENDING(sock);
967
968     silc_buffer_clear(sock->outbuf);
969     return;
970   }
971
972   /* Packet receiving */
973   if (type == SILC_TASK_READ) {
974     /* Read data from network */
975     ret = silc_packet_receive(sock);
976     if (ret < 0)
977       return;
978     
979     /* EOF */
980     if (ret == 0) {
981       SILC_LOG_DEBUG(("Read EOF"));
982
983       /* If connection is disconnecting already we will finally
984          close the connection */
985       if (SILC_IS_DISCONNECTING(sock)) {
986         if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
987           client->internal->ops->disconnected(client, conn, 0, NULL);
988         silc_client_close_connection_real(client, sock, conn);
989         return;
990       }
991       
992       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
993       if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
994         client->internal->ops->disconnected(client, conn, 0, NULL);
995       silc_client_close_connection_real(client, sock, conn);
996       return;
997     }
998
999     /* Process the packet. This will call the parser that will then
1000        decrypt and parse the packet. */
1001     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1002       silc_packet_receive_process(sock, FALSE, conn->internal->receive_key, 
1003                                   conn->internal->hmac_receive,
1004                                   conn->internal->psn_receive,
1005                                   silc_client_packet_parse, client);
1006     else
1007       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
1008                                   silc_client_packet_parse, client);
1009   }
1010 }
1011
1012 /* Parser callback called by silc_packet_receive_process. Thie merely
1013    registers timeout that will handle the actual parsing when appropriate. */
1014
1015 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
1016                                      void *context)
1017 {
1018   SilcClient client = (SilcClient)context;
1019   SilcSocketConnection sock = parser_context->sock;
1020   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1021   SilcPacketContext *packet = parser_context->packet;
1022   SilcPacketType ret;
1023
1024   if (conn && conn->internal->hmac_receive && conn->sock == sock)
1025     conn->internal->psn_receive = parser_context->packet->sequence + 1;
1026
1027   /* Parse the packet immediately */
1028   if (parser_context->normal)
1029     ret = silc_packet_parse(packet, conn->internal->receive_key);
1030   else
1031     ret = silc_packet_parse_special(packet, conn->internal->receive_key);
1032
1033   if (ret == SILC_PACKET_NONE) {
1034     silc_packet_context_free(packet);
1035     silc_free(parser_context);
1036     return FALSE;
1037   }
1038   
1039   /* If protocol for this connection is key exchange or rekey then we'll
1040      process all packets synchronously, since there might be packets in
1041      queue that we are not able to decrypt without first processing the
1042      packets before them. */
1043   if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
1044       (sock->protocol && sock->protocol->protocol && 
1045        (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1046         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
1047
1048     /* Parse the incoming packet type */
1049     silc_client_packet_parse_type(client, sock, packet);
1050     silc_packet_context_free(packet);
1051     silc_free(parser_context);
1052
1053     /* Reprocess the buffer since we'll return FALSE. This is because
1054        the `conn->internal->receive_key' might have become valid by processing
1055        the previous packet */
1056     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1057       silc_packet_receive_process(sock, FALSE, conn->internal->receive_key, 
1058                                   conn->internal->hmac_receive,
1059                                   conn->internal->psn_receive,
1060                                   silc_client_packet_parse, client);
1061     else
1062       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
1063                                   silc_client_packet_parse, client);
1064     
1065     return FALSE;
1066   }
1067
1068   /* Parse the incoming packet type */
1069   silc_client_packet_parse_type(client, sock, packet);
1070   silc_packet_context_free(packet);
1071   silc_free(parser_context);
1072   return TRUE;
1073 }
1074
1075 /* Parses the packet type and calls what ever routines the packet type
1076    requires. This is done for all incoming packets. */
1077
1078 void silc_client_packet_parse_type(SilcClient client, 
1079                                    SilcSocketConnection sock,
1080                                    SilcPacketContext *packet)
1081 {
1082   SilcBuffer buffer = packet->buffer;
1083   SilcPacketType type = packet->type;
1084
1085   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
1086
1087   /* Parse the packet type */
1088   switch(type) {
1089
1090   case SILC_PACKET_DISCONNECT:
1091     silc_client_disconnected_by_server(client, sock, buffer);
1092     break;
1093
1094   case SILC_PACKET_SUCCESS:
1095     /*
1096      * Success received for something. For now we can have only
1097      * one protocol for connection executing at once hence this
1098      * success message is for whatever protocol is executing currently.
1099      */
1100     if (sock->protocol)
1101       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1102     break;
1103
1104   case SILC_PACKET_FAILURE:
1105     /*
1106      * Failure received for some protocol. Set the protocol state to 
1107      * error and call the protocol callback. This fill cause error on
1108      * protocol and it will call the final callback.
1109      */
1110     silc_client_process_failure(client, sock, packet);
1111     break;
1112
1113   case SILC_PACKET_REJECT:
1114     break;
1115
1116   case SILC_PACKET_NOTIFY:
1117     /*
1118      * Received notify message 
1119      */
1120     silc_client_notify_by_server(client, sock, packet);
1121     break;
1122
1123   case SILC_PACKET_ERROR:
1124     /*
1125      * Received error message
1126      */
1127     silc_client_error_by_server(client, sock, buffer);
1128     break;
1129
1130   case SILC_PACKET_CHANNEL_MESSAGE:
1131     /*
1132      * Received message to (from, actually) a channel
1133      */
1134     silc_client_channel_message(client, sock, packet);
1135     break;
1136
1137   case SILC_PACKET_CHANNEL_KEY:
1138     /*
1139      * Received key for a channel. By receiving this key the client will be
1140      * able to talk to the channel it has just joined. This can also be
1141      * a new key for existing channel as keys expire peridiocally.
1142      */
1143     silc_client_receive_channel_key(client, sock, buffer);
1144     break;
1145
1146   case SILC_PACKET_PRIVATE_MESSAGE:
1147     /*
1148      * Received private message
1149      */
1150     silc_client_private_message(client, sock, packet);
1151     break;
1152
1153   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
1154     /*
1155      * Received private message key
1156      */
1157     break;
1158
1159   case SILC_PACKET_COMMAND:
1160     /*
1161      * Received command packet, a special case since normally client
1162      * does not receive commands.
1163      */
1164     silc_client_command_process(client, sock, packet);
1165     break;
1166
1167   case SILC_PACKET_COMMAND_REPLY:
1168     /*
1169      * Recived reply for a command
1170      */
1171     silc_client_command_reply_process(client, sock, packet);
1172     break;
1173
1174   case SILC_PACKET_KEY_EXCHANGE:
1175     if (sock->protocol && sock->protocol->protocol && 
1176         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1177       SilcClientKEInternalContext *proto_ctx = 
1178         (SilcClientKEInternalContext *)sock->protocol->context;
1179
1180       proto_ctx->packet = silc_packet_context_dup(packet);
1181       proto_ctx->dest_id_type = packet->src_id_type;
1182       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1183                                           packet->src_id_type);
1184       if (!proto_ctx->dest_id)
1185         break;
1186
1187       /* Let the protocol handle the packet */
1188       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1189     } else {
1190       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
1191                       "protocol active, packet dropped."));
1192     }
1193     break;
1194
1195   case SILC_PACKET_KEY_EXCHANGE_1:
1196     if (sock->protocol && sock->protocol->protocol && 
1197         (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1198          sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1199
1200       if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1201         SilcClientRekeyInternalContext *proto_ctx = 
1202           (SilcClientRekeyInternalContext *)sock->protocol->context;
1203         
1204         if (proto_ctx->packet)
1205           silc_packet_context_free(proto_ctx->packet);
1206         
1207         proto_ctx->packet = silc_packet_context_dup(packet);
1208
1209         /* Let the protocol handle the packet */
1210         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1211       } else {
1212         SilcClientKEInternalContext *proto_ctx = 
1213           (SilcClientKEInternalContext *)sock->protocol->context;
1214         
1215         if (proto_ctx->packet)
1216           silc_packet_context_free(proto_ctx->packet);
1217         
1218         proto_ctx->packet = silc_packet_context_dup(packet);
1219         proto_ctx->dest_id_type = packet->src_id_type;
1220         proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1221                                             packet->src_id_type);
1222         if (!proto_ctx->dest_id)
1223           break;
1224         
1225         /* Let the protocol handle the packet */
1226         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1227       }
1228     } else {
1229       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1230                       "protocol active, packet dropped."));
1231     }
1232     break;
1233
1234   case SILC_PACKET_KEY_EXCHANGE_2:
1235     if (sock->protocol && sock->protocol->protocol && 
1236         (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1237          sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1238
1239       if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1240         SilcClientRekeyInternalContext *proto_ctx = 
1241           (SilcClientRekeyInternalContext *)sock->protocol->context;
1242         
1243         if (proto_ctx->packet)
1244           silc_packet_context_free(proto_ctx->packet);
1245         
1246         proto_ctx->packet = silc_packet_context_dup(packet);
1247
1248         /* Let the protocol handle the packet */
1249         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1250       } else {
1251         SilcClientKEInternalContext *proto_ctx = 
1252           (SilcClientKEInternalContext *)sock->protocol->context;
1253         
1254         if (proto_ctx->packet)
1255           silc_packet_context_free(proto_ctx->packet);
1256         if (proto_ctx->dest_id)
1257           silc_free(proto_ctx->dest_id);
1258         proto_ctx->packet = silc_packet_context_dup(packet);
1259         proto_ctx->dest_id_type = packet->src_id_type;
1260         proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1261                                             packet->src_id_type);
1262         if (!proto_ctx->dest_id)
1263           break;
1264         
1265         /* Let the protocol handle the packet */
1266         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1267       }
1268     } else {
1269       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1270                       "protocol active, packet dropped."));
1271     }
1272     break;
1273
1274   case SILC_PACKET_NEW_ID:
1275     {
1276       /*
1277        * Received new ID from server. This packet is received at
1278        * the connection to the server.  New ID is also received when 
1279        * user changes nickname but in that case the new ID is received
1280        * as command reply and not as this packet type.
1281        */
1282       SilcIDPayload idp;
1283
1284       idp = silc_id_payload_parse(buffer->data, buffer->len);
1285       if (!idp)
1286         break;
1287       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1288         break;
1289
1290       silc_client_receive_new_id(client, sock, idp);
1291       silc_id_payload_free(idp);
1292       break;
1293     }
1294
1295   case SILC_PACKET_HEARTBEAT:
1296     /*
1297      * Received heartbeat packet
1298      */
1299     SILC_LOG_DEBUG(("Heartbeat packet"));
1300     break;
1301
1302   case SILC_PACKET_KEY_AGREEMENT:
1303     /*
1304      * Received key agreement packet
1305      */
1306     SILC_LOG_DEBUG(("Key agreement packet"));
1307     silc_client_key_agreement(client, sock, packet);
1308     break;
1309
1310   case SILC_PACKET_REKEY:
1311     SILC_LOG_DEBUG(("Re-key packet"));
1312     /* We ignore this for now */
1313     break;
1314
1315   case SILC_PACKET_REKEY_DONE:
1316     SILC_LOG_DEBUG(("Re-key done packet"));
1317
1318     if (sock->protocol && sock->protocol->protocol && 
1319         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1320
1321       SilcClientRekeyInternalContext *proto_ctx = 
1322         (SilcClientRekeyInternalContext *)sock->protocol->context;
1323       
1324       if (proto_ctx->packet)
1325         silc_packet_context_free(proto_ctx->packet);
1326       
1327       proto_ctx->packet = silc_packet_context_dup(packet);
1328
1329       /* Let the protocol handle the packet */
1330       if (proto_ctx->responder == FALSE)
1331         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1332       else
1333         /* Let the protocol handle the packet */
1334         silc_protocol_execute(sock->protocol, client->schedule, 
1335                               0, 100000);
1336     } else {
1337       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1338                       "protocol active, packet dropped."));
1339     }
1340     break;
1341
1342   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1343     /*
1344      * Reveived reply to our connection authentication method request
1345      * packet. This is used to resolve the authentication method for the
1346      * current session from the server if the client does not know it.
1347      */
1348     silc_client_connection_auth_request(client, sock, packet);
1349     break;
1350
1351   case SILC_PACKET_FTP:
1352     /* Received file transfer packet. */
1353     silc_client_ftp(client, sock, packet);
1354     break;
1355
1356   default:
1357     SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1358     break;
1359   }
1360 }
1361
1362 /* Sends packet. This doesn't actually send the packet instead it assembles
1363    it and marks it to be sent. However, if force_send is TRUE the packet
1364    is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1365    will be derived from sock argument. Otherwise the valid arguments sent
1366    are used. */
1367
1368 void silc_client_packet_send(SilcClient client, 
1369                              SilcSocketConnection sock,
1370                              SilcPacketType type, 
1371                              void *dst_id,
1372                              SilcIdType dst_id_type,
1373                              SilcCipher cipher,
1374                              SilcHmac hmac,
1375                              unsigned char *data, 
1376                              SilcUInt32 data_len, 
1377                              bool force_send)
1378 {
1379   SilcPacketContext packetdata;
1380   const SilcBufferStruct packet;
1381   int block_len;
1382   SilcUInt32 sequence = 0;
1383
1384   if (!sock)
1385     return;
1386
1387   SILC_LOG_DEBUG(("Sending packet, type %d", type));
1388
1389   /* Get data used in the packet sending, keys and stuff */
1390   if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1391     if (!cipher && ((SilcClientConnection)sock->user_data)->internal->send_key)
1392       cipher = ((SilcClientConnection)sock->user_data)->internal->send_key;
1393
1394     if (!hmac && ((SilcClientConnection)sock->user_data)->internal->hmac_send)
1395       hmac = ((SilcClientConnection)sock->user_data)->internal->hmac_send;
1396
1397     if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1398       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1399       dst_id_type = SILC_ID_SERVER;
1400     }
1401
1402     if (hmac)
1403       sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++;
1404
1405     /* Check for mandatory rekey */
1406     if (sequence == SILC_CLIENT_REKEY_THRESHOLD)
1407       silc_schedule_task_add(client->schedule, sock->sock,
1408                              silc_client_rekey_callback, sock, 0, 1,
1409                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1410   }
1411
1412   block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1413
1414   /* Set the packet context pointers */
1415   packetdata.flags = 0;
1416   packetdata.type = type;
1417   if (sock->user_data && 
1418       ((SilcClientConnection)sock->user_data)->local_id_data) {
1419     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1420     packetdata.src_id_len = 
1421       silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1422                       SILC_ID_CLIENT);
1423   } else { 
1424     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1425     packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1426   }
1427   packetdata.src_id_type = SILC_ID_CLIENT;
1428   if (dst_id) {
1429     packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1430     packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1431     packetdata.dst_id_type = dst_id_type;
1432   } else {
1433     packetdata.dst_id = NULL;
1434     packetdata.dst_id_len = 0;
1435     packetdata.dst_id_type = SILC_ID_NONE;
1436   }
1437   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1438                                             packetdata.src_id_len + 
1439                                             packetdata.dst_id_len));
1440   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
1441     packetdata.src_id_len + packetdata.dst_id_len;
1442   if (type == SILC_PACKET_CONNECTION_AUTH)
1443     SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen);
1444   else
1445     SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
1446
1447   /* Create the outgoing packet */
1448   if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, 
1449                             data, data_len, (const SilcBuffer)&packet)) {
1450     SILC_LOG_ERROR(("Error assembling packet"));
1451     return;
1452   }
1453
1454   /* Encrypt the packet */
1455   if (cipher)
1456     silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, 
1457                         packet.len);
1458
1459   SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
1460                    packet.data, packet.len);
1461
1462   /* Now actually send the packet */
1463   silc_client_packet_send_real(client, sock, force_send);
1464 }
1465
1466 /* Packet sending routine for application.  This is the only routine that
1467    is provided for application to send SILC packets. */
1468
1469 bool silc_client_send_packet(SilcClient client,
1470                              SilcClientConnection conn,
1471                              SilcPacketType type,
1472                              const unsigned char *data,
1473                              SilcUInt32 data_len)
1474 {
1475
1476   assert(client);
1477   if (!conn)
1478     return FALSE;
1479
1480   silc_client_packet_send(client, conn->sock, type, NULL, 0, NULL, NULL,
1481                           (unsigned char *)data, data_len, TRUE);
1482   return TRUE;
1483 }
1484
1485 void silc_client_packet_queue_purge(SilcClient client,
1486                                     SilcSocketConnection sock)
1487 {
1488   if (sock && SILC_IS_OUTBUF_PENDING(sock) && 
1489       (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1490     silc_packet_send(sock, TRUE);
1491     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1492     SILC_UNSET_OUTBUF_PENDING(sock);
1493     silc_buffer_clear(sock->outbuf);
1494   }
1495 }
1496
1497 /* Closes connection to remote end. Free's all allocated data except
1498    for some information such as nickname etc. that are valid at all time. 
1499    If the `sock' is NULL then the conn->sock will be used.  If `sock' is
1500    provided it will be checked whether the sock and `conn->sock' are the
1501    same (they can be different, ie. a socket can use `conn' as its
1502    connection but `conn->sock' might be actually a different connection
1503    than the `sock'). */
1504
1505 void silc_client_close_connection_real(SilcClient client,
1506                                        SilcSocketConnection sock,
1507                                        SilcClientConnection conn)
1508 {
1509   int del = FALSE;
1510
1511   SILC_LOG_DEBUG(("Start"));
1512
1513   if (!sock && !conn)
1514     return;
1515
1516   if (!sock || (sock && conn->sock == sock))
1517     del = TRUE;
1518   if (!sock)
1519     sock = conn->sock;
1520
1521   /* We won't listen for this connection anymore */
1522   silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1523
1524   /* Unregister all tasks */
1525   silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1526
1527   /* Close the actual connection */
1528   silc_net_close_connection(sock->sock);
1529
1530   /* Cancel any active protocol */
1531   if (sock->protocol) {
1532     if (sock->protocol->protocol->type == 
1533         SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1534         sock->protocol->protocol->type == 
1535         SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1536       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1537       silc_protocol_execute_final(sock->protocol, client->schedule);
1538       /* The application will recall this function with these protocols
1539          (the ops->connected client operation). */
1540       return;
1541     } else {
1542       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1543       silc_protocol_execute_final(sock->protocol, client->schedule);
1544       sock->protocol = NULL;
1545     }
1546   }
1547
1548   /* Free everything */
1549   if (del && sock->user_data)
1550     silc_client_del_connection(client, conn);
1551
1552   silc_socket_free(sock);
1553 }
1554
1555 /* Closes the connection to the remote end */
1556
1557 void silc_client_close_connection(SilcClient client,
1558                                   SilcClientConnection conn)
1559 {
1560   silc_client_close_connection_real(client, NULL, conn);
1561 }
1562
1563 /* Called when we receive disconnection packet from server. This 
1564    closes our end properly and displays the reason of the disconnection
1565    on the screen. */
1566
1567 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1568 {
1569   SilcClient client = (SilcClient)context;
1570   SilcSocketConnection sock;
1571
1572   SILC_CLIENT_GET_SOCK(client, fd, sock);
1573   if (sock == NULL)
1574     return;
1575
1576   silc_client_close_connection_real(client, sock, sock->user_data);
1577 }
1578
1579 /* Called when we receive disconnection packet from server. This 
1580    closes our end properly and displays the reason of the disconnection
1581    on the screen. */
1582
1583 void silc_client_disconnected_by_server(SilcClient client,
1584                                         SilcSocketConnection sock,
1585                                         SilcBuffer packet)
1586 {
1587   SilcClientConnection conn;
1588   SilcStatus status;
1589   char *message = NULL;
1590
1591   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1592
1593   if (packet->len < 1)
1594     return;
1595
1596   status = (SilcStatus)packet->data[0];
1597
1598   if (packet->len > 1 &&
1599       silc_utf8_valid(packet->data + 1, packet->len - 1))
1600     message = silc_memdup(packet->data + 1, packet->len - 1);
1601
1602   conn = (SilcClientConnection)sock->user_data;
1603   if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1604     client->internal->ops->disconnected(client, conn, status, message);
1605
1606   silc_free(message);
1607
1608   SILC_SET_DISCONNECTED(sock);
1609
1610   /* Close connection through scheduler. */
1611   silc_schedule_task_add(client->schedule, sock->sock, 
1612                          silc_client_disconnected_by_server_later,
1613                          client, 0, 1, SILC_TASK_TIMEOUT, 
1614                          SILC_TASK_PRI_NORMAL);
1615 }
1616
1617 /* Received error message from server. Display it on the screen. 
1618    We don't take any action what so ever of the error message. */
1619
1620 void silc_client_error_by_server(SilcClient client,
1621                                  SilcSocketConnection sock,
1622                                  SilcBuffer message)
1623 {
1624   char *msg;
1625
1626   msg = silc_memdup(message->data, message->len);
1627   client->internal->ops->say(client, sock->user_data, 
1628                              SILC_CLIENT_MESSAGE_AUDIT, msg);
1629   silc_free(msg);
1630 }
1631
1632 /* Auto-nicking callback to send NICK command to server. */
1633
1634 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1635 {
1636   SilcClientConnection conn = (SilcClientConnection)context;
1637   SilcClient client = conn->client;
1638
1639   silc_client_command_send(client, conn, SILC_COMMAND_NICK, 
1640                            ++conn->cmd_ident, 1, 1, 
1641                            client->nickname, strlen(client->nickname));
1642 }
1643
1644 /* Client session resuming callback.  If the session was resumed
1645    this callback is called after the resuming is completed.  This
1646    will call the `connect' client operation to the application
1647    since it has not been called yet. */
1648
1649 static void silc_client_resume_session_cb(SilcClient client,
1650                                           SilcClientConnection conn,
1651                                           bool success,
1652                                           void *context)
1653 {
1654   SilcBuffer sidp;
1655
1656   /* Notify application that connection is created to server */
1657   client->internal->ops->connected(client, conn, success ?
1658                                    SILC_CLIENT_CONN_SUCCESS_RESUME :
1659                                    SILC_CLIENT_CONN_ERROR);
1660
1661   if (success) {
1662     /* Issue INFO command to fetch the real server name and server
1663        information and other stuff. */
1664     silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1665                                  silc_client_command_reply_info_i, 0, 
1666                                  ++conn->cmd_ident);
1667     sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1668     silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1669                              conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1670     silc_buffer_free(sidp);
1671   }
1672 }
1673
1674 /* Processes the received new Client ID from server. Old Client ID is
1675    deleted from cache and new one is added. */
1676
1677 void silc_client_receive_new_id(SilcClient client,
1678                                 SilcSocketConnection sock,
1679                                 SilcIDPayload idp)
1680 {
1681   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1682   int connecting = FALSE;
1683   SilcClientID *client_id = silc_id_payload_get_id(idp);
1684
1685   if (!conn->local_entry)
1686     connecting = TRUE;
1687
1688   /* Delete old ID from ID cache */
1689   if (conn->local_id) {
1690     /* Check whether they are different */
1691     if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1692       silc_free(client_id);
1693       return;
1694     }
1695
1696     silc_idcache_del_by_context(conn->internal->client_cache,
1697                                 conn->local_entry);
1698     silc_free(conn->local_id);
1699   }
1700   
1701   /* Save the new ID */
1702
1703   if (conn->local_id_data)
1704     silc_free(conn->local_id_data);
1705
1706   conn->local_id = client_id;
1707   conn->local_id_data = silc_id_payload_get_data(idp);
1708   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1709
1710   if (!conn->local_entry)
1711     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1712
1713   conn->local_entry->nickname = conn->nickname;
1714   if (!conn->local_entry->username)
1715     conn->local_entry->username = strdup(client->username);
1716   if (!conn->local_entry->server)
1717     conn->local_entry->server = strdup(conn->remote_host);
1718   conn->local_entry->id = conn->local_id;
1719   conn->local_entry->valid = TRUE;
1720   if (!conn->local_entry->channels)
1721     conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, 
1722                                                         NULL, NULL,
1723                                                         NULL, NULL, NULL, 
1724                                                         TRUE);
1725
1726   /* Put it to the ID cache */
1727   silc_idcache_add(conn->internal->client_cache,
1728                    strdup(conn->nickname), conn->local_id, 
1729                    (void *)conn->local_entry, 0, NULL);
1730
1731   if (connecting) {
1732     SilcBuffer sidp;
1733
1734     /* Issue IDENTIFY command for itself to get resolved hostname
1735        correctly from server. */
1736     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1737                                  silc_client_command_reply_identify_i, 0, 
1738                                  ++conn->cmd_ident);
1739     sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1740     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1741                              conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1742     silc_buffer_free(sidp);
1743
1744     if (!conn->internal->params.detach_data) {
1745       /* Send NICK command if the nickname was set by the application (and is
1746          not same as the username). Send this with little timeout. */
1747       if (client->nickname && strcmp(client->nickname, client->username))
1748         silc_schedule_task_add(client->schedule, 0,
1749                                silc_client_send_auto_nick, conn,
1750                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1751
1752       /* Notify application of successful connection. We do it here now that
1753          we've received the Client ID and are allowed to send traffic. */
1754       client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1755
1756       /* Issue INFO command to fetch the real server name and server
1757          information and other stuff. */
1758       silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1759                                    silc_client_command_reply_info_i, 0, 
1760                                    ++conn->cmd_ident);
1761       sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1762       silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1763                                conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1764       silc_buffer_free(sidp);
1765     } else {
1766       /* We are resuming session.  Start resolving informations from the
1767          server we need to set the client libary in the state before
1768          detaching the session.  The connect client operation is called
1769          after this is successfully completed */
1770       silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1771                                  NULL);
1772     }
1773   }
1774 }
1775
1776 /* Removes a client entry from all channels it has joined. */
1777
1778 void silc_client_remove_from_channels(SilcClient client,
1779                                       SilcClientConnection conn,
1780                                       SilcClientEntry client_entry)
1781 {
1782   SilcHashTableList htl;
1783   SilcChannelUser chu;
1784
1785   silc_hash_table_list(client_entry->channels, &htl);
1786   while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1787     silc_hash_table_del(chu->client->channels, chu->channel);
1788     silc_hash_table_del(chu->channel->user_list, chu->client);
1789     silc_free(chu);
1790   }
1791
1792   silc_hash_table_list_reset(&htl);
1793 }
1794
1795 /* Replaces `old' client entries from all channels to `new' client entry.
1796    This can be called for example when nickname changes and old ID entry
1797    is replaced from ID cache with the new one. If the old ID entry is only
1798    updated, then this fucntion needs not to be called. */
1799
1800 void silc_client_replace_from_channels(SilcClient client, 
1801                                        SilcClientConnection conn,
1802                                        SilcClientEntry old,
1803                                        SilcClientEntry new)
1804 {
1805   SilcHashTableList htl;
1806   SilcChannelUser chu;
1807
1808   silc_hash_table_list(old->channels, &htl);
1809   while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1810     /* Replace client entry */
1811     silc_hash_table_del(chu->client->channels, chu->channel);
1812     silc_hash_table_del(chu->channel->user_list, chu->client);
1813     
1814     chu->client = new;
1815     silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1816     silc_hash_table_add(chu->client->channels, chu->channel, chu);
1817   }
1818   silc_hash_table_list_reset(&htl);
1819 }
1820
1821 /* Registers failure timeout to process the received failure packet
1822    with timeout. */
1823
1824 void silc_client_process_failure(SilcClient client,
1825                                  SilcSocketConnection sock,
1826                                  SilcPacketContext *packet)
1827 {
1828   SilcUInt32 failure = 0;
1829
1830   if (sock->protocol) {
1831     if (packet->buffer->len >= 4)
1832       SILC_GET32_MSB(failure, packet->buffer->data);
1833
1834     /* Notify application */
1835     client->internal->ops->failure(client, sock->user_data, sock->protocol,
1836                                    (void *)failure);
1837   }
1838 }
1839
1840 /* A timeout callback for the re-key. We will be the initiator of the
1841    re-key protocol. */
1842
1843 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
1844 {
1845   SilcSocketConnection sock = (SilcSocketConnection)context;
1846   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1847   SilcClient client = (SilcClient)conn->internal->rekey->context;
1848   SilcProtocol protocol;
1849   SilcClientRekeyInternalContext *proto_ctx;
1850
1851   SILC_LOG_DEBUG(("Start"));
1852
1853   /* Allocate internal protocol context. This is sent as context
1854      to the protocol. */
1855   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1856   proto_ctx->client = (void *)client;
1857   proto_ctx->sock = silc_socket_dup(sock);
1858   proto_ctx->responder = FALSE;
1859   proto_ctx->pfs = conn->internal->rekey->pfs;
1860       
1861   /* Perform rekey protocol. Will call the final callback after the
1862      protocol is over. */
1863   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY, 
1864                       &protocol, proto_ctx, silc_client_rekey_final);
1865   sock->protocol = protocol;
1866       
1867   /* Run the protocol */
1868   silc_protocol_execute(protocol, client->schedule, 0, 0);
1869
1870   /* Re-register re-key timeout */
1871   silc_schedule_task_add(client->schedule, sock->sock, 
1872                          silc_client_rekey_callback,
1873                          context, conn->internal->rekey->timeout, 0,
1874                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1875 }
1876
1877 /* The final callback for the REKEY protocol. This will actually take the
1878    new key material into use. */
1879
1880 SILC_TASK_CALLBACK(silc_client_rekey_final)
1881 {
1882   SilcProtocol protocol = (SilcProtocol)context;
1883   SilcClientRekeyInternalContext *ctx =
1884     (SilcClientRekeyInternalContext *)protocol->context;
1885   SilcClient client = (SilcClient)ctx->client;
1886   SilcSocketConnection sock = ctx->sock;
1887
1888   SILC_LOG_DEBUG(("Start"));
1889
1890   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1891       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1892     /* Error occured during protocol */
1893     silc_protocol_cancel(protocol, client->schedule);
1894     silc_protocol_free(protocol);
1895     sock->protocol = NULL;
1896     if (ctx->packet)
1897       silc_packet_context_free(ctx->packet);
1898     if (ctx->ske)
1899       silc_ske_free(ctx->ske);
1900     silc_socket_free(ctx->sock);
1901     silc_free(ctx);
1902     return;
1903   }
1904
1905   /* Purge the outgoing data queue to assure that all rekey packets really
1906      go to the network before we quit the protocol. */
1907   silc_client_packet_queue_purge(client, sock);
1908
1909   /* Cleanup */
1910   silc_protocol_free(protocol);
1911   sock->protocol = NULL;
1912   if (ctx->packet)
1913     silc_packet_context_free(ctx->packet);
1914   if (ctx->ske)
1915     silc_ske_free(ctx->ske);
1916   silc_socket_free(ctx->sock);
1917   silc_free(ctx);
1918 }
1919
1920 /* Processes incoming connection authentication method request packet.
1921    It is a reply to our previously sent request. The packet can be used
1922    to resolve the authentication method for the current session if the
1923    client does not know it beforehand. */
1924
1925 void silc_client_connection_auth_request(SilcClient client,
1926                                          SilcSocketConnection sock,
1927                                          SilcPacketContext *packet)
1928 {
1929   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1930   SilcUInt16 conn_type, auth_meth;
1931   int ret;
1932
1933   /* If we haven't send our request then ignore this one. */
1934   if (!conn->internal->connauth)
1935     return;
1936
1937   /* Parse the payload */
1938   ret = silc_buffer_unformat(packet->buffer,
1939                              SILC_STR_UI_SHORT(&conn_type),
1940                              SILC_STR_UI_SHORT(&auth_meth),
1941                              SILC_STR_END);
1942   if (ret == -1)
1943     auth_meth = SILC_AUTH_NONE;
1944
1945   /* Call the request callback to notify application for received 
1946      authentication method information. */
1947   if (conn->internal->connauth->callback)
1948     (*conn->internal->connauth->callback)(client, conn, auth_meth,
1949                                           conn->internal->connauth->context);
1950
1951   silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1952
1953   silc_free(conn->internal->connauth);
1954   conn->internal->connauth = NULL;
1955 }
1956
1957 /* Timeout task callback called if the server does not reply to our 
1958    connection authentication method request in the specified time interval. */
1959
1960 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1961 {
1962   SilcClientConnection conn = (SilcClientConnection)context;
1963   SilcClient client = conn->client;
1964
1965   if (!conn->internal->connauth)
1966     return;
1967
1968   /* Call the request callback to notify application */
1969   if (conn->internal->connauth->callback)
1970     (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1971                                           conn->internal->connauth->context);
1972
1973   silc_free(conn->internal->connauth);
1974   conn->internal->connauth = NULL;
1975 }
1976
1977 /* This function can be used to request the current authentication method
1978    from the server. This may be called when connecting to the server
1979    and the client library requests the authentication data from the
1980    application. If the application does not know the current authentication
1981    method it can request it from the server using this function.
1982    The `callback' with `context' will be called after the server has
1983    replied back with the current authentication method. */
1984
1985 void 
1986 silc_client_request_authentication_method(SilcClient client,
1987                                           SilcClientConnection conn,
1988                                           SilcConnectionAuthRequest callback,
1989                                           void *context)
1990 {
1991   SilcClientConnAuthRequest connauth;
1992   SilcBuffer packet;
1993
1994   assert(client && conn);
1995   connauth = silc_calloc(1, sizeof(*connauth));
1996   connauth->callback = callback;
1997   connauth->context = context;
1998
1999   if (conn->internal->connauth)
2000     silc_free(conn->internal->connauth);
2001
2002   conn->internal->connauth = connauth;
2003
2004   /* Assemble the request packet and send it to the server */
2005   packet = silc_buffer_alloc(4);
2006   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
2007   silc_buffer_format(packet,
2008                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
2009                      SILC_STR_UI_SHORT(SILC_AUTH_NONE),
2010                      SILC_STR_END);
2011   silc_client_packet_send(client, conn->sock, 
2012                           SILC_PACKET_CONNECTION_AUTH_REQUEST,
2013                           NULL, 0, NULL, NULL, 
2014                           packet->data, packet->len, FALSE);
2015   silc_buffer_free(packet);
2016
2017   /* Register a timeout in case server does not reply anything back. */
2018   connauth->timeout =
2019     silc_schedule_task_add(client->schedule, conn->sock->sock, 
2020                            silc_client_request_authentication_method_timeout,
2021                            conn, 
2022                            client->internal->params->connauth_request_secs, 0,
2023                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
2024 }