5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
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.
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.
22 #include "clientlibincludes.h"
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);
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);
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. */
41 SilcClient silc_client_alloc(SilcClientOperations *ops, void *application)
43 SilcClient new_client;
45 new_client = silc_calloc(1, sizeof(*new_client));
46 new_client->application = application;
47 new_client->ops = ops;
52 /* Free's client object */
54 void silc_client_free(SilcClient client)
61 /* Initializes the client. This makes all the necessary steps to make
62 the client ready to be run. One must call silc_client_run to run the
65 int silc_client_init(SilcClient client)
67 SILC_LOG_DEBUG(("Initializing client"));
69 /* Initialize hash functions for client to use */
70 silc_hash_alloc("md5", &client->md5hash);
71 silc_hash_alloc("sha1", &client->sha1hash);
73 /* Initialize none cipher */
74 silc_cipher_alloc("none", &client->none_cipher);
76 /* Initialize random number generator */
77 client->rng = silc_rng_alloc();
78 silc_rng_init(client->rng);
79 silc_math_primegen_init(); /* XXX */
81 /* Register protocols */
82 silc_client_protocols_register();
84 /* Initialize the scheduler */
85 silc_schedule_init(&client->io_queue, &client->timeout_queue,
86 &client->generic_queue, 5000);
91 /* Stops the client. This is called to stop the client and thus to stop
94 void silc_client_stop(SilcClient client)
96 SILC_LOG_DEBUG(("Stopping client"));
98 /* Stop the scheduler, although it might be already stopped. This
99 doesn't hurt anyone. This removes all the tasks and task queues,
101 silc_schedule_stop();
102 silc_schedule_uninit();
104 silc_client_protocols_unregister();
106 SILC_LOG_DEBUG(("Client stopped"));
109 /* Runs the client. */
111 void silc_client_run(SilcClient client)
113 SILC_LOG_DEBUG(("Running client"));
115 /* Start the scheduler, the heart of the SILC client. When this returns
116 the program will be terminated. */
120 /* Allocates and adds new connection to the client. This adds the allocated
121 connection to the connection table and returns a pointer to it. A client
122 can have multiple connections to multiple servers. Every connection must
123 be added to the client using this function. User data `context' may
124 be sent as argument. */
126 SilcClientConnection silc_client_add_connection(SilcClient client,
131 SilcClientConnection conn;
134 conn = silc_calloc(1, sizeof(*conn));
136 /* Initialize ID caches */
137 conn->client_cache = silc_idcache_alloc(0);
138 conn->channel_cache = silc_idcache_alloc(0);
139 conn->server_cache = silc_idcache_alloc(0);
140 conn->client = client;
141 conn->remote_host = strdup(hostname);
142 conn->remote_port = port;
143 conn->context = context;
145 /* Add the connection to connections table */
146 for (i = 0; i < client->conns_count; i++)
147 if (client->conns && !client->conns[i]) {
148 client->conns[i] = conn;
152 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
153 * (client->conns_count + 1));
154 client->conns[client->conns_count] = conn;
155 client->conns_count++;
160 /* Removes connection from client. */
162 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
166 for (i = 0; i < client->conns_count; i++)
167 if (client->conns[i] == conn) {
169 client->conns[i] = NULL;
173 /* Internal context for connection process. This is needed as we
174 doing asynchronous connecting. */
177 SilcClientConnection conn;
183 } SilcClientInternalConnectContext;
186 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
190 /* XXX In the future we should give up this non-blocking connect all
191 together and use threads instead. */
192 /* Create connection to server asynchronously */
193 sock = silc_net_create_connection_async(ctx->port, ctx->host);
197 /* Register task that will receive the async connect and will
199 ctx->task = silc_task_register(ctx->client->io_queue, sock,
200 silc_client_connect_to_server_start,
203 SILC_TASK_PRI_NORMAL);
204 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
205 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
212 /* Connects to remote server. This is the main routine used to connect
213 to SILC server. Returns -1 on error and the created socket otherwise.
214 The `context' is user context that is saved into the SilcClientConnection
215 that is created after the connection is created. */
217 int silc_client_connect_to_server(SilcClient client, int port,
218 char *host, void *context)
220 SilcClientInternalConnectContext *ctx;
221 SilcClientConnection conn;
224 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
227 conn = silc_client_add_connection(client, host, port, context);
229 client->ops->say(client, conn,
230 "Connecting to port %d of server %s", port, host);
232 /* Allocate internal context for connection process. This is
233 needed as we are doing async connecting. */
234 ctx = silc_calloc(1, sizeof(*ctx));
235 ctx->client = client;
237 ctx->host = strdup(host);
241 /* Do the actual connecting process */
242 sock = silc_client_connect_to_server_internal(ctx);
244 silc_client_del_connection(client, conn);
248 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
249 key material between client and server. This function can be called
250 directly if application is performing its own connecting and does not
251 use the connecting provided by this library. */
253 int silc_client_start_key_exchange(SilcClient client,
254 SilcClientConnection conn,
257 SilcProtocol protocol;
258 SilcClientKEInternalContext *proto_ctx;
261 /* Allocate new socket connection object */
262 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
263 if (conn->sock == NULL) {
264 client->ops->say(client, conn,
265 "Error: Could not allocate connection socket");
269 conn->nickname = strdup(client->username);
270 conn->sock->hostname = conn->remote_host;
271 conn->sock->port = conn->remote_port;
273 /* Allocate internal Key Exchange context. This is sent to the
274 protocol as context. */
275 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
276 proto_ctx->client = (void *)client;
277 proto_ctx->sock = conn->sock;
278 proto_ctx->rng = client->rng;
279 proto_ctx->responder = FALSE;
281 /* Perform key exchange protocol. silc_client_connect_to_server_final
282 will be called after the protocol is finished. */
283 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
284 &protocol, (void *)proto_ctx,
285 silc_client_connect_to_server_second);
287 client->ops->say(client, conn,
288 "Error: Could not start authentication protocol");
291 conn->sock->protocol = protocol;
293 /* Register the connection for network input and output. This sets
294 that scheduler will listen for incoming packets for this connection
295 and sets that outgoing packets may be sent to this connection as well.
296 However, this doesn't set the scheduler for outgoing traffic, it will
297 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
298 later when outgoing data is available. */
299 context = (void *)client;
300 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
302 /* Execute the protocol */
303 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
307 /* Start of the connection to the remote server. This is called after
308 succesful TCP/IP connection has been established to the remote host. */
310 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
312 SilcClientInternalConnectContext *ctx =
313 (SilcClientInternalConnectContext *)context;
314 SilcClient client = ctx->client;
315 SilcClientConnection conn = ctx->conn;
316 int opt, opt_len = sizeof(opt);
318 SILC_LOG_DEBUG(("Start"));
320 /* Check the socket status as it might be in error */
321 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
323 if (ctx->tries < 2) {
324 /* Connection failed but lets try again */
325 client->ops->say(client, conn, "Could not connect to server %s: %s",
326 ctx->host, strerror(opt));
327 client->ops->say(client, conn,
328 "Connecting to port %d of server %s resumed",
329 ctx->port, ctx->host);
331 /* Unregister old connection try */
332 silc_schedule_unset_listen_fd(fd);
333 silc_net_close_connection(fd);
334 silc_task_unregister(client->io_queue, ctx->task);
337 silc_client_connect_to_server_internal(ctx);
340 /* Connection failed and we won't try anymore */
341 client->ops->say(client, conn, "Could not connect to server %s: %s",
342 ctx->host, strerror(opt));
343 silc_schedule_unset_listen_fd(fd);
344 silc_net_close_connection(fd);
345 silc_task_unregister(client->io_queue, ctx->task);
348 /* Notify application of failure */
349 client->ops->connect(client, conn, FALSE);
350 silc_client_del_connection(client, conn);
355 silc_schedule_unset_listen_fd(fd);
356 silc_task_unregister(client->io_queue, ctx->task);
359 if (!silc_client_start_key_exchange(client, conn, fd)) {
360 silc_net_close_connection(fd);
361 client->ops->connect(client, conn, FALSE);
365 /* Second part of the connecting to the server. This executed
366 authentication protocol. */
368 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
370 SilcProtocol protocol = (SilcProtocol)context;
371 SilcClientKEInternalContext *ctx =
372 (SilcClientKEInternalContext *)protocol->context;
373 SilcClient client = (SilcClient)ctx->client;
374 SilcSocketConnection sock = NULL;
375 SilcClientConnAuthInternalContext *proto_ctx;
377 SILC_LOG_DEBUG(("Start"));
379 if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
380 /* Error occured during protocol */
381 SILC_LOG_DEBUG(("Error during KE protocol"));
382 silc_protocol_free(protocol);
384 silc_ske_free(ctx->ske);
386 silc_free(ctx->dest_id);
387 ctx->sock->protocol = NULL;
389 /* Notify application of failure */
390 client->ops->connect(client, ctx->sock->user_data, FALSE);
395 /* Allocate internal context for the authentication protocol. This
396 is sent as context for the protocol. */
397 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
398 proto_ctx->client = (void *)client;
399 proto_ctx->sock = sock = ctx->sock;
400 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
401 proto_ctx->dest_id_type = ctx->dest_id_type;
402 proto_ctx->dest_id = ctx->dest_id;
404 /* Resolve the authentication method to be used in this connection */
405 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
406 sock->port, &proto_ctx->auth_meth,
407 &proto_ctx->auth_data,
408 &proto_ctx->auth_data_len))
410 /* XXX do AUTH_REQUEST resolcing with server */
411 proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
414 /* Free old protocol as it is finished now */
415 silc_protocol_free(protocol);
417 silc_buffer_free(ctx->packet);
419 /* silc_free(ctx->keymat....); */
420 sock->protocol = NULL;
422 /* Allocate the authentication protocol. This is allocated here
423 but we won't start it yet. We will be receiving party of this
424 protocol thus we will wait that connecting party will make
426 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
427 &sock->protocol, (void *)proto_ctx,
428 silc_client_connect_to_server_final);
430 /* Execute the protocol */
431 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
434 /* Finalizes the connection to the remote SILC server. This is called
435 after authentication protocol has been completed. This send our
436 user information to the server to receive our client ID from
439 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
441 SilcProtocol protocol = (SilcProtocol)context;
442 SilcClientConnAuthInternalContext *ctx =
443 (SilcClientConnAuthInternalContext *)protocol->context;
444 SilcClient client = (SilcClient)ctx->client;
445 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
448 SILC_LOG_DEBUG(("Start"));
450 if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
451 /* Error occured during protocol */
452 SILC_LOG_DEBUG(("Error during authentication protocol"));
453 silc_protocol_free(protocol);
455 silc_free(ctx->auth_data);
457 silc_ske_free(ctx->ske);
459 silc_free(ctx->dest_id);
460 conn->sock->protocol = NULL;
462 /* Notify application of failure */
463 client->ops->connect(client, ctx->sock->user_data, FALSE);
468 /* Send NEW_CLIENT packet to the server. We will become registered
469 to the SILC network after sending this packet and we will receive
470 client ID from the server. */
471 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
472 strlen(client->realname));
473 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
474 silc_buffer_format(packet,
475 SILC_STR_UI_SHORT(strlen(client->username)),
476 SILC_STR_UI_XNSTRING(client->username,
477 strlen(client->username)),
478 SILC_STR_UI_SHORT(strlen(client->realname)),
479 SILC_STR_UI_XNSTRING(client->realname,
480 strlen(client->realname)),
483 /* Send the packet */
484 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
486 packet->data, packet->len, TRUE);
487 silc_buffer_free(packet);
489 /* Save remote ID. */
490 conn->remote_id = ctx->dest_id;
491 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
492 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
494 /* Notify application of successful connection */
495 client->ops->connect(client, conn, TRUE);
497 silc_protocol_free(protocol);
499 silc_free(ctx->auth_data);
501 silc_ske_free(ctx->ske);
503 silc_free(ctx->dest_id);
505 conn->sock->protocol = NULL;
508 /* Internal routine that sends packet or marks packet to be sent. This
509 is used directly only in special cases. Normal cases should use
510 silc_server_packet_send. Returns < 0 on error. */
512 static int silc_client_packet_send_real(SilcClient client,
513 SilcSocketConnection sock,
518 /* Send the packet */
519 ret = silc_packet_send(sock, force_send);
523 /* Mark that there is some outgoing data available for this connection.
524 This call sets the connection both for input and output (the input
525 is set always and this call keeps the input setting, actually).
526 Actual data sending is performed by silc_client_packet_process. */
527 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
529 /* Mark to socket that data is pending in outgoing buffer. This flag
530 is needed if new data is added to the buffer before the earlier
531 put data is sent to the network. */
532 SILC_SET_OUTBUF_PENDING(sock);
537 /* Packet processing callback. This is used to send and receive packets
538 from network. This is generic task. */
540 SILC_TASK_CALLBACK(silc_client_packet_process)
542 SilcClient client = (SilcClient)context;
543 SilcSocketConnection sock = NULL;
544 SilcClientConnection conn;
547 SILC_LOG_DEBUG(("Processing packet"));
549 SILC_CLIENT_GET_SOCK(client, fd, sock);
553 conn = (SilcClientConnection)sock->user_data;
556 if (type == SILC_TASK_WRITE) {
557 SILC_LOG_DEBUG(("Writing data to connection"));
559 if (sock->outbuf->data - sock->outbuf->head)
560 silc_buffer_push(sock->outbuf,
561 sock->outbuf->data - sock->outbuf->head);
563 ret = silc_client_packet_send_real(client, sock, TRUE);
565 /* If returned -2 could not write to connection now, will do
570 /* The packet has been sent and now it is time to set the connection
571 back to only for input. When there is again some outgoing data
572 available for this connection it will be set for output as well.
573 This call clears the output setting and sets it only for input. */
574 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
575 SILC_UNSET_OUTBUF_PENDING(sock);
577 silc_buffer_clear(sock->outbuf);
581 /* Packet receiving */
582 if (type == SILC_TASK_READ) {
583 SILC_LOG_DEBUG(("Reading data from connection"));
585 /* Read data from network */
586 ret = silc_packet_receive(sock);
592 SILC_LOG_DEBUG(("Read EOF"));
594 /* If connection is disconnecting already we will finally
595 close the connection */
596 if (SILC_IS_DISCONNECTING(sock)) {
597 client->ops->disconnect(client, conn);
598 silc_client_close_connection(client, sock);
602 client->ops->say(client, conn, "Connection closed: premature EOF");
603 SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
604 client->ops->disconnect(client, conn);
605 silc_client_close_connection(client, sock);
609 /* Process the packet. This will call the parser that will then
610 decrypt and parse the packet. */
611 silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
612 silc_client_packet_parse, client);
616 /* Parses whole packet, received earlier. */
618 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
620 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
621 SilcClient client = (SilcClient)parse_ctx->context;
622 SilcPacketContext *packet = parse_ctx->packet;
623 SilcBuffer buffer = packet->buffer;
624 SilcSocketConnection sock = parse_ctx->sock;
625 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
628 SILC_LOG_DEBUG(("Start"));
630 /* Decrypt the received packet */
631 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
636 /* Parse the packet. Packet type is returned. */
637 ret = silc_packet_parse(packet);
639 /* Parse the packet header in special way as this is "special"
641 ret = silc_packet_parse_special(packet);
644 if (ret == SILC_PACKET_NONE)
647 /* Parse the incoming packet type */
648 silc_client_packet_parse_type(client, sock, packet);
651 silc_buffer_clear(buffer);
653 silc_free(parse_ctx);
656 /* Parser callback called by silc_packet_receive_process. Thie merely
657 registers timeout that will handle the actual parsing when appropriate. */
659 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
661 SilcClient client = (SilcClient)parser_context->context;
663 /* Parse the packet */
664 silc_task_register(client->timeout_queue, parser_context->sock->sock,
665 silc_client_packet_parse_real,
666 (void *)parser_context, 0, 1,
668 SILC_TASK_PRI_NORMAL);
671 /* Parses the packet type and calls what ever routines the packet type
672 requires. This is done for all incoming packets. */
674 void silc_client_packet_parse_type(SilcClient client,
675 SilcSocketConnection sock,
676 SilcPacketContext *packet)
678 SilcBuffer buffer = packet->buffer;
679 SilcPacketType type = packet->type;
681 SILC_LOG_DEBUG(("Parsing packet type %d", type));
683 /* Parse the packet type */
685 case SILC_PACKET_DISCONNECT:
686 silc_client_disconnected_by_server(client, sock, buffer);
688 case SILC_PACKET_SUCCESS:
690 * Success received for something. For now we can have only
691 * one protocol for connection executing at once hence this
692 * success message is for whatever protocol is executing currently.
694 if (sock->protocol) {
695 sock->protocol->execute(client->timeout_queue, 0,
696 sock->protocol, sock->sock, 0, 0);
699 case SILC_PACKET_FAILURE:
701 * Failure received for some protocol. Set the protocol state to
702 * error and call the protocol callback. This fill cause error on
703 * protocol and it will call the final callback.
705 if (sock->protocol) {
706 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
707 sock->protocol->execute(client->timeout_queue, 0,
708 sock->protocol, sock->sock, 0, 0);
711 case SILC_PACKET_REJECT:
714 case SILC_PACKET_NOTIFY:
716 * Received notify message
718 silc_client_notify_by_server(client, sock, buffer);
721 case SILC_PACKET_ERROR:
723 * Received error message
725 silc_client_error_by_server(client, sock, buffer);
728 case SILC_PACKET_CHANNEL_MESSAGE:
730 * Received message to (from, actually) a channel
732 silc_client_channel_message(client, sock, packet);
734 case SILC_PACKET_CHANNEL_KEY:
736 * Received key for a channel. By receiving this key the client will be
737 * able to talk to the channel it has just joined. This can also be
738 * a new key for existing channel as keys expire peridiocally.
740 silc_client_receive_channel_key(client, sock, buffer);
743 case SILC_PACKET_PRIVATE_MESSAGE:
745 * Received private message
747 silc_client_private_message(client, sock, packet);
749 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
751 * Received private message key
755 case SILC_PACKET_COMMAND_REPLY:
757 * Recived reply for a command
759 silc_client_command_reply_process(client, sock, packet);
762 case SILC_PACKET_KEY_EXCHANGE:
763 if (sock->protocol) {
764 SilcClientKEInternalContext *proto_ctx =
765 (SilcClientKEInternalContext *)sock->protocol->context;
767 proto_ctx->packet = buffer;
768 proto_ctx->dest_id_type = packet->src_id_type;
769 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
771 /* Let the protocol handle the packet */
772 sock->protocol->execute(client->timeout_queue, 0,
773 sock->protocol, sock->sock, 0, 0);
775 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
776 "protocol active, packet dropped."));
778 /* XXX Trigger KE protocol?? Rekey actually! */
782 case SILC_PACKET_KEY_EXCHANGE_1:
783 if (sock->protocol) {
786 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
787 "protocol active, packet dropped."));
790 case SILC_PACKET_KEY_EXCHANGE_2:
791 if (sock->protocol) {
792 SilcClientKEInternalContext *proto_ctx =
793 (SilcClientKEInternalContext *)sock->protocol->context;
795 if (proto_ctx->packet)
796 silc_buffer_free(proto_ctx->packet);
798 proto_ctx->packet = buffer;
799 proto_ctx->dest_id_type = packet->src_id_type;
800 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
802 /* Let the protocol handle the packet */
803 sock->protocol->execute(client->timeout_queue, 0,
804 sock->protocol, sock->sock, 0, 0);
806 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
807 "protocol active, packet dropped."));
811 case SILC_PACKET_NEW_ID:
814 * Received new ID from server. This packet is received at
815 * the connection to the server. New ID is also received when
816 * user changes nickname but in that case the new ID is received
817 * as command reply and not as this packet type.
819 unsigned char *id_string;
820 unsigned short id_type;
822 silc_buffer_unformat(buffer,
823 SILC_STR_UI_SHORT(&id_type),
824 SILC_STR_UI16_STRING_ALLOC(&id_string),
827 if ((SilcIdType)id_type != SILC_ID_CLIENT)
830 silc_client_receive_new_id(client, sock, id_string);
831 silc_free(id_string);
836 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
841 /* Sends packet. This doesn't actually send the packet instead it assembles
842 it and marks it to be sent. However, if force_send is TRUE the packet
843 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
844 will be derived from sock argument. Otherwise the valid arguments sent
847 void silc_client_packet_send(SilcClient client,
848 SilcSocketConnection sock,
851 SilcIdType dst_id_type,
855 unsigned int data_len,
858 SilcPacketContext packetdata;
860 SILC_LOG_DEBUG(("Sending packet, type %d", type));
862 /* Get data used in the packet sending, keys and stuff */
863 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
864 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
865 cipher = ((SilcClientConnection)sock->user_data)->send_key;
867 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
868 hmac = ((SilcClientConnection)sock->user_data)->hmac;
870 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
871 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
872 dst_id_type = SILC_ID_SERVER;
876 /* Set the packet context pointers */
877 packetdata.flags = 0;
878 packetdata.type = type;
879 if (((SilcClientConnection)sock->user_data)->local_id_data)
880 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
882 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
883 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
884 packetdata.src_id_type = SILC_ID_CLIENT;
886 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
887 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
888 packetdata.dst_id_type = dst_id_type;
890 packetdata.dst_id = NULL;
891 packetdata.dst_id_len = 0;
892 packetdata.dst_id_type = SILC_ID_NONE;
894 packetdata.rng = client->rng;
895 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
896 packetdata.src_id_len + packetdata.dst_id_len;
897 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
899 /* Prepare outgoing data buffer for packet sending */
900 silc_packet_send_prepare(sock,
901 SILC_PACKET_HEADER_LEN +
902 packetdata.src_id_len +
903 packetdata.dst_id_len,
907 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
909 packetdata.buffer = sock->outbuf;
911 /* Put the data to the buffer */
912 if (data && data_len)
913 silc_buffer_put(sock->outbuf, data, data_len);
915 /* Create the outgoing packet */
916 silc_packet_assemble(&packetdata);
918 /* Encrypt the packet */
920 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
922 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
923 sock->outbuf->data, sock->outbuf->len);
925 /* Now actually send the packet */
926 silc_client_packet_send_real(client, sock, force_send);
929 /* Sends packet to a channel. Packet to channel is always encrypted
930 differently from "normal" packets. SILC header of the packet is
931 encrypted with the next receiver's key and the rest of the packet is
932 encrypted with the channel specific key. Padding and HMAC is computed
933 with the next receiver's key. */
935 void silc_client_packet_send_to_channel(SilcClient client,
936 SilcSocketConnection sock,
937 SilcChannelEntry channel,
939 unsigned int data_len,
943 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
945 SilcPacketContext packetdata;
948 unsigned char *id_string;
950 SILC_LOG_DEBUG(("Sending packet to channel"));
952 if (!channel || !channel->key) {
953 client->ops->say(client, conn,
954 "Cannot talk to channel: key does not exist");
960 for (i = 0; i < 16; i++)
961 channel->iv[i] = silc_rng_get_byte(client->rng);
963 silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
965 /* Encode the channel payload */
966 payload = silc_channel_payload_encode(data_len, data, 16, channel->iv,
969 client->ops->say(client, conn,
970 "Error: Could not create packet to be sent to channel");
974 /* Get data used in packet header encryption, keys and stuff. Rest
975 of the packet (the payload) is, however, encrypted with the
976 specified channel key. */
977 cipher = conn->send_key;
979 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
981 /* Set the packet context pointers. The destination ID is always
982 the Channel ID of the channel. Server and router will handle the
983 distribution of the packet. */
984 packetdata.flags = 0;
985 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
986 packetdata.src_id = conn->local_id_data;
987 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
988 packetdata.src_id_type = SILC_ID_CLIENT;
989 packetdata.dst_id = id_string;
990 packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
991 packetdata.dst_id_type = SILC_ID_CHANNEL;
992 packetdata.rng = client->rng;
993 packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
994 packetdata.src_id_len + packetdata.dst_id_len;
995 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
996 packetdata.src_id_len +
997 packetdata.dst_id_len));
999 /* Prepare outgoing data buffer for packet sending */
1000 silc_packet_send_prepare(sock,
1001 SILC_PACKET_HEADER_LEN +
1002 packetdata.src_id_len +
1003 packetdata.dst_id_len,
1007 packetdata.buffer = sock->outbuf;
1009 /* Encrypt payload of the packet. This is encrypted with the channel key. */
1010 channel->channel_key->cipher->encrypt(channel->channel_key->context,
1011 payload->data, payload->data,
1012 payload->len - 16, /* -IV_LEN */
1015 /* Put the actual encrypted payload data into the buffer. */
1016 silc_buffer_put(sock->outbuf, payload->data, payload->len);
1018 /* Create the outgoing packet */
1019 silc_packet_assemble(&packetdata);
1021 /* Encrypt the header and padding of the packet. This is encrypted
1022 with normal session key shared with our server. */
1023 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1024 packetdata.src_id_len + packetdata.dst_id_len +
1027 SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1028 sock->outbuf->data, sock->outbuf->len);
1030 /* Now actually send the packet */
1031 silc_client_packet_send_real(client, sock, force_send);
1032 silc_buffer_free(payload);
1033 silc_free(id_string);
1036 /* Sends private message to remote client. If private message key has
1037 not been set with this client then the message will be encrypted using
1038 normal session keys. Private messages are special packets in SILC
1039 network hence we need this own function for them. This is similiar
1040 to silc_client_packet_send_to_channel except that we send private
1043 void silc_client_packet_send_private_message(SilcClient client,
1044 SilcSocketConnection sock,
1045 SilcClientEntry client_entry,
1046 unsigned char *data,
1047 unsigned int data_len,
1050 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1052 SilcPacketContext packetdata;
1053 unsigned int nick_len;
1057 SILC_LOG_DEBUG(("Sending private message"));
1059 /* Create private message payload */
1060 nick_len = strlen(conn->nickname);
1061 buffer = silc_buffer_alloc(2 + nick_len + data_len);
1062 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1063 silc_buffer_format(buffer,
1064 SILC_STR_UI_SHORT(nick_len),
1065 SILC_STR_UI_XNSTRING(conn->nickname,
1067 SILC_STR_UI_XNSTRING(data, data_len),
1070 /* If we don't have private message specific key then private messages
1071 are just as any normal packet thus call normal packet sending. If
1072 the key exist then the encryption process is a bit different and
1073 will be done in the rest of this function. */
1074 if (!client_entry->send_key) {
1075 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1076 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1077 buffer->data, buffer->len, force_send);
1081 /* We have private message specific key */
1083 /* Get data used in the encryption */
1084 cipher = client_entry->send_key;
1087 /* Set the packet context pointers. */
1088 packetdata.flags = 0;
1089 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1090 packetdata.src_id = conn->local_id_data;
1091 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1092 packetdata.src_id_type = SILC_ID_CLIENT;
1094 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1096 packetdata.dst_id = conn->local_id_data;
1097 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1098 packetdata.dst_id_type = SILC_ID_CLIENT;
1099 packetdata.rng = client->rng;
1100 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
1101 packetdata.src_id_len + packetdata.dst_id_len;
1102 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1103 packetdata.src_id_len +
1104 packetdata.dst_id_len));
1106 /* Prepare outgoing data buffer for packet sending */
1107 silc_packet_send_prepare(sock,
1108 SILC_PACKET_HEADER_LEN +
1109 packetdata.src_id_len +
1110 packetdata.dst_id_len,
1114 packetdata.buffer = sock->outbuf;
1116 /* Encrypt payload of the packet. Encrypt with private message specific
1117 key if it exist, otherwise with session key. */
1118 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1119 buffer->len, cipher->iv);
1121 /* Put the actual encrypted payload data into the buffer. */
1122 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1124 /* Create the outgoing packet */
1125 silc_packet_assemble(&packetdata);
1127 /* Encrypt the header and padding of the packet. */
1128 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1129 packetdata.src_id_len + packetdata.dst_id_len +
1132 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1133 sock->outbuf->data, sock->outbuf->len);
1135 /* Now actually send the packet */
1136 silc_client_packet_send_real(client, sock, force_send);
1137 silc_free(packetdata.dst_id);
1143 /* Closes connection to remote end. Free's all allocated data except
1144 for some information such as nickname etc. that are valid at all time. */
1146 void silc_client_close_connection(SilcClient client,
1147 SilcSocketConnection sock)
1149 SilcClientConnection conn;
1151 /* We won't listen for this connection anymore */
1152 silc_schedule_unset_listen_fd(sock->sock);
1154 /* Unregister all tasks */
1155 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1156 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1158 /* Close the actual connection */
1159 silc_net_close_connection(sock->sock);
1161 client->ops->say(client, sock->user_data,
1162 "Closed connection to host %s", sock->hostname ?
1163 sock->hostname : sock->ip);
1165 /* Free everything */
1166 if (sock->user_data) {
1167 conn = (SilcClientConnection)sock->user_data;
1169 /* XXX Free all client entries and channel entries. */
1171 /* Clear ID caches */
1172 silc_idcache_del_all(conn->client_cache);
1173 silc_idcache_del_all(conn->channel_cache);
1176 if (conn->remote_host)
1177 silc_free(conn->remote_host);
1179 silc_free(conn->local_id);
1180 if (conn->local_id_data)
1181 silc_free(conn->local_id_data);
1183 silc_cipher_free(conn->send_key);
1184 if (conn->receive_key)
1185 silc_cipher_free(conn->receive_key);
1187 silc_hmac_free(conn->hmac);
1188 if (conn->hmac_key) {
1189 memset(conn->hmac_key, 0, conn->hmac_key_len);
1190 silc_free(conn->hmac_key);
1194 conn->remote_port = 0;
1195 conn->remote_type = 0;
1196 conn->send_key = NULL;
1197 conn->receive_key = NULL;
1199 conn->hmac_key = NULL;
1200 conn->hmac_key_len = 0;
1201 conn->local_id = NULL;
1202 conn->local_id_data = NULL;
1203 conn->remote_host = NULL;
1204 conn->current_channel = NULL;
1206 silc_client_del_connection(client, conn);
1209 if (sock->protocol) {
1210 silc_protocol_free(sock->protocol);
1211 sock->protocol = NULL;
1213 silc_socket_free(sock);
1216 /* Called when we receive disconnection packet from server. This
1217 closes our end properly and displays the reason of the disconnection
1220 void silc_client_disconnected_by_server(SilcClient client,
1221 SilcSocketConnection sock,
1226 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1228 msg = silc_calloc(message->len + 1, sizeof(char));
1229 memcpy(msg, message->data, message->len);
1230 client->ops->say(client, sock->user_data, msg);
1233 SILC_SET_DISCONNECTED(sock);
1234 silc_client_close_connection(client, sock);
1237 /* Received error message from server. Display it on the screen.
1238 We don't take any action what so ever of the error message. */
1240 void silc_client_error_by_server(SilcClient client,
1241 SilcSocketConnection sock,
1246 msg = silc_calloc(message->len + 1, sizeof(char));
1247 memcpy(msg, message->data, message->len);
1248 client->ops->say(client, sock->user_data, msg);
1252 /* Received notify message from server */
1254 void silc_client_notify_by_server(SilcClient client,
1255 SilcSocketConnection sock,
1258 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1259 SilcNotifyPayload payload;
1260 SilcNotifyType type;
1261 SilcArgumentPayload args;
1264 SilcClientID *client_id = NULL;
1265 SilcChannelID *channel_id = NULL;
1267 SilcClientEntry client_entry;
1268 SilcChannelEntry channel;
1269 SilcIDCacheEntry id_cache = NULL;
1271 unsigned int tmp_len;
1273 payload = silc_notify_payload_parse(message);
1274 type = silc_notify_get_type(payload);
1275 args = silc_notify_get_args(payload);
1278 case SILC_NOTIFY_TYPE_NONE:
1280 case SILC_NOTIFY_TYPE_INVITE:
1282 * Someone invited me to a channel. Nothing interesting to do here.
1285 case SILC_NOTIFY_TYPE_JOIN:
1287 * Someone has joined to a channel. Get their ID and nickname and
1288 * cache them for later use.
1291 /* Get client ID (it's in ID payload) */
1292 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1293 idp = silc_id_payload_parse_data(tmp, tmp_len);
1294 client_id = silc_id_payload_get_id(idp);
1295 silc_id_payload_free(idp);
1297 /* If it's my ID, ignore */
1298 if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
1301 /* Check if we have that ID already */
1302 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1303 SILC_ID_CLIENT, &id_cache)) {
1304 /* Add client to cache */
1305 client_entry = silc_calloc(1, sizeof(*client_entry));
1306 client_entry->id = client_id;
1307 client_entry->nickname =
1308 strdup(silc_argument_get_arg_type(args, 2, NULL));
1309 silc_idcache_add(conn->client_cache, client_entry->nickname,
1310 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
1313 client_entry = (SilcClientEntry)id_cache->context;
1316 /* Get Channel ID (it's in ID payload) */
1317 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1318 idp = silc_id_payload_parse_data(tmp, tmp_len);
1319 channel_id = silc_id_payload_get_id(idp);
1320 silc_id_payload_free(idp);
1322 /* Find channel entry */
1323 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1324 SILC_ID_CHANNEL, &id_cache))
1327 channel = (SilcChannelEntry)id_cache->context;
1329 /* Add client to channel */
1330 for (i = 0; i < channel->clients_count; i++) {
1331 if (channel->clients[i] == NULL) {
1332 channel->clients[channel->clients_count] = client_entry;
1333 channel->clients_count++;
1338 if (i == channel->clients_count) {
1339 channel->clients = silc_realloc(channel->clients,
1340 sizeof(*channel->clients) *
1341 (channel->clients_count + 1));
1342 channel->clients[channel->clients_count] = client_entry;
1343 channel->clients_count++;
1346 /* XXX add support for multiple same nicks on same channel. Check
1349 case SILC_NOTIFY_TYPE_LEAVE:
1351 * Someone has left a channel. We will remove it from the channel but
1352 * we'll keep it in the cache in case we'll need it later.
1356 /* XXX Protocol must be changed to send Client ID */
1357 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1359 /* Find channel entry */
1360 /* XXX this can return wrong entry */
1361 client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
1365 /* Get Channel ID (it's in ID payload) */
1366 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1367 idp = silc_id_payload_parse_data(tmp, tmp_len);
1368 channel_id = silc_id_payload_get_id(idp);
1369 silc_id_payload_free(idp);
1371 /* Find channel entry */
1372 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1373 SILC_ID_CHANNEL, &id_cache))
1376 channel = (SilcChannelEntry)id_cache->context;
1378 /* Remove client from channel */
1379 for (i = 0; i < channel->clients_count; i++) {
1380 if (channel->clients[i] == client_entry) {
1381 channel->clients[i] = NULL;
1382 channel->clients_count--;
1387 case SILC_NOTIFY_TYPE_SIGNOFF:
1389 * Someone left SILC. We'll remove it from the channel and from cache.
1393 /* XXX Protocol must be changed to send Client ID */
1394 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1396 /* Find channel entry */
1397 /* XXX this can return wrong entry */
1398 client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
1402 /* Get Channel ID (it's in ID payload) */
1403 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1404 idp = silc_id_payload_parse_data(tmp, tmp_len);
1405 channel_id = silc_id_payload_get_id(idp);
1406 silc_id_payload_free(idp);
1408 /* Find channel entry */
1409 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1410 SILC_ID_CHANNEL, &id_cache))
1413 channel = (SilcChannelEntry)id_cache->context;
1415 /* Remove client from channel */
1416 for (i = 0; i < channel->clients_count; i++) {
1417 if (channel->clients[i] == client_entry) {
1418 channel->clients[i] = NULL;
1419 channel->clients_count--;
1424 /* Remove from cache */
1425 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1428 case SILC_NOTIFY_TYPE_TOPIC_SET:
1430 * Someone set the topic on a channel. Nothing interesting to do here.
1433 case SILC_NOTIFY_TYPE_NICK_CHANGE:
1435 * Someone changed their nickname. Cache the new Client ID.
1438 /* XXX Protocol must be changed to send the old Client ID and the
1439 new Client ID. Now we get only nickname, thus, we'll make NAMES
1440 to receive the new ID. Other choice is to do IDENTIFY but I'm
1441 doing NAMES for now. */
1444 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1446 /* Find channel entry */
1447 /* XXX this can return wrong entry */
1448 client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
1452 /* Get Channel ID (it's in ID payload) */
1453 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1454 idp = silc_id_payload_parse_data(tmp, tmp_len);
1455 channel_id = silc_id_payload_get_id(idp);
1456 silc_id_payload_free(idp);
1458 /* Find channel entry */
1459 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1460 SILC_ID_CHANNEL, &id_cache))
1463 channel = (SilcChannelEntry)id_cache->context;
1466 SilcClientCommandContext ctx;
1469 ctx = silc_calloc(1, sizeof(*ctx));
1470 ctx->client = client;
1472 ctx->command = silc_client_command_find("NAMES");
1473 memset(names, 0, sizeof(names));
1474 snprintf(names, sizeof(names), "NAMES %s", channel->channel_name);
1475 silc_parse_command_line(names, &ctx->argv, &ctx->argv_lens,
1476 &ctx->argv_types, &ctx->argc, 2);
1477 ctx->command->cb(ctx);
1484 client->ops->notify(client, conn, payload);
1485 silc_notify_payload_free(payload);
1487 silc_free(client_id);
1489 silc_free(channel_id);
1492 /* Processes the received new Client ID from server. Old Client ID is
1493 deleted from cache and new one is added. */
1495 void silc_client_receive_new_id(SilcClient client,
1496 SilcSocketConnection sock,
1497 unsigned char *id_string)
1499 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1501 /* Delete old ID from ID cache */
1502 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1504 /* Save the new ID */
1506 silc_free(conn->local_id);
1507 conn->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
1508 if (conn->local_id_data)
1509 silc_free(conn->local_id_data);
1510 conn->local_id_data =
1511 silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1512 memcpy(conn->local_id_data, id_string, SILC_ID_CLIENT_LEN);
1513 conn->local_id_data_len = SILC_ID_CLIENT_LEN;
1514 if (!conn->local_entry)
1515 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1516 conn->local_entry->nickname = conn->nickname;
1517 conn->local_entry->id = conn->local_id;
1519 /* Put it to the ID cache */
1520 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1521 conn->local_id, (void *)conn->local_entry, TRUE);
1524 /* Processed received Channel ID for a channel. This is called when client
1525 joins to channel and server replies with channel ID. The ID is cached. */
1527 void silc_client_new_channel_id(SilcClient client,
1528 SilcSocketConnection sock,
1531 unsigned char *id_string)
1533 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1535 SilcChannelEntry channel;
1537 SILC_LOG_DEBUG(("New channel ID"));
1539 id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
1540 channel = silc_calloc(1, sizeof(*channel));
1541 channel->channel_name = channel_name;
1543 channel->mode = mode;
1544 conn->current_channel = channel;
1546 /* Put it to the ID cache */
1547 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1548 (void *)id, (void *)channel, TRUE);
1551 /* Processes received key for channel. The received key will be used
1552 to protect the traffic on the channel for now on. Client must receive
1553 the key to the channel before talking on the channel is possible.
1554 This is the key that server has generated, this is not the channel
1555 private key, it is entirely local setting. */
1557 void silc_client_receive_channel_key(SilcClient client,
1558 SilcSocketConnection sock,
1561 unsigned char *id_string, *key, *cipher;
1562 unsigned int key_len;
1563 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1565 SilcIDCacheEntry id_cache = NULL;
1566 SilcChannelEntry channel;
1567 SilcChannelKeyPayload payload;
1569 SILC_LOG_DEBUG(("Received key for channel"));
1571 payload = silc_channel_key_payload_parse(packet);
1575 id_string = silc_channel_key_get_id(payload, NULL);
1577 silc_channel_key_payload_free(payload);
1580 id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
1583 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1584 SILC_ID_CHANNEL, &id_cache))
1588 key = silc_channel_key_get_key(payload, &key_len);
1589 cipher = silc_channel_key_get_cipher(payload, NULL);
1591 channel = (SilcChannelEntry)id_cache->context;
1592 channel->key_len = key_len;
1593 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1594 memcpy(channel->key, key, key_len);
1596 silc_cipher_alloc(cipher, &channel->channel_key);
1597 if (!channel->channel_key) {
1598 client->ops->say(client, conn,
1599 "Cannot talk to channel: unsupported cipher %s", cipher);
1602 channel->channel_key->cipher->set_key(channel->channel_key->context,
1605 /* Client is now joined to the channel */
1606 channel->on_channel = TRUE;
1610 silc_channel_key_payload_free(payload);
1613 /* Process received message to a channel (or from a channel, really). This
1614 decrypts the channel message with channel specific key and parses the
1615 channel payload. Finally it displays the message on the screen. */
1617 void silc_client_channel_message(SilcClient client,
1618 SilcSocketConnection sock,
1619 SilcPacketContext *packet)
1621 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1622 SilcBuffer buffer = packet->buffer;
1623 SilcChannelPayload payload = NULL;
1624 SilcChannelID *id = NULL;
1625 SilcChannelEntry channel;
1626 SilcIDCacheEntry id_cache = NULL;
1627 SilcClientID *client_id = NULL;
1632 if (packet->dst_id_type != SILC_ID_CHANNEL)
1635 client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1636 id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1638 /* Find the channel entry from channels on this connection */
1639 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1640 SILC_ID_CHANNEL, &id_cache))
1643 channel = (SilcChannelEntry)id_cache->context;
1645 /* Decrypt the channel message payload. Push the IV out of the way,
1646 since it is not encrypted (after pushing buffer->tail has the IV). */
1647 silc_buffer_push_tail(buffer, 16);
1648 channel->channel_key->cipher->decrypt(channel->channel_key->context,
1649 buffer->data, buffer->data,
1650 buffer->len, buffer->tail);
1651 silc_buffer_pull_tail(buffer, 16);
1653 /* Parse the channel message payload */
1654 payload = silc_channel_payload_parse(buffer);
1659 nickname = "[unknown]";
1660 for (i = 0; i < channel->clients_count; i++) {
1661 if (channel->clients[i] &&
1662 !SILC_ID_CLIENT_COMPARE(channel->clients[i]->id, client_id))
1663 nickname = channel->clients[i]->nickname;
1666 /* Pass the message to application */
1667 client->ops->channel_message(client, conn, nickname,
1668 channel->channel_name,
1669 silc_channel_get_data(payload, NULL));
1675 silc_free(client_id);
1677 silc_channel_payload_free(payload);
1680 /* Private message received. This processes the private message and
1681 finally displays it on the screen. */
1683 void silc_client_private_message(SilcClient client,
1684 SilcSocketConnection sock,
1685 SilcPacketContext *packet)
1687 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1688 SilcBuffer buffer = packet->buffer;
1689 unsigned short nick_len;
1690 unsigned char *nickname, *message;
1693 silc_buffer_unformat(buffer,
1694 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
1696 silc_buffer_pull(buffer, 2 + nick_len);
1698 message = silc_calloc(buffer->len + 1, sizeof(char));
1699 memcpy(message, buffer->data, buffer->len);
1701 /* Pass the private message to application */
1702 client->ops->private_message(client, conn, nickname, message);
1704 /* See if we are away (gone). If we are away we will reply to the
1705 sender with the set away message. */
1706 if (conn->away && conn->away->away) {
1707 SilcClientID *remote_id;
1708 SilcClientEntry remote_client;
1709 SilcIDCacheEntry id_cache;
1711 if (packet->src_id_type != SILC_ID_CLIENT)
1714 remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1718 /* If it's me, ignore */
1719 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
1722 /* Check whether we know this client already */
1723 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
1724 SILC_ID_CLIENT, &id_cache))
1726 /* Allocate client entry */
1727 remote_client = silc_calloc(1, sizeof(*remote_client));
1728 remote_client->id = remote_id;
1729 remote_client->nickname = strdup(nickname);
1731 /* Save the client to cache */
1732 silc_idcache_add(conn->client_cache, remote_client->nickname,
1733 SILC_ID_CLIENT, remote_client->id, remote_client,
1736 silc_free(remote_id);
1737 remote_client = (SilcClientEntry)id_cache->context;
1740 /* Send the away message */
1741 silc_client_packet_send_private_message(client, sock, remote_client,
1743 strlen(conn->away->away), TRUE);
1747 memset(message, 0, buffer->len);
1749 silc_free(nickname);