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