/************************** Private Message Send ****************************/
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcClientEntry client_entry;
+} *SilcClientPrvmsgContext;
+
+/* Message payload encoding callback */
+
+static void silc_client_send_private_message_final(SilcBuffer message,
+ void *context)
+{
+ SilcClientPrvmsgContext p = context;
+
+ /* Send the private message packet */
+ if (message)
+ silc_packet_send_ext(p->conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
+ p->client_entry->internal.send_key ?
+ SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
+ 0, NULL, SILC_ID_CLIENT, &p->client_entry->id,
+ silc_buffer_datalen(message), NULL, NULL);
+
+ silc_client_unref_client(p->client, p->conn, p->client_entry);
+ silc_free(p);
+}
+
/* Sends private message to remote client. */
SilcBool silc_client_send_private_message(SilcClient client,
unsigned char *data,
SilcUInt32 data_len)
{
- SilcBuffer buffer;
- SilcBool ret;
+ SilcClientPrvmsgContext p;
+ SilcID sid, rid;
if (silc_unlikely(!client || !conn || !client_entry))
return FALSE;
- if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
+ if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) {
+ SILC_LOG_ERROR(("Cannot send signed message without hash, missing "
+ "arguments"));
return FALSE;
+ }
if (silc_unlikely(conn->internal->disconnected))
return FALSE;
SILC_LOG_DEBUG(("Sending private message"));
- /* Encode private message payload */
- buffer =
- silc_message_payload_encode(flags, data, data_len,
- (!client_entry->internal.send_key ? FALSE :
- !client_entry->internal.generated),
- TRUE, client_entry->internal.send_key,
- client_entry->internal.hmac_send,
- client->rng, NULL, conn->private_key,
- hash, NULL);
- if (silc_unlikely(!buffer)) {
- SILC_LOG_ERROR(("Error encoding private message"));
+ sid.type = SILC_ID_CLIENT;
+ sid.u.client_id = conn->local_entry->id;
+ rid.type = SILC_ID_CLIENT;
+ rid.u.client_id = client_entry->id;
+
+ p = silc_calloc(1, sizeof(*p));
+ if (!p)
return FALSE;
- }
- /* Send the private message packet */
- ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
- client_entry->internal.send_key ?
- SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
- 0, NULL, SILC_ID_CLIENT, &client_entry->id,
- silc_buffer_datalen(buffer), NULL, NULL);
+ p->client = client;
+ p->conn = conn;
+ p->client_entry = silc_client_ref_client(client, conn, client_entry);
- silc_buffer_free(buffer);
- return ret;
+ /* Encode private message payload */
+ silc_message_payload_encode(flags, data, data_len,
+ (!client_entry->internal.send_key ? FALSE :
+ !client_entry->internal.generated),
+ TRUE, client_entry->internal.send_key,
+ client_entry->internal.hmac_send,
+ client->rng, NULL, conn->private_key,
+ hash, &sid, &rid, NULL,
+ silc_client_send_private_message_final, p);
+
+ return TRUE;
}
/************************* Private Message Receive **************************/
TRUE, !remote_client->internal.generated,
remote_client->internal.receive_key,
remote_client->internal.hmac_receive,
+ packet->src_id, packet->src_id_len,
+ packet->dst_id, packet->dst_id_len,
NULL, FALSE, NULL);
if (silc_unlikely(!payload))
goto out;
/* See if we are away (gone). If we are away we will reply to the
sender with the set away message. */
- if (conn->internal->away && conn->internal->away->away &&
+ if (conn->internal->away_message &&
!(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
/* If it's me, ignore */
if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
silc_client_send_private_message(client, conn, remote_client,
SILC_MESSAGE_FLAG_AUTOREPLY |
SILC_MESSAGE_FLAG_NOREPLY, NULL,
- conn->internal->away->away,
- strlen(conn->internal->away->away));
+ conn->internal->away_message,
+ strlen(conn->internal->away_message));
}
out:
return SILC_FSM_FINISH;
}
+/* Initialize private message waiter for the `conn' connection. */
+
+SilcBool silc_client_private_message_wait_init(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SilcID id;
+
+ if (client_entry->internal.prv_waiter)
+ return TRUE;
+
+ /* We want SILC_PACKET_PRIVATE_MESSAGE packets from this source ID. */
+ id.type = SILC_ID_CLIENT;
+ id.u.client_id = client_entry->id;
+
+ client_entry->internal.prv_waiter =
+ silc_packet_wait_init(conn->stream, &id, SILC_PACKET_PRIVATE_MESSAGE, -1);
+ if (!client_entry->internal.prv_waiter)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Uninitializes private message waiter. */
+
+void silc_client_private_message_wait_uninit(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ if (!client_entry->internal.prv_waiter)
+ return;
+ silc_packet_wait_uninit(client_entry->internal.prv_waiter, conn->stream);
+ client_entry->internal.prv_waiter = NULL;
+}
+
/* Blocks the calling process or thread until private message has been
received from the specified client. */
-SilcBool silc_client_private_message_wait(SilcClientConnection conn,
+SilcBool silc_client_private_message_wait(SilcClient client,
+ SilcClientConnection conn,
SilcClientEntry client_entry,
- void *waiter,
SilcMessagePayload *payload)
{
SilcPacket packet;
- SilcClientID remote_id;
- SilcFSMThread thread;
+
+ if (!client_entry->internal.prv_waiter)
+ return FALSE;
/* Block until private message arrives */
do {
- if ((silc_packet_wait(waiter, 0, &packet)) < 0)
+ if ((silc_packet_wait(client_entry->internal.prv_waiter, 0, &packet)) < 0)
return FALSE;
- /* Parse sender ID */
- if (!silc_id_str2id(packet->src_id, packet->src_id_len,
- SILC_ID_CLIENT, &remote_id,
- sizeof(remote_id))) {
- silc_packet_free(packet);
- continue;
- }
-
- /* If the private message is not for the requested client, pass it to
- normal private message processing. */
- if (!SILC_ID_CLIENT_COMPARE(&remote_id, &client_entry->id)) {
- thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
- silc_client_fsm_destructor, NULL, FALSE);
- if (!thread) {
- silc_packet_free(packet);
- continue;
- }
-
- /* The packet will be processed in the connection thread, after this
- FSM thread is started. */
- silc_fsm_set_state_context(thread, packet);
- silc_fsm_start(thread, silc_client_private_message);
- continue;
- }
-
/* Parse the payload and decrypt it also if private message key is set */
*payload =
silc_message_payload_parse(silc_buffer_data(&packet->buffer),
TRUE, !client_entry->internal.generated,
client_entry->internal.receive_key,
client_entry->internal.hmac_receive,
+ packet->src_id, packet->src_id_len,
+ packet->dst_id, packet->dst_id_len,
NULL, FALSE, NULL);
if (!(*payload)) {
silc_packet_free(packet);
SilcDList clients,
void *context)
{
- SilcPacket packet = context;
+ SilcFSMThread thread = context;
+ SilcPacket packet = silc_fsm_get_state_context(thread);
unsigned char *cipher = NULL, *hmac = NULL;
SilcClientEntry client_entry;
int ret;
if (!clients) {
silc_packet_free(packet);
+ silc_fsm_finish(thread);
return;
}
silc_free(cipher);
silc_free(hmac);
silc_packet_free(packet);
+ silc_fsm_finish(thread);
}
/* Processes incoming Private Message Key payload to indicate that the
silc_free(keys);
}
+/* Return private message key from the client entry. */
+
+SilcBool
+silc_client_private_message_key_is_set(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ return client_entry->internal.send_key != NULL;
+}
+
/* Sets away `message'. The away message may be set when the client's
mode is changed to SILC_UMODE_GONE and the client whishes to reply
to anyone who sends private message. The `message' will be sent
new one. If `message' is NULL the old away message is removed.
The sender may freely free the memory of the `message'. */
-void silc_client_set_away_message(SilcClient client,
- SilcClientConnection conn,
- char *message)
+SilcBool silc_client_set_away_message(SilcClient client,
+ SilcClientConnection conn,
+ char *message)
{
- assert(client && conn);
+ if (!client || !conn)
+ return FALSE;
- if (!message && conn->internal->away) {
- silc_free(conn->internal->away->away);
- silc_free(conn->internal->away);
- conn->internal->away = NULL;
+ if (!message) {
+ silc_free(conn->internal->away_message);
+ conn->internal->away_message = NULL;
+ return TRUE;
}
- if (message) {
- if (!conn->internal->away)
- conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
- if (conn->internal->away->away)
- silc_free(conn->internal->away->away);
- conn->internal->away->away = strdup(message);
- }
+ if (conn->internal->away_message)
+ silc_free(conn->internal->away_message);
+
+ conn->internal->away_message = strdup(message);
+ if (!conn->internal->away_message)
+ return FALSE;
+
+ return TRUE;
}