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;
144 conn->pending_commands = silc_dlist_init();
146 /* Add the connection to connections table */
147 for (i = 0; i < client->conns_count; i++)
148 if (client->conns && !client->conns[i]) {
149 client->conns[i] = conn;
153 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
154 * (client->conns_count + 1));
155 client->conns[client->conns_count] = conn;
156 client->conns_count++;
161 /* Removes connection from client. */
163 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
167 for (i = 0; i < client->conns_count; i++)
168 if (client->conns[i] == conn) {
169 if (conn->pending_commands)
170 silc_dlist_uninit(conn->pending_commands);
172 client->conns[i] = NULL;
176 /* Internal context for connection process. This is needed as we
177 doing asynchronous connecting. */
180 SilcClientConnection conn;
186 } SilcClientInternalConnectContext;
189 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
193 /* XXX In the future we should give up this non-blocking connect all
194 together and use threads instead. */
195 /* Create connection to server asynchronously */
196 sock = silc_net_create_connection_async(ctx->port, ctx->host);
200 /* Register task that will receive the async connect and will
202 ctx->task = silc_task_register(ctx->client->io_queue, sock,
203 silc_client_connect_to_server_start,
206 SILC_TASK_PRI_NORMAL);
207 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
208 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
215 /* Connects to remote server. This is the main routine used to connect
216 to SILC server. Returns -1 on error and the created socket otherwise.
217 The `context' is user context that is saved into the SilcClientConnection
218 that is created after the connection is created. */
220 int silc_client_connect_to_server(SilcClient client, int port,
221 char *host, void *context)
223 SilcClientInternalConnectContext *ctx;
224 SilcClientConnection conn;
227 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
230 conn = silc_client_add_connection(client, host, port, context);
232 client->ops->say(client, conn,
233 "Connecting to port %d of server %s", port, host);
235 /* Allocate internal context for connection process. This is
236 needed as we are doing async connecting. */
237 ctx = silc_calloc(1, sizeof(*ctx));
238 ctx->client = client;
240 ctx->host = strdup(host);
244 /* Do the actual connecting process */
245 sock = silc_client_connect_to_server_internal(ctx);
247 silc_client_del_connection(client, conn);
251 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
252 key material between client and server. This function can be called
253 directly if application is performing its own connecting and does not
254 use the connecting provided by this library. */
256 int silc_client_start_key_exchange(SilcClient client,
257 SilcClientConnection conn,
260 SilcProtocol protocol;
261 SilcClientKEInternalContext *proto_ctx;
264 /* Allocate new socket connection object */
265 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
266 if (conn->sock == NULL) {
267 client->ops->say(client, conn,
268 "Error: Could not allocate connection socket");
272 conn->nickname = strdup(client->username);
273 conn->sock->hostname = conn->remote_host;
274 conn->sock->port = conn->remote_port;
276 /* Allocate internal Key Exchange context. This is sent to the
277 protocol as context. */
278 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
279 proto_ctx->client = (void *)client;
280 proto_ctx->sock = conn->sock;
281 proto_ctx->rng = client->rng;
282 proto_ctx->responder = FALSE;
284 /* Perform key exchange protocol. silc_client_connect_to_server_final
285 will be called after the protocol is finished. */
286 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
287 &protocol, (void *)proto_ctx,
288 silc_client_connect_to_server_second);
290 client->ops->say(client, conn,
291 "Error: Could not start authentication protocol");
294 conn->sock->protocol = protocol;
296 /* Register the connection for network input and output. This sets
297 that scheduler will listen for incoming packets for this connection
298 and sets that outgoing packets may be sent to this connection as well.
299 However, this doesn't set the scheduler for outgoing traffic, it will
300 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
301 later when outgoing data is available. */
302 context = (void *)client;
303 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
305 /* Execute the protocol */
306 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
310 /* Start of the connection to the remote server. This is called after
311 succesful TCP/IP connection has been established to the remote host. */
313 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
315 SilcClientInternalConnectContext *ctx =
316 (SilcClientInternalConnectContext *)context;
317 SilcClient client = ctx->client;
318 SilcClientConnection conn = ctx->conn;
319 int opt, opt_len = sizeof(opt);
321 SILC_LOG_DEBUG(("Start"));
323 /* Check the socket status as it might be in error */
324 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
326 if (ctx->tries < 2) {
327 /* Connection failed but lets try again */
328 client->ops->say(client, conn, "Could not connect to server %s: %s",
329 ctx->host, strerror(opt));
330 client->ops->say(client, conn,
331 "Connecting to port %d of server %s resumed",
332 ctx->port, ctx->host);
334 /* Unregister old connection try */
335 silc_schedule_unset_listen_fd(fd);
336 silc_net_close_connection(fd);
337 silc_task_unregister(client->io_queue, ctx->task);
340 silc_client_connect_to_server_internal(ctx);
343 /* Connection failed and we won't try anymore */
344 client->ops->say(client, conn, "Could not connect to server %s: %s",
345 ctx->host, strerror(opt));
346 silc_schedule_unset_listen_fd(fd);
347 silc_net_close_connection(fd);
348 silc_task_unregister(client->io_queue, ctx->task);
351 /* Notify application of failure */
352 client->ops->connect(client, conn, FALSE);
353 silc_client_del_connection(client, conn);
358 silc_schedule_unset_listen_fd(fd);
359 silc_task_unregister(client->io_queue, ctx->task);
362 if (!silc_client_start_key_exchange(client, conn, fd)) {
363 silc_net_close_connection(fd);
364 client->ops->connect(client, conn, FALSE);
368 /* Second part of the connecting to the server. This executed
369 authentication protocol. */
371 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
373 SilcProtocol protocol = (SilcProtocol)context;
374 SilcClientKEInternalContext *ctx =
375 (SilcClientKEInternalContext *)protocol->context;
376 SilcClient client = (SilcClient)ctx->client;
377 SilcSocketConnection sock = NULL;
378 SilcClientConnAuthInternalContext *proto_ctx;
380 SILC_LOG_DEBUG(("Start"));
382 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
383 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
384 /* Error occured during protocol */
385 SILC_LOG_DEBUG(("Error during KE protocol"));
386 silc_protocol_free(protocol);
388 silc_ske_free(ctx->ske);
390 silc_free(ctx->dest_id);
391 ctx->sock->protocol = NULL;
393 /* Notify application of failure */
394 client->ops->connect(client, ctx->sock->user_data, FALSE);
399 /* Allocate internal context for the authentication protocol. This
400 is sent as context for the protocol. */
401 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
402 proto_ctx->client = (void *)client;
403 proto_ctx->sock = sock = ctx->sock;
404 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
405 proto_ctx->dest_id_type = ctx->dest_id_type;
406 proto_ctx->dest_id = ctx->dest_id;
408 /* Resolve the authentication method to be used in this connection */
409 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
410 sock->port, &proto_ctx->auth_meth,
411 &proto_ctx->auth_data,
412 &proto_ctx->auth_data_len))
414 /* XXX do AUTH_REQUEST resolcing with server */
415 proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
418 /* Free old protocol as it is finished now */
419 silc_protocol_free(protocol);
421 silc_packet_context_free(ctx->packet);
423 /* silc_free(ctx->keymat....); */
424 sock->protocol = NULL;
426 /* Allocate the authentication protocol. This is allocated here
427 but we won't start it yet. We will be receiving party of this
428 protocol thus we will wait that connecting party will make
430 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
431 &sock->protocol, (void *)proto_ctx,
432 silc_client_connect_to_server_final);
434 /* Execute the protocol */
435 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
438 /* Finalizes the connection to the remote SILC server. This is called
439 after authentication protocol has been completed. This send our
440 user information to the server to receive our client ID from
443 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
445 SilcProtocol protocol = (SilcProtocol)context;
446 SilcClientConnAuthInternalContext *ctx =
447 (SilcClientConnAuthInternalContext *)protocol->context;
448 SilcClient client = (SilcClient)ctx->client;
449 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
452 SILC_LOG_DEBUG(("Start"));
454 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
455 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
456 /* Error occured during protocol */
457 SILC_LOG_DEBUG(("Error during authentication protocol"));
458 silc_protocol_free(protocol);
460 silc_free(ctx->auth_data);
462 silc_ske_free(ctx->ske);
464 silc_free(ctx->dest_id);
465 conn->sock->protocol = NULL;
467 /* Notify application of failure */
468 client->ops->connect(client, ctx->sock->user_data, FALSE);
473 /* Send NEW_CLIENT packet to the server. We will become registered
474 to the SILC network after sending this packet and we will receive
475 client ID from the server. */
476 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
477 strlen(client->realname));
478 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
479 silc_buffer_format(packet,
480 SILC_STR_UI_SHORT(strlen(client->username)),
481 SILC_STR_UI_XNSTRING(client->username,
482 strlen(client->username)),
483 SILC_STR_UI_SHORT(strlen(client->realname)),
484 SILC_STR_UI_XNSTRING(client->realname,
485 strlen(client->realname)),
488 /* Send the packet */
489 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
491 packet->data, packet->len, TRUE);
492 silc_buffer_free(packet);
494 /* Save remote ID. */
495 conn->remote_id = ctx->dest_id;
496 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
497 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
499 /* Notify application of successful connection */
500 client->ops->connect(client, conn, TRUE);
502 silc_protocol_free(protocol);
504 silc_free(ctx->auth_data);
506 silc_ske_free(ctx->ske);
508 conn->sock->protocol = NULL;
511 /* Internal routine that sends packet or marks packet to be sent. This
512 is used directly only in special cases. Normal cases should use
513 silc_server_packet_send. Returns < 0 on error. */
515 static int silc_client_packet_send_real(SilcClient client,
516 SilcSocketConnection sock,
521 /* Send the packet */
522 ret = silc_packet_send(sock, force_send);
526 /* Mark that there is some outgoing data available for this connection.
527 This call sets the connection both for input and output (the input
528 is set always and this call keeps the input setting, actually).
529 Actual data sending is performed by silc_client_packet_process. */
530 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
532 /* Mark to socket that data is pending in outgoing buffer. This flag
533 is needed if new data is added to the buffer before the earlier
534 put data is sent to the network. */
535 SILC_SET_OUTBUF_PENDING(sock);
540 /* Packet processing callback. This is used to send and receive packets
541 from network. This is generic task. */
543 SILC_TASK_CALLBACK(silc_client_packet_process)
545 SilcClient client = (SilcClient)context;
546 SilcSocketConnection sock = NULL;
547 SilcClientConnection conn;
550 SILC_LOG_DEBUG(("Processing packet"));
552 SILC_CLIENT_GET_SOCK(client, fd, sock);
556 conn = (SilcClientConnection)sock->user_data;
559 if (type == SILC_TASK_WRITE) {
560 SILC_LOG_DEBUG(("Writing data to connection"));
562 if (sock->outbuf->data - sock->outbuf->head)
563 silc_buffer_push(sock->outbuf,
564 sock->outbuf->data - sock->outbuf->head);
566 ret = silc_client_packet_send_real(client, sock, TRUE);
568 /* If returned -2 could not write to connection now, will do
573 /* The packet has been sent and now it is time to set the connection
574 back to only for input. When there is again some outgoing data
575 available for this connection it will be set for output as well.
576 This call clears the output setting and sets it only for input. */
577 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
578 SILC_UNSET_OUTBUF_PENDING(sock);
580 silc_buffer_clear(sock->outbuf);
584 /* Packet receiving */
585 if (type == SILC_TASK_READ) {
586 SILC_LOG_DEBUG(("Reading data from connection"));
588 /* Read data from network */
589 ret = silc_packet_receive(sock);
595 SILC_LOG_DEBUG(("Read EOF"));
597 /* If connection is disconnecting already we will finally
598 close the connection */
599 if (SILC_IS_DISCONNECTING(sock)) {
600 client->ops->disconnect(client, conn);
601 silc_client_close_connection(client, sock);
605 client->ops->say(client, conn, "Connection closed: premature EOF");
606 SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
607 client->ops->disconnect(client, conn);
608 silc_client_close_connection(client, sock);
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);
619 /* Parses whole packet, received earlier. */
621 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
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;
631 SILC_LOG_DEBUG(("Start"));
633 /* Decrypt the received packet */
634 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
639 /* Parse the packet. Packet type is returned. */
640 ret = silc_packet_parse(packet);
642 /* Parse the packet header in special way as this is "special"
644 ret = silc_packet_parse_special(packet);
647 if (ret == SILC_PACKET_NONE)
650 /* Parse the incoming packet type */
651 silc_client_packet_parse_type(client, sock, packet);
654 silc_buffer_clear(sock->inbuf);
655 silc_packet_context_free(packet);
656 silc_free(parse_ctx);
659 /* Parser callback called by silc_packet_receive_process. Thie merely
660 registers timeout that will handle the actual parsing when appropriate. */
662 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
664 SilcClient client = (SilcClient)parser_context->context;
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,
671 SILC_TASK_PRI_NORMAL);
674 /* Parses the packet type and calls what ever routines the packet type
675 requires. This is done for all incoming packets. */
677 void silc_client_packet_parse_type(SilcClient client,
678 SilcSocketConnection sock,
679 SilcPacketContext *packet)
681 SilcBuffer buffer = packet->buffer;
682 SilcPacketType type = packet->type;
684 SILC_LOG_DEBUG(("Parsing packet type %d", type));
686 /* Parse the packet type */
688 case SILC_PACKET_DISCONNECT:
689 silc_client_disconnected_by_server(client, sock, buffer);
691 case SILC_PACKET_SUCCESS:
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.
697 if (sock->protocol) {
698 sock->protocol->execute(client->timeout_queue, 0,
699 sock->protocol, sock->sock, 0, 0);
702 case SILC_PACKET_FAILURE:
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.
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);
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;
718 SILC_GET32_MSB(failure, buffer->data);
720 /* Notify application */
721 client->ops->failure(client, sock->user_data, sock->protocol,
726 case SILC_PACKET_REJECT:
729 case SILC_PACKET_NOTIFY:
731 * Received notify message
733 silc_client_notify_by_server(client, sock, packet);
736 case SILC_PACKET_ERROR:
738 * Received error message
740 silc_client_error_by_server(client, sock, buffer);
743 case SILC_PACKET_CHANNEL_MESSAGE:
745 * Received message to (from, actually) a channel
747 silc_client_channel_message(client, sock, packet);
749 case SILC_PACKET_CHANNEL_KEY:
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.
755 silc_client_receive_channel_key(client, sock, buffer);
758 case SILC_PACKET_PRIVATE_MESSAGE:
760 * Received private message
762 silc_client_private_message(client, sock, packet);
764 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
766 * Received private message key
770 case SILC_PACKET_COMMAND_REPLY:
772 * Recived reply for a command
774 silc_client_command_reply_process(client, sock, packet);
777 case SILC_PACKET_KEY_EXCHANGE:
778 if (sock->protocol) {
779 SilcClientKEInternalContext *proto_ctx =
780 (SilcClientKEInternalContext *)sock->protocol->context;
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_type);
786 /* Let the protocol handle the packet */
787 sock->protocol->execute(client->timeout_queue, 0,
788 sock->protocol, sock->sock, 0, 0);
790 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
791 "protocol active, packet dropped."));
793 /* XXX Trigger KE protocol?? Rekey actually! */
797 case SILC_PACKET_KEY_EXCHANGE_1:
798 if (sock->protocol) {
801 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
802 "protocol active, packet dropped."));
805 case SILC_PACKET_KEY_EXCHANGE_2:
806 if (sock->protocol) {
807 SilcClientKEInternalContext *proto_ctx =
808 (SilcClientKEInternalContext *)sock->protocol->context;
810 if (proto_ctx->packet)
811 silc_packet_context_free(proto_ctx->packet);
813 proto_ctx->packet = silc_packet_context_dup(packet);
814 proto_ctx->dest_id_type = packet->src_id_type;
815 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
817 /* Let the protocol handle the packet */
818 sock->protocol->execute(client->timeout_queue, 0,
819 sock->protocol, sock->sock, 0, 0);
821 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
822 "protocol active, packet dropped."));
826 case SILC_PACKET_NEW_ID:
829 * Received new ID from server. This packet is received at
830 * the connection to the server. New ID is also received when
831 * user changes nickname but in that case the new ID is received
832 * as command reply and not as this packet type.
836 idp = silc_id_payload_parse(buffer);
837 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
840 silc_client_receive_new_id(client, sock, idp);
841 silc_id_payload_free(idp);
846 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
851 /* Sends packet. This doesn't actually send the packet instead it assembles
852 it and marks it to be sent. However, if force_send is TRUE the packet
853 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
854 will be derived from sock argument. Otherwise the valid arguments sent
857 void silc_client_packet_send(SilcClient client,
858 SilcSocketConnection sock,
861 SilcIdType dst_id_type,
865 unsigned int data_len,
868 SilcPacketContext packetdata;
870 SILC_LOG_DEBUG(("Sending packet, type %d", type));
872 /* Get data used in the packet sending, keys and stuff */
873 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
874 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
875 cipher = ((SilcClientConnection)sock->user_data)->send_key;
877 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
878 hmac = ((SilcClientConnection)sock->user_data)->hmac;
880 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
881 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
882 dst_id_type = SILC_ID_SERVER;
886 /* Set the packet context pointers */
887 packetdata.flags = 0;
888 packetdata.type = type;
889 if (((SilcClientConnection)sock->user_data)->local_id_data)
890 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
892 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
893 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
894 packetdata.src_id_type = SILC_ID_CLIENT;
896 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
897 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
898 packetdata.dst_id_type = dst_id_type;
900 packetdata.dst_id = NULL;
901 packetdata.dst_id_len = 0;
902 packetdata.dst_id_type = SILC_ID_NONE;
904 packetdata.rng = client->rng;
905 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
906 packetdata.src_id_len + packetdata.dst_id_len;
907 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
909 /* Prepare outgoing data buffer for packet sending */
910 silc_packet_send_prepare(sock,
911 SILC_PACKET_HEADER_LEN +
912 packetdata.src_id_len +
913 packetdata.dst_id_len,
917 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
919 packetdata.buffer = sock->outbuf;
921 /* Put the data to the buffer */
922 if (data && data_len)
923 silc_buffer_put(sock->outbuf, data, data_len);
925 /* Create the outgoing packet */
926 silc_packet_assemble(&packetdata);
928 /* Encrypt the packet */
930 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
932 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
933 sock->outbuf->data, sock->outbuf->len);
935 /* Now actually send the packet */
936 silc_client_packet_send_real(client, sock, force_send);
939 /* Sends packet to a channel. Packet to channel is always encrypted
940 differently from "normal" packets. SILC header of the packet is
941 encrypted with the next receiver's key and the rest of the packet is
942 encrypted with the channel specific key. Padding and HMAC is computed
943 with the next receiver's key. */
945 void silc_client_packet_send_to_channel(SilcClient client,
946 SilcSocketConnection sock,
947 SilcChannelEntry channel,
949 unsigned int data_len,
953 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
955 SilcPacketContext packetdata;
958 unsigned char *id_string;
960 SILC_LOG_DEBUG(("Sending packet to channel"));
962 if (!channel || !channel->key) {
963 client->ops->say(client, conn,
964 "Cannot talk to channel: key does not exist");
970 for (i = 0; i < 16; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
972 silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
974 /* Encode the channel payload */
975 payload = silc_channel_payload_encode(data_len, data, 16, channel->iv,
978 client->ops->say(client, conn,
979 "Error: Could not create packet to be sent to channel");
983 /* Get data used in packet header encryption, keys and stuff. Rest
984 of the packet (the payload) is, however, encrypted with the
985 specified channel key. */
986 cipher = conn->send_key;
988 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
990 /* Set the packet context pointers. The destination ID is always
991 the Channel ID of the channel. Server and router will handle the
992 distribution of the packet. */
993 packetdata.flags = 0;
994 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
995 packetdata.src_id = conn->local_id_data;
996 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
997 packetdata.src_id_type = SILC_ID_CLIENT;
998 packetdata.dst_id = id_string;
999 packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
1000 packetdata.dst_id_type = SILC_ID_CHANNEL;
1001 packetdata.rng = client->rng;
1002 packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
1003 packetdata.src_id_len + packetdata.dst_id_len;
1004 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1005 packetdata.src_id_len +
1006 packetdata.dst_id_len));
1008 /* Prepare outgoing data buffer for packet sending */
1009 silc_packet_send_prepare(sock,
1010 SILC_PACKET_HEADER_LEN +
1011 packetdata.src_id_len +
1012 packetdata.dst_id_len,
1016 packetdata.buffer = sock->outbuf;
1018 /* Encrypt payload of the packet. This is encrypted with the channel key. */
1019 channel->channel_key->cipher->encrypt(channel->channel_key->context,
1020 payload->data, payload->data,
1021 payload->len - 16, /* -IV_LEN */
1024 /* Put the actual encrypted payload data into the buffer. */
1025 silc_buffer_put(sock->outbuf, payload->data, payload->len);
1027 /* Create the outgoing packet */
1028 silc_packet_assemble(&packetdata);
1030 /* Encrypt the header and padding of the packet. This is encrypted
1031 with normal session key shared with our server. */
1032 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1033 packetdata.src_id_len + packetdata.dst_id_len +
1036 SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1037 sock->outbuf->data, sock->outbuf->len);
1039 /* Now actually send the packet */
1040 silc_client_packet_send_real(client, sock, force_send);
1041 silc_buffer_free(payload);
1042 silc_free(id_string);
1045 /* Sends private message to remote client. If private message key has
1046 not been set with this client then the message will be encrypted using
1047 normal session keys. Private messages are special packets in SILC
1048 network hence we need this own function for them. This is similiar
1049 to silc_client_packet_send_to_channel except that we send private
1052 void silc_client_packet_send_private_message(SilcClient client,
1053 SilcSocketConnection sock,
1054 SilcClientEntry client_entry,
1055 unsigned char *data,
1056 unsigned int data_len,
1059 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1061 SilcPacketContext packetdata;
1062 unsigned int nick_len;
1066 SILC_LOG_DEBUG(("Sending private message"));
1068 /* Create private message payload */
1069 nick_len = strlen(conn->nickname);
1070 buffer = silc_buffer_alloc(2 + nick_len + data_len);
1071 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1072 silc_buffer_format(buffer,
1073 SILC_STR_UI_SHORT(nick_len),
1074 SILC_STR_UI_XNSTRING(conn->nickname,
1076 SILC_STR_UI_XNSTRING(data, data_len),
1079 /* If we don't have private message specific key then private messages
1080 are just as any normal packet thus call normal packet sending. If
1081 the key exist then the encryption process is a bit different and
1082 will be done in the rest of this function. */
1083 if (!client_entry->send_key) {
1084 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1085 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1086 buffer->data, buffer->len, force_send);
1090 /* We have private message specific key */
1092 /* Get data used in the encryption */
1093 cipher = client_entry->send_key;
1096 /* Set the packet context pointers. */
1097 packetdata.flags = 0;
1098 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1099 packetdata.src_id = conn->local_id_data;
1100 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1101 packetdata.src_id_type = SILC_ID_CLIENT;
1103 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1105 packetdata.dst_id = conn->local_id_data;
1106 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1107 packetdata.dst_id_type = SILC_ID_CLIENT;
1108 packetdata.rng = client->rng;
1109 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
1110 packetdata.src_id_len + packetdata.dst_id_len;
1111 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1112 packetdata.src_id_len +
1113 packetdata.dst_id_len));
1115 /* Prepare outgoing data buffer for packet sending */
1116 silc_packet_send_prepare(sock,
1117 SILC_PACKET_HEADER_LEN +
1118 packetdata.src_id_len +
1119 packetdata.dst_id_len,
1123 packetdata.buffer = sock->outbuf;
1125 /* Encrypt payload of the packet. Encrypt with private message specific
1126 key if it exist, otherwise with session key. */
1127 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1128 buffer->len, cipher->iv);
1130 /* Put the actual encrypted payload data into the buffer. */
1131 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1133 /* Create the outgoing packet */
1134 silc_packet_assemble(&packetdata);
1136 /* Encrypt the header and padding of the packet. */
1137 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1138 packetdata.src_id_len + packetdata.dst_id_len +
1141 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1142 sock->outbuf->data, sock->outbuf->len);
1144 /* Now actually send the packet */
1145 silc_client_packet_send_real(client, sock, force_send);
1146 silc_free(packetdata.dst_id);
1152 /* Closes connection to remote end. Free's all allocated data except
1153 for some information such as nickname etc. that are valid at all time. */
1155 void silc_client_close_connection(SilcClient client,
1156 SilcSocketConnection sock)
1158 SilcClientConnection conn;
1160 /* We won't listen for this connection anymore */
1161 silc_schedule_unset_listen_fd(sock->sock);
1163 /* Unregister all tasks */
1164 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1165 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1167 /* Close the actual connection */
1168 silc_net_close_connection(sock->sock);
1170 client->ops->say(client, sock->user_data,
1171 "Closed connection to host %s", sock->hostname ?
1172 sock->hostname : sock->ip);
1174 /* Free everything */
1175 if (sock->user_data) {
1176 conn = (SilcClientConnection)sock->user_data;
1178 /* XXX Free all client entries and channel entries. */
1180 /* Clear ID caches */
1181 silc_idcache_del_all(conn->client_cache);
1182 silc_idcache_del_all(conn->channel_cache);
1185 if (conn->remote_host)
1186 silc_free(conn->remote_host);
1188 silc_free(conn->local_id);
1189 if (conn->local_id_data)
1190 silc_free(conn->local_id_data);
1192 silc_cipher_free(conn->send_key);
1193 if (conn->receive_key)
1194 silc_cipher_free(conn->receive_key);
1196 silc_hmac_free(conn->hmac);
1197 if (conn->hmac_key) {
1198 memset(conn->hmac_key, 0, conn->hmac_key_len);
1199 silc_free(conn->hmac_key);
1201 if (conn->pending_commands)
1202 silc_dlist_uninit(conn->pending_commands);
1205 conn->remote_port = 0;
1206 conn->remote_type = 0;
1207 conn->send_key = NULL;
1208 conn->receive_key = NULL;
1210 conn->hmac_key = NULL;
1211 conn->hmac_key_len = 0;
1212 conn->local_id = NULL;
1213 conn->local_id_data = NULL;
1214 conn->remote_host = NULL;
1215 conn->current_channel = NULL;
1216 conn->pending_commands = NULL;
1218 silc_client_del_connection(client, conn);
1221 if (sock->protocol) {
1222 silc_protocol_free(sock->protocol);
1223 sock->protocol = NULL;
1225 silc_socket_free(sock);
1228 /* Called when we receive disconnection packet from server. This
1229 closes our end properly and displays the reason of the disconnection
1232 void silc_client_disconnected_by_server(SilcClient client,
1233 SilcSocketConnection sock,
1238 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1240 msg = silc_calloc(message->len + 1, sizeof(char));
1241 memcpy(msg, message->data, message->len);
1242 client->ops->say(client, sock->user_data, msg);
1245 SILC_SET_DISCONNECTED(sock);
1246 silc_client_close_connection(client, sock);
1249 /* Received error message from server. Display it on the screen.
1250 We don't take any action what so ever of the error message. */
1252 void silc_client_error_by_server(SilcClient client,
1253 SilcSocketConnection sock,
1258 msg = silc_calloc(message->len + 1, sizeof(char));
1259 memcpy(msg, message->data, message->len);
1260 client->ops->say(client, sock->user_data, msg);
1264 /* Called when notify is received and some async operation (such as command)
1265 is required before processing the notify message. This calls again the
1266 silc_client_notify_by_server and reprocesses the original notify packet. */
1268 static void silc_client_notify_by_server_pending(void *context)
1270 SilcPacketContext *p = (SilcPacketContext *)context;
1271 silc_client_notify_by_server(p->context, p->sock, p);
1272 silc_packet_context_free(p);
1275 /* Received notify message from server */
1277 void silc_client_notify_by_server(SilcClient client,
1278 SilcSocketConnection sock,
1279 SilcPacketContext *packet)
1281 SilcBuffer buffer = packet->buffer;
1282 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1283 SilcNotifyPayload payload;
1284 SilcNotifyType type;
1285 SilcArgumentPayload args;
1287 SilcClientID *client_id = NULL;
1288 SilcChannelID *channel_id = NULL;
1289 SilcClientEntry client_entry;
1290 SilcClientEntry client_entry2;
1291 SilcChannelEntry channel;
1292 SilcChannelUser chu;
1293 SilcIDCacheEntry id_cache = NULL;
1295 unsigned int tmp_len, mode;
1297 payload = silc_notify_payload_parse(buffer);
1298 type = silc_notify_get_type(payload);
1299 args = silc_notify_get_args(payload);
1304 case SILC_NOTIFY_TYPE_NONE:
1305 /* Notify application */
1306 client->ops->notify(client, conn, type,
1307 silc_argument_get_arg_type(args, 1, NULL));
1310 case SILC_NOTIFY_TYPE_INVITE:
1312 * Someone invited me to a channel. Find Client and Channel entries
1313 * for the application.
1317 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1321 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1323 /* Find Client entry and if not found query it */
1324 client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1325 if (!client_entry) {
1326 SilcPacketContext *p = silc_packet_context_dup(packet);
1327 p->context = (void *)client;
1329 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1330 silc_client_notify_by_server_pending, p);
1334 /* Get Channel ID */
1335 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1339 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1341 /* XXX Will ALWAYS fail because currently we don't have way to resolve
1342 channel information for channel that we're not joined to. */
1343 /* XXX ways to fix: use (extended) LIST command, or define the channel
1344 name to the notfy type when name resolving is not mandatory. */
1345 /* Find channel entry */
1346 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1347 SILC_ID_CHANNEL, &id_cache))
1350 channel = (SilcChannelEntry)id_cache->context;
1352 /* Notify application */
1353 client->ops->notify(client, conn, type, client_entry, channel);
1356 case SILC_NOTIFY_TYPE_JOIN:
1358 * Someone has joined to a channel. Get their ID and nickname and
1359 * cache them for later use.
1363 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1367 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1369 /* Find Client entry and if not found query it */
1370 client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1371 if (!client_entry) {
1372 SilcPacketContext *p = silc_packet_context_dup(packet);
1373 p->context = (void *)client;
1375 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1376 silc_client_notify_by_server_pending, p);
1380 /* Get channel entry */
1381 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1382 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1383 SILC_ID_CHANNEL, &id_cache))
1386 channel = (SilcChannelEntry)id_cache->context;
1388 /* Add client to channel */
1389 chu = silc_calloc(1, sizeof(*chu));
1390 chu->client = client_entry;
1391 silc_list_add(channel->clients, chu);
1393 /* XXX add support for multiple same nicks on same channel. Check
1396 /* Notify application. The channel entry is sent last as this notify
1397 is for channel but application don't know it from the arguments
1399 client->ops->notify(client, conn, type, client_entry, channel);
1402 case SILC_NOTIFY_TYPE_LEAVE:
1404 * Someone has left a channel. We will remove it from the channel but
1405 * we'll keep it in the cache in case we'll need it later.
1409 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1413 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1415 /* Find Client entry */
1417 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1421 /* Get channel entry */
1422 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1423 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1424 SILC_ID_CHANNEL, &id_cache))
1427 channel = (SilcChannelEntry)id_cache->context;
1429 /* Remove client from channel */
1430 silc_list_start(channel->clients);
1431 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1432 if (chu->client == client_entry) {
1433 silc_list_del(channel->clients, chu);
1439 /* Notify application. The channel entry is sent last as this notify
1440 is for channel but application don't know it from the arguments
1442 client->ops->notify(client, conn, type, client_entry, channel);
1445 case SILC_NOTIFY_TYPE_SIGNOFF:
1447 * Someone left SILC. We'll remove it from all channels and from cache.
1451 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1455 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1457 /* Find Client entry */
1459 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1463 /* Remove from all channels */
1464 silc_client_remove_from_channels(client, conn, client_entry);
1466 /* Remove from cache */
1467 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1470 /* Notify application */
1471 client->ops->notify(client, conn, type, client_entry);
1474 if (client_entry->nickname)
1475 silc_free(client_entry->nickname);
1476 if (client_entry->server)
1477 silc_free(client_entry->server);
1478 if (client_entry->id)
1479 silc_free(client_entry->id);
1480 if (client_entry->send_key)
1481 silc_cipher_free(client_entry->send_key);
1482 if (client_entry->receive_key)
1483 silc_cipher_free(client_entry->receive_key);
1486 case SILC_NOTIFY_TYPE_TOPIC_SET:
1488 * Someone set the topic on a channel.
1492 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1496 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1498 /* Find Client entry */
1500 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1505 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1509 /* Get channel entry */
1510 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1511 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1512 SILC_ID_CHANNEL, &id_cache))
1515 channel = (SilcChannelEntry)id_cache->context;
1517 /* Notify application. The channel entry is sent last as this notify
1518 is for channel but application don't know it from the arguments
1520 client->ops->notify(client, conn, type, client_entry, tmp, channel);
1523 case SILC_NOTIFY_TYPE_NICK_CHANGE:
1525 * Someone changed their nickname. If we don't have entry for the new
1526 * ID we will query it and return here after it's done. After we've
1527 * returned we fetch the old entry and free it and notify the
1531 /* Get new Client ID */
1532 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1536 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1539 if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
1542 /* Find Client entry and if not found query it */
1544 silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1545 if (!client_entry2) {
1546 SilcPacketContext *p = silc_packet_context_dup(packet);
1547 p->context = (void *)client;
1549 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1550 silc_client_notify_by_server_pending, p);
1554 /* Get old Client ID */
1555 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1559 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1561 /* Find old Client entry */
1563 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1567 /* Remove the old from cache */
1568 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1571 /* Replace old ID entry with new one on all channels. */
1572 silc_client_replace_from_channels(client, conn, client_entry,
1575 /* Notify application */
1576 client->ops->notify(client, conn, type, client_entry, client_entry2);
1579 if (client_entry->nickname)
1580 silc_free(client_entry->nickname);
1581 if (client_entry->server)
1582 silc_free(client_entry->server);
1583 if (client_entry->id)
1584 silc_free(client_entry->id);
1585 if (client_entry->send_key)
1586 silc_cipher_free(client_entry->send_key);
1587 if (client_entry->receive_key)
1588 silc_cipher_free(client_entry->receive_key);
1591 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1593 * Someone changed a channel mode
1597 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1601 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1603 /* Find Client entry */
1605 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1610 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1614 SILC_GET32_MSB(mode, tmp);
1616 /* Get channel entry */
1617 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1618 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1619 SILC_ID_CHANNEL, &id_cache))
1622 channel = (SilcChannelEntry)id_cache->context;
1624 /* Save the new mode */
1625 channel->mode = mode;
1627 /* Notify application. The channel entry is sent last as this notify
1628 is for channel but application don't know it from the arguments
1630 client->ops->notify(client, conn, type, client_entry, mode, channel);
1633 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1635 * Someone changed user's mode on a channel
1639 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1643 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1645 /* Find Client entry */
1647 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1652 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1656 SILC_GET32_MSB(mode, tmp);
1658 /* Get target Client ID */
1659 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1663 silc_free(client_id);
1664 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1666 /* Find target Client entry */
1668 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1672 /* Get channel entry */
1673 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1674 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1675 SILC_ID_CHANNEL, &id_cache))
1678 channel = (SilcChannelEntry)id_cache->context;
1681 silc_list_start(channel->clients);
1682 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1683 if (chu->client == client_entry) {
1689 /* Notify application. The channel entry is sent last as this notify
1690 is for channel but application don't know it from the arguments
1692 client->ops->notify(client, conn, type, client_entry, mode,
1693 client_entry2, channel);
1696 case SILC_NOTIFY_TYPE_MOTD:
1698 * Received Message of the day
1702 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1706 /* Notify application */
1707 client->ops->notify(client, conn, type, tmp);
1715 silc_notify_payload_free(payload);
1717 silc_free(client_id);
1719 silc_free(channel_id);
1722 /* Processes the received new Client ID from server. Old Client ID is
1723 deleted from cache and new one is added. */
1725 void silc_client_receive_new_id(SilcClient client,
1726 SilcSocketConnection sock,
1729 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1731 /* Delete old ID from ID cache */
1732 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1734 /* Save the new ID */
1736 silc_free(conn->local_id);
1737 if (conn->local_id_data)
1738 silc_free(conn->local_id_data);
1740 conn->local_id = silc_id_payload_get_id(idp);
1741 conn->local_id_data = silc_id_payload_get_data(idp);
1742 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1744 if (!conn->local_entry)
1745 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1747 conn->local_entry->nickname = conn->nickname;
1748 if (!conn->local_entry->username) {
1749 conn->local_entry->username =
1750 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1751 sizeof(conn->local_entry->username));
1752 sprintf(conn->local_entry->username, "%s@%s", client->username,
1755 conn->local_entry->server = strdup(conn->remote_host);
1756 conn->local_entry->id = conn->local_id;
1758 /* Put it to the ID cache */
1759 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1760 conn->local_id, (void *)conn->local_entry, TRUE);
1763 /* Processed received Channel ID for a channel. This is called when client
1764 joins to channel and server replies with channel ID. The ID is cached. */
1766 void silc_client_new_channel_id(SilcClient client,
1767 SilcSocketConnection sock,
1769 unsigned int mode, SilcIDPayload idp)
1771 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1772 SilcChannelEntry channel;
1774 SILC_LOG_DEBUG(("New channel ID"));
1776 channel = silc_calloc(1, sizeof(*channel));
1777 channel->channel_name = channel_name;
1778 channel->id = silc_id_payload_get_id(idp);
1779 channel->mode = mode;
1780 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1782 conn->current_channel = channel;
1784 /* Put it to the ID cache */
1785 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1786 (void *)channel->id, (void *)channel, TRUE);
1789 /* Saves channel key from encoded `key_payload'. This is used when we
1790 receive Channel Key Payload and when we are processing JOIN command
1793 void silc_client_save_channel_key(SilcClientConnection conn,
1794 SilcBuffer key_payload,
1795 SilcChannelEntry channel)
1797 unsigned char *id_string, *key, *cipher;
1798 unsigned int tmp_len;
1800 SilcIDCacheEntry id_cache = NULL;
1801 SilcChannelKeyPayload payload;
1803 payload = silc_channel_key_payload_parse(key_payload);
1807 id_string = silc_channel_key_get_id(payload, &tmp_len);
1809 silc_channel_key_payload_free(payload);
1813 id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
1817 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1818 SILC_ID_CHANNEL, &id_cache))
1821 /* Get channel entry */
1822 channel = (SilcChannelEntry)id_cache->context;
1826 key = silc_channel_key_get_key(payload, &tmp_len);
1827 cipher = silc_channel_key_get_cipher(payload, NULL);
1828 channel->key_len = tmp_len;
1829 channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
1830 memcpy(channel->key, key, tmp_len);
1832 if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
1833 conn->client->ops->say(conn->client, conn,
1834 "Cannot talk to channel: unsupported cipher %s", cipher);
1837 channel->channel_key->cipher->set_key(channel->channel_key->context,
1840 /* Client is now joined to the channel */
1841 channel->on_channel = TRUE;
1845 silc_channel_key_payload_free(payload);
1848 /* Processes received key for channel. The received key will be used
1849 to protect the traffic on the channel for now on. Client must receive
1850 the key to the channel before talking on the channel is possible.
1851 This is the key that server has generated, this is not the channel
1852 private key, it is entirely local setting. */
1854 void silc_client_receive_channel_key(SilcClient client,
1855 SilcSocketConnection sock,
1858 SILC_LOG_DEBUG(("Received key for channel"));
1861 silc_client_save_channel_key(sock->user_data, packet, NULL);
1864 /* Process received message to a channel (or from a channel, really). This
1865 decrypts the channel message with channel specific key and parses the
1866 channel payload. Finally it displays the message on the screen. */
1868 void silc_client_channel_message(SilcClient client,
1869 SilcSocketConnection sock,
1870 SilcPacketContext *packet)
1872 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1873 SilcBuffer buffer = packet->buffer;
1874 SilcChannelPayload payload = NULL;
1875 SilcChannelID *id = NULL;
1876 SilcChannelEntry channel;
1877 SilcChannelUser chu;
1878 SilcIDCacheEntry id_cache = NULL;
1879 SilcClientID *client_id = NULL;
1883 if (packet->dst_id_type != SILC_ID_CHANNEL)
1886 client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1887 id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1889 /* Find the channel entry from channels on this connection */
1890 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1891 SILC_ID_CHANNEL, &id_cache))
1894 channel = (SilcChannelEntry)id_cache->context;
1896 /* Decrypt the channel message payload. Push the IV out of the way,
1897 since it is not encrypted (after pushing buffer->tail has the IV). */
1898 silc_buffer_push_tail(buffer, 16);
1899 channel->channel_key->cipher->decrypt(channel->channel_key->context,
1900 buffer->data, buffer->data,
1901 buffer->len, buffer->tail);
1902 silc_buffer_pull_tail(buffer, 16);
1904 /* Parse the channel message payload */
1905 payload = silc_channel_payload_parse(buffer);
1910 nickname = "[unknown]";
1911 silc_list_start(channel->clients);
1912 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1913 if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
1914 nickname = chu->client->nickname;
1919 /* Pass the message to application */
1920 client->ops->channel_message(client, conn, nickname,
1921 channel->channel_name,
1922 silc_channel_get_data(payload, NULL));
1928 silc_free(client_id);
1930 silc_channel_payload_free(payload);
1933 /* Private message received. This processes the private message and
1934 finally displays it on the screen. */
1936 void silc_client_private_message(SilcClient client,
1937 SilcSocketConnection sock,
1938 SilcPacketContext *packet)
1940 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1941 SilcBuffer buffer = packet->buffer;
1942 unsigned short nick_len;
1943 unsigned char *nickname, *message;
1946 silc_buffer_unformat(buffer,
1947 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
1949 silc_buffer_pull(buffer, 2 + nick_len);
1951 message = silc_calloc(buffer->len + 1, sizeof(char));
1952 memcpy(message, buffer->data, buffer->len);
1954 /* Pass the private message to application */
1955 client->ops->private_message(client, conn, nickname, message);
1957 /* See if we are away (gone). If we are away we will reply to the
1958 sender with the set away message. */
1959 if (conn->away && conn->away->away) {
1960 SilcClientID *remote_id;
1961 SilcClientEntry remote_client;
1962 SilcIDCacheEntry id_cache;
1964 if (packet->src_id_type != SILC_ID_CLIENT)
1967 remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1971 /* If it's me, ignore */
1972 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
1975 /* Check whether we know this client already */
1976 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
1977 SILC_ID_CLIENT, &id_cache))
1979 /* Allocate client entry */
1980 remote_client = silc_calloc(1, sizeof(*remote_client));
1981 remote_client->id = remote_id;
1982 silc_parse_nickname(nickname, &remote_client->nickname,
1983 &remote_client->server, &remote_client->num);
1985 /* Save the client to cache */
1986 silc_idcache_add(conn->client_cache, remote_client->nickname,
1987 SILC_ID_CLIENT, remote_client->id, remote_client,
1990 silc_free(remote_id);
1991 remote_client = (SilcClientEntry)id_cache->context;
1994 /* Send the away message */
1995 silc_client_packet_send_private_message(client, sock, remote_client,
1997 strlen(conn->away->away), TRUE);
2001 memset(message, 0, buffer->len);
2003 silc_free(nickname);
2006 /* Removes a client entry from all channel it has joined. This really is
2007 a performance killer (client_entry should have pointers to channel
2010 void silc_client_remove_from_channels(SilcClient client,
2011 SilcClientConnection conn,
2012 SilcClientEntry client_entry)
2014 SilcIDCacheEntry id_cache;
2015 SilcIDCacheList list;
2016 SilcChannelEntry channel;
2017 SilcChannelUser chu;
2019 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2020 SILC_ID_CHANNEL, &list))
2023 silc_idcache_list_first(list, &id_cache);
2024 channel = (SilcChannelEntry)id_cache->context;
2028 /* Remove client from channel */
2029 silc_list_start(channel->clients);
2030 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2031 if (chu->client == client_entry) {
2032 silc_list_del(channel->clients, chu);
2038 if (!silc_idcache_list_next(list, &id_cache))
2041 channel = (SilcChannelEntry)id_cache->context;
2044 silc_idcache_list_free(list);
2047 /* Replaces `old' client entries from all channels to `new' client entry.
2048 This can be called for example when nickname changes and old ID entry
2049 is replaced from ID cache with the new one. If the old ID entry is only
2050 updated, then this fucntion needs not to be called. */
2052 void silc_client_replace_from_channels(SilcClient client,
2053 SilcClientConnection conn,
2054 SilcClientEntry old,
2055 SilcClientEntry new)
2057 SilcIDCacheEntry id_cache;
2058 SilcIDCacheList list;
2059 SilcChannelEntry channel;
2060 SilcChannelUser chu;
2062 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2063 SILC_ID_CHANNEL, &list))
2066 silc_idcache_list_first(list, &id_cache);
2067 channel = (SilcChannelEntry)id_cache->context;
2071 /* Replace client entry */
2072 silc_list_start(channel->clients);
2073 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2074 if (chu->client == old) {
2080 if (!silc_idcache_list_next(list, &id_cache))
2083 channel = (SilcChannelEntry)id_cache->context;
2086 silc_idcache_list_free(list);
2089 /* Parses mode mask and returns the mode as string. */
2091 char *silc_client_chmode(unsigned int mode)
2098 memset(string, 0, sizeof(string));
2100 if (mode & SILC_CHANNEL_MODE_PRIVATE)
2101 strncat(string, "p", 1);
2103 if (mode & SILC_CHANNEL_MODE_SECRET)
2104 strncat(string, "s", 1);
2106 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
2107 strncat(string, "k", 1);
2109 if (mode & SILC_CHANNEL_MODE_INVITE)
2110 strncat(string, "i", 1);
2112 if (mode & SILC_CHANNEL_MODE_TOPIC)
2113 strncat(string, "t", 1);
2115 if (mode & SILC_CHANNEL_MODE_ULIMIT)
2116 strncat(string, "l", 1);
2118 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
2119 strncat(string, "a", 1);
2121 /* Rest of mode is ignored */
2123 return strdup(string);
2126 /* Parses channel user mode mask and returns te mode as string */
2128 char *silc_client_chumode(unsigned int mode)
2135 memset(string, 0, sizeof(string));
2137 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2138 strncat(string, "f", 1);
2140 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2141 strncat(string, "o", 1);
2143 return strdup(string);
2146 /* Parses channel user mode and returns it as special mode character. */
2148 char *silc_client_chumode_char(unsigned int mode)
2155 memset(string, 0, sizeof(string));
2157 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2158 strncat(string, "*", 1);
2160 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2161 strncat(string, "@", 1);
2163 return strdup(string);