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_len,
785 packet->src_id_type);
786 if (!proto_ctx->dest_id)
789 /* Let the protocol handle the packet */
790 sock->protocol->execute(client->timeout_queue, 0,
791 sock->protocol, sock->sock, 0, 0);
793 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
794 "protocol active, packet dropped."));
796 /* XXX Trigger KE protocol?? Rekey actually! */
800 case SILC_PACKET_KEY_EXCHANGE_1:
801 if (sock->protocol) {
804 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
805 "protocol active, packet dropped."));
808 case SILC_PACKET_KEY_EXCHANGE_2:
809 if (sock->protocol) {
810 SilcClientKEInternalContext *proto_ctx =
811 (SilcClientKEInternalContext *)sock->protocol->context;
813 if (proto_ctx->packet)
814 silc_packet_context_free(proto_ctx->packet);
816 proto_ctx->packet = silc_packet_context_dup(packet);
817 proto_ctx->dest_id_type = packet->src_id_type;
818 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
819 packet->src_id_type);
820 if (!proto_ctx->dest_id)
823 /* Let the protocol handle the packet */
824 sock->protocol->execute(client->timeout_queue, 0,
825 sock->protocol, sock->sock, 0, 0);
827 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
828 "protocol active, packet dropped."));
832 case SILC_PACKET_NEW_ID:
835 * Received new ID from server. This packet is received at
836 * the connection to the server. New ID is also received when
837 * user changes nickname but in that case the new ID is received
838 * as command reply and not as this packet type.
842 idp = silc_id_payload_parse(buffer);
845 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
848 silc_client_receive_new_id(client, sock, idp);
849 silc_id_payload_free(idp);
854 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
859 /* Sends packet. This doesn't actually send the packet instead it assembles
860 it and marks it to be sent. However, if force_send is TRUE the packet
861 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
862 will be derived from sock argument. Otherwise the valid arguments sent
865 void silc_client_packet_send(SilcClient client,
866 SilcSocketConnection sock,
869 SilcIdType dst_id_type,
873 unsigned int data_len,
876 SilcPacketContext packetdata;
878 SILC_LOG_DEBUG(("Sending packet, type %d", type));
880 /* Get data used in the packet sending, keys and stuff */
881 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
882 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
883 cipher = ((SilcClientConnection)sock->user_data)->send_key;
885 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
886 hmac = ((SilcClientConnection)sock->user_data)->hmac;
888 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
889 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
890 dst_id_type = SILC_ID_SERVER;
894 /* Set the packet context pointers */
895 packetdata.flags = 0;
896 packetdata.type = type;
897 if (((SilcClientConnection)sock->user_data)->local_id_data)
898 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
900 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
901 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
902 packetdata.src_id_type = SILC_ID_CLIENT;
904 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
905 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
906 packetdata.dst_id_type = dst_id_type;
908 packetdata.dst_id = NULL;
909 packetdata.dst_id_len = 0;
910 packetdata.dst_id_type = SILC_ID_NONE;
912 packetdata.rng = client->rng;
913 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
914 packetdata.src_id_len + packetdata.dst_id_len;
915 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
917 /* Prepare outgoing data buffer for packet sending */
918 silc_packet_send_prepare(sock,
919 SILC_PACKET_HEADER_LEN +
920 packetdata.src_id_len +
921 packetdata.dst_id_len,
925 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
927 packetdata.buffer = sock->outbuf;
929 /* Put the data to the buffer */
930 if (data && data_len)
931 silc_buffer_put(sock->outbuf, data, data_len);
933 /* Create the outgoing packet */
934 silc_packet_assemble(&packetdata);
936 /* Encrypt the packet */
938 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
940 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
941 sock->outbuf->data, sock->outbuf->len);
943 /* Now actually send the packet */
944 silc_client_packet_send_real(client, sock, force_send);
947 /* Sends packet to a channel. Packet to channel is always encrypted
948 differently from "normal" packets. SILC header of the packet is
949 encrypted with the next receiver's key and the rest of the packet is
950 encrypted with the channel specific key. Padding and HMAC is computed
951 with the next receiver's key. */
953 void silc_client_packet_send_to_channel(SilcClient client,
954 SilcSocketConnection sock,
955 SilcChannelEntry channel,
957 unsigned int data_len,
961 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
963 SilcPacketContext packetdata;
966 unsigned char *id_string;
968 SILC_LOG_DEBUG(("Sending packet to channel"));
970 if (!channel || !channel->key) {
971 client->ops->say(client, conn,
972 "Cannot talk to channel: key does not exist");
978 for (i = 0; i < 16; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
980 silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
982 /* Encode the channel payload */
983 payload = silc_channel_payload_encode(data_len, data, 16, channel->iv,
986 client->ops->say(client, conn,
987 "Error: Could not create packet to be sent to channel");
991 /* Get data used in packet header encryption, keys and stuff. Rest
992 of the packet (the payload) is, however, encrypted with the
993 specified channel key. */
994 cipher = conn->send_key;
996 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
998 /* Set the packet context pointers. The destination ID is always
999 the Channel ID of the channel. Server and router will handle the
1000 distribution of the packet. */
1001 packetdata.flags = 0;
1002 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
1003 packetdata.src_id = conn->local_id_data;
1004 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1005 packetdata.src_id_type = SILC_ID_CLIENT;
1006 packetdata.dst_id = id_string;
1007 packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
1008 packetdata.dst_id_type = SILC_ID_CHANNEL;
1009 packetdata.rng = client->rng;
1010 packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
1011 packetdata.src_id_len + packetdata.dst_id_len;
1012 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1013 packetdata.src_id_len +
1014 packetdata.dst_id_len));
1016 /* Prepare outgoing data buffer for packet sending */
1017 silc_packet_send_prepare(sock,
1018 SILC_PACKET_HEADER_LEN +
1019 packetdata.src_id_len +
1020 packetdata.dst_id_len,
1024 packetdata.buffer = sock->outbuf;
1026 /* Encrypt payload of the packet. This is encrypted with the channel key. */
1027 channel->channel_key->cipher->encrypt(channel->channel_key->context,
1028 payload->data, payload->data,
1029 payload->len - 16, /* -IV_LEN */
1032 /* Put the actual encrypted payload data into the buffer. */
1033 silc_buffer_put(sock->outbuf, payload->data, payload->len);
1035 /* Create the outgoing packet */
1036 silc_packet_assemble(&packetdata);
1038 /* Encrypt the header and padding of the packet. This is encrypted
1039 with normal session key shared with our server. */
1040 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1041 packetdata.src_id_len + packetdata.dst_id_len +
1044 SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1045 sock->outbuf->data, sock->outbuf->len);
1047 /* Now actually send the packet */
1048 silc_client_packet_send_real(client, sock, force_send);
1049 silc_buffer_free(payload);
1050 silc_free(id_string);
1053 /* Sends private message to remote client. If private message key has
1054 not been set with this client then the message will be encrypted using
1055 normal session keys. Private messages are special packets in SILC
1056 network hence we need this own function for them. This is similiar
1057 to silc_client_packet_send_to_channel except that we send private
1060 void silc_client_packet_send_private_message(SilcClient client,
1061 SilcSocketConnection sock,
1062 SilcClientEntry client_entry,
1063 unsigned char *data,
1064 unsigned int data_len,
1067 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1069 SilcPacketContext packetdata;
1070 unsigned int nick_len;
1074 SILC_LOG_DEBUG(("Sending private message"));
1076 /* Create private message payload */
1077 nick_len = strlen(conn->nickname);
1078 buffer = silc_buffer_alloc(2 + nick_len + data_len);
1079 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1080 silc_buffer_format(buffer,
1081 SILC_STR_UI_SHORT(nick_len),
1082 SILC_STR_UI_XNSTRING(conn->nickname,
1084 SILC_STR_UI_XNSTRING(data, data_len),
1087 /* If we don't have private message specific key then private messages
1088 are just as any normal packet thus call normal packet sending. If
1089 the key exist then the encryption process is a bit different and
1090 will be done in the rest of this function. */
1091 if (!client_entry->send_key) {
1092 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1093 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1094 buffer->data, buffer->len, force_send);
1098 /* We have private message specific key */
1100 /* Get data used in the encryption */
1101 cipher = client_entry->send_key;
1104 /* Set the packet context pointers. */
1105 packetdata.flags = 0;
1106 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1107 packetdata.src_id = conn->local_id_data;
1108 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1109 packetdata.src_id_type = SILC_ID_CLIENT;
1111 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1113 packetdata.dst_id = conn->local_id_data;
1114 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1115 packetdata.dst_id_type = SILC_ID_CLIENT;
1116 packetdata.rng = client->rng;
1117 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
1118 packetdata.src_id_len + packetdata.dst_id_len;
1119 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1120 packetdata.src_id_len +
1121 packetdata.dst_id_len));
1123 /* Prepare outgoing data buffer for packet sending */
1124 silc_packet_send_prepare(sock,
1125 SILC_PACKET_HEADER_LEN +
1126 packetdata.src_id_len +
1127 packetdata.dst_id_len,
1131 packetdata.buffer = sock->outbuf;
1133 /* Encrypt payload of the packet. Encrypt with private message specific
1134 key if it exist, otherwise with session key. */
1135 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1136 buffer->len, cipher->iv);
1138 /* Put the actual encrypted payload data into the buffer. */
1139 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1141 /* Create the outgoing packet */
1142 silc_packet_assemble(&packetdata);
1144 /* Encrypt the header and padding of the packet. */
1145 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1146 packetdata.src_id_len + packetdata.dst_id_len +
1149 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1150 sock->outbuf->data, sock->outbuf->len);
1152 /* Now actually send the packet */
1153 silc_client_packet_send_real(client, sock, force_send);
1154 silc_free(packetdata.dst_id);
1160 /* Closes connection to remote end. Free's all allocated data except
1161 for some information such as nickname etc. that are valid at all time. */
1163 void silc_client_close_connection(SilcClient client,
1164 SilcSocketConnection sock)
1166 SilcClientConnection conn;
1168 /* We won't listen for this connection anymore */
1169 silc_schedule_unset_listen_fd(sock->sock);
1171 /* Unregister all tasks */
1172 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1173 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1175 /* Close the actual connection */
1176 silc_net_close_connection(sock->sock);
1178 client->ops->say(client, sock->user_data,
1179 "Closed connection to host %s", sock->hostname ?
1180 sock->hostname : sock->ip);
1182 /* Free everything */
1183 if (sock->user_data) {
1184 conn = (SilcClientConnection)sock->user_data;
1186 /* XXX Free all client entries and channel entries. */
1188 /* Clear ID caches */
1189 silc_idcache_del_all(conn->client_cache);
1190 silc_idcache_del_all(conn->channel_cache);
1193 if (conn->remote_host)
1194 silc_free(conn->remote_host);
1196 silc_free(conn->local_id);
1197 if (conn->local_id_data)
1198 silc_free(conn->local_id_data);
1200 silc_cipher_free(conn->send_key);
1201 if (conn->receive_key)
1202 silc_cipher_free(conn->receive_key);
1204 silc_hmac_free(conn->hmac);
1205 if (conn->hmac_key) {
1206 memset(conn->hmac_key, 0, conn->hmac_key_len);
1207 silc_free(conn->hmac_key);
1209 if (conn->pending_commands)
1210 silc_dlist_uninit(conn->pending_commands);
1213 conn->remote_port = 0;
1214 conn->remote_type = 0;
1215 conn->send_key = NULL;
1216 conn->receive_key = NULL;
1218 conn->hmac_key = NULL;
1219 conn->hmac_key_len = 0;
1220 conn->local_id = NULL;
1221 conn->local_id_data = NULL;
1222 conn->remote_host = NULL;
1223 conn->current_channel = NULL;
1224 conn->pending_commands = NULL;
1226 silc_client_del_connection(client, conn);
1229 if (sock->protocol) {
1230 silc_protocol_free(sock->protocol);
1231 sock->protocol = NULL;
1233 silc_socket_free(sock);
1236 /* Called when we receive disconnection packet from server. This
1237 closes our end properly and displays the reason of the disconnection
1240 void silc_client_disconnected_by_server(SilcClient client,
1241 SilcSocketConnection sock,
1246 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1248 msg = silc_calloc(message->len + 1, sizeof(char));
1249 memcpy(msg, message->data, message->len);
1250 client->ops->say(client, sock->user_data, msg);
1253 SILC_SET_DISCONNECTED(sock);
1254 silc_client_close_connection(client, sock);
1257 /* Received error message from server. Display it on the screen.
1258 We don't take any action what so ever of the error message. */
1260 void silc_client_error_by_server(SilcClient client,
1261 SilcSocketConnection sock,
1266 msg = silc_calloc(message->len + 1, sizeof(char));
1267 memcpy(msg, message->data, message->len);
1268 client->ops->say(client, sock->user_data, msg);
1272 /* Called when notify is received and some async operation (such as command)
1273 is required before processing the notify message. This calls again the
1274 silc_client_notify_by_server and reprocesses the original notify packet. */
1276 static void silc_client_notify_by_server_pending(void *context)
1278 SilcPacketContext *p = (SilcPacketContext *)context;
1279 silc_client_notify_by_server(p->context, p->sock, p);
1280 silc_packet_context_free(p);
1283 /* Received notify message from server */
1285 void silc_client_notify_by_server(SilcClient client,
1286 SilcSocketConnection sock,
1287 SilcPacketContext *packet)
1289 SilcBuffer buffer = packet->buffer;
1290 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1291 SilcNotifyPayload payload;
1292 SilcNotifyType type;
1293 SilcArgumentPayload args;
1295 SilcClientID *client_id = NULL;
1296 SilcChannelID *channel_id = NULL;
1297 SilcClientEntry client_entry;
1298 SilcClientEntry client_entry2;
1299 SilcChannelEntry channel;
1300 SilcChannelUser chu;
1301 SilcIDCacheEntry id_cache = NULL;
1303 unsigned int tmp_len, mode;
1305 payload = silc_notify_payload_parse(buffer);
1309 type = silc_notify_get_type(payload);
1310 args = silc_notify_get_args(payload);
1315 case SILC_NOTIFY_TYPE_NONE:
1316 /* Notify application */
1317 client->ops->notify(client, conn, type,
1318 silc_argument_get_arg_type(args, 1, NULL));
1321 case SILC_NOTIFY_TYPE_INVITE:
1323 * Someone invited me to a channel. Find Client and Channel entries
1324 * for the application.
1328 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1332 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1336 /* Find Client entry and if not found query it */
1337 client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1338 if (!client_entry) {
1339 SilcPacketContext *p = silc_packet_context_dup(packet);
1340 p->context = (void *)client;
1342 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1343 silc_client_notify_by_server_pending, p);
1347 /* Get Channel ID */
1348 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1352 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1356 /* XXX Will ALWAYS fail because currently we don't have way to resolve
1357 channel information for channel that we're not joined to. */
1358 /* XXX ways to fix: use (extended) LIST command, or define the channel
1359 name to the notfy type when name resolving is not mandatory. */
1360 /* Find channel entry */
1361 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1362 SILC_ID_CHANNEL, &id_cache))
1365 channel = (SilcChannelEntry)id_cache->context;
1367 /* Notify application */
1368 client->ops->notify(client, conn, type, client_entry, channel);
1371 case SILC_NOTIFY_TYPE_JOIN:
1373 * Someone has joined to a channel. Get their ID and nickname and
1374 * cache them for later use.
1378 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1382 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1386 /* Find Client entry and if not found query it */
1387 client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1388 if (!client_entry) {
1389 SilcPacketContext *p = silc_packet_context_dup(packet);
1390 p->context = (void *)client;
1392 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1393 silc_client_notify_by_server_pending, p);
1397 /* Get channel entry */
1398 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1402 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1403 SILC_ID_CHANNEL, &id_cache))
1406 channel = (SilcChannelEntry)id_cache->context;
1408 /* Add client to channel */
1409 chu = silc_calloc(1, sizeof(*chu));
1410 chu->client = client_entry;
1411 silc_list_add(channel->clients, chu);
1413 /* XXX add support for multiple same nicks on same channel. Check
1416 /* Notify application. The channel entry is sent last as this notify
1417 is for channel but application don't know it from the arguments
1419 client->ops->notify(client, conn, type, client_entry, channel);
1422 case SILC_NOTIFY_TYPE_LEAVE:
1424 * Someone has left a channel. We will remove it from the channel but
1425 * we'll keep it in the cache in case we'll need it later.
1429 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1433 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1437 /* Find Client entry */
1439 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1443 /* Get channel entry */
1444 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1448 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1449 SILC_ID_CHANNEL, &id_cache))
1452 channel = (SilcChannelEntry)id_cache->context;
1454 /* Remove client from channel */
1455 silc_list_start(channel->clients);
1456 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1457 if (chu->client == client_entry) {
1458 silc_list_del(channel->clients, chu);
1464 /* Notify application. The channel entry is sent last as this notify
1465 is for channel but application don't know it from the arguments
1467 client->ops->notify(client, conn, type, client_entry, channel);
1470 case SILC_NOTIFY_TYPE_SIGNOFF:
1472 * Someone left SILC. We'll remove it from all channels and from cache.
1476 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1480 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1484 /* Find Client entry */
1486 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1490 /* Remove from all channels */
1491 silc_client_remove_from_channels(client, conn, client_entry);
1493 /* Remove from cache */
1494 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1497 /* Notify application */
1498 client->ops->notify(client, conn, type, client_entry);
1501 if (client_entry->nickname)
1502 silc_free(client_entry->nickname);
1503 if (client_entry->server)
1504 silc_free(client_entry->server);
1505 if (client_entry->id)
1506 silc_free(client_entry->id);
1507 if (client_entry->send_key)
1508 silc_cipher_free(client_entry->send_key);
1509 if (client_entry->receive_key)
1510 silc_cipher_free(client_entry->receive_key);
1513 case SILC_NOTIFY_TYPE_TOPIC_SET:
1515 * Someone set the topic on a channel.
1519 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1523 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1527 /* Find Client entry */
1529 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1534 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1538 /* Get channel entry */
1539 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1543 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1544 SILC_ID_CHANNEL, &id_cache))
1547 channel = (SilcChannelEntry)id_cache->context;
1549 /* Notify application. The channel entry is sent last as this notify
1550 is for channel but application don't know it from the arguments
1552 client->ops->notify(client, conn, type, client_entry, tmp, channel);
1555 case SILC_NOTIFY_TYPE_NICK_CHANGE:
1557 * Someone changed their nickname. If we don't have entry for the new
1558 * ID we will query it and return here after it's done. After we've
1559 * returned we fetch the old entry and free it and notify the
1563 /* Get new Client ID */
1564 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1568 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1573 if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
1576 /* Find Client entry and if not found query it */
1578 silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1579 if (!client_entry2) {
1580 SilcPacketContext *p = silc_packet_context_dup(packet);
1581 p->context = (void *)client;
1583 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1584 silc_client_notify_by_server_pending, p);
1588 /* Get old Client ID */
1589 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1593 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1597 /* Find old Client entry */
1599 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1603 /* Remove the old from cache */
1604 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1607 /* Replace old ID entry with new one on all channels. */
1608 silc_client_replace_from_channels(client, conn, client_entry,
1611 /* Notify application */
1612 client->ops->notify(client, conn, type, client_entry, client_entry2);
1615 if (client_entry->nickname)
1616 silc_free(client_entry->nickname);
1617 if (client_entry->server)
1618 silc_free(client_entry->server);
1619 if (client_entry->id)
1620 silc_free(client_entry->id);
1621 if (client_entry->send_key)
1622 silc_cipher_free(client_entry->send_key);
1623 if (client_entry->receive_key)
1624 silc_cipher_free(client_entry->receive_key);
1627 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1629 * Someone changed a channel mode
1633 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1637 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1641 /* Find Client entry */
1643 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1648 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1652 SILC_GET32_MSB(mode, tmp);
1654 /* Get channel entry */
1655 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1659 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1660 SILC_ID_CHANNEL, &id_cache))
1663 channel = (SilcChannelEntry)id_cache->context;
1665 /* Save the new mode */
1666 channel->mode = mode;
1668 /* Notify application. The channel entry is sent last as this notify
1669 is for channel but application don't know it from the arguments
1671 client->ops->notify(client, conn, type, client_entry, mode, channel);
1674 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1676 * Someone changed user's mode on a channel
1680 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1684 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1688 /* Find Client entry */
1690 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1695 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1699 SILC_GET32_MSB(mode, tmp);
1701 /* Get target Client ID */
1702 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1706 silc_free(client_id);
1707 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1711 /* Find target Client entry */
1713 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1717 /* Get channel entry */
1718 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1722 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1723 SILC_ID_CHANNEL, &id_cache))
1726 channel = (SilcChannelEntry)id_cache->context;
1729 silc_list_start(channel->clients);
1730 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1731 if (chu->client == client_entry) {
1737 /* Notify application. The channel entry is sent last as this notify
1738 is for channel but application don't know it from the arguments
1740 client->ops->notify(client, conn, type, client_entry, mode,
1741 client_entry2, channel);
1744 case SILC_NOTIFY_TYPE_MOTD:
1746 * Received Message of the day
1750 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1754 /* Notify application */
1755 client->ops->notify(client, conn, type, tmp);
1763 silc_notify_payload_free(payload);
1765 silc_free(client_id);
1767 silc_free(channel_id);
1770 /* Processes the received new Client ID from server. Old Client ID is
1771 deleted from cache and new one is added. */
1773 void silc_client_receive_new_id(SilcClient client,
1774 SilcSocketConnection sock,
1777 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1779 /* Delete old ID from ID cache */
1780 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1782 /* Save the new ID */
1784 silc_free(conn->local_id);
1785 if (conn->local_id_data)
1786 silc_free(conn->local_id_data);
1788 conn->local_id = silc_id_payload_get_id(idp);
1789 conn->local_id_data = silc_id_payload_get_data(idp);
1790 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1792 if (!conn->local_entry)
1793 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1795 conn->local_entry->nickname = conn->nickname;
1796 if (!conn->local_entry->username) {
1797 conn->local_entry->username =
1798 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1799 sizeof(conn->local_entry->username));
1800 sprintf(conn->local_entry->username, "%s@%s", client->username,
1803 conn->local_entry->server = strdup(conn->remote_host);
1804 conn->local_entry->id = conn->local_id;
1806 /* Put it to the ID cache */
1807 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1808 conn->local_id, (void *)conn->local_entry, TRUE);
1811 /* Processed received Channel ID for a channel. This is called when client
1812 joins to channel and server replies with channel ID. The ID is cached. */
1814 void silc_client_new_channel_id(SilcClient client,
1815 SilcSocketConnection sock,
1817 unsigned int mode, SilcIDPayload idp)
1819 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1820 SilcChannelEntry channel;
1822 SILC_LOG_DEBUG(("New channel ID"));
1824 channel = silc_calloc(1, sizeof(*channel));
1825 channel->channel_name = channel_name;
1826 channel->id = silc_id_payload_get_id(idp);
1827 channel->mode = mode;
1828 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1830 conn->current_channel = channel;
1832 /* Put it to the ID cache */
1833 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1834 (void *)channel->id, (void *)channel, TRUE);
1837 /* Saves channel key from encoded `key_payload'. This is used when we
1838 receive Channel Key Payload and when we are processing JOIN command
1841 void silc_client_save_channel_key(SilcClientConnection conn,
1842 SilcBuffer key_payload,
1843 SilcChannelEntry channel)
1845 unsigned char *id_string, *key, *cipher;
1846 unsigned int tmp_len;
1848 SilcIDCacheEntry id_cache = NULL;
1849 SilcChannelKeyPayload payload;
1851 payload = silc_channel_key_payload_parse(key_payload);
1855 id_string = silc_channel_key_get_id(payload, &tmp_len);
1857 silc_channel_key_payload_free(payload);
1861 id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
1863 silc_channel_key_payload_free(payload);
1869 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1870 SILC_ID_CHANNEL, &id_cache))
1873 /* Get channel entry */
1874 channel = (SilcChannelEntry)id_cache->context;
1878 key = silc_channel_key_get_key(payload, &tmp_len);
1879 cipher = silc_channel_key_get_cipher(payload, NULL);
1880 channel->key_len = tmp_len;
1881 channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
1882 memcpy(channel->key, key, tmp_len);
1884 if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
1885 conn->client->ops->say(conn->client, conn,
1886 "Cannot talk to channel: unsupported cipher %s", cipher);
1889 channel->channel_key->cipher->set_key(channel->channel_key->context,
1892 /* Client is now joined to the channel */
1893 channel->on_channel = TRUE;
1897 silc_channel_key_payload_free(payload);
1900 /* Processes received key for channel. The received key will be used
1901 to protect the traffic on the channel for now on. Client must receive
1902 the key to the channel before talking on the channel is possible.
1903 This is the key that server has generated, this is not the channel
1904 private key, it is entirely local setting. */
1906 void silc_client_receive_channel_key(SilcClient client,
1907 SilcSocketConnection sock,
1910 SILC_LOG_DEBUG(("Received key for channel"));
1913 silc_client_save_channel_key(sock->user_data, packet, NULL);
1916 /* Process received message to a channel (or from a channel, really). This
1917 decrypts the channel message with channel specific key and parses the
1918 channel payload. Finally it displays the message on the screen. */
1920 void silc_client_channel_message(SilcClient client,
1921 SilcSocketConnection sock,
1922 SilcPacketContext *packet)
1924 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1925 SilcBuffer buffer = packet->buffer;
1926 SilcChannelPayload payload = NULL;
1927 SilcChannelID *id = NULL;
1928 SilcChannelEntry channel;
1929 SilcChannelUser chu;
1930 SilcIDCacheEntry id_cache = NULL;
1931 SilcClientID *client_id = NULL;
1935 if (packet->dst_id_type != SILC_ID_CHANNEL)
1938 client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1942 id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
1946 /* Find the channel entry from channels on this connection */
1947 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1948 SILC_ID_CHANNEL, &id_cache))
1951 channel = (SilcChannelEntry)id_cache->context;
1953 /* Decrypt the channel message payload. Push the IV out of the way,
1954 since it is not encrypted (after pushing buffer->tail has the IV). */
1955 silc_buffer_push_tail(buffer, 16);
1956 channel->channel_key->cipher->decrypt(channel->channel_key->context,
1957 buffer->data, buffer->data,
1958 buffer->len, buffer->tail);
1959 silc_buffer_pull_tail(buffer, 16);
1961 /* Parse the channel message payload */
1962 payload = silc_channel_payload_parse(buffer);
1967 nickname = "[unknown]";
1968 silc_list_start(channel->clients);
1969 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1970 if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
1971 nickname = chu->client->nickname;
1976 /* Pass the message to application */
1977 client->ops->channel_message(client, conn, nickname,
1978 channel->channel_name,
1979 silc_channel_get_data(payload, NULL));
1985 silc_free(client_id);
1987 silc_channel_payload_free(payload);
1990 /* Private message received. This processes the private message and
1991 finally displays it on the screen. */
1993 void silc_client_private_message(SilcClient client,
1994 SilcSocketConnection sock,
1995 SilcPacketContext *packet)
1997 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1998 SilcBuffer buffer = packet->buffer;
1999 unsigned short nick_len;
2000 unsigned char *nickname, *message;
2004 ret = silc_buffer_unformat(buffer,
2005 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
2010 silc_buffer_pull(buffer, 2 + nick_len);
2012 message = silc_calloc(buffer->len + 1, sizeof(char));
2013 memcpy(message, buffer->data, buffer->len);
2015 /* Pass the private message to application */
2016 client->ops->private_message(client, conn, nickname, message);
2018 /* See if we are away (gone). If we are away we will reply to the
2019 sender with the set away message. */
2020 if (conn->away && conn->away->away) {
2021 SilcClientID *remote_id;
2022 SilcClientEntry remote_client;
2023 SilcIDCacheEntry id_cache;
2025 if (packet->src_id_type != SILC_ID_CLIENT)
2028 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
2033 /* If it's me, ignore */
2034 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
2037 /* Check whether we know this client already */
2038 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
2039 SILC_ID_CLIENT, &id_cache))
2041 /* Allocate client entry */
2042 remote_client = silc_calloc(1, sizeof(*remote_client));
2043 remote_client->id = remote_id;
2044 silc_parse_nickname(nickname, &remote_client->nickname,
2045 &remote_client->server, &remote_client->num);
2047 /* Save the client to cache */
2048 silc_idcache_add(conn->client_cache, remote_client->nickname,
2049 SILC_ID_CLIENT, remote_client->id, remote_client,
2052 silc_free(remote_id);
2053 remote_client = (SilcClientEntry)id_cache->context;
2056 /* Send the away message */
2057 silc_client_packet_send_private_message(client, sock, remote_client,
2059 strlen(conn->away->away), TRUE);
2063 memset(message, 0, buffer->len);
2065 silc_free(nickname);
2068 /* Removes a client entry from all channel it has joined. This really is
2069 a performance killer (client_entry should have pointers to channel
2072 void silc_client_remove_from_channels(SilcClient client,
2073 SilcClientConnection conn,
2074 SilcClientEntry client_entry)
2076 SilcIDCacheEntry id_cache;
2077 SilcIDCacheList list;
2078 SilcChannelEntry channel;
2079 SilcChannelUser chu;
2081 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2082 SILC_ID_CHANNEL, &list))
2085 silc_idcache_list_first(list, &id_cache);
2086 channel = (SilcChannelEntry)id_cache->context;
2090 /* Remove client from channel */
2091 silc_list_start(channel->clients);
2092 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2093 if (chu->client == client_entry) {
2094 silc_list_del(channel->clients, chu);
2100 if (!silc_idcache_list_next(list, &id_cache))
2103 channel = (SilcChannelEntry)id_cache->context;
2106 silc_idcache_list_free(list);
2109 /* Replaces `old' client entries from all channels to `new' client entry.
2110 This can be called for example when nickname changes and old ID entry
2111 is replaced from ID cache with the new one. If the old ID entry is only
2112 updated, then this fucntion needs not to be called. */
2114 void silc_client_replace_from_channels(SilcClient client,
2115 SilcClientConnection conn,
2116 SilcClientEntry old,
2117 SilcClientEntry new)
2119 SilcIDCacheEntry id_cache;
2120 SilcIDCacheList list;
2121 SilcChannelEntry channel;
2122 SilcChannelUser chu;
2124 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2125 SILC_ID_CHANNEL, &list))
2128 silc_idcache_list_first(list, &id_cache);
2129 channel = (SilcChannelEntry)id_cache->context;
2133 /* Replace client entry */
2134 silc_list_start(channel->clients);
2135 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2136 if (chu->client == old) {
2142 if (!silc_idcache_list_next(list, &id_cache))
2145 channel = (SilcChannelEntry)id_cache->context;
2148 silc_idcache_list_free(list);
2151 /* Parses mode mask and returns the mode as string. */
2153 char *silc_client_chmode(unsigned int mode)
2160 memset(string, 0, sizeof(string));
2162 if (mode & SILC_CHANNEL_MODE_PRIVATE)
2163 strncat(string, "p", 1);
2165 if (mode & SILC_CHANNEL_MODE_SECRET)
2166 strncat(string, "s", 1);
2168 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
2169 strncat(string, "k", 1);
2171 if (mode & SILC_CHANNEL_MODE_INVITE)
2172 strncat(string, "i", 1);
2174 if (mode & SILC_CHANNEL_MODE_TOPIC)
2175 strncat(string, "t", 1);
2177 if (mode & SILC_CHANNEL_MODE_ULIMIT)
2178 strncat(string, "l", 1);
2180 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
2181 strncat(string, "a", 1);
2183 /* Rest of mode is ignored */
2185 return strdup(string);
2188 /* Parses channel user mode mask and returns te mode as string */
2190 char *silc_client_chumode(unsigned int mode)
2197 memset(string, 0, sizeof(string));
2199 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2200 strncat(string, "f", 1);
2202 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2203 strncat(string, "o", 1);
2205 return strdup(string);
2208 /* Parses channel user mode and returns it as special mode character. */
2210 char *silc_client_chumode_char(unsigned int mode)
2217 memset(string, 0, sizeof(string));
2219 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2220 strncat(string, "*", 1);
2222 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2223 strncat(string, "@", 1);
2225 return strdup(string);