2 This file is part of GNUnet.
3 (C) 2008, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @brief convenience API for sending and receiving chat messages
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 * @author Vitaly Minko
30 #include "gnunet_constants.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_fs_service.h"
36 #define DEBUG_CHAT GNUNET_EXTRA_LOGGING
37 #define NICK_IDENTITY_PREFIX ".chat_identity_"
41 * Handle for a chat room.
43 struct GNUNET_CHAT_Room
45 struct GNUNET_CLIENT_Connection *client;
47 const struct GNUNET_CONFIGURATION_Handle *cfg;
49 struct GNUNET_CONTAINER_MetaData *member_info;
53 struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
55 struct MemberList *members;
59 GNUNET_CHAT_JoinCallback join_callback;
61 void *join_callback_cls;
63 GNUNET_CHAT_MessageCallback message_callback;
65 void *message_callback_cls;
67 GNUNET_CHAT_MemberListCallback member_list_callback;
69 void *member_list_callback_cls;
71 GNUNET_CHAT_MessageConfirmation confirmation_callback;
73 void *confirmation_cls;
75 uint32_t sequence_number;
82 * Linked list of members in the chat room.
86 struct MemberList *next;
89 * Description of the member.
91 struct GNUNET_CONTAINER_MetaData *meta;
94 * Member ID (pseudonym).
96 struct GNUNET_HashCode id;
101 * Context for transmitting a send-message request.
103 struct GNUNET_CHAT_SendMessageContext
106 * Handle for the chat room.
108 struct GNUNET_CHAT_Room *chat_room;
111 * Message that we're sending.
116 * Options for the message.
118 enum GNUNET_CHAT_MsgOptions options;
121 * Receiver of the message. NULL to send to everyone in the room.
123 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver;
126 * Sequence id of the message.
128 uint32_t sequence_number;
133 * Context for transmitting a confirmation receipt.
135 struct GNUNET_CHAT_SendReceiptContext
138 * Handle for the chat room.
140 struct GNUNET_CHAT_Room *chat_room;
143 * The original message that we're going to acknowledge.
145 struct ReceiveNotificationMessage *received_msg;
150 * Ask client to send a join request.
153 rejoin_room (struct GNUNET_CHAT_Room *chat_room);
157 * Transmit a confirmation receipt to the chat service.
159 * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext'
160 * @param size number of bytes available in buf
161 * @param buf where the callee should write the message
162 * @return number of bytes written to buf
165 transmit_acknowledge_request (void *cls, size_t size, void *buf)
167 struct GNUNET_CHAT_SendReceiptContext *src = cls;
168 struct ConfirmationReceiptMessage *receipt;
169 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key;
175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
176 _("Could not transmit confirmation receipt\n"));
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181 "Transmitting confirmation receipt to the service\n");
183 msg_size = sizeof (struct ConfirmationReceiptMessage);
184 GNUNET_assert (size >= msg_size);
186 receipt->header.size = htons (msg_size);
187 receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT);
188 receipt->reserved = htonl (0);
189 receipt->sequence_number = src->received_msg->sequence_number;
190 receipt->reserved2 = htonl (0);
191 receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
192 GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key);
193 GNUNET_CRYPTO_hash (&pub_key,
194 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
196 receipt->author = src->received_msg->sender;
197 receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT);
198 receipt->purpose.size =
199 htonl (msg_size - sizeof (struct GNUNET_MessageHeader) -
200 sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature));
202 ntohs (src->received_msg->header.size) -
203 sizeof (struct ReceiveNotificationMessage);
204 GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content);
205 GNUNET_assert (GNUNET_OK ==
206 GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key,
208 &receipt->signature));
209 GNUNET_free (src->received_msg);
216 * Handles messages received from the service. Calls the proper client
220 process_result (struct GNUNET_CHAT_Room *room,
221 const struct GNUNET_MessageHeader *reply)
223 struct LeaveNotificationMessage *leave_msg;
224 struct JoinNotificationMessage *join_msg;
225 struct ReceiveNotificationMessage *received_msg;
226 struct ConfirmationReceiptMessage *receipt;
227 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
228 struct GNUNET_HashCode id;
229 const struct GNUNET_HashCode *sender;
230 struct GNUNET_CONTAINER_MetaData *meta;
231 struct GNUNET_CHAT_SendReceiptContext *src;
232 struct MemberList *pos;
233 struct MemberList *prev;
234 struct GNUNET_CRYPTO_AesSessionKey key;
235 char decrypted_msg[MAX_MESSAGE_LENGTH];
239 char *message_content;
241 size = ntohs (reply->size);
242 switch (ntohs (reply->type))
244 case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION:
246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n");
248 if (size < sizeof (struct JoinNotificationMessage))
253 join_msg = (struct JoinNotificationMessage *) reply;
254 meta_len = size - sizeof (struct JoinNotificationMessage);
256 GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1],
263 pos = GNUNET_malloc (sizeof (struct MemberList));
265 GNUNET_CRYPTO_hash (&join_msg->public_key,
266 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
268 GNUNET_FS_pseudonym_add (room->cfg, &pos->id, meta);
269 pos->next = room->members;
271 if (GNUNET_NO == room->is_joined)
273 GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey);
275 memcmp (&join_msg->public_key, &pkey,
276 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
278 room->join_callback (room->join_callback_cls);
279 room->is_joined = GNUNET_YES;
283 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
284 _("The current user must be the the first one joined\n"));
290 room->member_list_callback (room->member_list_callback_cls, meta,
291 &join_msg->public_key,
292 ntohl (join_msg->msg_options));
294 case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION:
296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n");
298 if (size < sizeof (struct LeaveNotificationMessage))
303 leave_msg = (struct LeaveNotificationMessage *) reply;
304 room->member_list_callback (room->member_list_callback_cls, NULL,
305 &leave_msg->user, GNUNET_CHAT_MSG_OPTION_NONE);
306 GNUNET_CRYPTO_hash (&leave_msg->user,
307 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
311 while ((NULL != pos) &&
312 (0 != memcmp (&pos->id, &id, sizeof (struct GNUNET_HashCode))))
317 GNUNET_assert (NULL != pos);
319 room->members = pos->next;
321 prev->next = pos->next;
322 GNUNET_CONTAINER_meta_data_destroy (pos->meta);
325 case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION:
327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n");
329 if (size <= sizeof (struct ReceiveNotificationMessage))
334 received_msg = (struct ReceiveNotificationMessage *) reply;
335 if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED))
337 src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext));
338 src->chat_room = room;
339 src->received_msg = GNUNET_memdup (received_msg, size);
340 GNUNET_CLIENT_notify_transmit_ready (room->client,
342 ConfirmationReceiptMessage),
343 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
345 &transmit_acknowledge_request, src);
347 msg_len = size - sizeof (struct ReceiveNotificationMessage);
348 if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE))
351 GNUNET_CRYPTO_rsa_decrypt (room->my_private_key,
352 &received_msg->encrypted_key, &key,
354 GNUNET_CRYPTO_AesSessionKey)))
360 GNUNET_CRYPTO_aes_decrypt (&received_msg[1], msg_len, &key,
362 GNUNET_CRYPTO_AesInitializationVector *)
363 INITVALUE, decrypted_msg);
364 message_content = decrypted_msg;
368 message_content = GNUNET_malloc (msg_len + 1);
369 memcpy (message_content, &received_msg[1], msg_len);
371 message_content[msg_len] = '\0';
372 if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS))
380 while ((NULL != pos) &&
382 memcmp (&pos->id, &received_msg->sender,
383 sizeof (struct GNUNET_HashCode))))
385 GNUNET_assert (NULL != pos);
386 sender = &received_msg->sender;
389 room->message_callback (room->message_callback_cls, room, sender, meta,
391 GNUNET_TIME_absolute_ntoh (received_msg->timestamp),
392 ntohl (received_msg->msg_options));
393 if (message_content != decrypted_msg)
394 GNUNET_free (message_content);
396 case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION:
398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n");
400 if (size < sizeof (struct ConfirmationReceiptMessage))
405 receipt = (struct ConfirmationReceiptMessage *) reply;
406 if (NULL != room->confirmation_callback)
407 room->confirmation_callback (room->confirmation_cls, room,
408 ntohl (receipt->sequence_number),
409 GNUNET_TIME_absolute_ntoh
410 (receipt->timestamp), &receipt->target);
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unknown message type: '%u'\n"),
414 ntohs (reply->type));
422 * Listen for incoming messages on this chat room. Also, support servers going
423 * away/coming back (i.e. rejoin chat room to keep server state up to date).
425 * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room'
426 * @param msg message received, NULL on timeout or fatal error
429 receive_results (void *cls, const struct GNUNET_MessageHeader *msg)
431 struct GNUNET_CHAT_Room *chat_room = cls;
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n");
436 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ()))
441 rejoin_room (chat_room);
444 process_result (chat_room, msg);
445 if (NULL == chat_room->client)
446 return; /* fatal error */
447 /* continue receiving */
448 GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room,
449 GNUNET_TIME_UNIT_FOREVER_REL);
454 * Read existing private key from file or create a new one if it does not exist
456 * Returns the private key on success, NULL on error.
458 static struct GNUNET_CRYPTO_RsaPrivateKey *
459 init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg,
460 const char *nick_name)
464 struct GNUNET_CRYPTO_RsaPrivateKey *privKey;
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing private key\n");
470 GNUNET_CONFIGURATION_get_value_filename (cfg, "chat", "HOME", &home))
472 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
476 GNUNET_DISK_directory_create (home);
477 if (GNUNET_YES != GNUNET_DISK_directory_test (home, GNUNET_YES))
479 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
480 _("Failed to access chat home directory `%s'\n"), home);
484 /* read or create private key */
486 GNUNET_malloc (strlen (home) + strlen (NICK_IDENTITY_PREFIX) +
487 strlen (nick_name) + 2);
488 strcpy (keyfile, home);
490 if (keyfile[strlen (keyfile) - 1] != DIR_SEPARATOR)
491 strcat (keyfile, DIR_SEPARATOR_STR);
492 strcat (keyfile, NICK_IDENTITY_PREFIX);
493 strcat (keyfile, nick_name);
494 privKey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
497 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
498 _("Failed to create/open key in file `%s'\n"), keyfile);
500 GNUNET_free (keyfile);
506 * Transmit a join request to the chat service.
508 * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room'
509 * @param size number of bytes available in buf
510 * @param buf where the callee should write the message
511 * @return number of bytes written to buf
514 transmit_join_request (void *cls, size_t size, void *buf)
516 struct GNUNET_CHAT_Room *chat_room = cls;
517 struct JoinRequestMessage *join_msg;
527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528 "Could not transmit join request, retrying...\n");
530 rejoin_room (chat_room);
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535 "Transmitting join request to the service\n");
537 room_len = strlen (chat_room->room_name);
539 GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info);
540 size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len;
541 GNUNET_assert (size >= size_of_join);
543 join_msg->header.size = htons (size);
544 join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST);
545 join_msg->msg_options = htonl (chat_room->msg_options);
546 join_msg->room_name_len = htons (room_len);
547 join_msg->reserved = htons (0);
548 join_msg->reserved2 = htonl (0);
549 GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key,
550 &join_msg->public_key);
551 room = (char *) &join_msg[1];
552 memcpy (room, chat_room->room_name, room_len);
553 meta = &room[room_len];
555 GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta,
557 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL))
559 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n"));
562 GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room,
563 GNUNET_TIME_UNIT_FOREVER_REL);
569 * Ask to send a join request.
572 rejoin_room (struct GNUNET_CHAT_Room *chat_room)
577 sizeof (struct JoinRequestMessage) +
578 GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) +
579 strlen (chat_room->room_name);
581 GNUNET_CLIENT_notify_transmit_ready (chat_room->client, size_of_join,
582 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
583 GNUNET_YES, &transmit_join_request,
585 return GNUNET_SYSERR;
594 GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room)
596 struct MemberList *pos;
599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Leaving the room '%s'\n",
600 chat_room->room_name);
602 GNUNET_CLIENT_disconnect (chat_room->client);
603 GNUNET_free (chat_room->room_name);
604 GNUNET_CONTAINER_meta_data_destroy (chat_room->member_info);
605 GNUNET_CRYPTO_rsa_key_free (chat_room->my_private_key);
606 while (NULL != chat_room->members)
608 pos = chat_room->members;
609 chat_room->members = pos->next;
610 GNUNET_CONTAINER_meta_data_destroy (pos->meta);
613 GNUNET_free (chat_room);
620 * @param cfg configuration
621 * @param nick_name nickname of the user joining (used to
622 * determine which public key to use);
623 * the nickname should probably also
624 * be used in the member_info (as "EXTRACTOR_TITLE")
625 * @param member_info information about the joining member
626 * @param room_name name of the room
627 * @param msg_options message options of the joining user
628 * @param joinCallback function to call on successful join
629 * @param join_cls closure for joinCallback
630 * @param messageCallback which function to call if a message has
632 * @param message_cls argument to callback
633 * @param memberCallback which function to call for join/leave notifications
634 * @param member_cls argument to callback
635 * @param confirmationCallback which function to call for confirmations (maybe NULL)
636 * @param confirmation_cls argument to callback
637 * @param me member ID (pseudonym)
638 * @return NULL on error
640 struct GNUNET_CHAT_Room *
641 GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg,
642 const char *nick_name,
643 struct GNUNET_CONTAINER_MetaData *member_info,
644 const char *room_name,
645 enum GNUNET_CHAT_MsgOptions msg_options,
646 GNUNET_CHAT_JoinCallback joinCallback, void *join_cls,
647 GNUNET_CHAT_MessageCallback messageCallback,
649 GNUNET_CHAT_MemberListCallback memberCallback,
651 GNUNET_CHAT_MessageConfirmation confirmationCallback,
652 void *confirmation_cls, struct GNUNET_HashCode * me)
654 struct GNUNET_CHAT_Room *chat_room;
655 struct GNUNET_CRYPTO_RsaPrivateKey *priv_key;
656 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key;
657 struct GNUNET_CLIENT_Connection *client;
660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name);
662 priv_key = init_private_key (cfg, nick_name);
663 if (NULL == priv_key)
665 GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key);
666 GNUNET_CRYPTO_hash (&pub_key,
667 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
669 GNUNET_FS_pseudonym_add (cfg, me, member_info);
670 client = GNUNET_CLIENT_connect ("chat", cfg);
673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674 _("Failed to connect to the chat service\n"));
677 if (NULL == joinCallback)
679 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
680 _("Undefined mandatory parameter: joinCallback\n"));
683 if (NULL == messageCallback)
685 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
686 _("Undefined mandatory parameter: messageCallback\n"));
689 if (NULL == memberCallback)
691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
692 _("Undefined mandatory parameter: memberCallback\n"));
695 chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room));
696 chat_room->msg_options = msg_options;
697 chat_room->room_name = GNUNET_strdup (room_name);
698 chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info);
699 chat_room->my_private_key = priv_key;
700 chat_room->is_joined = GNUNET_NO;
701 chat_room->join_callback = joinCallback;
702 chat_room->join_callback_cls = join_cls;
703 chat_room->message_callback = messageCallback;
704 chat_room->message_callback_cls = message_cls;
705 chat_room->member_list_callback = memberCallback;
706 chat_room->member_list_callback_cls = member_cls;
707 chat_room->confirmation_callback = confirmationCallback;
708 chat_room->confirmation_cls = confirmation_cls;
709 chat_room->cfg = cfg;
710 chat_room->client = client;
711 chat_room->members = NULL;
712 if (GNUNET_SYSERR == rejoin_room (chat_room))
714 GNUNET_CHAT_leave_room (chat_room);
722 * Transmit a send-message request to the chat service.
724 * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext'
725 * @param size number of bytes available in buf
726 * @param buf where the callee should write the message
727 * @return number of bytes written to buf
730 transmit_send_request (void *cls, size_t size, void *buf)
732 struct GNUNET_CHAT_SendMessageContext *smc = cls;
733 struct TransmitRequestMessage *msg_to_send;
739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n");
744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745 "Transmitting a chat message to the service\n");
747 msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage);
748 GNUNET_assert (size >= msg_size);
750 msg_to_send->header.size = htons (msg_size);
751 msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST);
752 msg_to_send->msg_options = htonl (smc->options);
753 msg_to_send->sequence_number = htonl (smc->sequence_number);
754 msg_to_send->timestamp =
755 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
756 msg_to_send->reserved = htonl (0);
757 if (NULL == smc->receiver)
758 memset (&msg_to_send->target, 0, sizeof (struct GNUNET_HashCode));
760 GNUNET_CRYPTO_hash (smc->receiver,
761 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
762 &msg_to_send->target);
763 memcpy (&msg_to_send[1], smc->message, strlen (smc->message));
765 * Client don't encode private messages since public keys of other members are
766 * stored on the service side.
768 if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED)
770 msg_to_send->purpose.purpose =
771 htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
772 msg_to_send->purpose.size =
773 htonl (msg_size - sizeof (struct GNUNET_MessageHeader) -
774 sizeof (struct GNUNET_CRYPTO_RsaSignature));
775 GNUNET_assert (GNUNET_OK ==
776 GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key,
777 &msg_to_send->purpose,
778 &msg_to_send->signature));
780 GNUNET_free (smc->message);
789 * @param room handle for the chat room
790 * @param message message to be sent
791 * @param options options for the message
792 * @param receiver use NULL to send to everyone in the room
793 * @param sequence_number where to write the sequence id of the message
796 GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message,
797 enum GNUNET_CHAT_MsgOptions options,
798 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
799 *receiver, uint32_t * sequence_number)
802 struct GNUNET_CHAT_SendMessageContext *smc;
805 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n");
807 room->sequence_number++;
808 if (NULL != sequence_number)
809 *sequence_number = room->sequence_number;
810 smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext));
811 smc->chat_room = room;
812 smc->message = GNUNET_strdup (message);
813 smc->options = options;
814 smc->receiver = receiver;
815 smc->sequence_number = room->sequence_number;
816 msg_size = strlen (message) + sizeof (struct TransmitRequestMessage);
817 GNUNET_CLIENT_notify_transmit_ready (room->client, msg_size,
818 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
819 GNUNET_YES, &transmit_send_request, smc);