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