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   if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
696        !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
697       packet_type != SILC_PACKET_CHANNEL_MESSAGE)
698     return TRUE;
699
700   return FALSE;
701 }
702
703 /* Parses whole packet, received earlier. */
704
705 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
706 {
707   SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
708   SilcClient client = (SilcClient)parse_ctx->context;
709   SilcPacketContext *packet = parse_ctx->packet;
710   SilcBuffer buffer = packet->buffer;
711   SilcSocketConnection sock = parse_ctx->sock;
712   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
713   int ret;
714
715   SILC_LOG_DEBUG(("Start"));
716
717   /* Decrypt the received packet */
718   if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
719     ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
720                               silc_client_packet_decrypt_check, parse_ctx);
721   else
722     ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
723                               silc_client_packet_decrypt_check, parse_ctx);
724
725   if (ret < 0)
726     goto out;
727
728   if (ret == 0) {
729     /* Parse the packet. Packet type is returned. */
730     ret = silc_packet_parse(packet);
731   } else {
732     /* Parse the packet header in special way as this is "special"
733        packet type. */
734     ret = silc_packet_parse_special(packet);
735   }
736
737   if (ret == SILC_PACKET_NONE)
738     goto out;
739
740   /* Parse the incoming packet type */
741   silc_client_packet_parse_type(client, sock, packet);
742
743  out:
744   silc_buffer_clear(sock->inbuf);
745   silc_packet_context_free(packet);
746   silc_free(parse_ctx);
747 }
748
749 /* Parser callback called by silc_packet_receive_process. Thie merely
750    registers timeout that will handle the actual parsing when appropriate. */
751
752 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
753 {
754   SilcClient client = (SilcClient)parser_context->context;
755
756   /* Parse the packet */
757   silc_task_register(client->timeout_queue, parser_context->sock->sock, 
758                      silc_client_packet_parse_real,
759                      (void *)parser_context, 0, 1, 
760                      SILC_TASK_TIMEOUT,
761                      SILC_TASK_PRI_NORMAL);
762 }
763   
764 /* Parses the packet type and calls what ever routines the packet type
765    requires. This is done for all incoming packets. */
766
767 void silc_client_packet_parse_type(SilcClient client, 
768                                    SilcSocketConnection sock,
769                                    SilcPacketContext *packet)
770 {
771   SilcBuffer buffer = packet->buffer;
772   SilcPacketType type = packet->type;
773
774   SILC_LOG_DEBUG(("Parsing packet type %d", type));
775
776   /* Parse the packet type */
777   switch(type) {
778   case SILC_PACKET_DISCONNECT:
779     silc_client_disconnected_by_server(client, sock, buffer);
780     break;
781   case SILC_PACKET_SUCCESS:
782     /*
783      * Success received for something. For now we can have only
784      * one protocol for connection executing at once hence this
785      * success message is for whatever protocol is executing currently.
786      */
787     if (sock->protocol) {
788       sock->protocol->execute(client->timeout_queue, 0,
789                               sock->protocol, sock->sock, 0, 0);
790     }
791     break;
792   case SILC_PACKET_FAILURE:
793     /*
794      * Failure received for some protocol. Set the protocol state to 
795      * error and call the protocol callback. This fill cause error on
796      * protocol and it will call the final callback.
797      */
798     silc_client_process_failure(client, sock, packet);
799     break;
800   case SILC_PACKET_REJECT:
801     break;
802
803   case SILC_PACKET_NOTIFY:
804     /*
805      * Received notify message 
806      */
807     silc_client_notify_by_server(client, sock, packet);
808     break;
809
810   case SILC_PACKET_ERROR:
811     /*
812      * Received error message
813      */
814     silc_client_error_by_server(client, sock, buffer);
815     break;
816
817   case SILC_PACKET_CHANNEL_MESSAGE:
818     /*
819      * Received message to (from, actually) a channel
820      */
821     silc_client_channel_message(client, sock, packet);
822     break;
823   case SILC_PACKET_CHANNEL_KEY:
824     /*
825      * Received key for a channel. By receiving this key the client will be
826      * able to talk to the channel it has just joined. This can also be
827      * a new key for existing channel as keys expire peridiocally.
828      */
829     silc_client_receive_channel_key(client, sock, buffer);
830     break;
831
832   case SILC_PACKET_PRIVATE_MESSAGE:
833     /*
834      * Received private message
835      */
836     silc_client_private_message(client, sock, packet);
837     break;
838   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
839     /*
840      * Received private message key
841      */
842     break;
843
844   case SILC_PACKET_COMMAND_REPLY:
845     /*
846      * Recived reply for a command
847      */
848     silc_client_command_reply_process(client, sock, packet);
849     break;
850
851   case SILC_PACKET_KEY_EXCHANGE:
852     if (sock->protocol && sock->protocol->protocol->type 
853         == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
854       SilcClientKEInternalContext *proto_ctx = 
855         (SilcClientKEInternalContext *)sock->protocol->context;
856
857       proto_ctx->packet = silc_packet_context_dup(packet);
858       proto_ctx->dest_id_type = packet->src_id_type;
859       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
860                                           packet->src_id_type);
861       if (!proto_ctx->dest_id)
862         break;
863
864       /* Let the protocol handle the packet */
865       sock->protocol->execute(client->timeout_queue, 0,
866                               sock->protocol, sock->sock, 0, 0);
867     } else {
868       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
869                       "protocol active, packet dropped."));
870
871       /* XXX Trigger KE protocol?? Rekey actually! */
872     }
873     break;
874
875   case SILC_PACKET_KEY_EXCHANGE_1:
876     if (sock->protocol && sock->protocol->protocol->type 
877         == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
878       SilcClientKEInternalContext *proto_ctx = 
879         (SilcClientKEInternalContext *)sock->protocol->context;
880
881       if (proto_ctx->packet)
882         silc_packet_context_free(proto_ctx->packet);
883
884       proto_ctx->packet = silc_packet_context_dup(packet);
885       proto_ctx->dest_id_type = packet->src_id_type;
886       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
887                                           packet->src_id_type);
888       if (!proto_ctx->dest_id)
889         break;
890
891       /* Let the protocol handle the packet */
892       sock->protocol->execute(client->timeout_queue, 0,
893                               sock->protocol, sock->sock, 0, 0);
894     } else {
895       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
896                       "protocol active, packet dropped."));
897     }
898     break;
899   case SILC_PACKET_KEY_EXCHANGE_2:
900     if (sock->protocol && sock->protocol->protocol->type 
901         == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
902       SilcClientKEInternalContext *proto_ctx = 
903         (SilcClientKEInternalContext *)sock->protocol->context;
904
905       if (proto_ctx->packet)
906         silc_packet_context_free(proto_ctx->packet);
907
908       proto_ctx->packet = silc_packet_context_dup(packet);
909       proto_ctx->dest_id_type = packet->src_id_type;
910       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
911                                           packet->src_id_type);
912       if (!proto_ctx->dest_id)
913         break;
914
915       /* Let the protocol handle the packet */
916       sock->protocol->execute(client->timeout_queue, 0,
917                               sock->protocol, sock->sock, 0, 0);
918     } else {
919       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
920                       "protocol active, packet dropped."));
921     }
922     break;
923
924   case SILC_PACKET_NEW_ID:
925     {
926       /*
927        * Received new ID from server. This packet is received at
928        * the connection to the server.  New ID is also received when 
929        * user changes nickname but in that case the new ID is received
930        * as command reply and not as this packet type.
931        */
932       SilcIDPayload idp;
933
934       idp = silc_id_payload_parse(buffer);
935       if (!idp)
936         break;
937       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
938         break;
939
940       silc_client_receive_new_id(client, sock, idp);
941       silc_id_payload_free(idp);
942       break;
943     }
944
945   case SILC_PACKET_HEARTBEAT:
946     /*
947      * Received heartbeat packet
948      */
949     SILC_LOG_DEBUG(("Heartbeat packet"));
950     break;
951
952   case SILC_PACKET_KEY_AGREEMENT:
953     /*
954      * Received key agreement packet
955      */
956     SILC_LOG_DEBUG(("Key agreement packet"));
957     silc_client_key_agreement(client, sock, packet);
958     break;
959
960   default:
961     SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
962     break;
963   }
964 }
965
966 /* Sends packet. This doesn't actually send the packet instead it assembles
967    it and marks it to be sent. However, if force_send is TRUE the packet
968    is sent immediately. if dst_id, cipher and hmac are NULL those parameters
969    will be derived from sock argument. Otherwise the valid arguments sent
970    are used. */
971
972 void silc_client_packet_send(SilcClient client, 
973                              SilcSocketConnection sock,
974                              SilcPacketType type, 
975                              void *dst_id,
976                              SilcIdType dst_id_type,
977                              SilcCipher cipher,
978                              SilcHmac hmac,
979                              unsigned char *data, 
980                              unsigned int data_len, 
981                              int force_send)
982 {
983   SilcPacketContext packetdata;
984
985   SILC_LOG_DEBUG(("Sending packet, type %d", type));
986
987   /* Get data used in the packet sending, keys and stuff */
988   if ((!cipher || !hmac || !dst_id) && sock->user_data) {
989     if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
990       cipher = ((SilcClientConnection)sock->user_data)->send_key;
991
992     if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
993       hmac = ((SilcClientConnection)sock->user_data)->hmac;
994
995     if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
996       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
997       dst_id_type = SILC_ID_SERVER;
998     }
999   }
1000
1001   /* Set the packet context pointers */
1002   packetdata.flags = 0;
1003   packetdata.type = type;
1004   if (sock->user_data && 
1005       ((SilcClientConnection)sock->user_data)->local_id_data)
1006     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1007   else 
1008     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1009   packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1010   packetdata.src_id_type = SILC_ID_CLIENT;
1011   if (dst_id) {
1012     packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1013     packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1014     packetdata.dst_id_type = dst_id_type;
1015   } else {
1016     packetdata.dst_id = NULL;
1017     packetdata.dst_id_len = 0;
1018     packetdata.dst_id_type = SILC_ID_NONE;
1019   }
1020   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
1021     packetdata.src_id_len + packetdata.dst_id_len;
1022   packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1023
1024   /* Prepare outgoing data buffer for packet sending */
1025   silc_packet_send_prepare(sock, 
1026                            SILC_PACKET_HEADER_LEN +
1027                            packetdata.src_id_len + 
1028                            packetdata.dst_id_len,
1029                            packetdata.padlen,
1030                            data_len);
1031
1032   SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1033
1034   packetdata.buffer = sock->outbuf;
1035
1036   /* Put the data to the buffer */
1037   if (data && data_len)
1038     silc_buffer_put(sock->outbuf, data, data_len);
1039
1040   /* Create the outgoing packet */
1041   silc_packet_assemble(&packetdata);
1042
1043   /* Encrypt the packet */
1044   if (cipher)
1045     silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1046
1047   SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1048                    sock->outbuf->data, sock->outbuf->len);
1049
1050   /* Now actually send the packet */
1051   silc_client_packet_send_real(client, sock, force_send);
1052 }
1053
1054 /* Closes connection to remote end. Free's all allocated data except
1055    for some information such as nickname etc. that are valid at all time. */
1056
1057 void silc_client_close_connection(SilcClient client,
1058                                   SilcClientConnection conn)
1059 {
1060   SilcSocketConnection sock = conn->sock;
1061
1062   /* We won't listen for this connection anymore */
1063   silc_schedule_unset_listen_fd(sock->sock);
1064
1065   /* Unregister all tasks */
1066   silc_task_unregister_by_fd(client->io_queue, sock->sock);
1067   silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1068
1069   /* Close the actual connection */
1070   silc_net_close_connection(sock->sock);
1071
1072   client->ops->say(client, sock->user_data,
1073                    "Closed connection to host %s", sock->hostname);
1074
1075   /* Free everything */
1076   if (sock->user_data) {
1077     /* XXX Free all client entries and channel entries. */
1078
1079     /* Clear ID caches */
1080     silc_idcache_del_all(conn->client_cache);
1081     silc_idcache_del_all(conn->channel_cache);
1082
1083     /* Free data */
1084     if (conn->remote_host)
1085       silc_free(conn->remote_host);
1086     if (conn->local_id)
1087       silc_free(conn->local_id);
1088     if (conn->local_id_data)
1089       silc_free(conn->local_id_data);
1090     if (conn->send_key)
1091       silc_cipher_free(conn->send_key);
1092     if (conn->receive_key)
1093       silc_cipher_free(conn->receive_key);
1094     if (conn->hmac)
1095       silc_hmac_free(conn->hmac);
1096     if (conn->hmac_key) {
1097       memset(conn->hmac_key, 0, conn->hmac_key_len);
1098       silc_free(conn->hmac_key);
1099     }
1100     if (conn->pending_commands)
1101       silc_dlist_uninit(conn->pending_commands);
1102
1103     conn->sock = NULL;
1104     conn->remote_port = 0;
1105     conn->remote_type = 0;
1106     conn->send_key = NULL;
1107     conn->receive_key = NULL;
1108     conn->hmac = NULL;
1109     conn->hmac_key = NULL;
1110     conn->hmac_key_len = 0;
1111     conn->local_id = NULL;
1112     conn->local_id_data = NULL;
1113     conn->remote_host = NULL;
1114     conn->current_channel = NULL;
1115     conn->pending_commands = NULL;
1116
1117     silc_client_del_connection(client, conn);
1118   }
1119
1120   if (sock->protocol) {
1121     silc_protocol_free(sock->protocol);
1122     sock->protocol = NULL;
1123   }
1124   silc_socket_free(sock);
1125 }
1126
1127 /* Called when we receive disconnection packet from server. This 
1128    closes our end properly and displays the reason of the disconnection
1129    on the screen. */
1130
1131 void silc_client_disconnected_by_server(SilcClient client,
1132                                         SilcSocketConnection sock,
1133                                         SilcBuffer message)
1134 {
1135   char *msg;
1136
1137   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1138
1139   msg = silc_calloc(message->len + 1, sizeof(char));
1140   memcpy(msg, message->data, message->len);
1141   client->ops->say(client, sock->user_data, msg);
1142   silc_free(msg);
1143
1144   SILC_SET_DISCONNECTED(sock);
1145   silc_client_close_connection(client, sock->user_data);
1146 }
1147
1148 /* Received error message from server. Display it on the screen. 
1149    We don't take any action what so ever of the error message. */
1150
1151 void silc_client_error_by_server(SilcClient client,
1152                                  SilcSocketConnection sock,
1153                                  SilcBuffer message)
1154 {
1155   char *msg;
1156
1157   msg = silc_calloc(message->len + 1, sizeof(char));
1158   memcpy(msg, message->data, message->len);
1159   client->ops->say(client, sock->user_data, msg);
1160   silc_free(msg);
1161 }
1162
1163 /* Processes the received new Client ID from server. Old Client ID is
1164    deleted from cache and new one is added. */
1165
1166 void silc_client_receive_new_id(SilcClient client,
1167                                 SilcSocketConnection sock,
1168                                 SilcIDPayload idp)
1169 {
1170   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1171   int connecting = FALSE;
1172
1173   if (!conn->local_entry)
1174     connecting = TRUE;
1175
1176   /* Delete old ID from ID cache */
1177   silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1178   
1179   /* Save the new ID */
1180   if (conn->local_id)
1181     silc_free(conn->local_id);
1182   if (conn->local_id_data)
1183     silc_free(conn->local_id_data);
1184
1185   conn->local_id = silc_id_payload_get_id(idp);
1186   conn->local_id_data = silc_id_payload_get_data(idp);
1187   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1188
1189   if (!conn->local_entry)
1190     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1191
1192   conn->local_entry->nickname = conn->nickname;
1193   if (!conn->local_entry->username) {
1194     conn->local_entry->username = 
1195       silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1196                   sizeof(conn->local_entry->username));
1197     sprintf(conn->local_entry->username, "%s@%s", client->username,
1198             client->hostname);
1199   }
1200   conn->local_entry->server = strdup(conn->remote_host);
1201   conn->local_entry->id = conn->local_id;
1202   
1203   /* Put it to the ID cache */
1204   silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1205                    SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1206                    TRUE, FALSE);
1207
1208   /* Notify application of successful connection. We do it here now that
1209      we've received the Client ID and are allowed to send traffic. */
1210   if (connecting)
1211     client->ops->connect(client, conn, TRUE);
1212 }
1213
1214 /* Processed received Channel ID for a channel. This is called when client
1215    joins to channel and server replies with channel ID. The ID is cached. 
1216    Returns the created channel entry. */
1217
1218 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1219                                             SilcSocketConnection sock,
1220                                             char *channel_name,
1221                                             unsigned int mode, 
1222                                             SilcIDPayload idp)
1223 {
1224   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1225   SilcChannelEntry channel;
1226
1227   SILC_LOG_DEBUG(("New channel ID"));
1228
1229   channel = silc_calloc(1, sizeof(*channel));
1230   channel->channel_name = channel_name;
1231   channel->id = silc_id_payload_get_id(idp);
1232   channel->mode = mode;
1233   silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1234
1235   conn->current_channel = channel;
1236
1237   /* Put it to the ID cache */
1238   silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1239                    SILC_ID_CHANNEL, (void *)channel->id, (void *)channel, 
1240                    TRUE, FALSE);
1241
1242   return channel;
1243 }
1244
1245 /* Removes a client entry from all channel it has joined. This really is
1246    a performance killer (client_entry should have pointers to channel 
1247    entry list). */
1248
1249 void silc_client_remove_from_channels(SilcClient client,
1250                                       SilcClientConnection conn,
1251                                       SilcClientEntry client_entry)
1252 {
1253   SilcIDCacheEntry id_cache;
1254   SilcIDCacheList list;
1255   SilcChannelEntry channel;
1256   SilcChannelUser chu;
1257
1258   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1259                                SILC_ID_CHANNEL, &list))
1260     return;
1261
1262   silc_idcache_list_first(list, &id_cache);
1263   channel = (SilcChannelEntry)id_cache->context;
1264   
1265   while (channel) {
1266     
1267     /* Remove client from channel */
1268     silc_list_start(channel->clients);
1269     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1270       if (chu->client == client_entry) {
1271         silc_list_del(channel->clients, chu);
1272         silc_free(chu);
1273         break;
1274       }
1275     }
1276
1277     if (!silc_idcache_list_next(list, &id_cache))
1278       break;
1279     
1280     channel = (SilcChannelEntry)id_cache->context;
1281   }
1282
1283   silc_idcache_list_free(list);
1284 }
1285
1286 /* Replaces `old' client entries from all channels to `new' client entry.
1287    This can be called for example when nickname changes and old ID entry
1288    is replaced from ID cache with the new one. If the old ID entry is only
1289    updated, then this fucntion needs not to be called. */
1290
1291 void silc_client_replace_from_channels(SilcClient client, 
1292                                        SilcClientConnection conn,
1293                                        SilcClientEntry old,
1294                                        SilcClientEntry new)
1295 {
1296   SilcIDCacheEntry id_cache;
1297   SilcIDCacheList list;
1298   SilcChannelEntry channel;
1299   SilcChannelUser chu;
1300
1301   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1302                                SILC_ID_CHANNEL, &list))
1303     return;
1304
1305   silc_idcache_list_first(list, &id_cache);
1306   channel = (SilcChannelEntry)id_cache->context;
1307   
1308   while (channel) {
1309     
1310     /* Replace client entry */
1311     silc_list_start(channel->clients);
1312     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1313       if (chu->client == old) {
1314         chu->client = new;
1315         break;
1316       }
1317     }
1318
1319     if (!silc_idcache_list_next(list, &id_cache))
1320       break;
1321     
1322     channel = (SilcChannelEntry)id_cache->context;
1323   }
1324
1325   silc_idcache_list_free(list);
1326 }
1327
1328 /* Parses mode mask and returns the mode as string. */
1329
1330 char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
1331 {
1332   char string[100];
1333
1334   if (!mode)
1335     return NULL;
1336
1337   memset(string, 0, sizeof(string));
1338
1339   if (mode & SILC_CHANNEL_MODE_PRIVATE)
1340     strncat(string, "p", 1);
1341
1342   if (mode & SILC_CHANNEL_MODE_SECRET)
1343     strncat(string, "s", 1);
1344
1345   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1346     strncat(string, "k", 1);
1347
1348   if (mode & SILC_CHANNEL_MODE_INVITE)
1349     strncat(string, "i", 1);
1350
1351   if (mode & SILC_CHANNEL_MODE_TOPIC)
1352     strncat(string, "t", 1);
1353
1354   if (mode & SILC_CHANNEL_MODE_ULIMIT)
1355     strncat(string, "l", 1);
1356
1357   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1358     strncat(string, "a", 1);
1359
1360   if (mode & SILC_CHANNEL_MODE_CIPHER) {
1361     char cipher[30];
1362     memset(cipher, 0, sizeof(cipher));
1363     snprintf(cipher, sizeof(cipher), " c (%s)", 
1364              channel->channel_key->cipher->name);
1365     strncat(string, cipher, strlen(cipher));
1366   }
1367
1368   if (mode & SILC_CHANNEL_MODE_HMAC) {
1369     char hmac[30];
1370     memset(hmac, 0, sizeof(hmac));
1371     snprintf(hmac, sizeof(hmac), " h (%s)", 
1372              channel->hmac->hmac->name);
1373     strncat(string, hmac, strlen(hmac));
1374   }
1375
1376   /* Rest of mode is ignored */
1377
1378   return strdup(string);
1379 }
1380
1381 /* Parses channel user mode mask and returns te mode as string */
1382
1383 char *silc_client_chumode(unsigned int mode)
1384 {
1385   char string[4];
1386
1387   if (!mode)
1388     return NULL;
1389
1390   memset(string, 0, sizeof(string));
1391
1392   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1393     strncat(string, "f", 1);
1394
1395   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1396     strncat(string, "o", 1);
1397
1398   return strdup(string);
1399 }
1400
1401 /* Parses channel user mode and returns it as special mode character. */
1402
1403 char *silc_client_chumode_char(unsigned int mode)
1404 {
1405   char string[4];
1406
1407   if (!mode)
1408     return NULL;
1409
1410   memset(string, 0, sizeof(string));
1411
1412   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1413     strncat(string, "*", 1);
1414
1415   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1416     strncat(string, "@", 1);
1417
1418   return strdup(string);
1419 }
1420
1421 /* Failure timeout callback. If this is called then we will immediately
1422    process the received failure. We always process the failure with timeout
1423    since we do not want to blindly trust to received failure packets. 
1424    This won't be called (the timeout is cancelled) if the failure was
1425    bogus (it is bogus if remote does not close the connection after sending
1426    the failure). */
1427
1428 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1429 {
1430   SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1431
1432   if (f->sock->protocol) {
1433     f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1434     f->sock->protocol->execute(f->client->timeout_queue, 0,
1435                                f->sock->protocol, f->sock->sock, 0, 0);
1436     
1437     /* Notify application */
1438     f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1439                             (void *)f->failure);
1440   }
1441
1442   silc_free(f);
1443 }
1444
1445 /* Registers failure timeout to process the received failure packet
1446    with timeout. */
1447
1448 void silc_client_process_failure(SilcClient client,
1449                                  SilcSocketConnection sock,
1450                                  SilcPacketContext *packet)
1451 {
1452   SilcClientFailureContext *f;
1453   unsigned int failure = 0;
1454
1455   if (sock->protocol) {
1456     if (packet->buffer->len >= 4)
1457       SILC_GET32_MSB(failure, packet->buffer->data);
1458
1459     f = silc_calloc(1, sizeof(*f));
1460     f->client = client;
1461     f->sock = sock;
1462     f->failure = failure;
1463
1464     /* We will wait 5 seconds to process this failure packet */
1465     silc_task_register(client->timeout_queue, sock->sock,
1466                        silc_client_failure_callback, (void *)f, 5, 0,
1467                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1468   }
1469 }