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->ip = strdup(conn->remote_host);
275 conn->sock->port = conn->remote_port;
277 /* Allocate internal Key Exchange context. This is sent to the
278 protocol as context. */
279 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
280 proto_ctx->client = (void *)client;
281 proto_ctx->sock = conn->sock;
282 proto_ctx->rng = client->rng;
283 proto_ctx->responder = FALSE;
285 /* Perform key exchange protocol. silc_client_connect_to_server_final
286 will be called after the protocol is finished. */
287 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
288 &protocol, (void *)proto_ctx,
289 silc_client_connect_to_server_second);
291 client->ops->say(client, conn,
292 "Error: Could not start authentication protocol");
295 conn->sock->protocol = protocol;
297 /* Register the connection for network input and output. This sets
298 that scheduler will listen for incoming packets for this connection
299 and sets that outgoing packets may be sent to this connection as well.
300 However, this doesn't set the scheduler for outgoing traffic, it will
301 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
302 later when outgoing data is available. */
303 context = (void *)client;
304 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
306 /* Execute the protocol */
307 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
311 /* Start of the connection to the remote server. This is called after
312 succesful TCP/IP connection has been established to the remote host. */
314 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
316 SilcClientInternalConnectContext *ctx =
317 (SilcClientInternalConnectContext *)context;
318 SilcClient client = ctx->client;
319 SilcClientConnection conn = ctx->conn;
320 int opt, opt_len = sizeof(opt);
322 SILC_LOG_DEBUG(("Start"));
324 /* Check the socket status as it might be in error */
325 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
327 if (ctx->tries < 2) {
328 /* Connection failed but lets try again */
329 client->ops->say(client, conn, "Could not connect to server %s: %s",
330 ctx->host, strerror(opt));
331 client->ops->say(client, conn,
332 "Connecting to port %d of server %s resumed",
333 ctx->port, ctx->host);
335 /* Unregister old connection try */
336 silc_schedule_unset_listen_fd(fd);
337 silc_net_close_connection(fd);
338 silc_task_unregister(client->io_queue, ctx->task);
341 silc_client_connect_to_server_internal(ctx);
344 /* Connection failed and we won't try anymore */
345 client->ops->say(client, conn, "Could not connect to server %s: %s",
346 ctx->host, strerror(opt));
347 silc_schedule_unset_listen_fd(fd);
348 silc_net_close_connection(fd);
349 silc_task_unregister(client->io_queue, ctx->task);
352 /* Notify application of failure */
353 client->ops->connect(client, conn, FALSE);
354 silc_client_del_connection(client, conn);
359 silc_schedule_unset_listen_fd(fd);
360 silc_task_unregister(client->io_queue, ctx->task);
363 if (!silc_client_start_key_exchange(client, conn, fd)) {
364 silc_net_close_connection(fd);
365 client->ops->connect(client, conn, FALSE);
369 /* Second part of the connecting to the server. This executed
370 authentication protocol. */
372 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
374 SilcProtocol protocol = (SilcProtocol)context;
375 SilcClientKEInternalContext *ctx =
376 (SilcClientKEInternalContext *)protocol->context;
377 SilcClient client = (SilcClient)ctx->client;
378 SilcSocketConnection sock = NULL;
379 SilcClientConnAuthInternalContext *proto_ctx;
381 SILC_LOG_DEBUG(("Start"));
383 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
384 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
385 /* Error occured during protocol */
386 SILC_LOG_DEBUG(("Error during KE protocol"));
387 silc_protocol_free(protocol);
389 silc_ske_free(ctx->ske);
391 silc_free(ctx->dest_id);
392 ctx->sock->protocol = NULL;
394 /* Notify application of failure */
395 client->ops->connect(client, ctx->sock->user_data, FALSE);
400 /* Allocate internal context for the authentication protocol. This
401 is sent as context for the protocol. */
402 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
403 proto_ctx->client = (void *)client;
404 proto_ctx->sock = sock = ctx->sock;
405 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
406 proto_ctx->dest_id_type = ctx->dest_id_type;
407 proto_ctx->dest_id = ctx->dest_id;
409 /* Resolve the authentication method to be used in this connection */
410 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
411 sock->port, &proto_ctx->auth_meth,
412 &proto_ctx->auth_data,
413 &proto_ctx->auth_data_len))
415 /* XXX do AUTH_REQUEST resolcing with server */
416 proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
419 /* Free old protocol as it is finished now */
420 silc_protocol_free(protocol);
422 silc_packet_context_free(ctx->packet);
424 /* silc_free(ctx->keymat....); */
425 sock->protocol = NULL;
427 /* Allocate the authentication protocol. This is allocated here
428 but we won't start it yet. We will be receiving party of this
429 protocol thus we will wait that connecting party will make
431 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
432 &sock->protocol, (void *)proto_ctx,
433 silc_client_connect_to_server_final);
435 /* Execute the protocol */
436 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
439 /* Finalizes the connection to the remote SILC server. This is called
440 after authentication protocol has been completed. This send our
441 user information to the server to receive our client ID from
444 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
446 SilcProtocol protocol = (SilcProtocol)context;
447 SilcClientConnAuthInternalContext *ctx =
448 (SilcClientConnAuthInternalContext *)protocol->context;
449 SilcClient client = (SilcClient)ctx->client;
450 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
453 SILC_LOG_DEBUG(("Start"));
455 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
456 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
457 /* Error occured during protocol */
458 SILC_LOG_DEBUG(("Error during authentication protocol"));
459 silc_protocol_free(protocol);
461 silc_free(ctx->auth_data);
463 silc_ske_free(ctx->ske);
465 silc_free(ctx->dest_id);
466 conn->sock->protocol = NULL;
468 /* Notify application of failure */
469 client->ops->connect(client, ctx->sock->user_data, FALSE);
474 /* Send NEW_CLIENT packet to the server. We will become registered
475 to the SILC network after sending this packet and we will receive
476 client ID from the server. */
477 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
478 strlen(client->realname));
479 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
480 silc_buffer_format(packet,
481 SILC_STR_UI_SHORT(strlen(client->username)),
482 SILC_STR_UI_XNSTRING(client->username,
483 strlen(client->username)),
484 SILC_STR_UI_SHORT(strlen(client->realname)),
485 SILC_STR_UI_XNSTRING(client->realname,
486 strlen(client->realname)),
489 /* Send the packet */
490 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
492 packet->data, packet->len, TRUE);
493 silc_buffer_free(packet);
495 /* Save remote ID. */
496 conn->remote_id = ctx->dest_id;
497 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
498 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
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_len,
783 packet->src_id_type);
784 if (!proto_ctx->dest_id)
787 /* Let the protocol handle the packet */
788 sock->protocol->execute(client->timeout_queue, 0,
789 sock->protocol, sock->sock, 0, 0);
791 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
792 "protocol active, packet dropped."));
794 /* XXX Trigger KE protocol?? Rekey actually! */
798 case SILC_PACKET_KEY_EXCHANGE_1:
799 if (sock->protocol) {
802 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
803 "protocol active, packet dropped."));
806 case SILC_PACKET_KEY_EXCHANGE_2:
807 if (sock->protocol) {
808 SilcClientKEInternalContext *proto_ctx =
809 (SilcClientKEInternalContext *)sock->protocol->context;
811 if (proto_ctx->packet)
812 silc_packet_context_free(proto_ctx->packet);
814 proto_ctx->packet = silc_packet_context_dup(packet);
815 proto_ctx->dest_id_type = packet->src_id_type;
816 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
817 packet->src_id_type);
818 if (!proto_ctx->dest_id)
821 /* Let the protocol handle the packet */
822 sock->protocol->execute(client->timeout_queue, 0,
823 sock->protocol, sock->sock, 0, 0);
825 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
826 "protocol active, packet dropped."));
830 case SILC_PACKET_NEW_ID:
833 * Received new ID from server. This packet is received at
834 * the connection to the server. New ID is also received when
835 * user changes nickname but in that case the new ID is received
836 * as command reply and not as this packet type.
840 idp = silc_id_payload_parse(buffer);
843 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
846 silc_client_receive_new_id(client, sock, idp);
847 silc_id_payload_free(idp);
851 case SILC_PACKET_HEARTBEAT:
853 * Received heartbeat packet
855 SILC_LOG_DEBUG(("Heartbeat packet"));
859 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
864 /* Sends packet. This doesn't actually send the packet instead it assembles
865 it and marks it to be sent. However, if force_send is TRUE the packet
866 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
867 will be derived from sock argument. Otherwise the valid arguments sent
870 void silc_client_packet_send(SilcClient client,
871 SilcSocketConnection sock,
874 SilcIdType dst_id_type,
878 unsigned int data_len,
881 SilcPacketContext packetdata;
883 SILC_LOG_DEBUG(("Sending packet, type %d", type));
885 /* Get data used in the packet sending, keys and stuff */
886 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
887 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
888 cipher = ((SilcClientConnection)sock->user_data)->send_key;
890 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
891 hmac = ((SilcClientConnection)sock->user_data)->hmac;
893 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
894 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
895 dst_id_type = SILC_ID_SERVER;
899 /* Set the packet context pointers */
900 packetdata.flags = 0;
901 packetdata.type = type;
902 if (((SilcClientConnection)sock->user_data)->local_id_data)
903 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
905 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
906 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
907 packetdata.src_id_type = SILC_ID_CLIENT;
909 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
910 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
911 packetdata.dst_id_type = dst_id_type;
913 packetdata.dst_id = NULL;
914 packetdata.dst_id_len = 0;
915 packetdata.dst_id_type = SILC_ID_NONE;
917 packetdata.rng = client->rng;
918 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
919 packetdata.src_id_len + packetdata.dst_id_len;
920 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
922 /* Prepare outgoing data buffer for packet sending */
923 silc_packet_send_prepare(sock,
924 SILC_PACKET_HEADER_LEN +
925 packetdata.src_id_len +
926 packetdata.dst_id_len,
930 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
932 packetdata.buffer = sock->outbuf;
934 /* Put the data to the buffer */
935 if (data && data_len)
936 silc_buffer_put(sock->outbuf, data, data_len);
938 /* Create the outgoing packet */
939 silc_packet_assemble(&packetdata);
941 /* Encrypt the packet */
943 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
945 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
946 sock->outbuf->data, sock->outbuf->len);
948 /* Now actually send the packet */
949 silc_client_packet_send_real(client, sock, force_send);
952 /* Sends packet to a channel. Packet to channel is always encrypted
953 differently from "normal" packets. SILC header of the packet is
954 encrypted with the next receiver's key and the rest of the packet is
955 encrypted with the channel specific key. Padding and HMAC is computed
956 with the next receiver's key. */
958 void silc_client_packet_send_to_channel(SilcClient client,
959 SilcSocketConnection sock,
960 SilcChannelEntry channel,
962 unsigned int data_len,
966 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
968 SilcPacketContext packetdata;
971 unsigned char *id_string;
973 SILC_LOG_DEBUG(("Sending packet to channel"));
975 if (!channel || !channel->key) {
976 client->ops->say(client, conn,
977 "Cannot talk to channel: key does not exist");
983 for (i = 0; i < 16; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
985 silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
987 /* Encode the channel payload */
988 payload = silc_channel_payload_encode(data_len, data, 16, channel->iv,
991 client->ops->say(client, conn,
992 "Error: Could not create packet to be sent to channel");
996 /* Get data used in packet header encryption, keys and stuff. Rest
997 of the packet (the payload) is, however, encrypted with the
998 specified channel key. */
999 cipher = conn->send_key;
1001 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1003 /* Set the packet context pointers. The destination ID is always
1004 the Channel ID of the channel. Server and router will handle the
1005 distribution of the packet. */
1006 packetdata.flags = 0;
1007 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
1008 packetdata.src_id = conn->local_id_data;
1009 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1010 packetdata.src_id_type = SILC_ID_CLIENT;
1011 packetdata.dst_id = id_string;
1012 packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
1013 packetdata.dst_id_type = SILC_ID_CHANNEL;
1014 packetdata.rng = client->rng;
1015 packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
1016 packetdata.src_id_len + packetdata.dst_id_len;
1017 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1018 packetdata.src_id_len +
1019 packetdata.dst_id_len));
1021 /* Prepare outgoing data buffer for packet sending */
1022 silc_packet_send_prepare(sock,
1023 SILC_PACKET_HEADER_LEN +
1024 packetdata.src_id_len +
1025 packetdata.dst_id_len,
1029 packetdata.buffer = sock->outbuf;
1031 /* Encrypt payload of the packet. This is encrypted with the channel key. */
1032 channel->channel_key->cipher->encrypt(channel->channel_key->context,
1033 payload->data, payload->data,
1034 payload->len - 16, /* -IV_LEN */
1037 /* Put the actual encrypted payload data into the buffer. */
1038 silc_buffer_put(sock->outbuf, payload->data, payload->len);
1040 /* Create the outgoing packet */
1041 silc_packet_assemble(&packetdata);
1043 /* Encrypt the header and padding of the packet. This is encrypted
1044 with normal session key shared with our server. */
1045 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1046 packetdata.src_id_len + packetdata.dst_id_len +
1049 SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1050 sock->outbuf->data, sock->outbuf->len);
1052 /* Now actually send the packet */
1053 silc_client_packet_send_real(client, sock, force_send);
1054 silc_buffer_free(payload);
1055 silc_free(id_string);
1058 /* Sends private message to remote client. If private message key has
1059 not been set with this client then the message will be encrypted using
1060 normal session keys. Private messages are special packets in SILC
1061 network hence we need this own function for them. This is similiar
1062 to silc_client_packet_send_to_channel except that we send private
1065 void silc_client_packet_send_private_message(SilcClient client,
1066 SilcSocketConnection sock,
1067 SilcClientEntry client_entry,
1068 unsigned char *data,
1069 unsigned int data_len,
1072 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1074 SilcPacketContext packetdata;
1075 unsigned int nick_len;
1079 SILC_LOG_DEBUG(("Sending private message"));
1081 /* Create private message payload */
1082 nick_len = strlen(conn->nickname);
1083 buffer = silc_buffer_alloc(2 + nick_len + data_len);
1084 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1085 silc_buffer_format(buffer,
1086 SILC_STR_UI_SHORT(nick_len),
1087 SILC_STR_UI_XNSTRING(conn->nickname,
1089 SILC_STR_UI_XNSTRING(data, data_len),
1092 /* If we don't have private message specific key then private messages
1093 are just as any normal packet thus call normal packet sending. If
1094 the key exist then the encryption process is a bit different and
1095 will be done in the rest of this function. */
1096 if (!client_entry->send_key) {
1097 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1098 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1099 buffer->data, buffer->len, force_send);
1103 /* We have private message specific key */
1105 /* Get data used in the encryption */
1106 cipher = client_entry->send_key;
1109 /* Set the packet context pointers. */
1110 packetdata.flags = 0;
1111 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1112 packetdata.src_id = conn->local_id_data;
1113 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1114 packetdata.src_id_type = SILC_ID_CLIENT;
1116 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1118 packetdata.dst_id = conn->local_id_data;
1119 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1120 packetdata.dst_id_type = SILC_ID_CLIENT;
1121 packetdata.rng = client->rng;
1122 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
1123 packetdata.src_id_len + packetdata.dst_id_len;
1124 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1125 packetdata.src_id_len +
1126 packetdata.dst_id_len));
1128 /* Prepare outgoing data buffer for packet sending */
1129 silc_packet_send_prepare(sock,
1130 SILC_PACKET_HEADER_LEN +
1131 packetdata.src_id_len +
1132 packetdata.dst_id_len,
1136 packetdata.buffer = sock->outbuf;
1138 /* Encrypt payload of the packet. Encrypt with private message specific
1139 key if it exist, otherwise with session key. */
1140 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1141 buffer->len, cipher->iv);
1143 /* Put the actual encrypted payload data into the buffer. */
1144 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1146 /* Create the outgoing packet */
1147 silc_packet_assemble(&packetdata);
1149 /* Encrypt the header and padding of the packet. */
1150 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1151 packetdata.src_id_len + packetdata.dst_id_len +
1154 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1155 sock->outbuf->data, sock->outbuf->len);
1157 /* Now actually send the packet */
1158 silc_client_packet_send_real(client, sock, force_send);
1159 silc_free(packetdata.dst_id);
1165 /* Closes connection to remote end. Free's all allocated data except
1166 for some information such as nickname etc. that are valid at all time. */
1168 void silc_client_close_connection(SilcClient client,
1169 SilcSocketConnection sock)
1171 SilcClientConnection conn;
1173 /* We won't listen for this connection anymore */
1174 silc_schedule_unset_listen_fd(sock->sock);
1176 /* Unregister all tasks */
1177 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1178 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1180 /* Close the actual connection */
1181 silc_net_close_connection(sock->sock);
1183 client->ops->say(client, sock->user_data,
1184 "Closed connection to host %s", sock->hostname);
1186 /* Free everything */
1187 if (sock->user_data) {
1188 conn = (SilcClientConnection)sock->user_data;
1190 /* XXX Free all client entries and channel entries. */
1192 /* Clear ID caches */
1193 silc_idcache_del_all(conn->client_cache);
1194 silc_idcache_del_all(conn->channel_cache);
1197 if (conn->remote_host)
1198 silc_free(conn->remote_host);
1200 silc_free(conn->local_id);
1201 if (conn->local_id_data)
1202 silc_free(conn->local_id_data);
1204 silc_cipher_free(conn->send_key);
1205 if (conn->receive_key)
1206 silc_cipher_free(conn->receive_key);
1208 silc_hmac_free(conn->hmac);
1209 if (conn->hmac_key) {
1210 memset(conn->hmac_key, 0, conn->hmac_key_len);
1211 silc_free(conn->hmac_key);
1213 if (conn->pending_commands)
1214 silc_dlist_uninit(conn->pending_commands);
1217 conn->remote_port = 0;
1218 conn->remote_type = 0;
1219 conn->send_key = NULL;
1220 conn->receive_key = NULL;
1222 conn->hmac_key = NULL;
1223 conn->hmac_key_len = 0;
1224 conn->local_id = NULL;
1225 conn->local_id_data = NULL;
1226 conn->remote_host = NULL;
1227 conn->current_channel = NULL;
1228 conn->pending_commands = NULL;
1230 silc_client_del_connection(client, conn);
1233 if (sock->protocol) {
1234 silc_protocol_free(sock->protocol);
1235 sock->protocol = NULL;
1237 silc_socket_free(sock);
1240 /* Called when we receive disconnection packet from server. This
1241 closes our end properly and displays the reason of the disconnection
1244 void silc_client_disconnected_by_server(SilcClient client,
1245 SilcSocketConnection sock,
1250 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1252 msg = silc_calloc(message->len + 1, sizeof(char));
1253 memcpy(msg, message->data, message->len);
1254 client->ops->say(client, sock->user_data, msg);
1257 SILC_SET_DISCONNECTED(sock);
1258 silc_client_close_connection(client, sock);
1261 /* Received error message from server. Display it on the screen.
1262 We don't take any action what so ever of the error message. */
1264 void silc_client_error_by_server(SilcClient client,
1265 SilcSocketConnection sock,
1270 msg = silc_calloc(message->len + 1, sizeof(char));
1271 memcpy(msg, message->data, message->len);
1272 client->ops->say(client, sock->user_data, msg);
1276 /* Called when notify is received and some async operation (such as command)
1277 is required before processing the notify message. This calls again the
1278 silc_client_notify_by_server and reprocesses the original notify packet. */
1280 static void silc_client_notify_by_server_pending(void *context)
1282 SilcPacketContext *p = (SilcPacketContext *)context;
1283 silc_client_notify_by_server(p->context, p->sock, p);
1286 /* Destructor for the pending command callback */
1288 static void silc_client_notify_by_server_destructor(void *context)
1290 silc_packet_context_free((SilcPacketContext *)context);
1293 /* Resolve client information from server by Client ID. */
1295 static void silc_client_notify_by_server_resolve(SilcClient client,
1296 SilcClientConnection conn,
1297 SilcPacketContext *packet,
1298 SilcClientID *client_id)
1300 SilcPacketContext *p = silc_packet_context_dup(packet);
1301 SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1303 p->context = (void *)client;
1304 p->sock = conn->sock;
1306 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
1307 1, 3, idp->data, idp->len);
1308 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1309 silc_client_notify_by_server_destructor,
1310 silc_client_notify_by_server_pending, p);
1311 silc_buffer_free(idp);
1314 /* Received notify message from server */
1316 void silc_client_notify_by_server(SilcClient client,
1317 SilcSocketConnection sock,
1318 SilcPacketContext *packet)
1320 SilcBuffer buffer = packet->buffer;
1321 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1322 SilcNotifyPayload payload;
1323 SilcNotifyType type;
1324 SilcArgumentPayload args;
1326 SilcClientID *client_id = NULL;
1327 SilcChannelID *channel_id = NULL;
1328 SilcClientEntry client_entry;
1329 SilcClientEntry client_entry2;
1330 SilcChannelEntry channel;
1331 SilcChannelUser chu;
1332 SilcIDCacheEntry id_cache = NULL;
1334 unsigned int tmp_len, mode;
1336 payload = silc_notify_payload_parse(buffer);
1340 type = silc_notify_get_type(payload);
1341 args = silc_notify_get_args(payload);
1346 case SILC_NOTIFY_TYPE_NONE:
1347 /* Notify application */
1348 client->ops->notify(client, conn, type,
1349 silc_argument_get_arg_type(args, 1, NULL));
1352 case SILC_NOTIFY_TYPE_INVITE:
1354 * Someone invited me to a channel. Find Client and Channel entries
1355 * for the application.
1359 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1363 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);
1369 if (!client_entry) {
1370 silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1374 /* Get Channel ID */
1375 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1379 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1383 /* XXX Will ALWAYS fail because currently we don't have way to resolve
1384 channel information for channel that we're not joined to. */
1385 /* XXX ways to fix: use (extended) LIST command, or define the channel
1386 name to the notfy type when name resolving is not mandatory. */
1387 /* Find channel entry */
1388 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1389 SILC_ID_CHANNEL, &id_cache))
1392 channel = (SilcChannelEntry)id_cache->context;
1394 /* Notify application */
1395 client->ops->notify(client, conn, type, client_entry, channel);
1398 case SILC_NOTIFY_TYPE_JOIN:
1400 * Someone has joined to a channel. Get their ID and nickname and
1401 * cache them for later use.
1405 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1409 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1413 /* Find Client entry and if not found query it */
1414 client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
1415 if (!client_entry) {
1416 silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1420 /* If nickname or username hasn't been resolved, do so */
1421 if (!client_entry->nickname || !client_entry->username) {
1422 silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1426 /* Get channel entry */
1427 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1431 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1432 SILC_ID_CHANNEL, &id_cache))
1435 channel = (SilcChannelEntry)id_cache->context;
1437 /* Add client to channel */
1438 chu = silc_calloc(1, sizeof(*chu));
1439 chu->client = client_entry;
1440 silc_list_add(channel->clients, chu);
1442 /* XXX add support for multiple same nicks on same channel. Check
1445 /* Notify application. The channel entry is sent last as this notify
1446 is for channel but application don't know it from the arguments
1448 client->ops->notify(client, conn, type, client_entry, channel);
1451 case SILC_NOTIFY_TYPE_LEAVE:
1453 * Someone has left a channel. We will remove it from the channel but
1454 * we'll keep it in the cache in case we'll need it later.
1458 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1462 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1466 /* Find Client entry */
1468 silc_idlist_get_client_by_id(client, conn, client_id);
1472 /* Get channel entry */
1473 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1477 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1478 SILC_ID_CHANNEL, &id_cache))
1481 channel = (SilcChannelEntry)id_cache->context;
1483 /* Remove client from channel */
1484 silc_list_start(channel->clients);
1485 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1486 if (chu->client == client_entry) {
1487 silc_list_del(channel->clients, chu);
1493 /* Notify application. The channel entry is sent last as this notify
1494 is for channel but application don't know it from the arguments
1496 client->ops->notify(client, conn, type, client_entry, channel);
1499 case SILC_NOTIFY_TYPE_SIGNOFF:
1501 * Someone left SILC. We'll remove it from all channels and from cache.
1505 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1509 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1513 /* Find Client entry */
1515 silc_idlist_get_client_by_id(client, conn, client_id);
1519 /* Remove from all channels */
1520 silc_client_remove_from_channels(client, conn, client_entry);
1522 /* Remove from cache */
1523 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1526 /* Notify application */
1527 client->ops->notify(client, conn, type, client_entry);
1530 if (client_entry->nickname)
1531 silc_free(client_entry->nickname);
1532 if (client_entry->server)
1533 silc_free(client_entry->server);
1534 if (client_entry->id)
1535 silc_free(client_entry->id);
1536 if (client_entry->send_key)
1537 silc_cipher_free(client_entry->send_key);
1538 if (client_entry->receive_key)
1539 silc_cipher_free(client_entry->receive_key);
1542 case SILC_NOTIFY_TYPE_TOPIC_SET:
1544 * Someone set the topic on a channel.
1548 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1552 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1556 /* Find Client entry */
1558 silc_idlist_get_client_by_id(client, conn, client_id);
1563 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1567 /* Get channel entry */
1568 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1572 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1573 SILC_ID_CHANNEL, &id_cache))
1576 channel = (SilcChannelEntry)id_cache->context;
1578 /* Notify application. The channel entry is sent last as this notify
1579 is for channel but application don't know it from the arguments
1581 client->ops->notify(client, conn, type, client_entry, tmp, channel);
1584 case SILC_NOTIFY_TYPE_NICK_CHANGE:
1586 * Someone changed their nickname. If we don't have entry for the new
1587 * ID we will query it and return here after it's done. After we've
1588 * returned we fetch the old entry and free it and notify the
1592 /* Get new Client ID */
1593 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1597 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1602 if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
1605 /* Find Client entry and if not found query it */
1607 silc_idlist_get_client_by_id(client, conn, client_id);
1608 if (!client_entry2) {
1609 silc_client_notify_by_server_resolve(client, conn, packet, client_id);
1612 silc_free(client_id);
1614 /* Get old Client ID */
1615 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1619 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1623 /* Find old Client entry */
1625 silc_idlist_get_client_by_id(client, conn, client_id);
1629 /* Remove the old from cache */
1630 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
1633 /* Replace old ID entry with new one on all channels. */
1634 silc_client_replace_from_channels(client, conn, client_entry,
1637 /* Notify application */
1638 client->ops->notify(client, conn, type, client_entry, client_entry2);
1641 if (client_entry->nickname)
1642 silc_free(client_entry->nickname);
1643 if (client_entry->server)
1644 silc_free(client_entry->server);
1645 if (client_entry->id)
1646 silc_free(client_entry->id);
1647 if (client_entry->send_key)
1648 silc_cipher_free(client_entry->send_key);
1649 if (client_entry->receive_key)
1650 silc_cipher_free(client_entry->receive_key);
1653 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1655 * Someone changed a channel mode
1659 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1663 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1667 /* Find Client entry */
1669 silc_idlist_get_client_by_id(client, conn, client_id);
1674 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1678 SILC_GET32_MSB(mode, tmp);
1680 /* Get channel entry */
1681 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1685 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1686 SILC_ID_CHANNEL, &id_cache))
1689 channel = (SilcChannelEntry)id_cache->context;
1691 /* Save the new mode */
1692 channel->mode = mode;
1694 /* Notify application. The channel entry is sent last as this notify
1695 is for channel but application don't know it from the arguments
1697 client->ops->notify(client, conn, type, client_entry, mode, channel);
1700 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1702 * Someone changed user's mode on a channel
1706 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1710 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1714 /* Find Client entry */
1716 silc_idlist_get_client_by_id(client, conn, client_id);
1721 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1725 SILC_GET32_MSB(mode, tmp);
1727 /* Get target Client ID */
1728 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1732 silc_free(client_id);
1733 client_id = silc_id_payload_parse_id(tmp, tmp_len);
1737 /* Find target Client entry */
1739 silc_idlist_get_client_by_id(client, conn, client_id);
1743 /* Get channel entry */
1744 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1748 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1749 SILC_ID_CHANNEL, &id_cache))
1752 channel = (SilcChannelEntry)id_cache->context;
1755 silc_list_start(channel->clients);
1756 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1757 if (chu->client == client_entry) {
1763 /* Notify application. The channel entry is sent last as this notify
1764 is for channel but application don't know it from the arguments
1766 client->ops->notify(client, conn, type, client_entry, mode,
1767 client_entry2, channel);
1770 case SILC_NOTIFY_TYPE_MOTD:
1772 * Received Message of the day
1776 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1780 /* Notify application */
1781 client->ops->notify(client, conn, type, tmp);
1784 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1786 * Router has enforced a new ID to a channel. Let's change the old
1787 * ID to the one provided here.
1790 /* Get the old ID */
1791 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1794 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1798 /* Get the channel entry */
1799 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1800 SILC_ID_CHANNEL, &id_cache))
1803 channel = (SilcChannelEntry)id_cache->context;
1805 /* Free the old ID */
1806 silc_free(channel_id);
1807 silc_free(channel->id);
1809 /* Get the new ID */
1810 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1813 channel->id = silc_id_payload_parse_id(tmp, tmp_len);
1817 id_cache->id = (void *)channel->id;
1819 /* Notify application */
1820 client->ops->notify(client, conn, type, channel, channel);
1828 silc_notify_payload_free(payload);
1830 silc_free(client_id);
1832 silc_free(channel_id);
1835 /* Processes the received new Client ID from server. Old Client ID is
1836 deleted from cache and new one is added. */
1838 void silc_client_receive_new_id(SilcClient client,
1839 SilcSocketConnection sock,
1842 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1843 int connecting = FALSE;
1845 if (!conn->local_entry)
1848 /* Delete old ID from ID cache */
1849 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1851 /* Save the new ID */
1853 silc_free(conn->local_id);
1854 if (conn->local_id_data)
1855 silc_free(conn->local_id_data);
1857 conn->local_id = silc_id_payload_get_id(idp);
1858 conn->local_id_data = silc_id_payload_get_data(idp);
1859 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1861 if (!conn->local_entry)
1862 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1864 conn->local_entry->nickname = conn->nickname;
1865 if (!conn->local_entry->username) {
1866 conn->local_entry->username =
1867 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1868 sizeof(conn->local_entry->username));
1869 sprintf(conn->local_entry->username, "%s@%s", client->username,
1872 conn->local_entry->server = strdup(conn->remote_host);
1873 conn->local_entry->id = conn->local_id;
1875 /* Put it to the ID cache */
1876 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1877 conn->local_id, (void *)conn->local_entry, TRUE);
1879 /* Notify application of successful connection. We do it here now that
1880 we've received the Client ID and are allowed to send traffic. */
1882 client->ops->connect(client, conn, TRUE);
1885 /* Processed received Channel ID for a channel. This is called when client
1886 joins to channel and server replies with channel ID. The ID is cached. */
1888 void silc_client_new_channel_id(SilcClient client,
1889 SilcSocketConnection sock,
1891 unsigned int mode, SilcIDPayload idp)
1893 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1894 SilcChannelEntry channel;
1896 SILC_LOG_DEBUG(("New channel ID"));
1898 channel = silc_calloc(1, sizeof(*channel));
1899 channel->channel_name = channel_name;
1900 channel->id = silc_id_payload_get_id(idp);
1901 channel->mode = mode;
1902 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1904 conn->current_channel = channel;
1906 /* Put it to the ID cache */
1907 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1908 (void *)channel->id, (void *)channel, TRUE);
1911 /* Saves channel key from encoded `key_payload'. This is used when we
1912 receive Channel Key Payload and when we are processing JOIN command
1915 void silc_client_save_channel_key(SilcClientConnection conn,
1916 SilcBuffer key_payload,
1917 SilcChannelEntry channel)
1919 unsigned char *id_string, *key, *cipher;
1920 unsigned int tmp_len;
1922 SilcIDCacheEntry id_cache = NULL;
1923 SilcChannelKeyPayload payload;
1925 payload = silc_channel_key_payload_parse(key_payload);
1929 id_string = silc_channel_key_get_id(payload, &tmp_len);
1931 silc_channel_key_payload_free(payload);
1935 id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
1937 silc_channel_key_payload_free(payload);
1943 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1944 SILC_ID_CHANNEL, &id_cache))
1947 /* Get channel entry */
1948 channel = (SilcChannelEntry)id_cache->context;
1952 key = silc_channel_key_get_key(payload, &tmp_len);
1953 cipher = silc_channel_key_get_cipher(payload, NULL);
1954 channel->key_len = tmp_len;
1955 channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
1956 memcpy(channel->key, key, tmp_len);
1958 if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
1959 conn->client->ops->say(conn->client, conn,
1960 "Cannot talk to channel: unsupported cipher %s", cipher);
1963 channel->channel_key->cipher->set_key(channel->channel_key->context,
1966 /* Client is now joined to the channel */
1967 channel->on_channel = TRUE;
1971 silc_channel_key_payload_free(payload);
1974 /* Processes received key for channel. The received key will be used
1975 to protect the traffic on the channel for now on. Client must receive
1976 the key to the channel before talking on the channel is possible.
1977 This is the key that server has generated, this is not the channel
1978 private key, it is entirely local setting. */
1980 void silc_client_receive_channel_key(SilcClient client,
1981 SilcSocketConnection sock,
1984 SILC_LOG_DEBUG(("Received key for channel"));
1987 silc_client_save_channel_key(sock->user_data, packet, NULL);
1990 /* Process received message to a channel (or from a channel, really). This
1991 decrypts the channel message with channel specific key and parses the
1992 channel payload. Finally it displays the message on the screen. */
1994 void silc_client_channel_message(SilcClient client,
1995 SilcSocketConnection sock,
1996 SilcPacketContext *packet)
1998 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1999 SilcBuffer buffer = packet->buffer;
2000 SilcChannelPayload payload = NULL;
2001 SilcChannelID *id = NULL;
2002 SilcChannelEntry channel;
2003 SilcChannelUser chu;
2004 SilcIDCacheEntry id_cache = NULL;
2005 SilcClientID *client_id = NULL;
2009 if (packet->dst_id_type != SILC_ID_CHANNEL)
2012 client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
2016 id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
2020 /* Find the channel entry from channels on this connection */
2021 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
2022 SILC_ID_CHANNEL, &id_cache))
2025 channel = (SilcChannelEntry)id_cache->context;
2027 /* Decrypt the channel message payload. Push the IV out of the way,
2028 since it is not encrypted (after pushing buffer->tail has the IV). */
2029 silc_buffer_push_tail(buffer, 16);
2030 channel->channel_key->cipher->decrypt(channel->channel_key->context,
2031 buffer->data, buffer->data,
2032 buffer->len, buffer->tail);
2033 silc_buffer_pull_tail(buffer, 16);
2035 /* Parse the channel message payload */
2036 payload = silc_channel_payload_parse(buffer);
2040 /* Find client entry */
2041 silc_list_start(channel->clients);
2042 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2043 if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
2049 /* Pass the message to application */
2050 client->ops->channel_message(client, conn, found ? chu->client : NULL,
2051 channel, silc_channel_get_data(payload, NULL));
2057 silc_free(client_id);
2059 silc_channel_payload_free(payload);
2062 /* Private message received. This processes the private message and
2063 finally displays it on the screen. */
2065 void silc_client_private_message(SilcClient client,
2066 SilcSocketConnection sock,
2067 SilcPacketContext *packet)
2069 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
2070 SilcBuffer buffer = packet->buffer;
2071 SilcIDCacheEntry id_cache;
2072 SilcClientID *remote_id = NULL;
2073 SilcClientEntry remote_client;
2074 unsigned short nick_len;
2075 unsigned char *nickname, *message = NULL;
2078 if (packet->src_id_type != SILC_ID_CLIENT)
2082 ret = silc_buffer_unformat(buffer,
2083 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
2088 silc_buffer_pull(buffer, 2 + nick_len);
2090 message = silc_calloc(buffer->len + 1, sizeof(char));
2091 memcpy(message, buffer->data, buffer->len);
2093 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
2098 /* Check whether we know this client already */
2099 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
2100 SILC_ID_CLIENT, &id_cache))
2102 /* Allocate client entry */
2103 remote_client = silc_calloc(1, sizeof(*remote_client));
2104 remote_client->id = remote_id;
2105 silc_parse_nickname(nickname, &remote_client->nickname,
2106 &remote_client->server, &remote_client->num);
2108 /* Save the client to cache */
2109 silc_idcache_add(conn->client_cache, remote_client->nickname,
2110 SILC_ID_CLIENT, remote_client->id, remote_client,
2113 remote_client = (SilcClientEntry)id_cache->context;
2116 /* Pass the private message to application */
2117 client->ops->private_message(client, conn, remote_client, message);
2119 /* See if we are away (gone). If we are away we will reply to the
2120 sender with the set away message. */
2121 if (conn->away && conn->away->away) {
2122 /* If it's me, ignore */
2123 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
2126 /* Send the away message */
2127 silc_client_packet_send_private_message(client, sock, remote_client,
2129 strlen(conn->away->away), TRUE);
2134 silc_free(remote_id);
2137 memset(message, 0, buffer->len);
2140 silc_free(nickname);
2143 /* Removes a client entry from all channel it has joined. This really is
2144 a performance killer (client_entry should have pointers to channel
2147 void silc_client_remove_from_channels(SilcClient client,
2148 SilcClientConnection conn,
2149 SilcClientEntry client_entry)
2151 SilcIDCacheEntry id_cache;
2152 SilcIDCacheList list;
2153 SilcChannelEntry channel;
2154 SilcChannelUser chu;
2156 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2157 SILC_ID_CHANNEL, &list))
2160 silc_idcache_list_first(list, &id_cache);
2161 channel = (SilcChannelEntry)id_cache->context;
2165 /* Remove client from channel */
2166 silc_list_start(channel->clients);
2167 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2168 if (chu->client == client_entry) {
2169 silc_list_del(channel->clients, chu);
2175 if (!silc_idcache_list_next(list, &id_cache))
2178 channel = (SilcChannelEntry)id_cache->context;
2181 silc_idcache_list_free(list);
2184 /* Replaces `old' client entries from all channels to `new' client entry.
2185 This can be called for example when nickname changes and old ID entry
2186 is replaced from ID cache with the new one. If the old ID entry is only
2187 updated, then this fucntion needs not to be called. */
2189 void silc_client_replace_from_channels(SilcClient client,
2190 SilcClientConnection conn,
2191 SilcClientEntry old,
2192 SilcClientEntry new)
2194 SilcIDCacheEntry id_cache;
2195 SilcIDCacheList list;
2196 SilcChannelEntry channel;
2197 SilcChannelUser chu;
2199 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
2200 SILC_ID_CHANNEL, &list))
2203 silc_idcache_list_first(list, &id_cache);
2204 channel = (SilcChannelEntry)id_cache->context;
2208 /* Replace client entry */
2209 silc_list_start(channel->clients);
2210 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
2211 if (chu->client == old) {
2217 if (!silc_idcache_list_next(list, &id_cache))
2220 channel = (SilcChannelEntry)id_cache->context;
2223 silc_idcache_list_free(list);
2226 /* Parses mode mask and returns the mode as string. */
2228 char *silc_client_chmode(unsigned int mode)
2235 memset(string, 0, sizeof(string));
2237 if (mode & SILC_CHANNEL_MODE_PRIVATE)
2238 strncat(string, "p", 1);
2240 if (mode & SILC_CHANNEL_MODE_SECRET)
2241 strncat(string, "s", 1);
2243 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
2244 strncat(string, "k", 1);
2246 if (mode & SILC_CHANNEL_MODE_INVITE)
2247 strncat(string, "i", 1);
2249 if (mode & SILC_CHANNEL_MODE_TOPIC)
2250 strncat(string, "t", 1);
2252 if (mode & SILC_CHANNEL_MODE_ULIMIT)
2253 strncat(string, "l", 1);
2255 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
2256 strncat(string, "a", 1);
2258 /* Rest of mode is ignored */
2260 return strdup(string);
2263 /* Parses channel user mode mask and returns te mode as string */
2265 char *silc_client_chumode(unsigned int mode)
2272 memset(string, 0, sizeof(string));
2274 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2275 strncat(string, "f", 1);
2277 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2278 strncat(string, "o", 1);
2280 return strdup(string);
2283 /* Parses channel user mode and returns it as special mode character. */
2285 char *silc_client_chumode_char(unsigned int mode)
2292 memset(string, 0, sizeof(string));
2294 if (mode & SILC_CHANNEL_UMODE_CHANFO)
2295 strncat(string, "*", 1);
2297 if (mode & SILC_CHANNEL_UMODE_CHANOP)
2298 strncat(string, "@", 1);
2300 return strdup(string);