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"
35 #define DEBUG_CHAT GNUNET_NO
36 #define NICK_IDENTITY_PREFIX ".chat_identity_"
40 * Handle for a chat room.
42 struct GNUNET_CHAT_Room
44 struct GNUNET_CLIENT_Connection *client;
46 const struct GNUNET_CONFIGURATION_Handle *cfg;
48 struct GNUNET_CONTAINER_MetaData *member_info;
52 struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
54 struct MemberList *members;
58 GNUNET_CHAT_JoinCallback join_callback;
60 void *join_callback_cls;
62 GNUNET_CHAT_MessageCallback message_callback;
64 void *message_callback_cls;
66 GNUNET_CHAT_MemberListCallback member_list_callback;
68 void *member_list_callback_cls;
70 GNUNET_CHAT_MessageConfirmation confirmation_callback;
72 void *confirmation_cls;
74 uint32_t sequence_number;
81 * Linked list of members in the chat room.
85 struct MemberList *next;
88 * Description of the member.
90 struct GNUNET_CONTAINER_MetaData *meta;
93 * Member ID (pseudonym).
100 * Context for transmitting a send-message request.
102 struct GNUNET_CHAT_SendMessageContext
105 * Handle for the chat room.
107 struct GNUNET_CHAT_Room *chat_room;
110 * Message that we're sending.
115 * Options for the message.
117 enum GNUNET_CHAT_MsgOptions options;
120 * Receiver of the message. NULL to send to everyone in the room.
122 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver;
125 * Sequence id of the message.
127 uint32_t sequence_number;
132 * Context for transmitting a confirmation receipt.
134 struct GNUNET_CHAT_SendReceiptContext
137 * Handle for the chat room.
139 struct GNUNET_CHAT_Room *chat_room;
142 * The original message that we're going to acknowledge.
144 struct ReceiveNotificationMessage *received_msg;
149 * Ask client to send a join request.
151 static int rejoin_room (struct GNUNET_CHAT_Room *chat_room);
155 * Transmit a confirmation receipt to the chat service.
157 * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext'
158 * @param size number of bytes available in buf
159 * @param buf where the callee should write the message
160 * @return number of bytes written to buf
163 transmit_acknowledge_request (void *cls, size_t size, void *buf)
165 struct GNUNET_CHAT_SendReceiptContext *src = cls;
166 struct ConfirmationReceiptMessage *receipt;
167 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key;
173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174 _("Could not transmit confirmation receipt\n"));
178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179 "Transmitting confirmation receipt to the service\n");
181 msg_size = sizeof (struct ConfirmationReceiptMessage);
182 GNUNET_assert (size >= msg_size);
184 receipt->header.size = htons (msg_size);
185 receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT);
186 receipt->reserved = htonl (0);
187 receipt->sequence_number = src->received_msg->sequence_number;
188 receipt->reserved2 = htonl (0);
189 receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
190 GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key);
191 GNUNET_CRYPTO_hash (&pub_key,
192 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
194 receipt->author = src->received_msg->sender;
195 receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT);
196 receipt->purpose.size =
198 sizeof (struct GNUNET_MessageHeader) -
199 sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature));
200 msg_len = ntohs (src->received_msg->header.size) -
201 sizeof (struct ReceiveNotificationMessage);
202 GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content);
203 GNUNET_assert (GNUNET_OK ==
204 GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key,
206 &receipt->signature));
207 GNUNET_free (src->received_msg);
214 * Handles messages received from the service. Calls the proper client
218 process_result (struct GNUNET_CHAT_Room *room,
219 const struct GNUNET_MessageHeader *reply)
221 struct LeaveNotificationMessage *leave_msg;
222 struct JoinNotificationMessage *join_msg;
223 struct ReceiveNotificationMessage *received_msg;
224 struct ConfirmationReceiptMessage *receipt;
225 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
227 const GNUNET_HashCode *sender;
228 struct GNUNET_CONTAINER_MetaData *meta;
229 struct GNUNET_CHAT_SendReceiptContext *src;
230 struct MemberList *pos;
231 struct MemberList *prev;
232 struct GNUNET_CRYPTO_AesSessionKey key;
233 char decrypted_msg[MAX_MESSAGE_LENGTH];
237 char *message_content;
239 size = ntohs (reply->size);
240 switch (ntohs (reply->type))
242 case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION:
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n");
246 if (size < sizeof (struct JoinNotificationMessage))
251 join_msg = (struct JoinNotificationMessage *) reply;
252 meta_len = size - sizeof (struct JoinNotificationMessage);
254 GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1],
261 pos = GNUNET_malloc (sizeof (struct MemberList));
263 GNUNET_CRYPTO_hash (&join_msg->public_key,
264 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
266 GNUNET_PSEUDONYM_add (room->cfg, &pos->id, meta);
267 pos->next = room->members;
269 if (GNUNET_NO == room->is_joined)
271 GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey);
272 if (0 == memcmp (&join_msg->public_key,
274 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
276 room->join_callback (room->join_callback_cls);
277 room->is_joined = GNUNET_YES;
281 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
282 _("The current user must be the the first one joined\n"));
288 room->member_list_callback (room->member_list_callback_cls,
289 meta, &join_msg->public_key,
290 ntohl (join_msg->msg_options));
292 case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION:
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n");
296 if (size < sizeof (struct LeaveNotificationMessage))
301 leave_msg = (struct LeaveNotificationMessage *) reply;
302 room->member_list_callback (room->member_list_callback_cls,
303 NULL, &leave_msg->user,
304 GNUNET_CHAT_MSG_OPTION_NONE);
305 GNUNET_CRYPTO_hash (&leave_msg->user,
306 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
310 while ((NULL != pos) &&
311 (0 != memcmp (&pos->id, &id, sizeof (GNUNET_HashCode))))
316 GNUNET_assert (NULL != pos);
318 room->members = pos->next;
320 prev->next = pos->next;
321 GNUNET_CONTAINER_meta_data_destroy (pos->meta);
324 case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION:
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n");
328 if (size <= sizeof (struct ReceiveNotificationMessage))
333 received_msg = (struct ReceiveNotificationMessage *) reply;
334 if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED))
336 src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext));
337 src->chat_room = room;
338 src->received_msg = GNUNET_memdup (received_msg, size);
339 GNUNET_CLIENT_notify_transmit_ready (room->client,
341 ConfirmationReceiptMessage),
342 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
344 &transmit_acknowledge_request, src);
346 msg_len = size - sizeof (struct ReceiveNotificationMessage);
347 if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE))
349 if (-1 == GNUNET_CRYPTO_rsa_decrypt (room->my_private_key,
350 &received_msg->encrypted_key,
353 GNUNET_CRYPTO_AesSessionKey)))
358 msg_len = GNUNET_CRYPTO_aes_decrypt (&received_msg[1],
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) &&
381 (0 != memcmp (&pos->id,
382 &received_msg->sender, sizeof (GNUNET_HashCode))))
384 GNUNET_assert (NULL != pos);
385 sender = &received_msg->sender;
388 room->message_callback (room->message_callback_cls,
393 GNUNET_TIME_absolute_ntoh (received_msg->timestamp),
394 ntohl (received_msg->msg_options));
395 if (message_content != decrypted_msg)
396 GNUNET_free (message_content);
398 case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION:
400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n");
402 if (size < sizeof (struct ConfirmationReceiptMessage))
407 receipt = (struct ConfirmationReceiptMessage *) reply;
408 if (NULL != room->confirmation_callback)
409 room->confirmation_callback (room->confirmation_cls,
411 ntohl (receipt->sequence_number),
412 GNUNET_TIME_absolute_ntoh
413 (receipt->timestamp), &receipt->target);
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 _("Unknown message type: '%u'\n"), ntohs (reply->type));
425 * Listen for incoming messages on this chat room. Also, support servers going
426 * away/coming back (i.e. rejoin chat room to keep server state up to date).
428 * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room'
429 * @param msg message received, NULL on timeout or fatal error
432 receive_results (void *cls, const struct GNUNET_MessageHeader *msg)
434 struct GNUNET_CHAT_Room *chat_room = cls;
437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n");
439 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ()))
444 rejoin_room (chat_room);
447 process_result (chat_room, msg);
448 if (NULL == chat_room->client)
449 return; /* fatal error */
450 /* continue receiving */
451 GNUNET_CLIENT_receive (chat_room->client,
453 chat_room, GNUNET_TIME_UNIT_FOREVER_REL);
458 * Read existing private key from file or create a new one if it does not exist
460 * Returns the private key on success, NULL on error.
462 static struct GNUNET_CRYPTO_RsaPrivateKey *
463 init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg,
464 const char *nick_name)
468 struct GNUNET_CRYPTO_RsaPrivateKey *privKey;
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing private key\n");
474 GNUNET_CONFIGURATION_get_value_filename (cfg, "chat", "HOME", &home))
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 _("Configuration option `%s' in section `%s' missing\n"),
481 GNUNET_DISK_directory_create (home);
482 if (GNUNET_OK != GNUNET_DISK_directory_test (home))
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 _("Failed to access chat home directory `%s'\n"), home);
489 /* read or create private key */
491 GNUNET_malloc (strlen (home) + strlen (NICK_IDENTITY_PREFIX) +
492 strlen (nick_name) + 2);
493 strcpy (keyfile, home);
495 if (keyfile[strlen (keyfile) - 1] != DIR_SEPARATOR)
496 strcat (keyfile, DIR_SEPARATOR_STR);
497 strcat (keyfile, NICK_IDENTITY_PREFIX);
498 strcat (keyfile, nick_name);
499 privKey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
502 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
503 _("Failed to create/open key in file `%s'\n"), keyfile);
505 GNUNET_free (keyfile);
511 * Transmit a join request to the chat service.
513 * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room'
514 * @param size number of bytes available in buf
515 * @param buf where the callee should write the message
516 * @return number of bytes written to buf
519 transmit_join_request (void *cls, size_t size, void *buf)
521 struct GNUNET_CHAT_Room *chat_room = cls;
522 struct JoinRequestMessage *join_msg;
532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
533 "Could not transmit join request, retrying...\n");
535 rejoin_room (chat_room);
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540 "Transmitting join request to the service\n");
542 room_len = strlen (chat_room->room_name);
544 GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info);
545 size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len;
546 GNUNET_assert (size >= size_of_join);
548 join_msg->header.size = htons (size);
549 join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST);
550 join_msg->msg_options = htonl (chat_room->msg_options);
551 join_msg->room_name_len = htons (room_len);
552 join_msg->reserved = htons (0);
553 join_msg->reserved2 = htonl (0);
554 GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key,
555 &join_msg->public_key);
556 room = (char *) &join_msg[1];
557 memcpy (room, chat_room->room_name, room_len);
558 meta = &room[room_len];
560 GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info,
563 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL))
565 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n"));
568 GNUNET_CLIENT_receive (chat_room->client,
570 chat_room, GNUNET_TIME_UNIT_FOREVER_REL);
576 * Ask to send a join request.
579 rejoin_room (struct GNUNET_CHAT_Room *chat_room)
583 size_of_join = sizeof (struct JoinRequestMessage) +
584 GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) +
585 strlen (chat_room->room_name);
587 GNUNET_CLIENT_notify_transmit_ready (chat_room->client,
589 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
591 &transmit_join_request, chat_room))
592 return GNUNET_SYSERR;
601 GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room)
603 struct MemberList *pos;
606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607 "Leaving the room '%s'\n", chat_room->room_name);
609 GNUNET_CLIENT_disconnect (chat_room->client, GNUNET_NO);
610 GNUNET_free (chat_room->room_name);
611 GNUNET_CONTAINER_meta_data_destroy (chat_room->member_info);
612 GNUNET_CRYPTO_rsa_key_free (chat_room->my_private_key);
613 while (NULL != chat_room->members)
615 pos = chat_room->members;
616 chat_room->members = pos->next;
617 GNUNET_CONTAINER_meta_data_destroy (pos->meta);
620 GNUNET_free (chat_room);
627 * @param cfg configuration
628 * @param nick_name nickname of the user joining (used to
629 * determine which public key to use);
630 * the nickname should probably also
631 * be used in the member_info (as "EXTRACTOR_TITLE")
632 * @param member_info information about the joining member
633 * @param room_name name of the room
634 * @param msg_options message options of the joining user
635 * @param joinCallback function to call on successful join
636 * @param join_cls closure for joinCallback
637 * @param messageCallback which function to call if a message has
639 * @param message_cls argument to callback
640 * @param memberCallback which function to call for join/leave notifications
641 * @param member_cls argument to callback
642 * @param confirmationCallback which function to call for confirmations (maybe NULL)
643 * @param confirmation_cls argument to callback
644 * @param me member ID (pseudonym)
645 * @return NULL on error
647 struct GNUNET_CHAT_Room *
648 GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg,
649 const char *nick_name,
650 struct GNUNET_CONTAINER_MetaData *member_info,
651 const char *room_name,
652 enum GNUNET_CHAT_MsgOptions msg_options,
653 GNUNET_CHAT_JoinCallback joinCallback,
655 GNUNET_CHAT_MessageCallback messageCallback,
657 GNUNET_CHAT_MemberListCallback memberCallback,
659 GNUNET_CHAT_MessageConfirmation confirmationCallback,
660 void *confirmation_cls, GNUNET_HashCode * me)
662 struct GNUNET_CHAT_Room *chat_room;
663 struct GNUNET_CRYPTO_RsaPrivateKey *priv_key;
664 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key;
665 struct GNUNET_CLIENT_Connection *client;
668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name);
670 priv_key = init_private_key (cfg, nick_name);
671 if (NULL == priv_key)
673 GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key);
674 GNUNET_CRYPTO_hash (&pub_key,
675 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
677 GNUNET_PSEUDONYM_add (cfg, me, member_info);
678 client = GNUNET_CLIENT_connect ("chat", cfg);
681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
682 _("Failed to connect to the chat service\n"));
685 if (NULL == joinCallback)
687 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
688 _("Undefined mandatory parameter: joinCallback\n"));
691 if (NULL == messageCallback)
693 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
694 _("Undefined mandatory parameter: messageCallback\n"));
697 if (NULL == memberCallback)
699 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
700 _("Undefined mandatory parameter: memberCallback\n"));
703 chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room));
704 chat_room->msg_options = msg_options;
705 chat_room->room_name = GNUNET_strdup (room_name);
706 chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info);
707 chat_room->my_private_key = priv_key;
708 chat_room->is_joined = GNUNET_NO;
709 chat_room->join_callback = joinCallback;
710 chat_room->join_callback_cls = join_cls;
711 chat_room->message_callback = messageCallback;
712 chat_room->message_callback_cls = message_cls;
713 chat_room->member_list_callback = memberCallback;
714 chat_room->member_list_callback_cls = member_cls;
715 chat_room->confirmation_callback = confirmationCallback;
716 chat_room->confirmation_cls = confirmation_cls;
717 chat_room->cfg = cfg;
718 chat_room->client = client;
719 chat_room->members = NULL;
720 if (GNUNET_SYSERR == rejoin_room (chat_room))
722 GNUNET_CHAT_leave_room (chat_room);
730 * Transmit a send-message request to the chat service.
732 * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext'
733 * @param size number of bytes available in buf
734 * @param buf where the callee should write the message
735 * @return number of bytes written to buf
738 transmit_send_request (void *cls, size_t size, void *buf)
740 struct GNUNET_CHAT_SendMessageContext *smc = cls;
741 struct TransmitRequestMessage *msg_to_send;
747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n");
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753 "Transmitting a chat message to the service\n");
755 msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage);
756 GNUNET_assert (size >= msg_size);
758 msg_to_send->header.size = htons (msg_size);
759 msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST);
760 msg_to_send->msg_options = htonl (smc->options);
761 msg_to_send->sequence_number = htonl (smc->sequence_number);
762 msg_to_send->timestamp =
763 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
764 msg_to_send->reserved = htonl (0);
765 if (NULL == smc->receiver)
766 memset (&msg_to_send->target, 0, sizeof (GNUNET_HashCode));
768 GNUNET_CRYPTO_hash (smc->receiver,
769 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
770 &msg_to_send->target);
771 memcpy (&msg_to_send[1], smc->message, strlen (smc->message));
773 * Client don't encode private messages since public keys of other members are
774 * stored on the service side.
776 if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED)
778 msg_to_send->purpose.purpose =
779 htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
780 msg_to_send->purpose.size =
782 sizeof (struct GNUNET_MessageHeader) -
783 sizeof (struct GNUNET_CRYPTO_RsaSignature));
784 GNUNET_assert (GNUNET_OK ==
785 GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key,
786 &msg_to_send->purpose,
787 &msg_to_send->signature));
789 GNUNET_free (smc->message);
798 * @param room handle for the chat room
799 * @param message message to be sent
800 * @param options options for the message
801 * @param receiver use NULL to send to everyone in the room
802 * @param sequence_number where to write the sequence id of the message
805 GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room,
807 enum GNUNET_CHAT_MsgOptions options,
808 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
809 *receiver, uint32_t * sequence_number)
812 struct GNUNET_CHAT_SendMessageContext *smc;
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n");
817 room->sequence_number++;
818 if (NULL != sequence_number)
819 *sequence_number = room->sequence_number;
820 smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext));
821 smc->chat_room = room;
822 smc->message = GNUNET_strdup (message);
823 smc->options = options;
824 smc->receiver = receiver;
825 smc->sequence_number = room->sequence_number;
826 msg_size = strlen (message) + sizeof (struct TransmitRequestMessage);
827 GNUNET_CLIENT_notify_transmit_ready (room->client,
829 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
830 GNUNET_YES, &transmit_send_request, smc);