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 /* Error occured during protocol */
384 SILC_LOG_DEBUG(("Error during KE protocol"));
385 silc_protocol_free(protocol);
387 silc_ske_free(ctx->ske);
389 silc_free(ctx->dest_id);
390 ctx->sock->protocol = NULL;
392 /* Notify application of failure */
393 client->ops->connect(client, ctx->sock->user_data, FALSE);
398 /* Allocate internal context for the authentication protocol. This
399 is sent as context for the protocol. */
400 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
401 proto_ctx->client = (void *)client;
402 proto_ctx->sock = sock = ctx->sock;
403 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
404 proto_ctx->dest_id_type = ctx->dest_id_type;
405 proto_ctx->dest_id = ctx->dest_id;
407 /* Resolve the authentication method to be used in this connection */
408 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
409 sock->port, &proto_ctx->auth_meth,
410 &proto_ctx->auth_data,
411 &proto_ctx->auth_data_len))
413 /* XXX do AUTH_REQUEST resolcing with server */
414 proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
417 /* Free old protocol as it is finished now */
418 silc_protocol_free(protocol);
420 silc_packet_context_free(ctx->packet);
422 /* silc_free(ctx->keymat....); */
423 sock->protocol = NULL;
425 /* Allocate the authentication protocol. This is allocated here
426 but we won't start it yet. We will be receiving party of this
427 protocol thus we will wait that connecting party will make
429 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
430 &sock->protocol, (void *)proto_ctx,
431 silc_client_connect_to_server_final);
433 /* Execute the protocol */
434 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
437 /* Finalizes the connection to the remote SILC server. This is called
438 after authentication protocol has been completed. This send our
439 user information to the server to receive our client ID from
442 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
444 SilcProtocol protocol = (SilcProtocol)context;
445 SilcClientConnAuthInternalContext *ctx =
446 (SilcClientConnAuthInternalContext *)protocol->context;
447 SilcClient client = (SilcClient)ctx->client;
448 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
451 SILC_LOG_DEBUG(("Start"));
453 if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
454 /* Error occured during protocol */
455 SILC_LOG_DEBUG(("Error during authentication protocol"));
456 silc_protocol_free(protocol);
458 silc_free(ctx->auth_data);
460 silc_ske_free(ctx->ske);
462 silc_free(ctx->dest_id);
463 conn->sock->protocol = NULL;
465 /* Notify application of failure */
466 client->ops->connect(client, ctx->sock->user_data, FALSE);
471 /* Send NEW_CLIENT packet to the server. We will become registered
472 to the SILC network after sending this packet and we will receive
473 client ID from the server. */
474 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
475 strlen(client->realname));
476 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
477 silc_buffer_format(packet,
478 SILC_STR_UI_SHORT(strlen(client->username)),
479 SILC_STR_UI_XNSTRING(client->username,
480 strlen(client->username)),
481 SILC_STR_UI_SHORT(strlen(client->realname)),
482 SILC_STR_UI_XNSTRING(client->realname,
483 strlen(client->realname)),
486 /* Send the packet */
487 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
489 packet->data, packet->len, TRUE);
490 silc_buffer_free(packet);
492 /* Save remote ID. */
493 conn->remote_id = ctx->dest_id;
494 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
495 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
497 /* Notify application of successful connection */
498 client->ops->connect(client, conn, TRUE);
500 silc_protocol_free(protocol);
502 silc_free(ctx->auth_data);
504 silc_ske_free(ctx->ske);
506 conn->sock->protocol = NULL;
509 /* Internal routine that sends packet or marks packet to be sent. This
510 is used directly only in special cases. Normal cases should use
511 silc_server_packet_send. Returns < 0 on error. */
513 static int silc_client_packet_send_real(SilcClient client,
514 SilcSocketConnection sock,
519 /* Send the packet */
520 ret = silc_packet_send(sock, force_send);
524 /* Mark that there is some outgoing data available for this connection.
525 This call sets the connection both for input and output (the input
526 is set always and this call keeps the input setting, actually).
527 Actual data sending is performed by silc_client_packet_process. */
528 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
530 /* Mark to socket that data is pending in outgoing buffer. This flag
531 is needed if new data is added to the buffer before the earlier
532 put data is sent to the network. */
533 SILC_SET_OUTBUF_PENDING(sock);
538 /* Packet processing callback. This is used to send and receive packets
539 from network. This is generic task. */
541 SILC_TASK_CALLBACK(silc_client_packet_process)
543 SilcClient client = (SilcClient)context;
544 SilcSocketConnection sock = NULL;
545 SilcClientConnection conn;
548 SILC_LOG_DEBUG(("Processing packet"));
550 SILC_CLIENT_GET_SOCK(client, fd, sock);
554 conn = (SilcClientConnection)sock->user_data;
557 if (type == SILC_TASK_WRITE) {
558 SILC_LOG_DEBUG(("Writing data to connection"));
560 if (sock->outbuf->data - sock->outbuf->head)
561 silc_buffer_push(sock->outbuf,
562 sock->outbuf->data - sock->outbuf->head);
564 ret = silc_client_packet_send_real(client, sock, TRUE);
566 /* If returned -2 could not write to connection now, will do
571 /* The packet has been sent and now it is time to set the connection
572 back to only for input. When there is again some outgoing data
573 available for this connection it will be set for output as well.
574 This call clears the output setting and sets it only for input. */
575 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
576 SILC_UNSET_OUTBUF_PENDING(sock);
578 silc_buffer_clear(sock->outbuf);
582 /* Packet receiving */
583 if (type == SILC_TASK_READ) {
584 SILC_LOG_DEBUG(("Reading data from connection"));
586 /* Read data from network */
587 ret = silc_packet_receive(sock);
593 SILC_LOG_DEBUG(("Read EOF"));
595 /* If connection is disconnecting already we will finally
596 close the connection */
597 if (SILC_IS_DISCONNECTING(sock)) {
598 client->ops->disconnect(client, conn);
599 silc_client_close_connection(client, sock);
603 client->ops->say(client, conn, "Connection closed: premature EOF");
604 SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
605 client->ops->disconnect(client, conn);
606 silc_client_close_connection(client, sock);
610 /* Process the packet. This will call the parser that will then
611 decrypt and parse the packet. */
612 silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
613 silc_client_packet_parse, client);
617 /* Parses whole packet, received earlier. */
619 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
621 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
622 SilcClient client = (SilcClient)parse_ctx->context;
623 SilcPacketContext *packet = parse_ctx->packet;
624 SilcBuffer buffer = packet->buffer;
625 SilcSocketConnection sock = parse_ctx->sock;
626 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
629 SILC_LOG_DEBUG(("Start"));
631 /* Decrypt the received packet */
632 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
637 /* Parse the packet. Packet type is returned. */
638 ret = silc_packet_parse(packet);
640 /* Parse the packet header in special way as this is "special"
642 ret = silc_packet_parse_special(packet);
645 if (ret == SILC_PACKET_NONE)
648 /* Parse the incoming packet type */
649 silc_client_packet_parse_type(client, sock, packet);
652 silc_buffer_clear(sock->inbuf);
653 silc_packet_context_free(packet);
654 silc_free(parse_ctx);
657 /* Parser callback called by silc_packet_receive_process. Thie merely
658 registers timeout that will handle the actual parsing when appropriate. */
660 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
662 SilcClient client = (SilcClient)parser_context->context;
664 /* Parse the packet */
665 silc_task_register(client->timeout_queue, parser_context->sock->sock,
666 silc_client_packet_parse_real,
667 (void *)parser_context, 0, 1,
669 SILC_TASK_PRI_NORMAL);
672 /* Parses the packet type and calls what ever routines the packet type
673 requires. This is done for all incoming packets. */
675 void silc_client_packet_parse_type(SilcClient client,
676 SilcSocketConnection sock,
677 SilcPacketContext *packet)
679 SilcBuffer buffer = packet->buffer;
680 SilcPacketType type = packet->type;
682 SILC_LOG_DEBUG(("Parsing packet type %d", type));
684 /* Parse the packet type */
686 case SILC_PACKET_DISCONNECT:
687 silc_client_disconnected_by_server(client, sock, buffer);
689 case SILC_PACKET_SUCCESS:
691 * Success received for something. For now we can have only
692 * one protocol for connection executing at once hence this
693 * success message is for whatever protocol is executing currently.
695 if (sock->protocol) {
696 sock->protocol->execute(client->timeout_queue, 0,
697 sock->protocol, sock->sock, 0, 0);
700 case SILC_PACKET_FAILURE:
702 * Failure received for some protocol. Set the protocol state to
703 * error and call the protocol callback. This fill cause error on
704 * protocol and it will call the final callback.
706 if (sock->protocol) {
707 sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
708 sock->protocol->execute(client->timeout_queue, 0,
709 sock->protocol, sock->sock, 0, 0);
711 /* XXX We have only two protocols currently thus we know what this
712 failure indication is. */
713 if (buffer->len >= 4) {
714 unsigned int failure;
716 SILC_GET32_MSB(failure, buffer->data);
718 /* Notify application */
719 client->ops->failure(client, sock->user_data, sock->protocol,
724 case SILC_PACKET_REJECT:
727 case SILC_PACKET_NOTIFY:
729 * Received notify message
731 silc_client_notify_by_server(client, sock, packet);
734 case SILC_PACKET_ERROR:
736 * Received error message
738 silc_client_error_by_server(client, sock, buffer);
741 case SILC_PACKET_CHANNEL_MESSAGE:
743 * Received message to (from, actually) a channel
745 silc_client_channel_message(client, sock, packet);
747 case SILC_PACKET_CHANNEL_KEY:
749 * Received key for a channel. By receiving this key the client will be
750 * able to talk to the channel it has just joined. This can also be
751 * a new key for existing channel as keys expire peridiocally.
753 silc_client_receive_channel_key(client, sock, buffer);
756 case SILC_PACKET_PRIVATE_MESSAGE:
758 * Received private message
760 silc_client_private_message(client, sock, packet);
762 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
764 * Received private message key
768 case SILC_PACKET_COMMAND_REPLY:
770 * Recived reply for a command
772 silc_client_command_reply_process(client, sock, packet);
775 case SILC_PACKET_KEY_EXCHANGE:
776 if (sock->protocol) {
777 SilcClientKEInternalContext *proto_ctx =
778 (SilcClientKEInternalContext *)sock->protocol->context;
780 proto_ctx->packet = silc_packet_context_dup(packet);
781 proto_ctx->dest_id_type = packet->src_id_type;
782 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
784 /* Let the protocol handle the packet */
785 sock->protocol->execute(client->timeout_queue, 0,
786 sock->protocol, sock->sock, 0, 0);
788 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
789 "protocol active, packet dropped."));
791 /* XXX Trigger KE protocol?? Rekey actually! */
795 case SILC_PACKET_KEY_EXCHANGE_1:
796 if (sock->protocol) {
799 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
800 "protocol active, packet dropped."));
803 case SILC_PACKET_KEY_EXCHANGE_2:
804 if (sock->protocol) {
805 SilcClientKEInternalContext *proto_ctx =
806 (SilcClientKEInternalContext *)sock->protocol->context;
808 if (proto_ctx->packet)
809 silc_packet_context_free(proto_ctx->packet);
811 proto_ctx->packet = silc_packet_context_dup(packet);
812 proto_ctx->dest_id_type = packet->src_id_type;
813 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
815 /* Let the protocol handle the packet */
816 sock->protocol->execute(client->timeout_queue, 0,
817 sock->protocol, sock->sock, 0, 0);
819 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
820 "protocol active, packet dropped."));
824 case SILC_PACKET_NEW_ID:
827 * Received new ID from server. This packet is received at
828 * the connection to the server. New ID is also received when
829 * user changes nickname but in that case the new ID is received
830 * as command reply and not as this packet type.
834 idp = silc_id_payload_parse(buffer);
835 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
838 silc_client_receive_new_id(client, sock, idp);
839 silc_id_payload_free(idp);
844 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
849 /* Sends packet. This doesn't actually send the packet instead it assembles
850 it and marks it to be sent. However, if force_send is TRUE the packet
851 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
852 will be derived from sock argument. Otherwise the valid arguments sent
855 void silc_client_packet_send(SilcClient client,
856 SilcSocketConnection sock,
859 SilcIdType dst_id_type,
863 unsigned int data_len,
866 SilcPacketContext packetdata;
868 SILC_LOG_DEBUG(("Sending packet, type %d", type));
870 /* Get data used in the packet sending, keys and stuff */
871 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
872 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
873 cipher = ((SilcClientConnection)sock->user_data)->send_key;
875 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
876 hmac = ((SilcClientConnection)sock->user_data)->hmac;
878 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
879 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
880 dst_id_type = SILC_ID_SERVER;
884 /* Set the packet context pointers */
885 packetdata.flags = 0;
886 packetdata.type = type;
887 if (((SilcClientConnection)sock->user_data)->local_id_data)
888 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
890 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
891 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
892 packetdata.src_id_type = SILC_ID_CLIENT;
894 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
895 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
896 packetdata.dst_id_type = dst_id_type;
898 packetdata.dst_id = NULL;
899 packetdata.dst_id_len = 0;
900 packetdata.dst_id_type = SILC_ID_NONE;
902 packetdata.rng = client->rng;
903 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
904 packetdata.src_id_len + packetdata.dst_id_len;
905 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
907 /* Prepare outgoing data buffer for packet sending */
908 silc_packet_send_prepare(sock,
909 SILC_PACKET_HEADER_LEN +
910 packetdata.src_id_len +
911 packetdata.dst_id_len,
915 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
917 packetdata.buffer = sock->outbuf;
919 /* Put the data to the buffer */
920 if (data && data_len)
921 silc_buffer_put(sock->outbuf, data, data_len);
923 /* Create the outgoing packet */
924 silc_packet_assemble(&packetdata);
926 /* Encrypt the packet */
928 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
930 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
931 sock->outbuf->data, sock->outbuf->len);
933 /* Now actually send the packet */
934 silc_client_packet_send_real(client, sock, force_send);
937 /* Sends packet to a channel. Packet to channel is always encrypted
938 differently from "normal" packets. SILC header of the packet is
939 encrypted with the next receiver's key and the rest of the packet is
940 encrypted with the channel specific key. Padding and HMAC is computed
941 with the next receiver's key. */
943 void silc_client_packet_send_to_channel(SilcClient client,
944 SilcSocketConnection sock,
945 SilcChannelEntry channel,
947 unsigned int data_len,
951 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
953 SilcPacketContext packetdata;
956 unsigned char *id_string;
958 SILC_LOG_DEBUG(("Sending packet to channel"));
960 if (!channel || !channel->key) {
961 client->ops->say(client, conn,
962 "Cannot talk to channel: key does not exist");
968 for (i = 0; i < 16; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
970 silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
972 /* Encode the channel payload */
973 payload = silc_channel_payload_encode(data_len, data, 16, channel->iv,
976 client->ops->say(client, conn,
977 "Error: Could not create packet to be sent to channel");
981 /* Get data used in packet header encryption, keys and stuff. Rest
982 of the packet (the payload) is, however, encrypted with the
983 specified channel key. */
984 cipher = conn->send_key;
986 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
988 /* Set the packet context pointers. The destination ID is always
989 the Channel ID of the channel. Server and router will handle the
990 distribution of the packet. */
991 packetdata.flags = 0;
992 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
993 packetdata.src_id = conn->local_id_data;
994 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
995 packetdata.src_id_type = SILC_ID_CLIENT;
996 packetdata.dst_id = id_string;
997 packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
998 packetdata.dst_id_type = SILC_ID_CHANNEL;
999 packetdata.rng = client->rng;
1000 packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
1001 packetdata.src_id_len + packetdata.dst_id_len;
1002 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1003 packetdata.src_id_len +
1004 packetdata.dst_id_len));
1006 /* Prepare outgoing data buffer for packet sending */
1007 silc_packet_send_prepare(sock,
1008 SILC_PACKET_HEADER_LEN +
1009 packetdata.src_id_len +
1010 packetdata.dst_id_len,
1014 packetdata.buffer = sock->outbuf;
1016 /* Encrypt payload of the packet. This is encrypted with the channel key. */
1017 channel->channel_key->cipher->encrypt(channel->channel_key->context,
1018 payload->data, payload->data,
1019 payload->len - 16, /* -IV_LEN */
1022 /* Put the actual encrypted payload data into the buffer. */
1023 silc_buffer_put(sock->outbuf, payload->data, payload->len);
1025 /* Create the outgoing packet */
1026 silc_packet_assemble(&packetdata);
1028 /* Encrypt the header and padding of the packet. This is encrypted
1029 with normal session key shared with our server. */
1030 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1031 packetdata.src_id_len + packetdata.dst_id_len +
1034 SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1035 sock->outbuf->data, sock->outbuf->len);
1037 /* Now actually send the packet */
1038 silc_client_packet_send_real(client, sock, force_send);
1039 silc_buffer_free(payload);
1040 silc_free(id_string);
1043 /* Sends private message to remote client. If private message key has
1044 not been set with this client then the message will be encrypted using
1045 normal session keys. Private messages are special packets in SILC
1046 network hence we need this own function for them. This is similiar
1047 to silc_client_packet_send_to_channel except that we send private
1050 void silc_client_packet_send_private_message(SilcClient client,
1051 SilcSocketConnection sock,
1052 SilcClientEntry client_entry,
1053 unsigned char *data,
1054 unsigned int data_len,
1057 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1059 SilcPacketContext packetdata;
1060 unsigned int nick_len;
1064 SILC_LOG_DEBUG(("Sending private message"));
1066 /* Create private message payload */
1067 nick_len = strlen(conn->nickname);
1068 buffer = silc_buffer_alloc(2 + nick_len + data_len);
1069 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1070 silc_buffer_format(buffer,
1071 SILC_STR_UI_SHORT(nick_len),
1072 SILC_STR_UI_XNSTRING(conn->nickname,
1074 SILC_STR_UI_XNSTRING(data, data_len),
1077 /* If we don't have private message specific key then private messages
1078 are just as any normal packet thus call normal packet sending. If
1079 the key exist then the encryption process is a bit different and
1080 will be done in the rest of this function. */
1081 if (!client_entry->send_key) {
1082 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1083 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1084 buffer->data, buffer->len, force_send);
1088 /* We have private message specific key */
1090 /* Get data used in the encryption */
1091 cipher = client_entry->send_key;
1094 /* Set the packet context pointers. */
1095 packetdata.flags = 0;
1096 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1097 packetdata.src_id = conn->local_id_data;
1098 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1099 packetdata.src_id_type = SILC_ID_CLIENT;
1101 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1103 packetdata.dst_id = conn->local_id_data;
1104 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1105 packetdata.dst_id_type = SILC_ID_CLIENT;
1106 packetdata.rng = client->rng;
1107 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
1108 packetdata.src_id_len + packetdata.dst_id_len;
1109 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1110 packetdata.src_id_len +
1111 packetdata.dst_id_len));
1113 /* Prepare outgoing data buffer for packet sending */
1114 silc_packet_send_prepare(sock,
1115 SILC_PACKET_HEADER_LEN +
1116 packetdata.src_id_len +
1117 packetdata.dst_id_len,
1121 packetdata.buffer = sock->outbuf;
1123 /* Encrypt payload of the packet. Encrypt with private message specific
1124 key if it exist, otherwise with session key. */
1125 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1126 buffer->len, cipher->iv);
1128 /* Put the actual encrypted payload data into the buffer. */
1129 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1131 /* Create the outgoing packet */
1132 silc_packet_assemble(&packetdata);
1134 /* Encrypt the header and padding of the packet. */
1135 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1136 packetdata.src_id_len + packetdata.dst_id_len +
1139 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1140 sock->outbuf->data, sock->outbuf->len);
1142 /* Now actually send the packet */
1143 silc_client_packet_send_real(client, sock, force_send);
1144 silc_free(packetdata.dst_id);
1150 /* Closes connection to remote end. Free's all allocated data except
1151 for some information such as nickname etc. that are valid at all time. */
1153 void silc_client_close_connection(SilcClient client,
1154 SilcSocketConnection sock)
1156 SilcClientConnection conn;
1158 /* We won't listen for this connection anymore */
1159 silc_schedule_unset_listen_fd(sock->sock);
1161 /* Unregister all tasks */
1162 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1163 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1165 /* Close the actual connection */
1166 silc_net_close_connection(sock->sock);
1168 client->ops->say(client, sock->user_data,
1169 "Closed connection to host %s", sock->hostname ?
1170 sock->hostname : sock->ip);
1172 /* Free everything */
1173 if (sock->user_data) {
1174 conn = (SilcClientConnection)sock->user_data;
1176 /* XXX Free all client entries and channel entries. */
1178 /* Clear ID caches */
1179 silc_idcache_del_all(conn->client_cache);
1180 silc_idcache_del_all(conn->channel_cache);
1183 if (conn->remote_host)
1184 silc_free(conn->remote_host);
1186 silc_free(conn->local_id);
1187 if (conn->local_id_data)
1188 silc_free(conn->local_id_data);
1190 silc_cipher_free(conn->send_key);
1191 if (conn->receive_key)
1192 silc_cipher_free(conn->receive_key);
1194 silc_hmac_free(conn->hmac);
1195 if (conn->hmac_key) {
1196 memset(conn->hmac_key, 0, conn->hmac_key_len);
1197 silc_free(conn->hmac_key);
1199 if (conn->pending_commands)
1200 silc_dlist_uninit(conn->pending_commands);
1203 conn->remote_port = 0;
1204 conn->remote_type = 0;
1205 conn->send_key = NULL;
1206 conn->receive_key = NULL;
1208 conn->hmac_key = NULL;
1209 conn->hmac_key_len = 0;
1210 conn->local_id = NULL;
1211 conn->local_id_data = NULL;
1212 conn->remote_host = NULL;
1213 conn->current_channel = NULL;
1214 conn->pending_commands = NULL;
1216 silc_client_del_connection(client, conn);
1219 if (sock->protocol) {
1220 silc_protocol_free(sock->protocol);
1221 sock->protocol = NULL;
1223 silc_socket_free(sock);
1226 /* Called when we receive disconnection packet from server. This
1227 closes our end properly and displays the reason of the disconnection
1230 void silc_client_disconnected_by_server(SilcClient client,
1231 SilcSocketConnection sock,
1236 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1238 msg = silc_calloc(message->len + 1, sizeof(char));
1239 memcpy(msg, message->data, message->len);
1240 client->ops->say(client, sock->user_data, msg);
1243 SILC_SET_DISCONNECTED(sock);
1244 silc_client_close_connection(client, sock);
1247 /* Received error message from server. Display it on the screen.
1248 We don't take any action what so ever of the error message. */
1250 void silc_client_error_by_server(SilcClient client,
1251 SilcSocketConnection sock,
1256 msg = silc_calloc(message->len + 1, sizeof(char));
1257 memcpy(msg, message->data, message->len);
1258 client->ops->say(client, sock->user_data, msg);
1262 /* Called when notify is received and some async operation (such as command)
1263 is required before processing the notify message. This calls again the
1264 silc_client_notify_by_server and reprocesses the original notify packet. */
1266 static void silc_client_notify_by_server_pending(void *context)
1268 SilcPacketContext *p = (SilcPacketContext *)context;
1269 silc_client_notify_by_server(p->context, p->sock, p);
1270 silc_packet_context_free(p);
1273 /* Received notify message from server */
1275 void silc_client_notify_by_server(SilcClient client,
1276 SilcSocketConnection sock,
1277 SilcPacketContext *packet)
1279 SilcBuffer buffer = packet->buffer;
1280 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1281 SilcNotifyPayload payload;
1282 SilcNotifyType type;
1283 SilcArgumentPayload args;
1285 SilcClientID *client_id = NULL;
1286 SilcChannelID *channel_id = NULL;
1287 SilcClientEntry client_entry;
1288 SilcClientEntry client_entry2;
1289 SilcChannelEntry channel;
1290 SilcChannelUser chu;
1291 SilcIDCacheEntry id_cache = NULL;
1293 unsigned int tmp_len, mode;
1295 payload = silc_notify_payload_parse(buffer);
1296 type = silc_notify_get_type(payload);
1297 args = silc_notify_get_args(payload);
1302 case SILC_NOTIFY_TYPE_NONE:
1303 /* Notify application */
1304 client->ops->notify(client, conn, type,
1305 silc_argument_get_arg_type(args, 1, NULL));
1308 case SILC_NOTIFY_TYPE_INVITE:
1310 * Someone invited me to a channel. Find Client and Channel entries
1311 * for the application.
1315 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1319 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1321 /* Find Client entry and if not found query it */
1322 client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1323 if (!client_entry) {
1324 SilcPacketContext *p = silc_packet_context_dup(packet);
1325 p->context = (void *)client;
1327 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1328 silc_client_notify_by_server_pending, p);
1332 /* Get Channel ID */
1333 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1337 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1339 /* XXX Will ALWAYS fail because currently we don't have way to resolve
1340 channel information for channel that we're not joined to. */
1341 /* XXX ways to fix: use (extended) LIST command, or define the channel
1342 name to the notfy type when name resolving is not mandatory. */
1343 /* Find channel entry */
1344 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1345 SILC_ID_CHANNEL, &id_cache))
1348 channel = (SilcChannelEntry)id_cache->context;
1350 /* Notify application */
1351 client->ops->notify(client, conn, type, client_entry, channel);
1354 case SILC_NOTIFY_TYPE_JOIN:
1356 * Someone has joined to a channel. Get their ID and nickname and
1357 * cache them for later use.
1361 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1365 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1367 /* Find Client entry and if not found query it */
1368 client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1369 if (!client_entry) {
1370 SilcPacketContext *p = silc_packet_context_dup(packet);
1371 p->context = (void *)client;
1373 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1374 silc_client_notify_by_server_pending, p);
1378 /* Get channel entry */
1379 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1380 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1381 SILC_ID_CHANNEL, &id_cache))
1384 channel = (SilcChannelEntry)id_cache->context;
1386 /* Add client to channel */
1387 chu = silc_calloc(1, sizeof(*chu));
1388 chu->client = client_entry;
1389 silc_list_add(channel->clients, chu);
1391 /* XXX add support for multiple same nicks on same channel. Check
1394 /* Notify application. The channel entry is sent last as this notify
1395 is for channel but application don't know it from the arguments
1397 client->ops->notify(client, conn, type, client_entry, channel);
1400 case SILC_NOTIFY_TYPE_LEAVE:
1402 * Someone has left a channel. We will remove it from the channel but
1403 * we'll keep it in the cache in case we'll need it later.
1407 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1411 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1413 /* Find Client entry */
1415 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1419 /* Get channel entry */
1420 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1421 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1422 SILC_ID_CHANNEL, &id_cache))
1425 channel = (SilcChannelEntry)id_cache->context;
1427 /* Remove client from channel */
1428 silc_list_start(channel->clients);
1429 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1430 if (chu->client == client_entry) {
1431 silc_list_del(channel->clients, chu);
1437 /* Notify application. The channel entry is sent last as this notify
1438 is for channel but application don't know it from the arguments
1440 client->ops->notify(client, conn, type, client_entry, channel);
1443 case SILC_NOTIFY_TYPE_SIGNOFF:
1445 * Someone left SILC. We'll remove it from all channels and from cache.
1449 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1453 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1455 /* Find Client entry */
1457 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1461 /* Remove from all channels */
1462 silc_client_remove_from_channels(client, conn, client_entry);
1464 /* Remove from cache */
1465 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1468 /* Notify application */
1469 client->ops->notify(client, conn, type, client_entry);
1472 if (client_entry->nickname)
1473 silc_free(client_entry->nickname);
1474 if (client_entry->server)
1475 silc_free(client_entry->server);
1476 if (client_entry->id)
1477 silc_free(client_entry->id);
1478 if (client_entry->send_key)
1479 silc_cipher_free(client_entry->send_key);
1480 if (client_entry->receive_key)
1481 silc_cipher_free(client_entry->receive_key);
1484 case SILC_NOTIFY_TYPE_TOPIC_SET:
1486 * Someone set the topic on a channel.
1490 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1494 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1496 /* Find Client entry */
1498 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1503 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1507 /* Get channel entry */
1508 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1509 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1510 SILC_ID_CHANNEL, &id_cache))
1513 channel = (SilcChannelEntry)id_cache->context;
1515 /* Notify application. The channel entry is sent last as this notify
1516 is for channel but application don't know it from the arguments
1518 client->ops->notify(client, conn, type, client_entry, tmp, channel);
1521 case SILC_NOTIFY_TYPE_NICK_CHANGE:
1523 * Someone changed their nickname. If we don't have entry for the new
1524 * ID we will query it and return here after it's done. After we've
1525 * returned we fetch the old entry and free it and notify the
1529 /* Get new Client ID */
1530 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1534 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1537 if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
1540 /* Find Client entry and if not found query it */
1542 silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
1543 if (!client_entry2) {
1544 SilcPacketContext *p = silc_packet_context_dup(packet);
1545 p->context = (void *)client;
1547 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
1548 silc_client_notify_by_server_pending, p);
1552 /* Get old Client ID */
1553 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1557 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1559 /* Find old Client entry */
1561 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1565 /* Remove the old from cache */
1566 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1569 /* Replace old ID entry with new one on all channels. */
1570 silc_client_replace_from_channels(client, conn, client_entry,
1573 /* Notify application */
1574 client->ops->notify(client, conn, type, client_entry, client_entry2);
1577 if (client_entry->nickname)
1578 silc_free(client_entry->nickname);
1579 if (client_entry->server)
1580 silc_free(client_entry->server);
1581 if (client_entry->id)
1582 silc_free(client_entry->id);
1583 if (client_entry->send_key)
1584 silc_cipher_free(client_entry->send_key);
1585 if (client_entry->receive_key)
1586 silc_cipher_free(client_entry->receive_key);
1589 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1591 * Someone changed a channel mode
1595 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1599 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1601 /* Find Client entry */
1603 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1608 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1612 SILC_GET32_MSB(mode, tmp);
1614 /* Get channel entry */
1615 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1616 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1617 SILC_ID_CHANNEL, &id_cache))
1620 channel = (SilcChannelEntry)id_cache->context;
1622 /* Save the new mode */
1623 channel->mode = mode;
1625 /* Notify application. The channel entry is sent last as this notify
1626 is for channel but application don't know it from the arguments
1628 client->ops->notify(client, conn, type, client_entry, mode, channel);
1631 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1633 * Someone changed user's mode on a channel
1637 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1641 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1643 /* Find Client entry */
1645 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1650 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1654 SILC_GET32_MSB(mode, tmp);
1656 /* Get target Client ID */
1657 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1661 silc_free(client_id);
1662 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1664 /* Find target Client entry */
1666 silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
1670 /* Get channel entry */
1671 channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1672 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1673 SILC_ID_CHANNEL, &id_cache))
1676 channel = (SilcChannelEntry)id_cache->context;
1679 silc_list_start(channel->clients);
1680 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1681 if (chu->client == client_entry) {
1687 /* Notify application. The channel entry is sent last as this notify
1688 is for channel but application don't know it from the arguments
1690 client->ops->notify(client, conn, type, client_entry, mode,
1691 client_entry2, channel);
1694 case SILC_NOTIFY_TYPE_MOTD:
1696 * Received Message of the day
1700 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1704 /* Notify application */
1705 client->ops->notify(client, conn, type, tmp);
1713 silc_notify_payload_free(payload);
1715 silc_free(client_id);
1717 silc_free(channel_id);
1720 /* Processes the received new Client ID from server. Old Client ID is
1721 deleted from cache and new one is added. */
1723 void silc_client_receive_new_id(SilcClient client,
1724 SilcSocketConnection sock,
1727 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1729 /* Delete old ID from ID cache */
1730 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1732 /* Save the new ID */
1734 silc_free(conn->local_id);
1735 if (conn->local_id_data)
1736 silc_free(conn->local_id_data);
1738 conn->local_id = silc_id_payload_get_id(idp);
1739 conn->local_id_data = silc_id_payload_get_data(idp);
1740 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1742 if (!conn->local_entry)
1743 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1745 conn->local_entry->nickname = conn->nickname;
1746 if (!conn->local_entry->username) {
1747 conn->local_entry->username =
1748 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1749 sizeof(conn->local_entry->username));
1750 sprintf(conn->local_entry->username, "%s@%s", client->username,
1753 conn->local_entry->server = strdup(conn->remote_host);
1754 conn->local_entry->id = conn->local_id;
1756 /* Put it to the ID cache */
1757 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1758 conn->local_id, (void *)conn->local_entry, TRUE);
1761 /* Processed received Channel ID for a channel. This is called when client
1762 joins to channel and server replies with channel ID. The ID is cached. */
1764 void silc_client_new_channel_id(SilcClient client,
1765 SilcSocketConnection sock,
1767 unsigned int mode, SilcIDPayload idp)
1769 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1770 SilcChannelEntry channel;
1772 SILC_LOG_DEBUG(("New channel ID"));
1774 channel = silc_calloc(1, sizeof(*channel));
1775 channel->channel_name = channel_name;
1776 channel->id = silc_id_payload_get_id(idp);
1777 channel->mode = mode;
1778 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1780 conn->current_channel = channel;
1782 /* Put it to the ID cache */
1783 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1784 (void *)channel->id, (void *)channel, TRUE);
1787 /* Saves channel key from encoded `key_payload'. This is used when we
1788 receive Channel Key Payload and when we are processing JOIN command
1791 void silc_client_save_channel_key(SilcClientConnection conn,
1792 SilcBuffer key_payload,
1793 SilcChannelEntry channel)
1795 unsigned char *id_string, *key, *cipher;
1796 unsigned int tmp_len;
1798 SilcIDCacheEntry id_cache = NULL;
1799 SilcChannelKeyPayload payload;
1801 payload = silc_channel_key_payload_parse(key_payload);
1805 id_string = silc_channel_key_get_id(payload, &tmp_len);
1807 silc_channel_key_payload_free(payload);
1811 id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
1815 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1816 SILC_ID_CHANNEL, &id_cache))
1819 /* Get channel entry */
1820 channel = (SilcChannelEntry)id_cache->context;
1824 key = silc_channel_key_get_key(payload, &tmp_len);
1825 cipher = silc_channel_key_get_cipher(payload, NULL);
1826 channel->key_len = tmp_len;
1827 channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
1828 memcpy(channel->key, key, tmp_len);
1830 if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
1831 conn->client->ops->say(conn->client, conn,
1832 "Cannot talk to channel: unsupported cipher %s", cipher);
1835 channel->channel_key->cipher->set_key(channel->channel_key->context,
1838 /* Client is now joined to the channel */
1839 channel->on_channel = TRUE;
1843 silc_channel_key_payload_free(payload);
1846 /* Processes received key for channel. The received key will be used
1847 to protect the traffic on the channel for now on. Client must receive
1848 the key to the channel before talking on the channel is possible.
1849 This is the key that server has generated, this is not the channel
1850 private key, it is entirely local setting. */
1852 void silc_client_receive_channel_key(SilcClient client,
1853 SilcSocketConnection sock,
1856 SILC_LOG_DEBUG(("Received key for channel"));
1859 silc_client_save_channel_key(sock->user_data, packet, NULL);
1862 /* Process received message to a channel (or from a channel, really). This
1863 decrypts the channel message with channel specific key and parses the
1864 channel payload. Finally it displays the message on the screen. */
1866 void silc_client_channel_message(SilcClient client,
1867 SilcSocketConnection sock,
1868 SilcPacketContext *packet)
1870 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1871 SilcBuffer buffer = packet->buffer;
1872 SilcChannelPayload payload = NULL;
1873 SilcChannelID *id = NULL;
1874 SilcChannelEntry channel;
1875 SilcChannelUser chu;
1876 SilcIDCacheEntry id_cache = NULL;
1877 SilcClientID *client_id = NULL;
1881 if (packet->dst_id_type != SILC_ID_CHANNEL)
1884 client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1885 id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1887 /* Find the channel entry from channels on this connection */
1888 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1889 SILC_ID_CHANNEL, &id_cache))
1892 channel = (SilcChannelEntry)id_cache->context;
1894 /* Decrypt the channel message payload. Push the IV out of the way,
1895 since it is not encrypted (after pushing buffer->tail has the IV). */
1896 silc_buffer_push_tail(buffer, 16);
1897 channel->channel_key->cipher->decrypt(channel->channel_key->context,
1898 buffer->data, buffer->data,
1899 buffer->len, buffer->tail);
1900 silc_buffer_pull_tail(buffer, 16);
1902 /* Parse the channel message payload */
1903 payload = silc_channel_payload_parse(buffer);
1908 nickname = "[unknown]";
1909 silc_list_start(channel->clients);
1910 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1911 if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
1912 nickname = chu->client->nickname;
1917 /* Pass the message to application */
1918 client->ops->channel_message(client, conn, nickname,
1919 channel->channel_name,
1920 silc_channel_get_data(payload, NULL));
1926 silc_free(client_id);
1928 silc_channel_payload_free(payload);
1931 /* Private message received. This processes the private message and
1932 finally displays it on the screen. */
1934 void silc_client_private_message(SilcClient client,
1935 SilcSocketConnection sock,
1936 SilcPacketContext *packet)
1938 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1939 SilcBuffer buffer = packet->buffer;
1940 unsigned short nick_len;
1941 unsigned char *nickname, *message;
1944 silc_buffer_unformat(buffer,
1945 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
1947 silc_buffer_pull(buffer, 2 + nick_len);
1949 message = silc_calloc(buffer->len + 1, sizeof(char));
1950 memcpy(message, buffer->data, buffer->len);
1952 /* Pass the private message to application */
1953 client->ops->private_message(client, conn, nickname, message);
1955 /* See if we are away (gone). If we are away we will reply to the
1956 sender with the set away message. */
1957 if (conn->away && conn->away->away) {
1958 SilcClientID *remote_id;
1959 SilcClientEntry remote_client;
1960 SilcIDCacheEntry id_cache;
1962 if (packet->src_id_type != SILC_ID_CLIENT)
1965 remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1969 /* If it's me, ignore */
1970 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
1973 /* Check whether we know this client already */
1974 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
1975 SILC_ID_CLIENT, &id_cache))
1977 /* Allocate client entry */
1978 remote_client = silc_calloc(1, sizeof(*remote_client));
1979 remote_client->id = remote_id;
1980 silc_parse_nickname(nickname, &remote_client->nickname,
1981 &remote_client->server, &remote_client->num);
1983 /* Save the client to cache */
1984 silc_idcache_add(conn->client_cache, remote_client->nickname,
1985 SILC_ID_CLIENT, remote_client->id, remote_client,
1988 silc_free(remote_id);
1989 remote_client = (SilcClientEntry)id_cache->context;
1992 /* Send the away message */
1993 silc_client_packet_send_private_message(client, sock, remote_client,
1995 strlen(conn->away->away), TRUE);
1999 memset(message, 0, buffer->len);
2001 silc_free(nickname);
2004 /* Removes a client entry from all channel it has joined. This really is
2005 a performance killer (client_entry should have pointers to channel
2008 void silc_client_remove_from_channels(SilcClient client,
2009 SilcClientConnection conn,
2010 SilcClientEntry client_entry)
2012 SilcIDCacheEntry id_cache;
2013 SilcIDCacheList list;
2014 SilcChannelEntry channel;
2015 SilcChannelUser chu;
2017 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2018 SILC_ID_CHANNEL, &list))
2021 silc_idcache_list_first(list, &id_cache);
2022 channel = (SilcChannelEntry)id_cache->context;
2026 /* Remove client from channel */
2027 silc_list_start(channel->clients);
2028 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2029 if (chu->client == client_entry) {
2030 silc_list_del(channel->clients, chu);
2036 if (!silc_idcache_list_next(list, &id_cache))
2039 channel = (SilcChannelEntry)id_cache->context;
2042 silc_idcache_list_free(list);
2045 /* Replaces `old' client entries from all channels to `new' client entry.
2046 This can be called for example when nickname changes and old ID entry
2047 is replaced from ID cache with the new one. If the old ID entry is only
2048 updated, then this fucntion needs not to be called. */
2050 void silc_client_replace_from_channels(SilcClient client,
2051 SilcClientConnection conn,
2052 SilcClientEntry old,
2053 SilcClientEntry new)
2055 SilcIDCacheEntry id_cache;
2056 SilcIDCacheList list;
2057 SilcChannelEntry channel;
2058 SilcChannelUser chu;
2060 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2061 SILC_ID_CHANNEL, &list))
2064 silc_idcache_list_first(list, &id_cache);
2065 channel = (SilcChannelEntry)id_cache->context;
2069 /* Replace client entry */
2070 silc_list_start(channel->clients);
2071 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2072 if (chu->client == old) {
2078 if (!silc_idcache_list_next(list, &id_cache))
2081 channel = (SilcChannelEntry)id_cache->context;
2084 silc_idcache_list_free(list);
2087 /* Parses mode mask and returns the mode as string. */
2089 char *silc_client_chmode(unsigned int mode)
2096 memset(string, 0, sizeof(string));
2098 if (mode & SILC_CHANNEL_MODE_PRIVATE)
2099 strncat(string, "p", 1);
2101 if (mode & SILC_CHANNEL_MODE_SECRET)
2102 strncat(string, "s", 1);
2104 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
2105 strncat(string, "k", 1);
2107 if (mode & SILC_CHANNEL_MODE_INVITE)
2108 strncat(string, "i", 1);
2110 if (mode & SILC_CHANNEL_MODE_TOPIC)
2111 strncat(string, "t", 1);
2113 if (mode & SILC_CHANNEL_MODE_ULIMIT)
2114 strncat(string, "l", 1);
2116 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
2117 strncat(string, "a", 1);
2119 /* Rest of mode is ignored */
2121 return strdup(string);
2124 /* Parses channel user mode mask and returns te mode as string */
2126 char *silc_client_chumode(unsigned int mode)
2133 memset(string, 0, sizeof(string));
2135 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2136 strncat(string, "f", 1);
2138 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2139 strncat(string, "o", 1);
2141 return strdup(string);
2144 /* Parses channel user mode and returns it as special mode character. */
2146 char *silc_client_chumode_char(unsigned int mode)
2153 memset(string, 0, sizeof(string));
2155 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2156 strncat(string, "*", 1);
2158 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2159 strncat(string, "@", 1);
2161 return strdup(string);