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 - 2000 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
24 /* Static task callback prototypes */
25 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
28 SILC_TASK_CALLBACK(silc_client_packet_process);
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 /* Free's client object */
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. */
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. */
113
114 void silc_client_run(SilcClient client)
115 {
116   SILC_LOG_DEBUG(("Running client"));
117
118   /* Start the scheduler, the heart of the SILC client. When this returns
119      the program will be terminated. */
120   silc_schedule();
121 }
122
123 /* Allocates and adds new connection to the client. This adds the allocated
124    connection to the connection table and returns a pointer to it. A client
125    can have multiple connections to multiple servers. Every connection must
126    be added to the client using this function. User data `context' may
127    be sent as argument. */
128
129 SilcClientConnection silc_client_add_connection(SilcClient client,
130                                                 char *hostname,
131                                                 int port,
132                                                 void *context)
133 {
134   SilcClientConnection conn;
135   int i;
136
137   conn = silc_calloc(1, sizeof(*conn));
138
139   /* Initialize ID caches */
140   conn->client_cache = silc_idcache_alloc(0);
141   conn->channel_cache = silc_idcache_alloc(0);
142   conn->server_cache = silc_idcache_alloc(0);
143   conn->client = client;
144   conn->remote_host = strdup(hostname);
145   conn->remote_port = port;
146   conn->context = context;
147   conn->pending_commands = silc_dlist_init();
148
149   /* Add the connection to connections table */
150   for (i = 0; i < client->conns_count; i++)
151     if (client->conns && !client->conns[i]) {
152       client->conns[i] = conn;
153       return conn;
154     }
155
156   client->conns = silc_realloc(client->conns, sizeof(*client->conns)
157                                * (client->conns_count + 1));
158   client->conns[client->conns_count] = conn;
159   client->conns_count++;
160
161   return conn;
162 }
163
164 /* Removes connection from client. */
165
166 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
167 {
168   int i;
169
170   for (i = 0; i < client->conns_count; i++)
171     if (client->conns[i] == conn) {
172       if (conn->pending_commands)
173         silc_dlist_uninit(conn->pending_commands);
174       silc_free(conn);
175       client->conns[i] = NULL;
176     }
177 }
178
179 /* Internal context for connection process. This is needed as we
180    doing asynchronous connecting. */
181 typedef struct {
182   SilcClient client;
183   SilcClientConnection conn;
184   SilcTask task;
185   int sock;
186   char *host;
187   int port;
188   int tries;
189 } SilcClientInternalConnectContext;
190
191 static int 
192 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
193 {
194   int sock;
195
196   /* XXX In the future we should give up this non-blocking connect all
197      together and use threads instead. */
198   /* Create connection to server asynchronously */
199   sock = silc_net_create_connection_async(ctx->port, ctx->host);
200   if (sock < 0)
201     return -1;
202
203   /* Register task that will receive the async connect and will
204      read the result. */
205   ctx->task = silc_task_register(ctx->client->io_queue, sock, 
206                                  silc_client_connect_to_server_start,
207                                  (void *)ctx, 0, 0, 
208                                  SILC_TASK_FD,
209                                  SILC_TASK_PRI_NORMAL);
210   silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
211   silc_schedule_set_listen_fd(sock, ctx->task->iomask);
212
213   ctx->sock = sock;
214
215   return sock;
216 }
217
218 /* Connects to remote server. This is the main routine used to connect
219    to SILC server. Returns -1 on error and the created socket otherwise. 
220    The `context' is user context that is saved into the SilcClientConnection
221    that is created after the connection is created. */
222
223 int silc_client_connect_to_server(SilcClient client, int port,
224                                   char *host, void *context)
225 {
226   SilcClientInternalConnectContext *ctx;
227   SilcClientConnection conn;
228   int sock;
229
230   SILC_LOG_DEBUG(("Connecting to port %d of server %s",
231                   port, host));
232
233   conn = silc_client_add_connection(client, host, port, context);
234
235   client->ops->say(client, conn, 
236                    "Connecting to port %d of server %s", port, host);
237
238   /* Allocate internal context for connection process. This is
239      needed as we are doing async connecting. */
240   ctx = silc_calloc(1, sizeof(*ctx));
241   ctx->client = client;
242   ctx->conn = conn;
243   ctx->host = strdup(host);
244   ctx->port = port;
245   ctx->tries = 0;
246
247   /* Do the actual connecting process */
248   sock = silc_client_connect_to_server_internal(ctx);
249   if (sock == -1)
250     silc_client_del_connection(client, conn);
251   return sock;
252 }
253
254 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
255    key material between client and server.  This function can be called
256    directly if application is performing its own connecting and does not
257    use the connecting provided by this library. */
258
259 int silc_client_start_key_exchange(SilcClient client,
260                                    SilcClientConnection conn,
261                                    int fd)
262 {
263   SilcProtocol protocol;
264   SilcClientKEInternalContext *proto_ctx;
265   void *context;
266
267   /* Allocate new socket connection object */
268   silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
269   if (conn->sock == NULL) {
270     client->ops->say(client, conn, 
271                      "Error: Could not allocate connection socket");
272     return FALSE;
273   }
274
275   conn->nickname = strdup(client->username);
276   conn->sock->hostname = conn->remote_host;
277   conn->sock->ip = strdup(conn->remote_host);
278   conn->sock->port = conn->remote_port;
279
280   /* Allocate internal Key Exchange context. This is sent to the
281      protocol as context. */
282   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
283   proto_ctx->client = (void *)client;
284   proto_ctx->sock = conn->sock;
285   proto_ctx->rng = client->rng;
286   proto_ctx->responder = FALSE;
287
288   /* Perform key exchange protocol. silc_client_connect_to_server_final
289      will be called after the protocol is finished. */
290   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
291                       &protocol, (void *)proto_ctx,
292                       silc_client_connect_to_server_second);
293   if (!protocol) {
294     client->ops->say(client, conn, 
295                      "Error: Could not start authentication protocol");
296     return FALSE;
297   }
298   conn->sock->protocol = protocol;
299
300   /* Register the connection for network input and output. This sets
301      that scheduler will listen for incoming packets for this connection 
302      and sets that outgoing packets may be sent to this connection as well.
303      However, this doesn't set the scheduler for outgoing traffic, it will 
304      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
305      later when outgoing data is available. */
306   context = (void *)client;
307   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
308
309   /* Execute the protocol */
310   protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
311   return TRUE;
312 }
313
314 /* Start of the connection to the remote server. This is called after
315    succesful TCP/IP connection has been established to the remote host. */
316
317 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
318 {
319   SilcClientInternalConnectContext *ctx =
320     (SilcClientInternalConnectContext *)context;
321   SilcClient client = ctx->client;
322   SilcClientConnection conn = ctx->conn;
323   int opt, opt_len = sizeof(opt);
324
325   SILC_LOG_DEBUG(("Start"));
326
327   /* Check the socket status as it might be in error */
328   getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
329   if (opt != 0) {
330     if (ctx->tries < 2) {
331       /* Connection failed but lets try again */
332       client->ops->say(client, conn, "Could not connect to server %s: %s",
333                        ctx->host, strerror(opt));
334       client->ops->say(client, conn, 
335                        "Connecting to port %d of server %s resumed", 
336                        ctx->port, ctx->host);
337
338       /* Unregister old connection try */
339       silc_schedule_unset_listen_fd(fd);
340       silc_net_close_connection(fd);
341       silc_task_unregister(client->io_queue, ctx->task);
342
343       /* Try again */
344       silc_client_connect_to_server_internal(ctx);
345       ctx->tries++;
346     } else {
347       /* Connection failed and we won't try anymore */
348       client->ops->say(client, conn, "Could not connect to server %s: %s",
349                        ctx->host, strerror(opt));
350       silc_schedule_unset_listen_fd(fd);
351       silc_net_close_connection(fd);
352       silc_task_unregister(client->io_queue, ctx->task);
353       silc_free(ctx);
354
355       /* Notify application of failure */
356       client->ops->connect(client, conn, FALSE);
357       silc_client_del_connection(client, conn);
358     }
359     return;
360   }
361
362   silc_schedule_unset_listen_fd(fd);
363   silc_task_unregister(client->io_queue, ctx->task);
364   silc_free(ctx);
365
366   if (!silc_client_start_key_exchange(client, conn, fd)) {
367     silc_net_close_connection(fd);
368     client->ops->connect(client, conn, FALSE);
369   }
370 }
371
372 /* Second part of the connecting to the server. This executed 
373    authentication protocol. */
374
375 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
376 {
377   SilcProtocol protocol = (SilcProtocol)context;
378   SilcClientKEInternalContext *ctx = 
379     (SilcClientKEInternalContext *)protocol->context;
380   SilcClient client = (SilcClient)ctx->client;
381   SilcSocketConnection sock = NULL;
382   SilcClientConnAuthInternalContext *proto_ctx;
383
384   SILC_LOG_DEBUG(("Start"));
385
386   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
387       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
388     /* Error occured during protocol */
389     SILC_LOG_DEBUG(("Error during KE protocol"));
390     silc_protocol_free(protocol);
391     if (ctx->ske)
392       silc_ske_free(ctx->ske);
393     if (ctx->dest_id)
394       silc_free(ctx->dest_id);
395     ctx->sock->protocol = NULL;
396
397     /* Notify application of failure */
398     client->ops->connect(client, ctx->sock->user_data, FALSE);
399     silc_free(ctx);
400     return;
401   }
402
403   /* Allocate internal context for the authentication protocol. This
404      is sent as context for the protocol. */
405   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
406   proto_ctx->client = (void *)client;
407   proto_ctx->sock = sock = ctx->sock;
408   proto_ctx->ske = ctx->ske;    /* Save SKE object from previous protocol */
409   proto_ctx->dest_id_type = ctx->dest_id_type;
410   proto_ctx->dest_id = ctx->dest_id;
411
412   /* Resolve the authentication method to be used in this connection */
413   if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
414                                     sock->port, &proto_ctx->auth_meth,
415                                     &proto_ctx->auth_data, 
416                                     &proto_ctx->auth_data_len))
417     {
418       /* XXX do AUTH_REQUEST resolcing with server */
419       proto_ctx->auth_meth = SILC_AUTH_NONE;
420     }
421
422   /* Free old protocol as it is finished now */
423   silc_protocol_free(protocol);
424   if (ctx->packet)
425     silc_packet_context_free(ctx->packet);
426   silc_free(ctx);
427   /* silc_free(ctx->keymat....); */
428   sock->protocol = NULL;
429
430   /* Allocate the authentication protocol. This is allocated here
431      but we won't start it yet. We will be receiving party of this
432      protocol thus we will wait that connecting party will make
433      their first move. */
434   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
435                       &sock->protocol, (void *)proto_ctx, 
436                       silc_client_connect_to_server_final);
437
438   /* Execute the protocol */
439   sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
440 }
441
442 /* Finalizes the connection to the remote SILC server. This is called
443    after authentication protocol has been completed. This send our
444    user information to the server to receive our client ID from
445    server. */
446
447 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
448 {
449   SilcProtocol protocol = (SilcProtocol)context;
450   SilcClientConnAuthInternalContext *ctx = 
451     (SilcClientConnAuthInternalContext *)protocol->context;
452   SilcClient client = (SilcClient)ctx->client;
453   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
454   SilcBuffer packet;
455
456   SILC_LOG_DEBUG(("Start"));
457
458   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
459       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
460     /* Error occured during protocol */
461     SILC_LOG_DEBUG(("Error during authentication protocol"));
462     silc_protocol_free(protocol);
463     if (ctx->auth_data)
464       silc_free(ctx->auth_data);
465     if (ctx->ske)
466       silc_ske_free(ctx->ske);
467     if (ctx->dest_id)
468       silc_free(ctx->dest_id);
469     conn->sock->protocol = NULL;
470
471     /* Notify application of failure */
472     client->ops->connect(client, ctx->sock->user_data, FALSE);
473     silc_free(ctx);
474     return;
475   }
476
477   /* Send NEW_CLIENT packet to the server. We will become registered
478      to the SILC network after sending this packet and we will receive
479      client ID from the server. */
480   packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
481                              strlen(client->realname));
482   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
483   silc_buffer_format(packet,
484                      SILC_STR_UI_SHORT(strlen(client->username)),
485                      SILC_STR_UI_XNSTRING(client->username,
486                                           strlen(client->username)),
487                      SILC_STR_UI_SHORT(strlen(client->realname)),
488                      SILC_STR_UI_XNSTRING(client->realname,
489                                           strlen(client->realname)),
490                      SILC_STR_END);
491
492   /* Send the packet */
493   silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
494                           NULL, 0, NULL, NULL, 
495                           packet->data, packet->len, TRUE);
496   silc_buffer_free(packet);
497
498   /* Save remote ID. */
499   conn->remote_id = ctx->dest_id;
500   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
501   conn->remote_id_data_len = SILC_ID_SERVER_LEN;
502
503   silc_protocol_free(protocol);
504   if (ctx->auth_data)
505     silc_free(ctx->auth_data);
506   if (ctx->ske)
507     silc_ske_free(ctx->ske);
508   silc_free(ctx);
509   conn->sock->protocol = NULL;
510 }
511
512 /* Internal routine that sends packet or marks packet to be sent. This
513    is used directly only in special cases. Normal cases should use
514    silc_server_packet_send. Returns < 0 on error. */
515
516 static int silc_client_packet_send_real(SilcClient client,
517                                         SilcSocketConnection sock,
518                                         int force_send)
519 {
520   int ret;
521
522   /* Send the packet */
523   ret = silc_packet_send(sock, force_send);
524   if (ret != -2)
525     return ret;
526
527   /* Mark that there is some outgoing data available for this connection. 
528      This call sets the connection both for input and output (the input
529      is set always and this call keeps the input setting, actually). 
530      Actual data sending is performed by silc_client_packet_process. */
531   SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
532
533   /* Mark to socket that data is pending in outgoing buffer. This flag
534      is needed if new data is added to the buffer before the earlier
535      put data is sent to the network. */
536   SILC_SET_OUTBUF_PENDING(sock);
537
538   return 0;
539 }
540
541 /* Packet processing callback. This is used to send and receive packets
542    from network. This is generic task. */
543
544 SILC_TASK_CALLBACK(silc_client_packet_process)
545 {
546   SilcClient client = (SilcClient)context;
547   SilcSocketConnection sock = NULL;
548   SilcClientConnection conn;
549   int ret;
550
551   SILC_LOG_DEBUG(("Processing packet"));
552
553   SILC_CLIENT_GET_SOCK(client, fd, sock);
554   if (sock == NULL)
555     return;
556
557   conn = (SilcClientConnection)sock->user_data;
558
559   /* Packet sending */
560   if (type == SILC_TASK_WRITE) {
561     SILC_LOG_DEBUG(("Writing data to connection"));
562
563     if (sock->outbuf->data - sock->outbuf->head)
564       silc_buffer_push(sock->outbuf, 
565                        sock->outbuf->data - sock->outbuf->head);
566
567     ret = silc_client_packet_send_real(client, sock, TRUE);
568
569     /* If returned -2 could not write to connection now, will do
570        it later. */
571     if (ret == -2)
572       return;
573     
574     /* The packet has been sent and now it is time to set the connection
575        back to only for input. When there is again some outgoing data 
576        available for this connection it will be set for output as well. 
577        This call clears the output setting and sets it only for input. */
578     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
579     SILC_UNSET_OUTBUF_PENDING(sock);
580
581     silc_buffer_clear(sock->outbuf);
582     return;
583   }
584
585   /* Packet receiving */
586   if (type == SILC_TASK_READ) {
587     SILC_LOG_DEBUG(("Reading data from connection"));
588
589     /* Read data from network */
590     ret = silc_packet_receive(sock);
591     if (ret < 0)
592       return;
593     
594     /* EOF */
595     if (ret == 0) {
596       SILC_LOG_DEBUG(("Read EOF"));
597
598       /* If connection is disconnecting already we will finally
599          close the connection */
600       if (SILC_IS_DISCONNECTING(sock)) {
601         client->ops->disconnect(client, conn);
602         silc_client_close_connection(client, sock);
603         return;
604       }
605       
606       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
607       client->ops->disconnect(client, conn);
608       silc_client_close_connection(client, sock);
609       return;
610     }
611
612     /* Process the packet. This will call the parser that will then
613        decrypt and parse the packet. */
614     silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
615                                 silc_client_packet_parse, client);
616   }
617 }
618
619 /* Parses whole packet, received earlier. */
620
621 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
622 {
623   SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
624   SilcClient client = (SilcClient)parse_ctx->context;
625   SilcPacketContext *packet = parse_ctx->packet;
626   SilcBuffer buffer = packet->buffer;
627   SilcSocketConnection sock = parse_ctx->sock;
628   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
629   int ret;
630
631   SILC_LOG_DEBUG(("Start"));
632
633   /* Decrypt the received packet */
634   ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
635   if (ret < 0)
636     goto out;
637
638   if (ret == 0) {
639     /* Parse the packet. Packet type is returned. */
640     ret = silc_packet_parse(packet);
641   } else {
642     /* Parse the packet header in special way as this is "special"
643        packet type. */
644     ret = silc_packet_parse_special(packet);
645   }
646
647   if (ret == SILC_PACKET_NONE)
648     goto out;
649
650   /* Parse the incoming packet type */
651   silc_client_packet_parse_type(client, sock, packet);
652
653  out:
654   silc_buffer_clear(sock->inbuf);
655   silc_packet_context_free(packet);
656   silc_free(parse_ctx);
657 }
658
659 /* Parser callback called by silc_packet_receive_process. Thie merely
660    registers timeout that will handle the actual parsing when appropriate. */
661
662 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
663 {
664   SilcClient client = (SilcClient)parser_context->context;
665
666   /* Parse the packet */
667   silc_task_register(client->timeout_queue, parser_context->sock->sock, 
668                      silc_client_packet_parse_real,
669                      (void *)parser_context, 0, 1, 
670                      SILC_TASK_TIMEOUT,
671                      SILC_TASK_PRI_NORMAL);
672 }
673   
674 /* Parses the packet type and calls what ever routines the packet type
675    requires. This is done for all incoming packets. */
676
677 void silc_client_packet_parse_type(SilcClient client, 
678                                    SilcSocketConnection sock,
679                                    SilcPacketContext *packet)
680 {
681   SilcBuffer buffer = packet->buffer;
682   SilcPacketType type = packet->type;
683
684   SILC_LOG_DEBUG(("Parsing packet type %d", type));
685
686   /* Parse the packet type */
687   switch(type) {
688   case SILC_PACKET_DISCONNECT:
689     silc_client_disconnected_by_server(client, sock, buffer);
690     break;
691   case SILC_PACKET_SUCCESS:
692     /*
693      * Success received for something. For now we can have only
694      * one protocol for connection executing at once hence this
695      * success message is for whatever protocol is executing currently.
696      */
697     if (sock->protocol) {
698       sock->protocol->execute(client->timeout_queue, 0,
699                               sock->protocol, sock->sock, 0, 0);
700     }
701     break;
702   case SILC_PACKET_FAILURE:
703     /*
704      * Failure received for some protocol. Set the protocol state to 
705      * error and call the protocol callback. This fill cause error on
706      * protocol and it will call the final callback.
707      */
708     if (sock->protocol) {
709       sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
710       sock->protocol->execute(client->timeout_queue, 0,
711                               sock->protocol, sock->sock, 0, 0);
712
713       /* XXX We have only two protocols currently thus we know what this
714          failure indication is. */
715       if (buffer->len >= 4) {
716         unsigned int failure;
717
718         SILC_GET32_MSB(failure, buffer->data);
719
720         /* Notify application */
721         client->ops->failure(client, sock->user_data, sock->protocol,
722                              (void *)failure);
723       }
724     }
725     break;
726   case SILC_PACKET_REJECT:
727     break;
728
729   case SILC_PACKET_NOTIFY:
730     /*
731      * Received notify message 
732      */
733     silc_client_notify_by_server(client, sock, packet);
734     break;
735
736   case SILC_PACKET_ERROR:
737     /*
738      * Received error message
739      */
740     silc_client_error_by_server(client, sock, buffer);
741     break;
742
743   case SILC_PACKET_CHANNEL_MESSAGE:
744     /*
745      * Received message to (from, actually) a channel
746      */
747     silc_client_channel_message(client, sock, packet);
748     break;
749   case SILC_PACKET_CHANNEL_KEY:
750     /*
751      * Received key for a channel. By receiving this key the client will be
752      * able to talk to the channel it has just joined. This can also be
753      * a new key for existing channel as keys expire peridiocally.
754      */
755     silc_client_receive_channel_key(client, sock, buffer);
756     break;
757
758   case SILC_PACKET_PRIVATE_MESSAGE:
759     /*
760      * Received private message
761      */
762     silc_client_private_message(client, sock, packet);
763     break;
764   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
765     /*
766      * Received private message key
767      */
768     break;
769
770   case SILC_PACKET_COMMAND_REPLY:
771     /*
772      * Recived reply for a command
773      */
774     silc_client_command_reply_process(client, sock, packet);
775     break;
776
777   case SILC_PACKET_KEY_EXCHANGE:
778     if (sock->protocol) {
779       SilcClientKEInternalContext *proto_ctx = 
780         (SilcClientKEInternalContext *)sock->protocol->context;
781
782       proto_ctx->packet = silc_packet_context_dup(packet);
783       proto_ctx->dest_id_type = packet->src_id_type;
784       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
785                                           packet->src_id_type);
786       if (!proto_ctx->dest_id)
787         break;
788
789       /* Let the protocol handle the packet */
790       sock->protocol->execute(client->timeout_queue, 0,
791                               sock->protocol, sock->sock, 0, 0);
792     } else {
793       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
794                       "protocol active, packet dropped."));
795
796       /* XXX Trigger KE protocol?? Rekey actually! */
797     }
798     break;
799
800   case SILC_PACKET_KEY_EXCHANGE_1:
801     if (sock->protocol) {
802
803     } else {
804       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
805                       "protocol active, packet dropped."));
806     }
807     break;
808   case SILC_PACKET_KEY_EXCHANGE_2:
809     if (sock->protocol) {
810       SilcClientKEInternalContext *proto_ctx = 
811         (SilcClientKEInternalContext *)sock->protocol->context;
812
813       if (proto_ctx->packet)
814         silc_packet_context_free(proto_ctx->packet);
815
816       proto_ctx->packet = silc_packet_context_dup(packet);
817       proto_ctx->dest_id_type = packet->src_id_type;
818       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
819                                           packet->src_id_type);
820       if (!proto_ctx->dest_id)
821         break;
822
823       /* Let the protocol handle the packet */
824       sock->protocol->execute(client->timeout_queue, 0,
825                               sock->protocol, sock->sock, 0, 0);
826     } else {
827       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
828                       "protocol active, packet dropped."));
829     }
830     break;
831
832   case SILC_PACKET_NEW_ID:
833     {
834       /*
835        * Received new ID from server. This packet is received at
836        * the connection to the server.  New ID is also received when 
837        * user changes nickname but in that case the new ID is received
838        * as command reply and not as this packet type.
839        */
840       SilcIDPayload idp;
841
842       idp = silc_id_payload_parse(buffer);
843       if (!idp)
844         break;
845       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
846         break;
847
848       silc_client_receive_new_id(client, sock, idp);
849       silc_id_payload_free(idp);
850       break;
851     }
852
853   case SILC_PACKET_HEARTBEAT:
854     /*
855      * Received heartbeat packet
856      */
857     SILC_LOG_DEBUG(("Heartbeat packet"));
858     break;
859
860   default:
861     SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
862     break;
863   }
864 }
865
866 /* Sends packet. This doesn't actually send the packet instead it assembles
867    it and marks it to be sent. However, if force_send is TRUE the packet
868    is sent immediately. if dst_id, cipher and hmac are NULL those parameters
869    will be derived from sock argument. Otherwise the valid arguments sent
870    are used. */
871
872 void silc_client_packet_send(SilcClient client, 
873                              SilcSocketConnection sock,
874                              SilcPacketType type, 
875                              void *dst_id,
876                              SilcIdType dst_id_type,
877                              SilcCipher cipher,
878                              SilcHmac hmac,
879                              unsigned char *data, 
880                              unsigned int data_len, 
881                              int force_send)
882 {
883   SilcPacketContext packetdata;
884
885   SILC_LOG_DEBUG(("Sending packet, type %d", type));
886
887   /* Get data used in the packet sending, keys and stuff */
888   if ((!cipher || !hmac || !dst_id) && sock->user_data) {
889     if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
890       cipher = ((SilcClientConnection)sock->user_data)->send_key;
891
892     if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
893       hmac = ((SilcClientConnection)sock->user_data)->hmac;
894
895     if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
896       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
897       dst_id_type = SILC_ID_SERVER;
898     }
899   }
900
901   /* Set the packet context pointers */
902   packetdata.flags = 0;
903   packetdata.type = type;
904   if (((SilcClientConnection)sock->user_data)->local_id_data)
905     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
906   else 
907     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
908   packetdata.src_id_len = SILC_ID_CLIENT_LEN;
909   packetdata.src_id_type = SILC_ID_CLIENT;
910   if (dst_id) {
911     packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
912     packetdata.dst_id_len = silc_id_get_len(dst_id_type);
913     packetdata.dst_id_type = dst_id_type;
914   } else {
915     packetdata.dst_id = NULL;
916     packetdata.dst_id_len = 0;
917     packetdata.dst_id_type = SILC_ID_NONE;
918   }
919   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
920     packetdata.src_id_len + packetdata.dst_id_len;
921   packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
922
923   /* Prepare outgoing data buffer for packet sending */
924   silc_packet_send_prepare(sock, 
925                            SILC_PACKET_HEADER_LEN +
926                            packetdata.src_id_len + 
927                            packetdata.dst_id_len,
928                            packetdata.padlen,
929                            data_len);
930
931   SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
932
933   packetdata.buffer = sock->outbuf;
934
935   /* Put the data to the buffer */
936   if (data && data_len)
937     silc_buffer_put(sock->outbuf, data, data_len);
938
939   /* Create the outgoing packet */
940   silc_packet_assemble(&packetdata);
941
942   /* Encrypt the packet */
943   if (cipher)
944     silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
945
946   SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
947                    sock->outbuf->data, sock->outbuf->len);
948
949   /* Now actually send the packet */
950   silc_client_packet_send_real(client, sock, force_send);
951 }
952
953 /* Sends packet to a channel. Packet to channel is always encrypted
954    differently from "normal" packets. SILC header of the packet is 
955    encrypted with the next receiver's key and the rest of the packet is
956    encrypted with the channel specific key. Padding and HMAC is computed
957    with the next receiver's key. */
958
959 void silc_client_packet_send_to_channel(SilcClient client, 
960                                         SilcSocketConnection sock,
961                                         SilcChannelEntry channel,
962                                         unsigned char *data, 
963                                         unsigned int data_len, 
964                                         int force_send)
965 {
966   int i;
967   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
968   SilcBuffer payload;
969   SilcPacketContext packetdata;
970   SilcCipher cipher;
971   SilcHmac hmac;
972   unsigned char *id_string;
973   unsigned int block_len;
974
975   SILC_LOG_DEBUG(("Sending packet to channel"));
976
977   if (!channel || !channel->key) {
978     client->ops->say(client, conn, 
979                      "Cannot talk to channel: key does not exist");
980     return;
981   }
982
983   /* Generate IV */
984   block_len = silc_cipher_get_block_len(channel->channel_key);
985   if (channel->iv[0] == '\0')
986     for (i = 0; i < block_len; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
987   else
988     silc_hash_make(client->md5hash, channel->iv, block_len, channel->iv);
989
990   /* Encode the channel payload */
991   payload = silc_channel_payload_encode(data_len, data, block_len, 
992                                         channel->iv, client->rng);
993   if (!payload) {
994     client->ops->say(client, conn, 
995                      "Error: Could not create packet to be sent to channel");
996     return;
997   }
998
999   /* Get data used in packet header encryption, keys and stuff. Rest
1000      of the packet (the payload) is, however, encrypted with the 
1001      specified channel key. */
1002   cipher = conn->send_key;
1003   hmac = conn->hmac;
1004   id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1005
1006   /* Set the packet context pointers. The destination ID is always
1007      the Channel ID of the channel. Server and router will handle the
1008      distribution of the packet. */
1009   packetdata.flags = 0;
1010   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
1011   packetdata.src_id = conn->local_id_data;
1012   packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1013   packetdata.src_id_type = SILC_ID_CLIENT;
1014   packetdata.dst_id = id_string;
1015   packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
1016   packetdata.dst_id_type = SILC_ID_CHANNEL;
1017   packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
1018     packetdata.src_id_len + packetdata.dst_id_len;
1019   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1020                                           packetdata.src_id_len +
1021                                           packetdata.dst_id_len));
1022
1023   /* Prepare outgoing data buffer for packet sending */
1024   silc_packet_send_prepare(sock, 
1025                            SILC_PACKET_HEADER_LEN +
1026                            packetdata.src_id_len + 
1027                            packetdata.dst_id_len,
1028                            packetdata.padlen,
1029                            payload->len);
1030
1031   packetdata.buffer = sock->outbuf;
1032
1033   /* Encrypt payload of the packet. This is encrypted with the channel key. */
1034   channel->channel_key->cipher->encrypt(channel->channel_key->context,
1035                                         payload->data, payload->data,
1036                                         payload->len - block_len, /* -IV_LEN */
1037                                         channel->iv);
1038
1039   /* Put the actual encrypted payload data into the buffer. */
1040   silc_buffer_put(sock->outbuf, payload->data, payload->len);
1041
1042   /* Create the outgoing packet */
1043   silc_packet_assemble(&packetdata);
1044
1045   /* Encrypt the header and padding of the packet. This is encrypted 
1046      with normal session key shared with our server. */
1047   silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
1048                       packetdata.src_id_len + packetdata.dst_id_len +
1049                       packetdata.padlen);
1050
1051   SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1052                    sock->outbuf->data, sock->outbuf->len);
1053
1054   /* Now actually send the packet */
1055   silc_client_packet_send_real(client, sock, force_send);
1056   silc_buffer_free(payload);
1057   silc_free(id_string);
1058 }
1059
1060 /* Sends private message to remote client. If private message key has
1061    not been set with this client then the message will be encrypted using
1062    normal session keys. Private messages are special packets in SILC
1063    network hence we need this own function for them. This is similiar
1064    to silc_client_packet_send_to_channel except that we send private
1065    message. */
1066
1067 void silc_client_packet_send_private_message(SilcClient client,
1068                                              SilcSocketConnection sock,
1069                                              SilcClientEntry client_entry,
1070                                              unsigned char *data, 
1071                                              unsigned int data_len, 
1072                                              int force_send)
1073 {
1074   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1075   SilcBuffer buffer;
1076   SilcPacketContext packetdata;
1077   unsigned int nick_len;
1078   SilcCipher cipher;
1079   SilcHmac hmac;
1080
1081   SILC_LOG_DEBUG(("Sending private message"));
1082
1083   /* Create private message payload */
1084   nick_len = strlen(conn->nickname);
1085   buffer = silc_buffer_alloc(2 + nick_len + data_len);
1086   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1087   silc_buffer_format(buffer,
1088                      SILC_STR_UI_SHORT(nick_len),
1089                      SILC_STR_UI_XNSTRING(conn->nickname,
1090                                           nick_len),
1091                      SILC_STR_UI_XNSTRING(data, data_len),
1092                      SILC_STR_END);
1093
1094   /* If we don't have private message specific key then private messages
1095      are just as any normal packet thus call normal packet sending.  If
1096      the key exist then the encryption process is a bit different and
1097      will be done in the rest of this function. */
1098   if (!client_entry->send_key) {
1099     silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1100                             client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1101                             buffer->data, buffer->len, force_send);
1102     goto out;
1103   }
1104
1105   /* We have private message specific key */
1106
1107   /* Get data used in the encryption */
1108   cipher = client_entry->send_key;
1109   hmac = conn->hmac;
1110
1111   /* Set the packet context pointers. */
1112   packetdata.flags = 0;
1113   packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1114   packetdata.src_id = conn->local_id_data;
1115   packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1116   packetdata.src_id_type = SILC_ID_CLIENT;
1117   if (client_entry)
1118     packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1119   else
1120     packetdata.dst_id = conn->local_id_data;
1121   packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1122   packetdata.dst_id_type = SILC_ID_CLIENT;
1123   packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
1124     packetdata.src_id_len + packetdata.dst_id_len;
1125   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1126                                           packetdata.src_id_len +
1127                                           packetdata.dst_id_len));
1128
1129   /* Prepare outgoing data buffer for packet sending */
1130   silc_packet_send_prepare(sock, 
1131                            SILC_PACKET_HEADER_LEN +
1132                            packetdata.src_id_len + 
1133                            packetdata.dst_id_len,
1134                            packetdata.padlen,
1135                            buffer->len);
1136   
1137   packetdata.buffer = sock->outbuf;
1138
1139   /* Encrypt payload of the packet. Encrypt with private message specific
1140      key if it exist, otherwise with session key. */
1141   cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1142                           buffer->len, cipher->iv);
1143       
1144   /* Put the actual encrypted payload data into the buffer. */
1145   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1146
1147   /* Create the outgoing packet */
1148   silc_packet_assemble(&packetdata);
1149
1150   /* Encrypt the header and padding of the packet. */
1151   silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
1152                       packetdata.src_id_len + packetdata.dst_id_len +
1153                       packetdata.padlen);
1154
1155   SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1156                    sock->outbuf->data, sock->outbuf->len);
1157
1158   /* Now actually send the packet */
1159   silc_client_packet_send_real(client, sock, force_send);
1160   silc_free(packetdata.dst_id);
1161
1162  out:
1163   silc_free(buffer);
1164 }     
1165
1166 /* Closes connection to remote end. Free's all allocated data except
1167    for some information such as nickname etc. that are valid at all time. */
1168
1169 void silc_client_close_connection(SilcClient client,
1170                                   SilcSocketConnection sock)
1171 {
1172   SilcClientConnection conn;
1173
1174   /* We won't listen for this connection anymore */
1175   silc_schedule_unset_listen_fd(sock->sock);
1176
1177   /* Unregister all tasks */
1178   silc_task_unregister_by_fd(client->io_queue, sock->sock);
1179   silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1180
1181   /* Close the actual connection */
1182   silc_net_close_connection(sock->sock);
1183
1184   client->ops->say(client, sock->user_data,
1185                    "Closed connection to host %s", sock->hostname);
1186
1187   /* Free everything */
1188   if (sock->user_data) {
1189     conn = (SilcClientConnection)sock->user_data;
1190
1191     /* XXX Free all client entries and channel entries. */
1192
1193     /* Clear ID caches */
1194     silc_idcache_del_all(conn->client_cache);
1195     silc_idcache_del_all(conn->channel_cache);
1196
1197     /* Free data */
1198     if (conn->remote_host)
1199       silc_free(conn->remote_host);
1200     if (conn->local_id)
1201       silc_free(conn->local_id);
1202     if (conn->local_id_data)
1203       silc_free(conn->local_id_data);
1204     if (conn->send_key)
1205       silc_cipher_free(conn->send_key);
1206     if (conn->receive_key)
1207       silc_cipher_free(conn->receive_key);
1208     if (conn->hmac)
1209       silc_hmac_free(conn->hmac);
1210     if (conn->hmac_key) {
1211       memset(conn->hmac_key, 0, conn->hmac_key_len);
1212       silc_free(conn->hmac_key);
1213     }
1214     if (conn->pending_commands)
1215       silc_dlist_uninit(conn->pending_commands);
1216
1217     conn->sock = NULL;
1218     conn->remote_port = 0;
1219     conn->remote_type = 0;
1220     conn->send_key = NULL;
1221     conn->receive_key = NULL;
1222     conn->hmac = NULL;
1223     conn->hmac_key = NULL;
1224     conn->hmac_key_len = 0;
1225     conn->local_id = NULL;
1226     conn->local_id_data = NULL;
1227     conn->remote_host = NULL;
1228     conn->current_channel = NULL;
1229     conn->pending_commands = NULL;
1230
1231     silc_client_del_connection(client, conn);
1232   }
1233
1234   if (sock->protocol) {
1235     silc_protocol_free(sock->protocol);
1236     sock->protocol = NULL;
1237   }
1238   silc_socket_free(sock);
1239 }
1240
1241 /* Called when we receive disconnection packet from server. This 
1242    closes our end properly and displays the reason of the disconnection
1243    on the screen. */
1244
1245 void silc_client_disconnected_by_server(SilcClient client,
1246                                         SilcSocketConnection sock,
1247                                         SilcBuffer message)
1248 {
1249   char *msg;
1250
1251   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1252
1253   msg = silc_calloc(message->len + 1, sizeof(char));
1254   memcpy(msg, message->data, message->len);
1255   client->ops->say(client, sock->user_data, msg);
1256   silc_free(msg);
1257
1258   SILC_SET_DISCONNECTED(sock);
1259   silc_client_close_connection(client, sock);
1260 }
1261
1262 /* Received error message from server. Display it on the screen. 
1263    We don't take any action what so ever of the error message. */
1264
1265 void silc_client_error_by_server(SilcClient client,
1266                                  SilcSocketConnection sock,
1267                                  SilcBuffer message)
1268 {
1269   char *msg;
1270
1271   msg = silc_calloc(message->len + 1, sizeof(char));
1272   memcpy(msg, message->data, message->len);
1273   client->ops->say(client, sock->user_data, msg);
1274   silc_free(msg);
1275 }
1276
1277 /* Called when notify is received and some async operation (such as command)
1278    is required before processing the notify message. This calls again the
1279    silc_client_notify_by_server and reprocesses the original notify packet. */
1280
1281 static void silc_client_notify_by_server_pending(void *context)
1282 {
1283   SilcPacketContext *p = (SilcPacketContext *)context;
1284   silc_client_notify_by_server(p->context, p->sock, p);
1285 }
1286
1287 /* Destructor for the pending command callback */
1288
1289 static void silc_client_notify_by_server_destructor(void *context)
1290 {
1291   silc_packet_context_free((SilcPacketContext *)context);
1292 }
1293
1294 /* Resolve client information from server by Client ID. */
1295
1296 static void silc_client_notify_by_server_resolve(SilcClient client,
1297                                                  SilcClientConnection conn,
1298                                                  SilcPacketContext *packet,
1299                                                  SilcClientID *client_id)
1300 {
1301   SilcPacketContext *p = silc_packet_context_dup(packet);
1302   SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1303
1304   p->context = (void *)client;
1305   p->sock = conn->sock;
1306
1307   silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
1308                            1, 3, idp->data, idp->len);
1309   silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1310                               silc_client_notify_by_server_destructor,
1311                               silc_client_notify_by_server_pending, p);
1312   silc_buffer_free(idp);
1313 }
1314
1315 /* Received notify message from server */
1316
1317 void silc_client_notify_by_server(SilcClient client,
1318                                   SilcSocketConnection sock,
1319                                   SilcPacketContext *packet)
1320 {
1321   SilcBuffer buffer = packet->buffer;
1322   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1323   SilcNotifyPayload payload;
1324   SilcNotifyType type;
1325   SilcArgumentPayload args;
1326
1327   SilcClientID *client_id = NULL;
1328   SilcChannelID *channel_id = NULL;
1329   SilcClientEntry client_entry;
1330   SilcClientEntry client_entry2;
1331   SilcChannelEntry channel;
1332   SilcChannelUser chu;
1333   SilcIDCacheEntry id_cache = NULL;
1334   unsigned char *tmp;
1335   unsigned int tmp_len, mode;
1336
1337   payload = silc_notify_payload_parse(buffer);
1338   if (!payload)
1339     goto out;
1340
1341   type = silc_notify_get_type(payload);
1342   args = silc_notify_get_args(payload);
1343   if (!args)
1344     goto out;
1345
1346   switch(type) {
1347   case SILC_NOTIFY_TYPE_NONE:
1348     /* Notify application */
1349     client->ops->notify(client, conn, type, 
1350                         silc_argument_get_arg_type(args, 1, NULL));
1351     break;
1352
1353   case SILC_NOTIFY_TYPE_INVITE:
1354     /* 
1355      * Someone invited me to a channel. Find Client and Channel entries
1356      * for the application.
1357      */
1358     
1359     /* Get Client ID */
1360     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1361     if (!tmp)
1362       goto out;
1363
1364     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1365     if (!client_id)
1366       goto out;
1367
1368     /* Find Client entry and if not found query it */
1369     client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
1370     if (!client_entry) {
1371       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1372       goto out;
1373     }
1374
1375     /* Get Channel ID */
1376     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1377     if (!tmp)
1378       goto out;
1379
1380     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1381     if (!channel_id)
1382       goto out;
1383
1384     /* XXX Will ALWAYS fail because currently we don't have way to resolve
1385        channel information for channel that we're not joined to. */
1386     /* XXX ways to fix: use (extended) LIST command, or define the channel
1387        name to the notfy type when name resolving is not mandatory. */
1388     /* Find channel entry */
1389     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1390                                      SILC_ID_CHANNEL, &id_cache))
1391       goto out;
1392
1393     channel = (SilcChannelEntry)id_cache->context;
1394
1395     /* Notify application */
1396     client->ops->notify(client, conn, type, client_entry, channel);
1397     break;
1398
1399   case SILC_NOTIFY_TYPE_JOIN:
1400     /*
1401      * Someone has joined to a channel. Get their ID and nickname and
1402      * cache them for later use.
1403      */
1404
1405     /* Get Client ID */
1406     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1407     if (!tmp)
1408       goto out;
1409
1410     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1411     if (!client_id)
1412       goto out;
1413
1414     /* Find Client entry and if not found query it */
1415     client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
1416     if (!client_entry) {
1417       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1418       goto out;
1419     }
1420
1421     /* If nickname or username hasn't been resolved, do so */
1422     if (!client_entry->nickname || !client_entry->username) {
1423       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1424       goto out;
1425     }
1426
1427     /* Get Channel ID */
1428     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1429     if (!tmp)
1430       goto out;
1431
1432     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1433     if (!channel_id)
1434       goto out;
1435
1436     /* Get channel entry */
1437     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1438                                      SILC_ID_CHANNEL, &id_cache))
1439       break;
1440
1441     channel = (SilcChannelEntry)id_cache->context;
1442
1443     /* Add client to channel */
1444     chu = silc_calloc(1, sizeof(*chu));
1445     chu->client = client_entry;
1446     silc_list_add(channel->clients, chu);
1447
1448     /* XXX add support for multiple same nicks on same channel. Check
1449        for them here */
1450
1451     /* Notify application. The channel entry is sent last as this notify
1452        is for channel but application don't know it from the arguments
1453        sent by server. */
1454     client->ops->notify(client, conn, type, client_entry, channel);
1455     break;
1456
1457   case SILC_NOTIFY_TYPE_LEAVE:
1458     /*
1459      * Someone has left a channel. We will remove it from the channel but
1460      * we'll keep it in the cache in case we'll need it later.
1461      */
1462     
1463     /* Get Client ID */
1464     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1465     if (!tmp)
1466       goto out;
1467
1468     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1469     if (!client_id)
1470       goto out;
1471
1472     /* Find Client entry */
1473     client_entry = 
1474       silc_idlist_get_client_by_id(client, conn, client_id);
1475     if (!client_entry)
1476       goto out;
1477
1478     /* Get channel entry */
1479     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1480                                 SILC_ID_CHANNEL);
1481     if (!channel_id)
1482       goto out;
1483     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1484                                      SILC_ID_CHANNEL, &id_cache))
1485       break;
1486
1487     channel = (SilcChannelEntry)id_cache->context;
1488
1489     /* Remove client from channel */
1490     silc_list_start(channel->clients);
1491     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1492       if (chu->client == client_entry) {
1493         silc_list_del(channel->clients, chu);
1494         silc_free(chu);
1495         break;
1496       }
1497     }
1498
1499     /* Notify application. The channel entry is sent last as this notify
1500        is for channel but application don't know it from the arguments
1501        sent by server. */
1502     client->ops->notify(client, conn, type, client_entry, channel);
1503     break;
1504
1505   case SILC_NOTIFY_TYPE_SIGNOFF:
1506     /*
1507      * Someone left SILC. We'll remove it from all channels and from cache.
1508      */
1509
1510     /* Get Client ID */
1511     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1512     if (!tmp)
1513       goto out;
1514
1515     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1516     if (!client_id)
1517       goto out;
1518
1519     /* Find Client entry */
1520     client_entry = 
1521       silc_idlist_get_client_by_id(client, conn, client_id);
1522     if (!client_entry)
1523       goto out;
1524
1525     /* Remove from all channels */
1526     silc_client_remove_from_channels(client, conn, client_entry);
1527
1528     /* Remove from cache */
1529     silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
1530                            client_entry->id);
1531
1532     /* Get signoff message */
1533     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1534     if (tmp_len > 128)
1535       tmp = NULL;
1536
1537     /* Notify application */
1538     client->ops->notify(client, conn, type, client_entry, tmp);
1539
1540     /* Free data */
1541     if (client_entry->nickname)
1542       silc_free(client_entry->nickname);
1543     if (client_entry->server)
1544       silc_free(client_entry->server);
1545     if (client_entry->id)
1546       silc_free(client_entry->id);
1547     if (client_entry->send_key)
1548       silc_cipher_free(client_entry->send_key);
1549     if (client_entry->receive_key)
1550       silc_cipher_free(client_entry->receive_key);
1551     break;
1552
1553   case SILC_NOTIFY_TYPE_TOPIC_SET:
1554     /*
1555      * Someone set the topic on a channel.
1556      */
1557
1558     /* Get Client ID */
1559     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1560     if (!tmp)
1561       goto out;
1562
1563     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1564     if (!client_id)
1565       goto out;
1566
1567     /* Find Client entry */
1568     client_entry = 
1569       silc_idlist_get_client_by_id(client, conn, client_id);
1570     if (!client_entry)
1571       goto out;
1572
1573     /* Get topic */
1574     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1575     if (!tmp)
1576       goto out;
1577
1578     /* Get channel entry */
1579     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1580                                 SILC_ID_CHANNEL);
1581     if (!channel_id)
1582       goto out;
1583     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1584                                      SILC_ID_CHANNEL, &id_cache))
1585       break;
1586
1587     channel = (SilcChannelEntry)id_cache->context;
1588
1589     /* Notify application. The channel entry is sent last as this notify
1590        is for channel but application don't know it from the arguments
1591        sent by server. */
1592     client->ops->notify(client, conn, type, client_entry, tmp, channel);
1593     break;
1594
1595   case SILC_NOTIFY_TYPE_NICK_CHANGE:
1596     /*
1597      * Someone changed their nickname. If we don't have entry for the new
1598      * ID we will query it and return here after it's done. After we've
1599      * returned we fetch the old entry and free it and notify the 
1600      * application.
1601      */
1602
1603     /* Get new Client ID */
1604     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1605     if (!tmp)
1606       goto out;
1607
1608     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1609     if (!client_id)
1610       goto out;
1611
1612     /* Ignore my ID */
1613     if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
1614       break;
1615
1616     /* Find Client entry and if not found query it */
1617     client_entry2 = 
1618       silc_idlist_get_client_by_id(client, conn, client_id);
1619     if (!client_entry2) {
1620       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1621       goto out;
1622     }
1623     silc_free(client_id);
1624
1625     /* Get old Client ID */
1626     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1627     if (!tmp)
1628       goto out;
1629
1630     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1631     if (!client_id)
1632       goto out;
1633
1634     /* Find old Client entry */
1635     client_entry = 
1636       silc_idlist_get_client_by_id(client, conn, client_id);
1637     if (!client_entry)
1638       goto out;
1639
1640     /* Remove the old from cache */
1641     silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
1642                            client_entry->id);
1643
1644     /* Replace old ID entry with new one on all channels. */
1645     silc_client_replace_from_channels(client, conn, client_entry,
1646                                       client_entry2);
1647
1648     /* Notify application */
1649     client->ops->notify(client, conn, type, client_entry, client_entry2);
1650
1651     /* Free data */
1652     if (client_entry->nickname)
1653       silc_free(client_entry->nickname);
1654     if (client_entry->server)
1655       silc_free(client_entry->server);
1656     if (client_entry->id)
1657       silc_free(client_entry->id);
1658     if (client_entry->send_key)
1659       silc_cipher_free(client_entry->send_key);
1660     if (client_entry->receive_key)
1661       silc_cipher_free(client_entry->receive_key);
1662     break;
1663
1664   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1665     /*
1666      * Someone changed a channel mode
1667      */
1668
1669     /* Get Client ID */
1670     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1671     if (!tmp)
1672       goto out;
1673
1674     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1675     if (!client_id)
1676       goto out;
1677
1678     /* Find Client entry */
1679     client_entry = 
1680       silc_idlist_get_client_by_id(client, conn, client_id);
1681     if (!client_entry)
1682       goto out;
1683
1684     /* Get the mode */
1685     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1686     if (!tmp)
1687       goto out;
1688
1689     SILC_GET32_MSB(mode, tmp);
1690
1691     /* Get channel entry */
1692     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1693                                 SILC_ID_CHANNEL);
1694     if (!channel_id)
1695       goto out;
1696     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1697                                      SILC_ID_CHANNEL, &id_cache))
1698       break;
1699
1700     channel = (SilcChannelEntry)id_cache->context;
1701
1702     /* Save the new mode */
1703     channel->mode = mode;
1704
1705     /* Notify application. The channel entry is sent last as this notify
1706        is for channel but application don't know it from the arguments
1707        sent by server. */
1708     client->ops->notify(client, conn, type, client_entry, mode, channel);
1709     break;
1710
1711   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1712     /*
1713      * Someone changed user's mode on a channel
1714      */
1715
1716     /* Get Client ID */
1717     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1718     if (!tmp)
1719       goto out;
1720
1721     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1722     if (!client_id)
1723       goto out;
1724
1725     /* Find Client entry */
1726     client_entry = 
1727       silc_idlist_get_client_by_id(client, conn, client_id);
1728     if (!client_entry)
1729       goto out;
1730
1731     /* Get the mode */
1732     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1733     if (!tmp)
1734       goto out;
1735
1736     SILC_GET32_MSB(mode, tmp);
1737
1738     /* Get target Client ID */
1739     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1740     if (!tmp)
1741       goto out;
1742
1743     silc_free(client_id);
1744     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1745     if (!client_id)
1746       goto out;
1747
1748     /* Find target Client entry */
1749     client_entry2 = 
1750       silc_idlist_get_client_by_id(client, conn, client_id);
1751     if (!client_entry2)
1752       goto out;
1753
1754     /* Get channel entry */
1755     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1756                                 SILC_ID_CHANNEL);
1757     if (!channel_id)
1758       goto out;
1759     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1760                                      SILC_ID_CHANNEL, &id_cache))
1761       break;
1762
1763     channel = (SilcChannelEntry)id_cache->context;
1764
1765     /* Save the mode */
1766     silc_list_start(channel->clients);
1767     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1768       if (chu->client == client_entry) {
1769         chu->mode = mode;
1770         break;
1771       }
1772     }
1773
1774     /* Notify application. The channel entry is sent last as this notify
1775        is for channel but application don't know it from the arguments
1776        sent by server. */
1777     client->ops->notify(client, conn, type, client_entry, mode, 
1778                         client_entry2, channel);
1779     break;
1780
1781   case SILC_NOTIFY_TYPE_MOTD:
1782     /*
1783      * Received Message of the day
1784      */
1785
1786     /* Get motd */
1787     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1788     if (!tmp)
1789       goto out;
1790     
1791     /* Notify application */
1792     client->ops->notify(client, conn, type, tmp);
1793     break;
1794
1795   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1796     /*
1797      * Router has enforced a new ID to a channel. Let's change the old
1798      * ID to the one provided here.
1799      */
1800
1801     /* Get the old ID */
1802     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1803     if (!tmp)
1804       goto out;
1805     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1806     if (!channel_id)
1807       goto out;
1808     
1809     /* Get the channel entry */
1810     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1811                                      SILC_ID_CHANNEL, &id_cache))
1812       break;
1813
1814     channel = (SilcChannelEntry)id_cache->context;
1815
1816     /* Free the old ID */
1817     silc_free(channel_id);
1818     silc_free(channel->id);
1819
1820     /* Get the new ID */
1821     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1822     if (!tmp)
1823       goto out;
1824     channel->id = silc_id_payload_parse_id(tmp, tmp_len);
1825     if (!channel->id)
1826       goto out;
1827
1828     id_cache->id = (void *)channel->id;
1829
1830     /* Notify application */
1831     client->ops->notify(client, conn, type, channel, channel);
1832     break;
1833
1834   case SILC_NOTIFY_TYPE_KICKED:
1835     /*
1836      * A client (maybe me) was kicked from a channel
1837      */
1838
1839     /* Get Client ID */
1840     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1841     if (!tmp)
1842       goto out;
1843
1844     client_id = silc_id_payload_parse_id(tmp, tmp_len);
1845     if (!client_id)
1846       goto out;
1847
1848     /* Find Client entry */
1849     client_entry = 
1850       silc_idlist_get_client_by_id(client, conn, client_id);
1851     if (!client_entry)
1852       goto out;
1853
1854     /* Get channel entry */
1855     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1856                                 SILC_ID_CHANNEL);
1857     if (!channel_id)
1858       goto out;
1859     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1860                                      SILC_ID_CHANNEL, &id_cache))
1861       break;
1862
1863     channel = (SilcChannelEntry)id_cache->context;
1864
1865     /* Get comment */
1866     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1867
1868     /* Notify application. The channel entry is sent last as this notify
1869        is for channel but application don't know it from the arguments
1870        sent by server. */
1871     client->ops->notify(client, conn, type, client_entry, tmp, channel);
1872
1873     /* If I was kicked from channel, remove the channel */
1874     if (client_entry == conn->local_entry) {
1875       if (conn->current_channel == channel)
1876         conn->current_channel = NULL;
1877       silc_idcache_del_by_id(conn->channel_cache, 
1878                              SILC_ID_CHANNEL, channel->id);
1879       silc_free(channel->channel_name);
1880       silc_free(channel->id);
1881       silc_free(channel->key);
1882       silc_cipher_free(channel->channel_key);
1883       silc_free(channel);
1884     }
1885     break;
1886     
1887   default:
1888     break;
1889   }
1890
1891  out:
1892   silc_notify_payload_free(payload);
1893   if (client_id)
1894     silc_free(client_id);
1895   if (channel_id)
1896     silc_free(channel_id);
1897 }
1898
1899 /* Processes the received new Client ID from server. Old Client ID is
1900    deleted from cache and new one is added. */
1901
1902 void silc_client_receive_new_id(SilcClient client,
1903                                 SilcSocketConnection sock,
1904                                 SilcIDPayload idp)
1905 {
1906   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1907   int connecting = FALSE;
1908
1909   if (!conn->local_entry)
1910     connecting = TRUE;
1911
1912   /* Delete old ID from ID cache */
1913   silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1914   
1915   /* Save the new ID */
1916   if (conn->local_id)
1917     silc_free(conn->local_id);
1918   if (conn->local_id_data)
1919     silc_free(conn->local_id_data);
1920
1921   conn->local_id = silc_id_payload_get_id(idp);
1922   conn->local_id_data = silc_id_payload_get_data(idp);
1923   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1924
1925   if (!conn->local_entry)
1926     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1927
1928   conn->local_entry->nickname = conn->nickname;
1929   if (!conn->local_entry->username) {
1930     conn->local_entry->username = 
1931       silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1932                   sizeof(conn->local_entry->username));
1933     sprintf(conn->local_entry->username, "%s@%s", client->username,
1934             client->hostname);
1935   }
1936   conn->local_entry->server = strdup(conn->remote_host);
1937   conn->local_entry->id = conn->local_id;
1938   
1939   /* Put it to the ID cache */
1940   silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1941                    conn->local_id, (void *)conn->local_entry, TRUE);
1942
1943   /* Notify application of successful connection. We do it here now that
1944      we've received the Client ID and are allowed to send traffic. */
1945   if (connecting)
1946     client->ops->connect(client, conn, TRUE);
1947 }
1948
1949 /* Processed received Channel ID for a channel. This is called when client
1950    joins to channel and server replies with channel ID. The ID is cached. */
1951
1952 void silc_client_new_channel_id(SilcClient client,
1953                                 SilcSocketConnection sock,
1954                                 char *channel_name,
1955                                 unsigned int mode, SilcIDPayload idp)
1956 {
1957   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1958   SilcChannelEntry channel;
1959
1960   SILC_LOG_DEBUG(("New channel ID"));
1961
1962   channel = silc_calloc(1, sizeof(*channel));
1963   channel->channel_name = channel_name;
1964   channel->id = silc_id_payload_get_id(idp);
1965   channel->mode = mode;
1966   silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1967
1968   conn->current_channel = channel;
1969
1970   /* Put it to the ID cache */
1971   silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1972                    (void *)channel->id, (void *)channel, TRUE);
1973 }
1974
1975 /* Saves channel key from encoded `key_payload'. This is used when we
1976    receive Channel Key Payload and when we are processing JOIN command 
1977    reply. */
1978
1979 void silc_client_save_channel_key(SilcClientConnection conn,
1980                                   SilcBuffer key_payload, 
1981                                   SilcChannelEntry channel)
1982 {
1983   unsigned char *id_string, *key, *cipher;
1984   unsigned int tmp_len;
1985   SilcChannelID *id;
1986   SilcIDCacheEntry id_cache = NULL;
1987   SilcChannelKeyPayload payload;
1988
1989   payload = silc_channel_key_payload_parse(key_payload);
1990   if (!payload)
1991     return;
1992
1993   id_string = silc_channel_key_get_id(payload, &tmp_len);
1994   if (!id_string) {
1995     silc_channel_key_payload_free(payload);
1996     return;
1997   }
1998
1999   id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
2000   if (!id) {
2001     silc_channel_key_payload_free(payload);
2002     return;
2003   }
2004
2005   /* Find channel. */
2006   if (!channel) {
2007     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
2008                                      SILC_ID_CHANNEL, &id_cache))
2009       goto out;
2010     
2011     /* Get channel entry */
2012     channel = (SilcChannelEntry)id_cache->context;
2013   }
2014
2015   /* Save the key */
2016   key = silc_channel_key_get_key(payload, &tmp_len);
2017   cipher = silc_channel_key_get_cipher(payload, NULL);
2018   channel->key_len = tmp_len * 8;
2019   channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
2020   memcpy(channel->key, key, tmp_len);
2021
2022   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
2023     conn->client->ops->say(conn->client, conn,
2024                      "Cannot talk to channel: unsupported cipher %s", cipher);
2025     goto out;
2026   }
2027   channel->channel_key->cipher->set_key(channel->channel_key->context, 
2028                                         key, channel->key_len);
2029
2030   /* Client is now joined to the channel */
2031   channel->on_channel = TRUE;
2032
2033  out:
2034   silc_free(id);
2035   silc_channel_key_payload_free(payload);
2036 }
2037
2038 /* Processes received key for channel. The received key will be used
2039    to protect the traffic on the channel for now on. Client must receive
2040    the key to the channel before talking on the channel is possible. 
2041    This is the key that server has generated, this is not the channel
2042    private key, it is entirely local setting. */
2043
2044 void silc_client_receive_channel_key(SilcClient client,
2045                                      SilcSocketConnection sock,
2046                                      SilcBuffer packet)
2047 {
2048   SILC_LOG_DEBUG(("Received key for channel"));
2049
2050   /* Save the key */
2051   silc_client_save_channel_key(sock->user_data, packet, NULL);
2052 }
2053
2054 /* Process received message to a channel (or from a channel, really). This
2055    decrypts the channel message with channel specific key and parses the
2056    channel payload. Finally it displays the message on the screen. */
2057
2058 void silc_client_channel_message(SilcClient client, 
2059                                  SilcSocketConnection sock, 
2060                                  SilcPacketContext *packet)
2061 {
2062   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
2063   SilcBuffer buffer = packet->buffer;
2064   SilcChannelPayload payload = NULL;
2065   SilcChannelID *id = NULL;
2066   SilcChannelEntry channel;
2067   SilcChannelUser chu;
2068   SilcIDCacheEntry id_cache = NULL;
2069   SilcClientID *client_id = NULL;
2070   int found = FALSE;
2071   unsigned int block_len;
2072
2073   /* Sanity checks */
2074   if (packet->dst_id_type != SILC_ID_CHANNEL)
2075     goto out;
2076
2077   client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
2078                              SILC_ID_CLIENT);
2079   if (!client_id)
2080     goto out;
2081   id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
2082   if (!id)
2083     goto out;
2084
2085   /* Find the channel entry from channels on this connection */
2086   if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
2087                                    SILC_ID_CHANNEL, &id_cache))
2088     goto out;
2089
2090   channel = (SilcChannelEntry)id_cache->context;
2091
2092   /* Decrypt the channel message payload. Push the IV out of the way,
2093      since it is not encrypted (after pushing buffer->tail has the IV). */
2094   block_len = silc_cipher_get_block_len(channel->channel_key);
2095   silc_buffer_push_tail(buffer, block_len);
2096   channel->channel_key->cipher->decrypt(channel->channel_key->context,
2097                                         buffer->data, buffer->data,
2098                                         buffer->len, buffer->tail);
2099   silc_buffer_pull_tail(buffer, block_len);
2100
2101   /* Parse the channel message payload */
2102   payload = silc_channel_payload_parse(buffer);
2103   if (!payload)
2104     goto out;
2105
2106   /* Find client entry */
2107   silc_list_start(channel->clients);
2108   while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2109     if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
2110       found = TRUE;
2111       break;
2112     }
2113   }
2114
2115   /* Pass the message to application */
2116   client->ops->channel_message(client, conn, found ? chu->client : NULL,
2117                                channel, silc_channel_get_data(payload, NULL));
2118
2119  out:
2120   if (id)
2121     silc_free(id);
2122   if (client_id)
2123     silc_free(client_id);
2124   if (payload)
2125     silc_channel_payload_free(payload);
2126 }
2127
2128 /* Private message received. This processes the private message and
2129    finally displays it on the screen. */
2130
2131 void silc_client_private_message(SilcClient client, 
2132                                  SilcSocketConnection sock, 
2133                                  SilcPacketContext *packet)
2134 {
2135   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
2136   SilcBuffer buffer = packet->buffer;
2137   SilcIDCacheEntry id_cache;
2138   SilcClientID *remote_id = NULL;
2139   SilcClientEntry remote_client;
2140   unsigned short nick_len;
2141   unsigned char *nickname, *message = NULL;
2142   int ret;
2143
2144   if (packet->src_id_type != SILC_ID_CLIENT)
2145     goto out;
2146
2147   /* Get nickname */
2148   ret = silc_buffer_unformat(buffer, 
2149                              SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
2150                              SILC_STR_END);
2151   if (ret == -1)
2152     return;
2153
2154   silc_buffer_pull(buffer, 2 + nick_len);
2155
2156   message = silc_calloc(buffer->len + 1, sizeof(char));
2157   memcpy(message, buffer->data, buffer->len);
2158
2159   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
2160                              SILC_ID_CLIENT);
2161   if (!remote_id)
2162     goto out;
2163
2164   /* Check whether we know this client already */
2165   if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
2166                                    SILC_ID_CLIENT, &id_cache))
2167     {
2168       /* Allocate client entry */
2169       remote_client = silc_calloc(1, sizeof(*remote_client));
2170       remote_client->id = remote_id;
2171       silc_parse_nickname(nickname, &remote_client->nickname, 
2172                           &remote_client->server, &remote_client->num);
2173       
2174       /* Save the client to cache */
2175       silc_idcache_add(conn->client_cache, remote_client->nickname,
2176                        SILC_ID_CLIENT, remote_client->id, remote_client, 
2177                        TRUE);
2178     } else {
2179       remote_client = (SilcClientEntry)id_cache->context;
2180     }
2181
2182   /* Pass the private message to application */
2183   client->ops->private_message(client, conn, remote_client, message);
2184
2185   /* See if we are away (gone). If we are away we will reply to the
2186      sender with the set away message. */
2187   if (conn->away && conn->away->away) {
2188     /* If it's me, ignore */
2189     if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
2190       goto out;
2191
2192     /* Send the away message */
2193     silc_client_packet_send_private_message(client, sock, remote_client,
2194                                             conn->away->away,
2195                                             strlen(conn->away->away), TRUE);
2196   }
2197
2198  out:
2199   if (remote_id)
2200     silc_free(remote_id);
2201
2202   if (message) {
2203     memset(message, 0, buffer->len);
2204     silc_free(message);
2205   }
2206   silc_free(nickname);
2207 }
2208
2209 /* Removes a client entry from all channel it has joined. This really is
2210    a performance killer (client_entry should have pointers to channel 
2211    entry list). */
2212
2213 void silc_client_remove_from_channels(SilcClient client,
2214                                       SilcClientConnection conn,
2215                                       SilcClientEntry client_entry)
2216 {
2217   SilcIDCacheEntry id_cache;
2218   SilcIDCacheList list;
2219   SilcChannelEntry channel;
2220   SilcChannelUser chu;
2221
2222   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2223                                SILC_ID_CHANNEL, &list))
2224     return;
2225
2226   silc_idcache_list_first(list, &id_cache);
2227   channel = (SilcChannelEntry)id_cache->context;
2228   
2229   while (channel) {
2230     
2231     /* Remove client from channel */
2232     silc_list_start(channel->clients);
2233     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2234       if (chu->client == client_entry) {
2235         silc_list_del(channel->clients, chu);
2236         silc_free(chu);
2237         break;
2238       }
2239     }
2240
2241     if (!silc_idcache_list_next(list, &id_cache))
2242       break;
2243     
2244     channel = (SilcChannelEntry)id_cache->context;
2245   }
2246
2247   silc_idcache_list_free(list);
2248 }
2249
2250 /* Replaces `old' client entries from all channels to `new' client entry.
2251    This can be called for example when nickname changes and old ID entry
2252    is replaced from ID cache with the new one. If the old ID entry is only
2253    updated, then this fucntion needs not to be called. */
2254
2255 void silc_client_replace_from_channels(SilcClient client, 
2256                                        SilcClientConnection conn,
2257                                        SilcClientEntry old,
2258                                        SilcClientEntry new)
2259 {
2260   SilcIDCacheEntry id_cache;
2261   SilcIDCacheList list;
2262   SilcChannelEntry channel;
2263   SilcChannelUser chu;
2264
2265   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2266                                SILC_ID_CHANNEL, &list))
2267     return;
2268
2269   silc_idcache_list_first(list, &id_cache);
2270   channel = (SilcChannelEntry)id_cache->context;
2271   
2272   while (channel) {
2273     
2274     /* Replace client entry */
2275     silc_list_start(channel->clients);
2276     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2277       if (chu->client == old) {
2278         chu->client = new;
2279         break;
2280       }
2281     }
2282
2283     if (!silc_idcache_list_next(list, &id_cache))
2284       break;
2285     
2286     channel = (SilcChannelEntry)id_cache->context;
2287   }
2288
2289   silc_idcache_list_free(list);
2290 }
2291
2292 /* Parses mode mask and returns the mode as string. */
2293
2294 char *silc_client_chmode(unsigned int mode)
2295 {
2296   char string[20];
2297
2298   if (!mode)
2299     return NULL;
2300
2301   memset(string, 0, sizeof(string));
2302
2303   if (mode & SILC_CHANNEL_MODE_PRIVATE)
2304     strncat(string, "p", 1);
2305
2306   if (mode & SILC_CHANNEL_MODE_SECRET)
2307     strncat(string, "s", 1);
2308
2309   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
2310     strncat(string, "k", 1);
2311
2312   if (mode & SILC_CHANNEL_MODE_INVITE)
2313     strncat(string, "i", 1);
2314
2315   if (mode & SILC_CHANNEL_MODE_TOPIC)
2316     strncat(string, "t", 1);
2317
2318   if (mode & SILC_CHANNEL_MODE_ULIMIT)
2319     strncat(string, "l", 1);
2320
2321   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
2322     strncat(string, "a", 1);
2323
2324   /* Rest of mode is ignored */
2325
2326   return strdup(string);
2327 }
2328
2329 /* Parses channel user mode mask and returns te mode as string */
2330
2331 char *silc_client_chumode(unsigned int mode)
2332 {
2333   char string[4];
2334
2335   if (!mode)
2336     return NULL;
2337
2338   memset(string, 0, sizeof(string));
2339
2340   if (mode & SILC_CHANNEL_UMODE_CHANFO)
2341     strncat(string, "f", 1);
2342
2343   if (mode & SILC_CHANNEL_UMODE_CHANOP)
2344     strncat(string, "o", 1);
2345
2346   return strdup(string);
2347 }
2348
2349 /* Parses channel user mode and returns it as special mode character. */
2350
2351 char *silc_client_chumode_char(unsigned int mode)
2352 {
2353   char string[4];
2354
2355   if (!mode)
2356     return NULL;
2357
2358   memset(string, 0, sizeof(string));
2359
2360   if (mode & SILC_CHANNEL_UMODE_CHANFO)
2361     strncat(string, "*", 1);
2362
2363   if (mode & SILC_CHANNEL_UMODE_CHANOP)
2364     strncat(string, "@", 1);
2365
2366   return strdup(string);
2367 }