updates.
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "clientlibincludes.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_packet_parse_real);
30
31 static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
32 static void silc_client_packet_parse_type(SilcClient client, 
33                                           SilcSocketConnection sock,
34                                           SilcPacketContext *packet);
35
36 /* Allocates new client object. This has to be done before client may
37    work. After calling this one must call silc_client_init to initialize
38    the client. The `application' is application specific user data pointer
39    and caller must free it. */
40
41 SilcClient silc_client_alloc(SilcClientOperations *ops, void *application)
42 {
43   SilcClient new_client;
44
45   new_client = silc_calloc(1, sizeof(*new_client));
46   new_client->application = application;
47   new_client->ops = ops;
48
49   return new_client;
50 }
51
52 /* Frees client object and its internals. */
53
54 void silc_client_free(SilcClient client)
55 {
56   if (client) {
57     if (client->rng)
58       silc_rng_free(client->rng);
59
60     silc_free(client);
61   }
62 }
63
64 /* Initializes the client. This makes all the necessary steps to make
65    the client ready to be run. One must call silc_client_run to run the
66    client. Returns FALSE if error occured, TRUE otherwise. */
67
68 int silc_client_init(SilcClient client)
69 {
70   SILC_LOG_DEBUG(("Initializing client"));
71
72   /* Initialize hash functions for client to use */
73   silc_hash_alloc("md5", &client->md5hash);
74   silc_hash_alloc("sha1", &client->sha1hash);
75
76   /* Initialize none cipher */
77   silc_cipher_alloc("none", &client->none_cipher);
78
79   /* Initialize random number generator */
80   client->rng = silc_rng_alloc();
81   silc_rng_init(client->rng);
82   silc_rng_global_init(client->rng);
83
84   /* Register protocols */
85   silc_client_protocols_register();
86
87   /* Initialize the scheduler */
88   silc_schedule_init(&client->io_queue, &client->timeout_queue, 
89                      &client->generic_queue, 5000);
90
91   return TRUE;
92 }
93
94 /* Stops the client. This is called to stop the client and thus to stop
95    the program. */
96
97 void silc_client_stop(SilcClient client)
98 {
99   SILC_LOG_DEBUG(("Stopping client"));
100
101   /* Stop the scheduler, although it might be already stopped. This
102      doesn't hurt anyone. This removes all the tasks and task queues,
103      as well. */
104   silc_schedule_stop();
105   silc_schedule_uninit();
106
107   silc_client_protocols_unregister();
108
109   SILC_LOG_DEBUG(("Client stopped"));
110 }
111
112 /* Runs the client. This starts the scheduler from the utility library.
113    When this functions returns the execution of the appliation is over. */
114
115 void silc_client_run(SilcClient client)
116 {
117   SILC_LOG_DEBUG(("Running client"));
118
119   /* Start the scheduler, the heart of the SILC client. When this returns
120      the program will be terminated. */
121   silc_schedule();
122 }
123
124 /* Allocates and adds new connection to the client. This adds the allocated
125    connection to the connection table and returns a pointer to it. A client
126    can have multiple connections to multiple servers. Every connection must
127    be added to the client using this function. User data `context' may
128    be sent as argument. This function is normally used only if the 
129    application performed the connecting outside the library. The library
130    however may use this internally. */
131
132 SilcClientConnection silc_client_add_connection(SilcClient client,
133                                                 char *hostname,
134                                                 int port,
135                                                 void *context)
136 {
137   SilcClientConnection conn;
138   int i;
139
140   conn = silc_calloc(1, sizeof(*conn));
141
142   /* Initialize ID caches */
143   conn->client_cache = silc_idcache_alloc(0, NULL);
144   conn->channel_cache = silc_idcache_alloc(0, NULL);
145   conn->server_cache = silc_idcache_alloc(0, NULL);
146   conn->client = client;
147   conn->remote_host = strdup(hostname);
148   conn->remote_port = port;
149   conn->context = context;
150   conn->pending_commands = silc_dlist_init();
151
152   /* Add the connection to connections table */
153   for (i = 0; i < client->conns_count; i++)
154     if (client->conns && !client->conns[i]) {
155       client->conns[i] = conn;
156       return conn;
157     }
158
159   client->conns = silc_realloc(client->conns, sizeof(*client->conns)
160                                * (client->conns_count + 1));
161   client->conns[client->conns_count] = conn;
162   client->conns_count++;
163
164   return conn;
165 }
166
167 /* Removes connection from client. Frees all memory. */
168
169 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
170 {
171   int i;
172
173   for (i = 0; i < client->conns_count; i++)
174     if (client->conns[i] == conn) {
175       if (conn->pending_commands)
176         silc_dlist_uninit(conn->pending_commands);
177       silc_free(conn);
178       client->conns[i] = NULL;
179     }
180 }
181
182 /* Adds listener socket to the listener sockets table. This function is
183    used to add socket objects that are listeners to the client.  This should
184    not be used to add other connection objects. */
185
186 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
187 {
188   int i;
189
190   if (!client->sockets) {
191     client->sockets = silc_calloc(1, sizeof(*client->sockets));
192     client->sockets[0] = sock;
193     client->sockets_count = 1;
194     return;
195   }
196
197   for (i = 0; i < client->sockets_count; i++) {
198     if (client->sockets[i] == NULL) {
199       client->sockets[i] = sock;
200       return;
201     }
202   }
203
204   client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
205                                  (client->sockets_count + 1));
206   client->sockets[client->sockets_count] = sock;
207   client->sockets_count++;
208 }
209
210 /* Deletes listener socket from the listener sockets table. */
211
212 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
213 {
214   int i;
215
216   if (!client->sockets)
217     return;
218
219   for (i = 0; i < client->sockets_count; i++) {
220     if (client->sockets[i] == sock) {
221       client->sockets[i] = NULL;
222       return;
223     }
224   }
225 }
226
227 static int 
228 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
229 {
230   int sock;
231
232   /* XXX In the future we should give up this non-blocking connect all
233      together and use threads instead. */
234   /* Create connection to server asynchronously */
235   sock = silc_net_create_connection_async(ctx->port, ctx->host);
236   if (sock < 0)
237     return -1;
238
239   /* Register task that will receive the async connect and will
240      read the result. */
241   ctx->task = silc_task_register(ctx->client->io_queue, sock, 
242                                  silc_client_connect_to_server_start,
243                                  (void *)ctx, 0, 0, 
244                                  SILC_TASK_FD,
245                                  SILC_TASK_PRI_NORMAL);
246   silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
247   silc_schedule_set_listen_fd(sock, ctx->task->iomask);
248
249   ctx->sock = sock;
250
251   return sock;
252 }
253
254 /* Connects to remote server. This is the main routine used to connect
255    to SILC server. Returns -1 on error and the created socket otherwise. 
256    The `context' is user context that is saved into the SilcClientConnection
257    that is created after the connection is created. Note that application
258    may handle the connecting process outside the library. If this is the
259    case then this function is not used at all. When the connecting is
260    done the `connect' client operation is called. */
261
262 int silc_client_connect_to_server(SilcClient client, int port,
263                                   char *host, void *context)
264 {
265   SilcClientInternalConnectContext *ctx;
266   SilcClientConnection conn;
267   int sock;
268
269   SILC_LOG_DEBUG(("Connecting to port %d of server %s",
270                   port, host));
271
272   conn = silc_client_add_connection(client, host, port, context);
273
274   client->ops->say(client, conn, 
275                    "Connecting to port %d of server %s", port, host);
276
277   /* Allocate internal context for connection process. This is
278      needed as we are doing async connecting. */
279   ctx = silc_calloc(1, sizeof(*ctx));
280   ctx->client = client;
281   ctx->conn = conn;
282   ctx->host = strdup(host);
283   ctx->port = port;
284   ctx->tries = 0;
285
286   /* Do the actual connecting process */
287   sock = silc_client_connect_to_server_internal(ctx);
288   if (sock == -1)
289     silc_client_del_connection(client, conn);
290   return sock;
291 }
292
293 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
294    key material between client and server.  This function can be called
295    directly if application is performing its own connecting and does not
296    use the connecting provided by this library. This function is normally
297    used only if the application performed the connecting outside the library.
298    The library however may use this internally. */
299
300 int silc_client_start_key_exchange(SilcClient client,
301                                    SilcClientConnection conn,
302                                    int fd)
303 {
304   SilcProtocol protocol;
305   SilcClientKEInternalContext *proto_ctx;
306   void *context;
307
308   /* Allocate new socket connection object */
309   silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
310
311   conn->nickname = strdup(client->username);
312   conn->sock->hostname = conn->remote_host;
313   conn->sock->ip = strdup(conn->remote_host);
314   conn->sock->port = conn->remote_port;
315
316   /* Allocate internal Key Exchange context. This is sent to the
317      protocol as context. */
318   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
319   proto_ctx->client = (void *)client;
320   proto_ctx->sock = conn->sock;
321   proto_ctx->rng = client->rng;
322   proto_ctx->responder = FALSE;
323   proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
324   proto_ctx->verify = silc_client_protocol_ke_verify_key;
325
326   /* Perform key exchange protocol. silc_client_connect_to_server_final
327      will be called after the protocol is finished. */
328   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
329                       &protocol, (void *)proto_ctx,
330                       silc_client_connect_to_server_second);
331   if (!protocol) {
332     client->ops->say(client, conn, 
333                      "Error: Could not start authentication protocol");
334     return FALSE;
335   }
336   conn->sock->protocol = protocol;
337
338   /* Register the connection for network input and output. This sets
339      that scheduler will listen for incoming packets for this connection 
340      and sets that outgoing packets may be sent to this connection as well.
341      However, this doesn't set the scheduler for outgoing traffic, it will 
342      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
343      later when outgoing data is available. */
344   context = (void *)client;
345   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
346
347   /* Execute the protocol */
348   protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
349   return TRUE;
350 }
351
352 /* Start of the connection to the remote server. This is called after
353    succesful TCP/IP connection has been established to the remote host. */
354
355 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
356 {
357   SilcClientInternalConnectContext *ctx =
358     (SilcClientInternalConnectContext *)context;
359   SilcClient client = ctx->client;
360   SilcClientConnection conn = ctx->conn;
361   int opt, opt_len = sizeof(opt);
362
363   SILC_LOG_DEBUG(("Start"));
364
365   /* Check the socket status as it might be in error */
366   getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
367   if (opt != 0) {
368     if (ctx->tries < 2) {
369       /* Connection failed but lets try again */
370       client->ops->say(client, conn, "Could not connect to server %s: %s",
371                        ctx->host, strerror(opt));
372       client->ops->say(client, conn, 
373                        "Connecting to port %d of server %s resumed", 
374                        ctx->port, ctx->host);
375
376       /* Unregister old connection try */
377       silc_schedule_unset_listen_fd(fd);
378       silc_net_close_connection(fd);
379       silc_task_unregister(client->io_queue, ctx->task);
380
381       /* Try again */
382       silc_client_connect_to_server_internal(ctx);
383       ctx->tries++;
384     } else {
385       /* Connection failed and we won't try anymore */
386       client->ops->say(client, conn, "Could not connect to server %s: %s",
387                        ctx->host, strerror(opt));
388       silc_schedule_unset_listen_fd(fd);
389       silc_net_close_connection(fd);
390       silc_task_unregister(client->io_queue, ctx->task);
391       silc_free(ctx);
392
393       /* Notify application of failure */
394       client->ops->connect(client, conn, FALSE);
395       silc_client_del_connection(client, conn);
396     }
397     return;
398   }
399
400   silc_schedule_unset_listen_fd(fd);
401   silc_task_unregister(client->io_queue, ctx->task);
402   silc_free(ctx);
403
404   if (!silc_client_start_key_exchange(client, conn, fd)) {
405     silc_net_close_connection(fd);
406     client->ops->connect(client, conn, FALSE);
407   }
408 }
409
410 /* Second part of the connecting to the server. This executed 
411    authentication protocol. */
412
413 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
414 {
415   SilcProtocol protocol = (SilcProtocol)context;
416   SilcClientKEInternalContext *ctx = 
417     (SilcClientKEInternalContext *)protocol->context;
418   SilcClient client = (SilcClient)ctx->client;
419   SilcSocketConnection sock = NULL;
420   SilcClientConnAuthInternalContext *proto_ctx;
421
422   SILC_LOG_DEBUG(("Start"));
423
424   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
425       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
426     /* Error occured during protocol */
427     SILC_LOG_DEBUG(("Error during KE protocol"));
428     silc_protocol_free(protocol);
429     silc_ske_free_key_material(ctx->keymat);
430     if (ctx->ske)
431       silc_ske_free(ctx->ske);
432     if (ctx->dest_id)
433       silc_free(ctx->dest_id);
434     ctx->sock->protocol = NULL;
435     silc_task_unregister_by_callback(client->timeout_queue,
436                                      silc_client_failure_callback);
437
438     /* Notify application of failure */
439     client->ops->connect(client, ctx->sock->user_data, FALSE);
440     silc_free(ctx);
441     return;
442   }
443
444   /* We now have the key material as the result of the key exchange
445      protocol. Take the key material into use. Free the raw key material
446      as soon as we've set them into use. */
447   silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
448                                    ctx->ske->prop->cipher,
449                                    ctx->ske->prop->pkcs,
450                                    ctx->ske->prop->hash,
451                                    ctx->ske->prop->hmac);
452   silc_ske_free_key_material(ctx->keymat);
453
454   /* Allocate internal context for the authentication protocol. This
455      is sent as context for the protocol. */
456   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
457   proto_ctx->client = (void *)client;
458   proto_ctx->sock = sock = ctx->sock;
459   proto_ctx->ske = ctx->ske;    /* Save SKE object from previous protocol */
460   proto_ctx->dest_id_type = ctx->dest_id_type;
461   proto_ctx->dest_id = ctx->dest_id;
462
463   /* Resolve the authentication method to be used in this connection */
464   if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
465                                     sock->port, &proto_ctx->auth_meth,
466                                     &proto_ctx->auth_data, 
467                                     &proto_ctx->auth_data_len)) {
468     client->ops->say(client, ctx->sock->user_data, 
469                      "Could not resolve authentication method to use, "
470                      "assume no authentication");
471     proto_ctx->auth_meth = SILC_AUTH_NONE;
472   }
473
474   /* Free old protocol as it is finished now */
475   silc_protocol_free(protocol);
476   if (ctx->packet)
477     silc_packet_context_free(ctx->packet);
478   silc_free(ctx);
479   sock->protocol = NULL;
480
481   /* Allocate the authentication protocol. This is allocated here
482      but we won't start it yet. We will be receiving party of this
483      protocol thus we will wait that connecting party will make
484      their first move. */
485   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
486                       &sock->protocol, (void *)proto_ctx, 
487                       silc_client_connect_to_server_final);
488
489   /* Execute the protocol */
490   sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
491 }
492
493 /* Finalizes the connection to the remote SILC server. This is called
494    after authentication protocol has been completed. This send our
495    user information to the server to receive our client ID from
496    server. */
497
498 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
499 {
500   SilcProtocol protocol = (SilcProtocol)context;
501   SilcClientConnAuthInternalContext *ctx = 
502     (SilcClientConnAuthInternalContext *)protocol->context;
503   SilcClient client = (SilcClient)ctx->client;
504   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
505   SilcBuffer packet;
506
507   SILC_LOG_DEBUG(("Start"));
508
509   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
510       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
511     /* Error occured during protocol */
512     SILC_LOG_DEBUG(("Error during authentication protocol"));
513     silc_protocol_free(protocol);
514     if (ctx->auth_data)
515       silc_free(ctx->auth_data);
516     if (ctx->ske)
517       silc_ske_free(ctx->ske);
518     if (ctx->dest_id)
519       silc_free(ctx->dest_id);
520     conn->sock->protocol = NULL;
521     silc_task_unregister_by_callback(client->timeout_queue,
522                                      silc_client_failure_callback);
523
524     /* Notify application of failure */
525     client->ops->connect(client, ctx->sock->user_data, FALSE);
526     silc_free(ctx);
527     return;
528   }
529
530   /* Send NEW_CLIENT packet to the server. We will become registered
531      to the SILC network after sending this packet and we will receive
532      client ID from the server. */
533   packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
534                              strlen(client->realname));
535   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
536   silc_buffer_format(packet,
537                      SILC_STR_UI_SHORT(strlen(client->username)),
538                      SILC_STR_UI_XNSTRING(client->username,
539                                           strlen(client->username)),
540                      SILC_STR_UI_SHORT(strlen(client->realname)),
541                      SILC_STR_UI_XNSTRING(client->realname,
542                                           strlen(client->realname)),
543                      SILC_STR_END);
544
545   /* Send the packet */
546   silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
547                           NULL, 0, NULL, NULL, 
548                           packet->data, packet->len, TRUE);
549   silc_buffer_free(packet);
550
551   /* Save remote ID. */
552   conn->remote_id = ctx->dest_id;
553   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
554   conn->remote_id_data_len = SILC_ID_SERVER_LEN;
555
556   silc_task_unregister_by_callback(client->timeout_queue,
557                                    silc_client_failure_callback);
558   silc_protocol_free(protocol);
559   if (ctx->auth_data)
560     silc_free(ctx->auth_data);
561   if (ctx->ske)
562     silc_ske_free(ctx->ske);
563   silc_free(ctx);
564   conn->sock->protocol = NULL;
565 }
566
567 /* Internal routine that sends packet or marks packet to be sent. This
568    is used directly only in special cases. Normal cases should use
569    silc_server_packet_send. Returns < 0 on error. */
570
571 int silc_client_packet_send_real(SilcClient client,
572                                  SilcSocketConnection sock,
573                                  int force_send)
574 {
575   int ret;
576
577   /* Send the packet */
578   ret = silc_packet_send(sock, force_send);
579   if (ret != -2)
580     return ret;
581
582   /* Mark that there is some outgoing data available for this connection. 
583      This call sets the connection both for input and output (the input
584      is set always and this call keeps the input setting, actually). 
585      Actual data sending is performed by silc_client_packet_process. */
586   SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
587
588   /* Mark to socket that data is pending in outgoing buffer. This flag
589      is needed if new data is added to the buffer before the earlier
590      put data is sent to the network. */
591   SILC_SET_OUTBUF_PENDING(sock);
592
593   return 0;
594 }
595
596 /* Packet processing callback. This is used to send and receive packets
597    from network. This is generic task. */
598
599 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
600 {
601   SilcClient client = (SilcClient)context;
602   SilcSocketConnection sock = NULL;
603   SilcClientConnection conn;
604   int ret;
605
606   SILC_LOG_DEBUG(("Processing packet"));
607
608   SILC_CLIENT_GET_SOCK(client, fd, sock);
609   if (sock == NULL)
610     return;
611
612   conn = (SilcClientConnection)sock->user_data;
613
614   /* Packet sending */
615   if (type == SILC_TASK_WRITE) {
616     SILC_LOG_DEBUG(("Writing data to connection"));
617
618     if (sock->outbuf->data - sock->outbuf->head)
619       silc_buffer_push(sock->outbuf, 
620                        sock->outbuf->data - sock->outbuf->head);
621
622     ret = silc_client_packet_send_real(client, sock, TRUE);
623
624     /* If returned -2 could not write to connection now, will do
625        it later. */
626     if (ret == -2)
627       return;
628     
629     /* The packet has been sent and now it is time to set the connection
630        back to only for input. When there is again some outgoing data 
631        available for this connection it will be set for output as well. 
632        This call clears the output setting and sets it only for input. */
633     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
634     SILC_UNSET_OUTBUF_PENDING(sock);
635
636     silc_buffer_clear(sock->outbuf);
637     return;
638   }
639
640   /* Packet receiving */
641   if (type == SILC_TASK_READ) {
642     SILC_LOG_DEBUG(("Reading data from connection"));
643
644     /* Read data from network */
645     ret = silc_packet_receive(sock);
646     if (ret < 0)
647       return;
648     
649     /* EOF */
650     if (ret == 0) {
651       SILC_LOG_DEBUG(("Read EOF"));
652
653       /* If connection is disconnecting already we will finally
654          close the connection */
655       if (SILC_IS_DISCONNECTING(sock)) {
656         client->ops->disconnect(client, conn);
657         silc_client_close_connection(client, conn);
658         return;
659       }
660       
661       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
662       client->ops->disconnect(client, conn);
663       silc_client_close_connection(client, conn);
664       return;
665     }
666
667     /* Process the packet. This will call the parser that will then
668        decrypt and parse the packet. */
669     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
670       silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
671                                   silc_client_packet_parse, client);
672     else
673       silc_packet_receive_process(sock, NULL, NULL,
674                                   silc_client_packet_parse, client);
675   }
676 }
677
678 /* Callback function that the silc_packet_decrypt will call to make the
679    decision whether the packet is normal or special packet. We will 
680    return TRUE if it is normal and FALSE if it is special */
681
682 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
683                                             SilcBuffer buffer,
684                                             SilcPacketContext *packet,
685                                             void *context)
686 {
687
688   /* Packet is normal packet, if: 
689
690      1) packet is private message packet and does not have private key set
691      2) is other packet than channel message packet
692
693      all other packets are special packets 
694   */
695
696   if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
697       (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
698     return FALSE;
699
700   if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
701     return TRUE;
702
703   return FALSE;
704 }
705
706 /* Parses whole packet, received earlier. */
707
708 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
709 {
710   SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
711   SilcClient client = (SilcClient)parse_ctx->context;
712   SilcPacketContext *packet = parse_ctx->packet;
713   SilcBuffer buffer = packet->buffer;
714   SilcSocketConnection sock = parse_ctx->sock;
715   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
716   int ret;
717
718   SILC_LOG_DEBUG(("Start"));
719
720   /* Decrypt the received packet */
721   if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
722     ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
723                               silc_client_packet_decrypt_check, parse_ctx);
724   else
725     ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
726                               silc_client_packet_decrypt_check, parse_ctx);
727
728   if (ret < 0)
729     goto out;
730
731   if (ret == 0) {
732     /* Parse the packet. Packet type is returned. */
733     ret = silc_packet_parse(packet);
734   } else {
735     /* Parse the packet header in special way as this is "special"
736        packet type. */
737     ret = silc_packet_parse_special(packet);
738   }
739
740   if (ret == SILC_PACKET_NONE)
741     goto out;
742
743   /* Parse the incoming packet type */
744   silc_client_packet_parse_type(client, sock, packet);
745
746  out:
747   silc_buffer_clear(sock->inbuf);
748   silc_packet_context_free(packet);
749   silc_free(parse_ctx);
750 }
751
752 /* Parser callback called by silc_packet_receive_process. Thie merely
753    registers timeout that will handle the actual parsing when appropriate. */
754
755 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
756 {
757   SilcClient client = (SilcClient)parser_context->context;
758
759   /* Parse the packet */
760   silc_task_register(client->timeout_queue, parser_context->sock->sock, 
761                      silc_client_packet_parse_real,
762                      (void *)parser_context, 0, 1, 
763                      SILC_TASK_TIMEOUT,
764                      SILC_TASK_PRI_NORMAL);
765 }
766   
767 /* Parses the packet type and calls what ever routines the packet type
768    requires. This is done for all incoming packets. */
769
770 void silc_client_packet_parse_type(SilcClient client, 
771                                    SilcSocketConnection sock,
772                                    SilcPacketContext *packet)
773 {
774   SilcBuffer buffer = packet->buffer;
775   SilcPacketType type = packet->type;
776
777   SILC_LOG_DEBUG(("Parsing packet type %d", type));
778
779   /* Parse the packet type */
780   switch(type) {
781   case SILC_PACKET_DISCONNECT:
782     silc_client_disconnected_by_server(client, sock, buffer);
783     break;
784   case SILC_PACKET_SUCCESS:
785     /*
786      * Success received for something. For now we can have only
787      * one protocol for connection executing at once hence this
788      * success message is for whatever protocol is executing currently.
789      */
790     if (sock->protocol) {
791       sock->protocol->execute(client->timeout_queue, 0,
792                               sock->protocol, sock->sock, 0, 0);
793     }
794     break;
795   case SILC_PACKET_FAILURE:
796     /*
797      * Failure received for some protocol. Set the protocol state to 
798      * error and call the protocol callback. This fill cause error on
799      * protocol and it will call the final callback.
800      */
801     silc_client_process_failure(client, sock, packet);
802     break;
803   case SILC_PACKET_REJECT:
804     break;
805
806   case SILC_PACKET_NOTIFY:
807     /*
808      * Received notify message 
809      */
810     silc_client_notify_by_server(client, sock, packet);
811     break;
812
813   case SILC_PACKET_ERROR:
814     /*
815      * Received error message
816      */
817     silc_client_error_by_server(client, sock, buffer);
818     break;
819
820   case SILC_PACKET_CHANNEL_MESSAGE:
821     /*
822      * Received message to (from, actually) a channel
823      */
824     silc_client_channel_message(client, sock, packet);
825     break;
826   case SILC_PACKET_CHANNEL_KEY:
827     /*
828      * Received key for a channel. By receiving this key the client will be
829      * able to talk to the channel it has just joined. This can also be
830      * a new key for existing channel as keys expire peridiocally.
831      */
832     silc_client_receive_channel_key(client, sock, buffer);
833     break;
834
835   case SILC_PACKET_PRIVATE_MESSAGE:
836     /*
837      * Received private message
838      */
839     silc_client_private_message(client, sock, packet);
840     break;
841   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
842     /*
843      * Received private message key
844      */
845     break;
846
847   case SILC_PACKET_COMMAND_REPLY:
848     /*
849      * Recived reply for a command
850      */
851     silc_client_command_reply_process(client, sock, packet);
852     break;
853
854   case SILC_PACKET_KEY_EXCHANGE:
855     if (sock->protocol && sock->protocol->protocol->type 
856         == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
857       SilcClientKEInternalContext *proto_ctx = 
858         (SilcClientKEInternalContext *)sock->protocol->context;
859
860       proto_ctx->packet = silc_packet_context_dup(packet);
861       proto_ctx->dest_id_type = packet->src_id_type;
862       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
863                                           packet->src_id_type);
864       if (!proto_ctx->dest_id)
865         break;
866
867       /* Let the protocol handle the packet */
868       sock->protocol->execute(client->timeout_queue, 0,
869                               sock->protocol, sock->sock, 0, 0);
870     } else {
871       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
872                       "protocol active, packet dropped."));
873
874       /* XXX Trigger KE protocol?? Rekey actually! */
875     }
876     break;
877
878   case SILC_PACKET_KEY_EXCHANGE_1:
879     if (sock->protocol && sock->protocol->protocol->type 
880         == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
881       SilcClientKEInternalContext *proto_ctx = 
882         (SilcClientKEInternalContext *)sock->protocol->context;
883
884       if (proto_ctx->packet)
885         silc_packet_context_free(proto_ctx->packet);
886
887       proto_ctx->packet = silc_packet_context_dup(packet);
888       proto_ctx->dest_id_type = packet->src_id_type;
889       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
890                                           packet->src_id_type);
891       if (!proto_ctx->dest_id)
892         break;
893
894       /* Let the protocol handle the packet */
895       sock->protocol->execute(client->timeout_queue, 0,
896                               sock->protocol, sock->sock, 0, 0);
897     } else {
898       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
899                       "protocol active, packet dropped."));
900     }
901     break;
902   case SILC_PACKET_KEY_EXCHANGE_2:
903     if (sock->protocol && sock->protocol->protocol->type 
904         == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
905       SilcClientKEInternalContext *proto_ctx = 
906         (SilcClientKEInternalContext *)sock->protocol->context;
907
908       if (proto_ctx->packet)
909         silc_packet_context_free(proto_ctx->packet);
910
911       proto_ctx->packet = silc_packet_context_dup(packet);
912       proto_ctx->dest_id_type = packet->src_id_type;
913       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
914                                           packet->src_id_type);
915       if (!proto_ctx->dest_id)
916         break;
917
918       /* Let the protocol handle the packet */
919       sock->protocol->execute(client->timeout_queue, 0,
920                               sock->protocol, sock->sock, 0, 0);
921     } else {
922       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
923                       "protocol active, packet dropped."));
924     }
925     break;
926
927   case SILC_PACKET_NEW_ID:
928     {
929       /*
930        * Received new ID from server. This packet is received at
931        * the connection to the server.  New ID is also received when 
932        * user changes nickname but in that case the new ID is received
933        * as command reply and not as this packet type.
934        */
935       SilcIDPayload idp;
936
937       idp = silc_id_payload_parse(buffer);
938       if (!idp)
939         break;
940       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
941         break;
942
943       silc_client_receive_new_id(client, sock, idp);
944       silc_id_payload_free(idp);
945       break;
946     }
947
948   case SILC_PACKET_HEARTBEAT:
949     /*
950      * Received heartbeat packet
951      */
952     SILC_LOG_DEBUG(("Heartbeat packet"));
953     break;
954
955   case SILC_PACKET_KEY_AGREEMENT:
956     /*
957      * Received key agreement packet
958      */
959     SILC_LOG_DEBUG(("Key agreement packet"));
960     silc_client_key_agreement(client, sock, packet);
961     break;
962
963   default:
964     SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
965     break;
966   }
967 }
968
969 /* Sends packet. This doesn't actually send the packet instead it assembles
970    it and marks it to be sent. However, if force_send is TRUE the packet
971    is sent immediately. if dst_id, cipher and hmac are NULL those parameters
972    will be derived from sock argument. Otherwise the valid arguments sent
973    are used. */
974
975 void silc_client_packet_send(SilcClient client, 
976                              SilcSocketConnection sock,
977                              SilcPacketType type, 
978                              void *dst_id,
979                              SilcIdType dst_id_type,
980                              SilcCipher cipher,
981                              SilcHmac hmac,
982                              unsigned char *data, 
983                              unsigned int data_len, 
984                              int force_send)
985 {
986   SilcPacketContext packetdata;
987
988   SILC_LOG_DEBUG(("Sending packet, type %d", type));
989
990   /* Get data used in the packet sending, keys and stuff */
991   if ((!cipher || !hmac || !dst_id) && sock->user_data) {
992     if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
993       cipher = ((SilcClientConnection)sock->user_data)->send_key;
994
995     if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
996       hmac = ((SilcClientConnection)sock->user_data)->hmac;
997
998     if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
999       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1000       dst_id_type = SILC_ID_SERVER;
1001     }
1002   }
1003
1004   /* Set the packet context pointers */
1005   packetdata.flags = 0;
1006   packetdata.type = type;
1007   if (sock->user_data && 
1008       ((SilcClientConnection)sock->user_data)->local_id_data)
1009     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1010   else 
1011     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1012   packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1013   packetdata.src_id_type = SILC_ID_CLIENT;
1014   if (dst_id) {
1015     packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1016     packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1017     packetdata.dst_id_type = dst_id_type;
1018   } else {
1019     packetdata.dst_id = NULL;
1020     packetdata.dst_id_len = 0;
1021     packetdata.dst_id_type = SILC_ID_NONE;
1022   }
1023   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
1024     packetdata.src_id_len + packetdata.dst_id_len;
1025   packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1026
1027   /* Prepare outgoing data buffer for packet sending */
1028   silc_packet_send_prepare(sock, 
1029                            SILC_PACKET_HEADER_LEN +
1030                            packetdata.src_id_len + 
1031                            packetdata.dst_id_len,
1032                            packetdata.padlen,
1033                            data_len);
1034
1035   SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1036
1037   packetdata.buffer = sock->outbuf;
1038
1039   /* Put the data to the buffer */
1040   if (data && data_len)
1041     silc_buffer_put(sock->outbuf, data, data_len);
1042
1043   /* Create the outgoing packet */
1044   silc_packet_assemble(&packetdata);
1045
1046   /* Encrypt the packet */
1047   if (cipher)
1048     silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1049
1050   SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1051                    sock->outbuf->data, sock->outbuf->len);
1052
1053   /* Now actually send the packet */
1054   silc_client_packet_send_real(client, sock, force_send);
1055 }
1056
1057 /* Closes connection to remote end. Free's all allocated data except
1058    for some information such as nickname etc. that are valid at all time. */
1059
1060 void silc_client_close_connection(SilcClient client,
1061                                   SilcClientConnection conn)
1062 {
1063   SilcSocketConnection sock = conn->sock;
1064
1065   /* We won't listen for this connection anymore */
1066   silc_schedule_unset_listen_fd(sock->sock);
1067
1068   /* Unregister all tasks */
1069   silc_task_unregister_by_fd(client->io_queue, sock->sock);
1070   silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1071
1072   /* Close the actual connection */
1073   silc_net_close_connection(sock->sock);
1074
1075   client->ops->say(client, sock->user_data,
1076                    "Closed connection to host %s", sock->hostname);
1077
1078   /* Free everything */
1079   if (sock->user_data) {
1080     /* XXX Free all client entries and channel entries. */
1081
1082     /* Clear ID caches */
1083     silc_idcache_del_all(conn->client_cache);
1084     silc_idcache_del_all(conn->channel_cache);
1085
1086     /* Free data */
1087     if (conn->remote_host)
1088       silc_free(conn->remote_host);
1089     if (conn->local_id)
1090       silc_free(conn->local_id);
1091     if (conn->local_id_data)
1092       silc_free(conn->local_id_data);
1093     if (conn->send_key)
1094       silc_cipher_free(conn->send_key);
1095     if (conn->receive_key)
1096       silc_cipher_free(conn->receive_key);
1097     if (conn->hmac)
1098       silc_hmac_free(conn->hmac);
1099     if (conn->hmac_key) {
1100       memset(conn->hmac_key, 0, conn->hmac_key_len);
1101       silc_free(conn->hmac_key);
1102     }
1103     if (conn->pending_commands)
1104       silc_dlist_uninit(conn->pending_commands);
1105
1106     conn->sock = NULL;
1107     conn->remote_port = 0;
1108     conn->remote_type = 0;
1109     conn->send_key = NULL;
1110     conn->receive_key = NULL;
1111     conn->hmac = NULL;
1112     conn->hmac_key = NULL;
1113     conn->hmac_key_len = 0;
1114     conn->local_id = NULL;
1115     conn->local_id_data = NULL;
1116     conn->remote_host = NULL;
1117     conn->current_channel = NULL;
1118     conn->pending_commands = NULL;
1119
1120     silc_client_del_connection(client, conn);
1121   }
1122
1123   if (sock->protocol) {
1124     silc_protocol_free(sock->protocol);
1125     sock->protocol = NULL;
1126   }
1127   silc_socket_free(sock);
1128 }
1129
1130 /* Called when we receive disconnection packet from server. This 
1131    closes our end properly and displays the reason of the disconnection
1132    on the screen. */
1133
1134 void silc_client_disconnected_by_server(SilcClient client,
1135                                         SilcSocketConnection sock,
1136                                         SilcBuffer message)
1137 {
1138   char *msg;
1139
1140   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1141
1142   msg = silc_calloc(message->len + 1, sizeof(char));
1143   memcpy(msg, message->data, message->len);
1144   client->ops->say(client, sock->user_data, msg);
1145   silc_free(msg);
1146
1147   SILC_SET_DISCONNECTED(sock);
1148   silc_client_close_connection(client, sock->user_data);
1149 }
1150
1151 /* Received error message from server. Display it on the screen. 
1152    We don't take any action what so ever of the error message. */
1153
1154 void silc_client_error_by_server(SilcClient client,
1155                                  SilcSocketConnection sock,
1156                                  SilcBuffer message)
1157 {
1158   char *msg;
1159
1160   msg = silc_calloc(message->len + 1, sizeof(char));
1161   memcpy(msg, message->data, message->len);
1162   client->ops->say(client, sock->user_data, msg);
1163   silc_free(msg);
1164 }
1165
1166 /* Processes the received new Client ID from server. Old Client ID is
1167    deleted from cache and new one is added. */
1168
1169 void silc_client_receive_new_id(SilcClient client,
1170                                 SilcSocketConnection sock,
1171                                 SilcIDPayload idp)
1172 {
1173   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1174   int connecting = FALSE;
1175
1176   if (!conn->local_entry)
1177     connecting = TRUE;
1178
1179   /* Delete old ID from ID cache */
1180   silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1181   
1182   /* Save the new ID */
1183   if (conn->local_id)
1184     silc_free(conn->local_id);
1185   if (conn->local_id_data)
1186     silc_free(conn->local_id_data);
1187
1188   conn->local_id = silc_id_payload_get_id(idp);
1189   conn->local_id_data = silc_id_payload_get_data(idp);
1190   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1191
1192   if (!conn->local_entry)
1193     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1194
1195   conn->local_entry->nickname = conn->nickname;
1196   if (!conn->local_entry->username) {
1197     conn->local_entry->username = 
1198       silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1199                   sizeof(conn->local_entry->username));
1200     sprintf(conn->local_entry->username, "%s@%s", client->username,
1201             client->hostname);
1202   }
1203   conn->local_entry->server = strdup(conn->remote_host);
1204   conn->local_entry->id = conn->local_id;
1205   
1206   /* Put it to the ID cache */
1207   silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1208                    SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1209                    TRUE, FALSE);
1210
1211   /* Notify application of successful connection. We do it here now that
1212      we've received the Client ID and are allowed to send traffic. */
1213   if (connecting)
1214     client->ops->connect(client, conn, TRUE);
1215 }
1216
1217 /* Processed received Channel ID for a channel. This is called when client
1218    joins to channel and server replies with channel ID. The ID is cached. 
1219    Returns the created channel entry. */
1220
1221 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1222                                             SilcSocketConnection sock,
1223                                             char *channel_name,
1224                                             unsigned int mode, 
1225                                             SilcIDPayload idp)
1226 {
1227   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1228   SilcChannelEntry channel;
1229
1230   SILC_LOG_DEBUG(("New channel ID"));
1231
1232   channel = silc_calloc(1, sizeof(*channel));
1233   channel->channel_name = channel_name;
1234   channel->id = silc_id_payload_get_id(idp);
1235   channel->mode = mode;
1236   silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1237
1238   conn->current_channel = channel;
1239
1240   /* Put it to the ID cache */
1241   silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1242                    SILC_ID_CHANNEL, (void *)channel->id, (void *)channel, 
1243                    TRUE, FALSE);
1244
1245   return channel;
1246 }
1247
1248 /* Removes a client entry from all channel it has joined. This really is
1249    a performance killer (client_entry should have pointers to channel 
1250    entry list). */
1251
1252 void silc_client_remove_from_channels(SilcClient client,
1253                                       SilcClientConnection conn,
1254                                       SilcClientEntry client_entry)
1255 {
1256   SilcIDCacheEntry id_cache;
1257   SilcIDCacheList list;
1258   SilcChannelEntry channel;
1259   SilcChannelUser chu;
1260
1261   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1262                                SILC_ID_CHANNEL, &list))
1263     return;
1264
1265   silc_idcache_list_first(list, &id_cache);
1266   channel = (SilcChannelEntry)id_cache->context;
1267   
1268   while (channel) {
1269     
1270     /* Remove client from channel */
1271     silc_list_start(channel->clients);
1272     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1273       if (chu->client == client_entry) {
1274         silc_list_del(channel->clients, chu);
1275         silc_free(chu);
1276         break;
1277       }
1278     }
1279
1280     if (!silc_idcache_list_next(list, &id_cache))
1281       break;
1282     
1283     channel = (SilcChannelEntry)id_cache->context;
1284   }
1285
1286   silc_idcache_list_free(list);
1287 }
1288
1289 /* Replaces `old' client entries from all channels to `new' client entry.
1290    This can be called for example when nickname changes and old ID entry
1291    is replaced from ID cache with the new one. If the old ID entry is only
1292    updated, then this fucntion needs not to be called. */
1293
1294 void silc_client_replace_from_channels(SilcClient client, 
1295                                        SilcClientConnection conn,
1296                                        SilcClientEntry old,
1297                                        SilcClientEntry new)
1298 {
1299   SilcIDCacheEntry id_cache;
1300   SilcIDCacheList list;
1301   SilcChannelEntry channel;
1302   SilcChannelUser chu;
1303
1304   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1305                                SILC_ID_CHANNEL, &list))
1306     return;
1307
1308   silc_idcache_list_first(list, &id_cache);
1309   channel = (SilcChannelEntry)id_cache->context;
1310   
1311   while (channel) {
1312     
1313     /* Replace client entry */
1314     silc_list_start(channel->clients);
1315     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1316       if (chu->client == old) {
1317         chu->client = new;
1318         break;
1319       }
1320     }
1321
1322     if (!silc_idcache_list_next(list, &id_cache))
1323       break;
1324     
1325     channel = (SilcChannelEntry)id_cache->context;
1326   }
1327
1328   silc_idcache_list_free(list);
1329 }
1330
1331 /* Parses mode mask and returns the mode as string. */
1332
1333 char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
1334 {
1335   char string[100];
1336
1337   if (!mode)
1338     return NULL;
1339
1340   memset(string, 0, sizeof(string));
1341
1342   if (mode & SILC_CHANNEL_MODE_PRIVATE)
1343     strncat(string, "p", 1);
1344
1345   if (mode & SILC_CHANNEL_MODE_SECRET)
1346     strncat(string, "s", 1);
1347
1348   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1349     strncat(string, "k", 1);
1350
1351   if (mode & SILC_CHANNEL_MODE_INVITE)
1352     strncat(string, "i", 1);
1353
1354   if (mode & SILC_CHANNEL_MODE_TOPIC)
1355     strncat(string, "t", 1);
1356
1357   if (mode & SILC_CHANNEL_MODE_ULIMIT)
1358     strncat(string, "l", 1);
1359
1360   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1361     strncat(string, "a", 1);
1362
1363   if (mode & SILC_CHANNEL_MODE_CIPHER) {
1364     char cipher[30];
1365     memset(cipher, 0, sizeof(cipher));
1366     snprintf(cipher, sizeof(cipher), " c (%s)", 
1367              channel->channel_key->cipher->name);
1368     strncat(string, cipher, strlen(cipher));
1369   }
1370
1371   if (mode & SILC_CHANNEL_MODE_HMAC) {
1372     char hmac[30];
1373     memset(hmac, 0, sizeof(hmac));
1374     snprintf(hmac, sizeof(hmac), " h (%s)", 
1375              channel->hmac->hmac->name);
1376     strncat(string, hmac, strlen(hmac));
1377   }
1378
1379   /* Rest of mode is ignored */
1380
1381   return strdup(string);
1382 }
1383
1384 /* Parses channel user mode mask and returns te mode as string */
1385
1386 char *silc_client_chumode(unsigned int mode)
1387 {
1388   char string[4];
1389
1390   if (!mode)
1391     return NULL;
1392
1393   memset(string, 0, sizeof(string));
1394
1395   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1396     strncat(string, "f", 1);
1397
1398   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1399     strncat(string, "o", 1);
1400
1401   return strdup(string);
1402 }
1403
1404 /* Parses channel user mode and returns it as special mode character. */
1405
1406 char *silc_client_chumode_char(unsigned int mode)
1407 {
1408   char string[4];
1409
1410   if (!mode)
1411     return NULL;
1412
1413   memset(string, 0, sizeof(string));
1414
1415   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1416     strncat(string, "*", 1);
1417
1418   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1419     strncat(string, "@", 1);
1420
1421   return strdup(string);
1422 }
1423
1424 /* Failure timeout callback. If this is called then we will immediately
1425    process the received failure. We always process the failure with timeout
1426    since we do not want to blindly trust to received failure packets. 
1427    This won't be called (the timeout is cancelled) if the failure was
1428    bogus (it is bogus if remote does not close the connection after sending
1429    the failure). */
1430
1431 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1432 {
1433   SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1434
1435   if (f->sock->protocol) {
1436     f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1437     f->sock->protocol->execute(f->client->timeout_queue, 0,
1438                                f->sock->protocol, f->sock->sock, 0, 0);
1439     
1440     /* Notify application */
1441     f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1442                             (void *)f->failure);
1443   }
1444
1445   silc_free(f);
1446 }
1447
1448 /* Registers failure timeout to process the received failure packet
1449    with timeout. */
1450
1451 void silc_client_process_failure(SilcClient client,
1452                                  SilcSocketConnection sock,
1453                                  SilcPacketContext *packet)
1454 {
1455   SilcClientFailureContext *f;
1456   unsigned int failure = 0;
1457
1458   if (sock->protocol) {
1459     if (packet->buffer->len >= 4)
1460       SILC_GET32_MSB(failure, packet->buffer->data);
1461
1462     f = silc_calloc(1, sizeof(*f));
1463     f->client = client;
1464     f->sock = sock;
1465     f->failure = failure;
1466
1467     /* We will wait 5 seconds to process this failure packet */
1468     silc_task_register(client->timeout_queue, sock->sock,
1469                        silc_client_failure_callback, (void *)f, 5, 0,
1470                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1471   }
1472 }