aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-02-06 23:27:01 +0000
committerChristian Grothoff <christian@grothoff.org>2011-02-06 23:27:01 +0000
commita0b3e179abb44828f76843739487b2686b14cc8e (patch)
tree52b2cfb63a66b13ce39bd1bf8bed04ff74ae102a
parent7b3d9e8f57db9db2053dd7e25c9dbd92514819e0 (diff)
downloadgnunet-a0b3e179abb44828f76843739487b2686b14cc8e.tar.gz
gnunet-a0b3e179abb44828f76843739487b2686b14cc8e.zip
more chat code from Mantis #1657
-rw-r--r--AUTHORS1
-rw-r--r--src/chat/Makefile.am82
-rw-r--r--src/chat/chat.c96
-rw-r--r--src/chat/chat.h38
-rw-r--r--src/chat/gnunet-chat.c120
-rw-r--r--src/chat/gnunet-service-chat.c257
-rw-r--r--src/core/core.h2
-rw-r--r--src/include/gnunet_chat_service.h21
8 files changed, 503 insertions, 114 deletions
diff --git a/AUTHORS b/AUTHORS
index e9cb7b798..789f2662b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,6 +8,7 @@ Nathan Evans <evans@net.in.tum.de>
8Nils Durner <durner@gnunet.org> 8Nils Durner <durner@gnunet.org>
9Safey Allah Mohammed <safey.allah@gmail.com> 9Safey Allah Mohammed <safey.allah@gmail.com>
10Philipp Tölke <toelke@in.tum.de> 10Philipp Tölke <toelke@in.tum.de>
11Vitaly Minko <vitaly.minko@gmail.com>
11 12
12Code contributions also came from: 13Code contributions also came from:
13Adam Warrington [ UPnP ] 14Adam Warrington [ UPnP ]
diff --git a/src/chat/Makefile.am b/src/chat/Makefile.am
index ad099e6b1..f10796c23 100644
--- a/src/chat/Makefile.am
+++ b/src/chat/Makefile.am
@@ -37,3 +37,85 @@ gnunet_chat_LDADD = \
37 $(top_builddir)/src/chat/libgnunetchat.la \ 37 $(top_builddir)/src/chat/libgnunetchat.la \
38 $(top_builddir)/src/util/libgnunetutil.la \ 38 $(top_builddir)/src/util/libgnunetutil.la \
39 $(GN_LIBINTL) 39 $(GN_LIBINTL)
40
41check_PROGRAMS = \
42 test_chat \
43 test_chat_acknowledgement \
44 test_chat_anonymous \
45 test_chat_authentication \
46 test_chat_p2p \
47 test_chat_acknowledgement_p2p \
48 test_chat_anonymous_p2p \
49 test_chat_authentication_p2p \
50 test_chat_private \
51 test_chat_private_p2p
52
53if !DISABLE_TEST_RUN
54TESTS = $(check_PROGRAMS)
55endif
56
57test_chat_SOURCES = \
58 test_chat.c
59test_chat_LDADD = \
60 $(top_builddir)/src/chat/libgnunetchat.la \
61 $(top_builddir)/src/util/libgnunetutil.la
62
63test_chat_acknowledgement_SOURCES = \
64 test_chat.c
65test_chat_acknowledgement_LDADD = \
66 $(top_builddir)/src/chat/libgnunetchat.la \
67 $(top_builddir)/src/util/libgnunetutil.la
68
69test_chat_anonymous_SOURCES = \
70 test_chat.c
71test_chat_anonymous_LDADD = \
72 $(top_builddir)/src/chat/libgnunetchat.la \
73 $(top_builddir)/src/util/libgnunetutil.la
74
75test_chat_authentication_SOURCES = \
76 test_chat.c
77test_chat_authentication_LDADD = \
78 $(top_builddir)/src/chat/libgnunetchat.la \
79 $(top_builddir)/src/util/libgnunetutil.la
80
81test_chat_p2p_SOURCES = \
82 test_chat.c
83test_chat_p2p_LDADD = \
84 $(top_builddir)/src/chat/libgnunetchat.la \
85 $(top_builddir)/src/util/libgnunetutil.la
86
87test_chat_acknowledgement_p2p_SOURCES = \
88 test_chat.c
89test_chat_acknowledgement_p2p_LDADD = \
90 $(top_builddir)/src/chat/libgnunetchat.la \
91 $(top_builddir)/src/util/libgnunetutil.la
92
93test_chat_anonymous_p2p_SOURCES = \
94 test_chat.c
95test_chat_anonymous_p2p_LDADD = \
96 $(top_builddir)/src/chat/libgnunetchat.la \
97 $(top_builddir)/src/util/libgnunetutil.la
98
99test_chat_authentication_p2p_SOURCES = \
100 test_chat.c
101test_chat_authentication_p2p_LDADD = \
102 $(top_builddir)/src/chat/libgnunetchat.la \
103 $(top_builddir)/src/util/libgnunetutil.la
104
105test_chat_private_SOURCES = \
106 test_chat_private.c
107test_chat_private_LDADD = \
108 $(top_builddir)/src/chat/libgnunetchat.la \
109 $(top_builddir)/src/util/libgnunetutil.la
110
111test_chat_private_p2p_SOURCES = \
112 test_chat_private.c
113test_chat_private_p2p_LDADD = \
114 $(top_builddir)/src/chat/libgnunetchat.la \
115 $(top_builddir)/src/util/libgnunetutil.la
116
117EXTRA_DIST = \
118 test_chat_data.conf \
119 test_chat_peer1.conf \
120 test_chat_peer2.conf \
121 test_chat_peer3.conf
diff --git a/src/chat/chat.c b/src/chat/chat.c
index da1237d84..f3e3470a0 100644
--- a/src/chat/chat.c
+++ b/src/chat/chat.c
@@ -32,12 +32,12 @@
32#include "gnunet_signatures.h" 32#include "gnunet_signatures.h"
33#include "chat.h" 33#include "chat.h"
34 34
35#define DEBUG_CHAT GNUNET_YES 35#define DEBUG_CHAT GNUNET_NO
36#define NICK_IDENTITY_PREFIX ".chat_identity_" 36#define NICK_IDENTITY_PREFIX ".chat_identity_"
37 37
38 38
39/** 39/**
40 * Handle for a (joined) chat room. 40 * Handle for a chat room.
41 */ 41 */
42struct GNUNET_CHAT_Room 42struct GNUNET_CHAT_Room
43{ 43{
@@ -53,6 +53,12 @@ struct GNUNET_CHAT_Room
53 53
54 struct MemberList *members; 54 struct MemberList *members;
55 55
56 int is_joined;
57
58 GNUNET_CHAT_JoinCallback join_callback;
59
60 void *join_callback_cls;
61
56 GNUNET_CHAT_MessageCallback message_callback; 62 GNUNET_CHAT_MessageCallback message_callback;
57 63
58 void *message_callback_cls; 64 void *message_callback_cls;
@@ -221,7 +227,9 @@ process_result (struct GNUNET_CHAT_Room *room,
221 struct JoinNotificationMessage *join_msg; 227 struct JoinNotificationMessage *join_msg;
222 struct ReceiveNotificationMessage *received_msg; 228 struct ReceiveNotificationMessage *received_msg;
223 struct ConfirmationReceiptMessage *receipt; 229 struct ConfirmationReceiptMessage *receipt;
230 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
224 GNUNET_HashCode id; 231 GNUNET_HashCode id;
232 const GNUNET_HashCode *sender;
225 struct GNUNET_CONTAINER_MetaData *meta; 233 struct GNUNET_CONTAINER_MetaData *meta;
226 struct GNUNET_CHAT_SendReceiptContext *src; 234 struct GNUNET_CHAT_SendReceiptContext *src;
227 struct MemberList *pos; 235 struct MemberList *pos;
@@ -261,11 +269,30 @@ process_result (struct GNUNET_CHAT_Room *room,
261 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 269 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
262 &pos->id); 270 &pos->id);
263 GNUNET_PSEUDONYM_add (room->cfg, &pos->id, meta); 271 GNUNET_PSEUDONYM_add (room->cfg, &pos->id, meta);
272 pos->next = room->members;
273 room->members = pos;
274 if (GNUNET_NO == room->is_joined)
275 {
276 GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey);
277 if (0 == memcmp (&join_msg->public_key,
278 &pkey,
279 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
280 {
281 room->join_callback (room->join_callback_cls);
282 room->is_joined = GNUNET_YES;
283 }
284 else
285 {
286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
287 _("The current user must be the the first one joined\n"));
288 GNUNET_break (0);
289 return;
290 }
291 }
292 else
264 room->member_list_callback (room->member_list_callback_cls, 293 room->member_list_callback (room->member_list_callback_cls,
265 meta, &join_msg->public_key, 294 meta, &join_msg->public_key,
266 ntohl (join_msg->msg_options)); 295 ntohl (join_msg->msg_options));
267 pos->next = room->members;
268 room->members = pos;
269 break; 296 break;
270 case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION: 297 case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION:
271#if DEBUG_CHAT 298#if DEBUG_CHAT
@@ -347,6 +374,13 @@ process_result (struct GNUNET_CHAT_Room *room,
347 memcpy (message_content, &received_msg[1], msg_len); 374 memcpy (message_content, &received_msg[1], msg_len);
348 } 375 }
349 message_content[msg_len] = '\0'; 376 message_content[msg_len] = '\0';
377 if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS))
378 {
379 sender = NULL;
380 meta = NULL;
381 }
382 else
383 {
350 pos = room->members; 384 pos = room->members;
351 while ((NULL != pos) && 385 while ((NULL != pos) &&
352 (0 != memcmp (&pos->id, 386 (0 != memcmp (&pos->id,
@@ -354,11 +388,15 @@ process_result (struct GNUNET_CHAT_Room *room,
354 sizeof (GNUNET_HashCode)))) 388 sizeof (GNUNET_HashCode))))
355 pos = pos->next; 389 pos = pos->next;
356 GNUNET_assert (NULL != pos); 390 GNUNET_assert (NULL != pos);
391 sender = &received_msg->sender;
392 meta = pos->meta;
393 }
357 room->message_callback (room->message_callback_cls, 394 room->message_callback (room->message_callback_cls,
358 room, 395 room,
359 &received_msg->sender, 396 sender,
360 pos->meta, 397 meta,
361 message_content, 398 message_content,
399 GNUNET_TIME_absolute_ntoh (received_msg->timestamp),
362 ntohl (received_msg->msg_options)); 400 ntohl (received_msg->msg_options));
363 if (message_content != decrypted_msg) 401 if (message_content != decrypted_msg)
364 GNUNET_free (message_content); 402 GNUNET_free (message_content);
@@ -378,9 +416,7 @@ process_result (struct GNUNET_CHAT_Room *room,
378 room, 416 room,
379 ntohl (receipt->sequence_number), 417 ntohl (receipt->sequence_number),
380 GNUNET_TIME_absolute_ntoh (receipt->timestamp), 418 GNUNET_TIME_absolute_ntoh (receipt->timestamp),
381 &receipt->target, 419 &receipt->target);
382 &receipt->content,
383 &receipt->signature);
384 break; 420 break;
385 default: 421 default:
386 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -510,8 +546,9 @@ transmit_join_request (void *cls,
510 { 546 {
511#if DEBUG_CHAT 547#if DEBUG_CHAT
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 "Could not transmit join request\n"); 549 "Could not transmit join request, retrying...\n");
514#endif 550#endif
551 GNUNET_CHAT_rejoin_room (chat_room);
515 return 0; 552 return 0;
516 } 553 }
517#if DEBUG_CHAT 554#if DEBUG_CHAT
@@ -542,6 +579,10 @@ transmit_join_request (void *cls,
542 _("Could not serialize metadata\n")); 579 _("Could not serialize metadata\n"));
543 return 0; 580 return 0;
544 } 581 }
582 GNUNET_CLIENT_receive (chat_room->client,
583 &receive_results,
584 chat_room,
585 GNUNET_TIME_UNIT_FOREVER_REL);
545 return size_of_join; 586 return size_of_join;
546} 587}
547 588
@@ -623,6 +664,8 @@ GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg,
623 struct GNUNET_CONTAINER_MetaData *member_info, 664 struct GNUNET_CONTAINER_MetaData *member_info,
624 const char *room_name, 665 const char *room_name,
625 enum GNUNET_CHAT_MsgOptions msg_options, 666 enum GNUNET_CHAT_MsgOptions msg_options,
667 GNUNET_CHAT_JoinCallback joinCallback,
668 void *join_cls,
626 GNUNET_CHAT_MessageCallback messageCallback, 669 GNUNET_CHAT_MessageCallback messageCallback,
627 void *message_cls, 670 void *message_cls,
628 GNUNET_CHAT_MemberListCallback memberCallback, 671 GNUNET_CHAT_MemberListCallback memberCallback,
@@ -654,11 +697,32 @@ GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg,
654 _("Failed to connect to the chat service\n")); 697 _("Failed to connect to the chat service\n"));
655 return NULL; 698 return NULL;
656 } 699 }
700 if (NULL == joinCallback)
701 {
702 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703 _("Undefined mandatory parameter: joinCallback\n"));
704 return NULL;
705 }
706 if (NULL == messageCallback)
707 {
708 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
709 _("Undefined mandatory parameter: messageCallback\n"));
710 return NULL;
711 }
712 if (NULL == memberCallback)
713 {
714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
715 _("Undefined mandatory parameter: memberCallback\n"));
716 return NULL;
717 }
657 chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room)); 718 chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room));
658 chat_room->msg_options = msg_options; 719 chat_room->msg_options = msg_options;
659 chat_room->room_name = GNUNET_strdup (room_name); 720 chat_room->room_name = GNUNET_strdup (room_name);
660 chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info); 721 chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info);
661 chat_room->my_private_key = priv_key; 722 chat_room->my_private_key = priv_key;
723 chat_room->is_joined = GNUNET_NO;
724 chat_room->join_callback = joinCallback;
725 chat_room->join_callback_cls = join_cls;
662 chat_room->message_callback = messageCallback; 726 chat_room->message_callback = messageCallback;
663 chat_room->message_callback_cls = message_cls; 727 chat_room->message_callback_cls = message_cls;
664 chat_room->member_list_callback = memberCallback; 728 chat_room->member_list_callback = memberCallback;
@@ -668,10 +732,6 @@ GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg,
668 chat_room->cfg = cfg; 732 chat_room->cfg = cfg;
669 chat_room->client = client; 733 chat_room->client = client;
670 chat_room->members = NULL; 734 chat_room->members = NULL;
671 GNUNET_CLIENT_receive (client,
672 &receive_results,
673 chat_room,
674 GNUNET_TIME_UNIT_FOREVER_REL);
675 if (GNUNET_SYSERR == GNUNET_CHAT_rejoin_room (chat_room)) 735 if (GNUNET_SYSERR == GNUNET_CHAT_rejoin_room (chat_room))
676 { 736 {
677 GNUNET_CHAT_leave_room (chat_room); 737 GNUNET_CHAT_leave_room (chat_room);
@@ -717,6 +777,8 @@ transmit_send_request (void *cls,
717 msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST); 777 msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST);
718 msg_to_send->msg_options = htonl (smc->options); 778 msg_to_send->msg_options = htonl (smc->options);
719 msg_to_send->sequence_number = htonl (smc->sequence_number); 779 msg_to_send->sequence_number = htonl (smc->sequence_number);
780 msg_to_send->timestamp =
781 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
720 msg_to_send->reserved = htonl (0); 782 msg_to_send->reserved = htonl (0);
721 if (NULL == smc->receiver) 783 if (NULL == smc->receiver)
722 memset (&msg_to_send->target, 0, sizeof (GNUNET_HashCode)); 784 memset (&msg_to_send->target, 0, sizeof (GNUNET_HashCode));
@@ -770,13 +832,15 @@ GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room,
770#if DEBUG_CHAT 832#if DEBUG_CHAT
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n"); 833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n");
772#endif 834#endif
773 *sequence_number = ++room->sequence_number; 835 room->sequence_number++;
836 if (NULL != sequence_number)
837 *sequence_number = room->sequence_number;
774 smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext)); 838 smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext));
775 smc->chat_room = room; 839 smc->chat_room = room;
776 smc->message = GNUNET_strdup (message); 840 smc->message = GNUNET_strdup (message);
777 smc->options = options; 841 smc->options = options;
778 smc->receiver = receiver; 842 smc->receiver = receiver;
779 smc->sequence_number = *sequence_number; 843 smc->sequence_number = room->sequence_number;
780 msg_size = strlen (message) + sizeof (struct TransmitRequestMessage); 844 msg_size = strlen (message) + sizeof (struct TransmitRequestMessage);
781 GNUNET_CLIENT_notify_transmit_ready (room->client, 845 GNUNET_CLIENT_notify_transmit_ready (room->client,
782 msg_size, 846 msg_size,
diff --git a/src/chat/chat.h b/src/chat/chat.h
index a9cf83a8c..9a52a2d75 100644
--- a/src/chat/chat.h
+++ b/src/chat/chat.h
@@ -70,8 +70,13 @@ struct ReceiveNotificationMessage
70 uint32_t reserved GNUNET_PACKED; 70 uint32_t reserved GNUNET_PACKED;
71 71
72 /** 72 /**
73 * Timestamp of the message.
74 */
75 struct GNUNET_TIME_AbsoluteNBO timestamp;
76
77 /**
73 * Hash of the public key of the pseudonym of the sender of the message. 78 * Hash of the public key of the pseudonym of the sender of the message.
74 * TBD: Should be all zeros for anonymous. 79 * Should be all zeros for anonymous.
75 */ 80 */
76 GNUNET_HashCode sender; 81 GNUNET_HashCode sender;
77 82
@@ -122,6 +127,11 @@ struct TransmitRequestMessage
122 uint32_t sequence_number GNUNET_PACKED; 127 uint32_t sequence_number GNUNET_PACKED;
123 128
124 /** 129 /**
130 * Timestamp of the message.
131 */
132 struct GNUNET_TIME_AbsoluteNBO timestamp;
133
134 /**
125 * Who should receive this message? Set to all zeros for "everyone". 135 * Who should receive this message? Set to all zeros for "everyone".
126 */ 136 */
127 GNUNET_HashCode target; 137 GNUNET_HashCode target;
@@ -131,12 +141,15 @@ struct TransmitRequestMessage
131 141
132/** 142/**
133 * Receipt sent from a message receiver to the service to confirm delivery of 143 * Receipt sent from a message receiver to the service to confirm delivery of
134 * a chat message. 144 * a chat message and from the service to sender of the original message to
145 * acknowledge delivery.
135 */ 146 */
136struct ConfirmationReceiptMessage 147struct ConfirmationReceiptMessage
137{ 148{
138 /** 149 /**
139 * Message type will be GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT 150 * Message type will be
151 * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT when sending from client,
152 * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION when sending to client.
140 */ 153 */
141 struct GNUNET_MessageHeader header; 154 struct GNUNET_MessageHeader header;
142 155
@@ -351,8 +364,9 @@ struct P2PLeaveNotificationMessage
351 364
352/** 365/**
353 * Message send by one peer to another to indicate receiving of a chat message. 366 * Message send by one peer to another to indicate receiving of a chat message.
354 * After this struct, the remaining bytes are the actual text message. If the 367 * This struct is followed by the room name (only if the message is anonymous)
355 * mesasge is private, then the text is encrypted, otherwise it's plaintext. 368 * and then the remaining bytes are the actual text message. If the mesasge is
369 * private, then the text is encrypted, otherwise it's plaintext.
356 */ 370 */
357struct P2PReceiveNotificationMessage 371struct P2PReceiveNotificationMessage
358{ 372{
@@ -372,13 +386,23 @@ struct P2PReceiveNotificationMessage
372 uint32_t sequence_number GNUNET_PACKED; 386 uint32_t sequence_number GNUNET_PACKED;
373 387
374 /** 388 /**
389 * Length of the room name. This is only used for anonymous messages.
390 */
391 uint16_t room_name_len GNUNET_PACKED;
392
393 /**
375 * Reserved (for alignment). 394 * Reserved (for alignment).
376 */ 395 */
377 uint32_t reserved GNUNET_PACKED; 396 uint16_t reserved GNUNET_PACKED;
397
398 /**
399 * Timestamp of the message.
400 */
401 struct GNUNET_TIME_AbsoluteNBO timestamp;
378 402
379 /** 403 /**
380 * Hash of the public key of the pseudonym of the sender of the message 404 * Hash of the public key of the pseudonym of the sender of the message
381 * TBD: Should be all zeros for anonymous. 405 * Should be all zeros for anonymous.
382 */ 406 */
383 GNUNET_HashCode sender; 407 GNUNET_HashCode sender;
384 408
diff --git a/src/chat/gnunet-chat.c b/src/chat/gnunet-chat.c
index 450996382..22bdcc237 100644
--- a/src/chat/gnunet-chat.c
+++ b/src/chat/gnunet-chat.c
@@ -78,6 +78,20 @@ static int do_help (const char *args, const void *xtra);
78 78
79 79
80/** 80/**
81 * Callback used for notification that we have joined the room.
82 *
83 * @param cls closure
84 * @return GNUNET_OK
85 */
86static int
87join_cb (void *cls)
88{
89 fprintf (stdout, _("Joined\n"));
90 return GNUNET_OK;
91}
92
93
94/**
81 * Callback used for notification about incoming messages. 95 * Callback used for notification about incoming messages.
82 * 96 *
83 * @param cls closure, NULL 97 * @param cls closure, NULL
@@ -93,11 +107,13 @@ static int
93receive_cb (void *cls, 107receive_cb (void *cls,
94 struct GNUNET_CHAT_Room *room, 108 struct GNUNET_CHAT_Room *room,
95 const GNUNET_HashCode *sender, 109 const GNUNET_HashCode *sender,
96 const struct GNUNET_CONTAINER_MetaData *meta, 110 const struct GNUNET_CONTAINER_MetaData *member_info,
97 const char *message, 111 const char *message,
112 struct GNUNET_TIME_Absolute timestamp,
98 enum GNUNET_CHAT_MsgOptions options) 113 enum GNUNET_CHAT_MsgOptions options)
99{ 114{
100 char *nick; 115 char *nick;
116 char *time;
101 const char *fmt; 117 const char *fmt;
102 118
103 if (NULL != sender) 119 if (NULL != sender)
@@ -109,43 +125,43 @@ receive_cb (void *cls,
109 { 125 {
110 case GNUNET_CHAT_MSG_OPTION_NONE: 126 case GNUNET_CHAT_MSG_OPTION_NONE:
111 case GNUNET_CHAT_MSG_ANONYMOUS: 127 case GNUNET_CHAT_MSG_ANONYMOUS:
112 fmt = _("`%s' said: %s\n"); 128 fmt = _("(%s) `%s' said: %s\n");
113 break; 129 break;
114 case GNUNET_CHAT_MSG_PRIVATE: 130 case GNUNET_CHAT_MSG_PRIVATE:
115 fmt = _("`%s' said to you: %s\n"); 131 fmt = _("(%s) `%s' said to you: %s\n");
116 break; 132 break;
117 case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS: 133 case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS:
118 fmt = _("`%s' said to you: %s\n"); 134 fmt = _("(%s) `%s' said to you: %s\n");
119 break; 135 break;
120 case GNUNET_CHAT_MSG_AUTHENTICATED: 136 case GNUNET_CHAT_MSG_AUTHENTICATED:
121 fmt = _("`%s' said for sure: %s\n"); 137 fmt = _("(%s) `%s' said for sure: %s\n");
122 break; 138 break;
123 case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED: 139 case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED:
124 fmt = _("`%s' said to you for sure: %s\n"); 140 fmt = _("(%s) `%s' said to you for sure: %s\n");
125 break; 141 break;
126 case GNUNET_CHAT_MSG_ACKNOWLEDGED: 142 case GNUNET_CHAT_MSG_ACKNOWLEDGED:
127 fmt = _("`%s' was confirmed that you received: %s\n"); 143 fmt = _("(%s) `%s' was confirmed that you received: %s\n");
128 break; 144 break;
129 case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: 145 case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED:
130 fmt = _("`%s' was confirmed that you and only you received: %s\n"); 146 fmt = _("(%s) `%s' was confirmed that you and only you received: %s\n");
131 break; 147 break;
132 case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED: 148 case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED:
133 fmt = _("`%s' was confirmed that you received from him or her: %s\n"); 149 fmt = _("(%s) `%s' was confirmed that you received from him or her: %s\n");
134 break; 150 break;
135 case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: 151 case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED:
136 fmt = 152 fmt = _("(%s) `%s' was confirmed that you and only you received from him or her: %s\n");
137 _
138 ("`%s' was confirmed that you and only you received from him or her: %s\n");
139 break; 153 break;
140 case GNUNET_CHAT_MSG_OFF_THE_RECORD: 154 case GNUNET_CHAT_MSG_OFF_THE_RECORD:
141 fmt = _("`%s' said off the record: %s\n"); 155 fmt = _("(%s) `%s' said off the record: %s\n");
142 break; 156 break;
143 default: 157 default:
144 fmt = _("<%s> said using an unknown message type: %s\n"); 158 fmt = _("(%s) <%s> said using an unknown message type: %s\n");
145 break; 159 break;
146 } 160 }
147 fprintf (stdout, fmt, nick, message); 161 time = GNUNET_STRINGS_absolute_time_to_string (timestamp);
162 fprintf (stdout, fmt, time, nick, message);
148 GNUNET_free (nick); 163 GNUNET_free (nick);
164 GNUNET_free (time);
149 return GNUNET_OK; 165 return GNUNET_OK;
150} 166}
151 167
@@ -168,9 +184,7 @@ confirmation_cb (void *cls,
168 struct GNUNET_CHAT_Room *room, 184 struct GNUNET_CHAT_Room *room,
169 uint32_t orig_seq_number, 185 uint32_t orig_seq_number,
170 struct GNUNET_TIME_Absolute timestamp, 186 struct GNUNET_TIME_Absolute timestamp,
171 const GNUNET_HashCode *receiver, 187 const GNUNET_HashCode *receiver)
172 const GNUNET_HashCode *msg_hash,
173 const struct GNUNET_CRYPTO_RsaSignature *receipt)
174{ 188{
175 char *nick; 189 char *nick;
176 190
@@ -248,18 +262,6 @@ member_list_cb (void *cls,
248 262
249 263
250static int 264static int
251do_transmit (const char *msg, const void *xtra)
252{
253 uint32_t seq;
254 GNUNET_CHAT_send_message (room,
255 msg,
256 GNUNET_CHAT_MSG_OPTION_NONE,
257 NULL, &seq);
258 return GNUNET_OK;
259}
260
261
262static int
263do_join (const char *arg, const void *xtra) 265do_join (const char *arg, const void *xtra)
264{ 266{
265 char *my_name; 267 char *my_name;
@@ -276,6 +278,7 @@ do_join (const char *arg, const void *xtra)
276 meta, 278 meta,
277 room_name, 279 room_name,
278 -1, 280 -1,
281 &join_cb, NULL,
279 &receive_cb, NULL, 282 &receive_cb, NULL,
280 &member_list_cb, NULL, 283 &member_list_cb, NULL,
281 &confirmation_cb, NULL, &me); 284 &confirmation_cb, NULL, &me);
@@ -285,7 +288,7 @@ do_join (const char *arg, const void *xtra)
285 return GNUNET_SYSERR; 288 return GNUNET_SYSERR;
286 } 289 }
287 my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); 290 my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me);
288 fprintf (stdout, _("Joined room `%s' as user `%s'\n"), room_name, my_name); 291 fprintf (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, my_name);
289 GNUNET_free (my_name); 292 GNUNET_free (my_name);
290 return GNUNET_OK; 293 return GNUNET_OK;
291} 294}
@@ -315,6 +318,7 @@ do_nick (const char *msg, const void *xtra)
315 meta, 318 meta,
316 room_name, 319 room_name,
317 -1, 320 -1,
321 &join_cb, NULL,
318 &receive_cb, NULL, 322 &receive_cb, NULL,
319 &member_list_cb, NULL, 323 &member_list_cb, NULL,
320 &confirmation_cb, NULL, &me); 324 &confirmation_cb, NULL, &me);
@@ -355,7 +359,19 @@ do_names (const char *msg, const void *xtra)
355 359
356 360
357static int 361static int
358do_pm (const char *msg, const void *xtra) 362do_send (const char *msg, const void *xtra)
363{
364 uint32_t seq;
365 GNUNET_CHAT_send_message (room,
366 msg,
367 GNUNET_CHAT_MSG_OPTION_NONE,
368 NULL, &seq);
369 return GNUNET_OK;
370}
371
372
373static int
374do_send_pm (const char *msg, const void *xtra)
359{ 375{
360 char *user; 376 char *user;
361 GNUNET_HashCode uid; 377 GNUNET_HashCode uid;
@@ -404,7 +420,7 @@ do_pm (const char *msg, const void *xtra)
404 420
405 421
406static int 422static int
407do_transmit_sig (const char *msg, const void *xtra) 423do_send_sig (const char *msg, const void *xtra)
408{ 424{
409 uint32_t seq; 425 uint32_t seq;
410 GNUNET_CHAT_send_message (room, 426 GNUNET_CHAT_send_message (room,
@@ -416,7 +432,7 @@ do_transmit_sig (const char *msg, const void *xtra)
416 432
417 433
418static int 434static int
419do_transmit_ack (const char *msg, const void *xtra) 435do_send_ack (const char *msg, const void *xtra)
420{ 436{
421 uint32_t seq; 437 uint32_t seq;
422 GNUNET_CHAT_send_message (room, 438 GNUNET_CHAT_send_message (room,
@@ -428,6 +444,18 @@ do_transmit_ack (const char *msg, const void *xtra)
428 444
429 445
430static int 446static int
447do_send_anonymous (const char *msg, const void *xtra)
448{
449 uint32_t seq;
450 GNUNET_CHAT_send_message (room,
451 msg,
452 GNUNET_CHAT_MSG_ANONYMOUS,
453 NULL, &seq);
454 return GNUNET_OK;
455}
456
457
458static int
431do_quit (const char *args, const void *xtra) 459do_quit (const char *args, const void *xtra)
432{ 460{
433 return GNUNET_SYSERR; 461 return GNUNET_SYSERR;
@@ -454,19 +482,24 @@ static struct ChatCommand commands[] = {
454 gettext_noop 482 gettext_noop
455 ("Use `/nick nickname' to change your nickname. This will cause you to" 483 ("Use `/nick nickname' to change your nickname. This will cause you to"
456 " leave the current room and immediately rejoin it with the new name.")}, 484 " leave the current room and immediately rejoin it with the new name.")},
457 {"/msg ", &do_pm, 485 {"/msg ", &do_send_pm,
458 gettext_noop 486 gettext_noop
459 ("Use `/msg nickname message' to send a private message to the specified" 487 ("Use `/msg nickname message' to send a private message to the specified"
460 " user")}, 488 " user")},
461 {"/notice ", &do_pm, 489 {"/notice ", &do_send_pm,
462 gettext_noop ("The `/notice' command is an alias for `/msg'")}, 490 gettext_noop ("The `/notice' command is an alias for `/msg'")},
463 {"/query ", &do_pm, 491 {"/query ", &do_send_pm,
464 gettext_noop ("The `/query' command is an alias for `/msg'")}, 492 gettext_noop ("The `/query' command is an alias for `/msg'")},
465 {"/sig ", &do_transmit_sig, 493 {"/sig ", &do_send_sig,
466 gettext_noop ("Use `/sig message' to send a signed public message")}, 494 gettext_noop ("Use `/sig message' to send a signed public message")},
467 {"/ack ", &do_transmit_ack, 495 {"/ack ", &do_send_ack,
468 gettext_noop 496 gettext_noop
469 ("Use `/ack message' to require signed acknowledgment of the message")}, 497 ("Use `/ack message' to require signed acknowledgment of the message")},
498 {"/anonymous ", &do_send_anonymous,
499 gettext_noop
500 ("Use `/anonymous message' to send a public anonymous message")},
501 {"/anon ", &do_send_anonymous,
502 gettext_noop ("The `/anon' command is an alias for `/anonymous'")},
470 {"/quit", &do_quit, 503 {"/quit", &do_quit,
471 gettext_noop ("Use `/quit' to terminate gnunet-chat")}, 504 gettext_noop ("Use `/quit' to terminate gnunet-chat")},
472 {"/leave", &do_quit, 505 {"/leave", &do_quit,
@@ -479,13 +512,9 @@ static struct ChatCommand commands[] = {
479 /* Add standard commands: 512 /* Add standard commands:
480 /whois (print metadata), 513 /whois (print metadata),
481 /ignore (set flag, check on receive!) */ 514 /ignore (set flag, check on receive!) */
482 /* Add special commands (currently supported):
483 + anonymous msgs
484 + authenticated msgs
485 */
486 /* the following three commands must be last! */ 515 /* the following three commands must be last! */
487 {"/", &do_unknown, NULL}, 516 {"/", &do_unknown, NULL},
488 {"", &do_transmit, NULL}, 517 {"", &do_send, NULL},
489 {NULL, NULL, NULL}, 518 {NULL, NULL, NULL},
490}; 519};
491 520
@@ -615,6 +644,7 @@ run (void *cls,
615 meta, 644 meta,
616 room_name, 645 room_name,
617 -1, 646 -1,
647 &join_cb, NULL,
618 &receive_cb, NULL, 648 &receive_cb, NULL,
619 &member_list_cb, NULL, 649 &member_list_cb, NULL,
620 &confirmation_cb, NULL, &me); 650 &confirmation_cb, NULL, &me);
@@ -628,7 +658,7 @@ run (void *cls,
628 return; 658 return;
629 } 659 }
630 my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); 660 my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me);
631 fprintf (stdout, _("Joined room `%s' as user `%s'\n"), room_name, my_name); 661 fprintf (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, my_name);
632 GNUNET_free (my_name); 662 GNUNET_free (my_name);
633 handle_cmd_task = 663 handle_cmd_task =
634 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, 664 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
diff --git a/src/chat/gnunet-service-chat.c b/src/chat/gnunet-service-chat.c
index e0a46abc4..69318e4e8 100644
--- a/src/chat/gnunet-service-chat.c
+++ b/src/chat/gnunet-service-chat.c
@@ -33,9 +33,10 @@
33#include "gnunet_signatures.h" 33#include "gnunet_signatures.h"
34#include "chat.h" 34#include "chat.h"
35 35
36#define DEBUG_CHAT_SERVICE GNUNET_YES 36#define DEBUG_CHAT_SERVICE GNUNET_NO
37#define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) 37#define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
38#define QUEUE_SIZE 16 38#define QUEUE_SIZE 16
39#define MAX_ANONYMOUS_MSG_LIST_LENGTH 16
39 40
40 41
41/** 42/**
@@ -93,6 +94,20 @@ struct ChatClient
93 94
94}; 95};
95 96
97/**
98 * Linked list of recent anonymous messages.
99 */
100struct AnonymousMessage
101{
102 struct AnonymousMessage *next;
103
104 /**
105 * Hash of the message.
106 */
107 GNUNET_HashCode hash;
108
109};
110
96 111
97/** 112/**
98 * Handle to the core service (NULL until we've connected to it). 113 * Handle to the core service (NULL until we've connected to it).
@@ -119,6 +134,56 @@ static struct ChatClient *client_list_head = NULL;
119 */ 134 */
120struct GNUNET_SERVER_NotificationContext *nc = NULL; 135struct GNUNET_SERVER_NotificationContext *nc = NULL;
121 136
137/**
138 * Head of the list of recent anonymous messages.
139 */
140static struct AnonymousMessage *anonymous_list_head = NULL;
141
142
143static void
144remember_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
145{
146 static GNUNET_HashCode hash;
147 struct AnonymousMessage *anon_msg;
148 struct AnonymousMessage *prev;
149 int anon_list_len;
150
151 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
152 anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage));
153 anon_msg->hash = hash;
154 anon_msg->next = anonymous_list_head;
155 anonymous_list_head = anon_msg;
156 anon_list_len = 1;
157 prev = NULL;
158 while ((NULL != anon_msg->next))
159 {
160 prev = anon_msg;
161 anon_msg = anon_msg->next;
162 anon_list_len++;
163 }
164 if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH)
165 {
166 GNUNET_free (anon_msg);
167 if (NULL != prev)
168 prev->next = NULL;
169 }
170}
171
172
173static int
174lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
175{
176 static GNUNET_HashCode hash;
177 struct AnonymousMessage *anon_msg;
178
179 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
180 anon_msg = anonymous_list_head;
181 while ((NULL != anon_msg) &&
182 (0 != memcmp (&anon_msg->hash, &hash, sizeof (GNUNET_HashCode))))
183 anon_msg = anon_msg->next;
184 return (NULL != anon_msg);
185}
186
122 187
123/** 188/**
124 * Transmit a message notification to the peer. 189 * Transmit a message notification to the peer.
@@ -141,9 +206,17 @@ transmit_message_notification_to_peer (void *cls,
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Transmitting P2P message notification\n"); 207 "Transmitting P2P message notification\n");
143#endif 208#endif
209 if (buf == NULL)
210 {
211 /* client disconnected */
212#if DEBUG_CHAT_SERVICE
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Buffer is NULL, dropping the message\n");
215#endif
216 return 0;
217 }
144 msg_size = ntohs (my_msg->header.size); 218 msg_size = ntohs (my_msg->header.size);
145 GNUNET_assert (size >= msg_size); 219 GNUNET_assert (size >= msg_size);
146 GNUNET_assert (NULL != buf);
147 memcpy (m, my_msg, msg_size); 220 memcpy (m, my_msg, msg_size);
148 GNUNET_free (my_msg); 221 GNUNET_free (my_msg);
149 return msg_size; 222 return msg_size;
@@ -205,8 +278,10 @@ handle_transmit_request (void *cls,
205 struct GNUNET_CRYPTO_AesSessionKey key; 278 struct GNUNET_CRYPTO_AesSessionKey key;
206 char encrypted_msg[MAX_MESSAGE_LENGTH]; 279 char encrypted_msg[MAX_MESSAGE_LENGTH];
207 const char *room; 280 const char *room;
281 size_t room_len;
208 int msg_len; 282 int msg_len;
209 int priv_msg; 283 int is_priv;
284 int is_anon;
210 285
211 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n"); 286 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
212 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage)) 287 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
@@ -218,8 +293,8 @@ handle_transmit_request (void *cls,
218 } 293 }
219 trmsg = (const struct TransmitRequestMessage *) message; 294 trmsg = (const struct TransmitRequestMessage *) message;
220 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage); 295 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
221 priv_msg = (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE) != 0; 296 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
222 if (priv_msg) 297 if (is_priv)
223 { 298 {
224#if DEBUG_CHAT_SERVICE 299#if DEBUG_CHAT_SERVICE
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n"); 300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
@@ -244,7 +319,7 @@ handle_transmit_request (void *cls,
244 msg_len); 319 msg_len);
245 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); 320 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
246 rnmsg->msg_options = trmsg->msg_options; 321 rnmsg->msg_options = trmsg->msg_options;
247 rnmsg->sequence_number = trmsg->sequence_number; 322 rnmsg->timestamp = trmsg->timestamp;
248 pos = client_list_head; 323 pos = client_list_head;
249 while ((NULL != pos) && (pos->client != client)) 324 while ((NULL != pos) && (pos->client != client))
250 pos = pos->next; 325 pos = pos->next;
@@ -260,11 +335,18 @@ handle_transmit_request (void *cls,
260 } 335 }
261 room = pos->room; 336 room = pos->room;
262 pos->msg_sequence_number = ntohl (trmsg->sequence_number); 337 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
263 if (0 == (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)) 338 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
264 rnmsg->sender = pos->id; 339 if (is_anon)
265 else 340 {
266 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode)); 341 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
267 if (priv_msg) 342 rnmsg->sequence_number = 0;
343 }
344 else
345 {
346 rnmsg->sender = pos->id;
347 rnmsg->sequence_number = trmsg->sequence_number;
348 }
349 if (is_priv)
268 { 350 {
269#if DEBUG_CHAT_SERVICE 351#if DEBUG_CHAT_SERVICE
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -323,7 +405,7 @@ handle_transmit_request (void *cls,
323 (NULL != pos->client) && 405 (NULL != pos->client) &&
324 (pos->client != client)) 406 (pos->client != client))
325 { 407 {
326 if (((!priv_msg) || 408 if (((!is_priv) ||
327 (0 == memcmp (&trmsg->target, 409 (0 == memcmp (&trmsg->target,
328 &pos->id, 410 &pos->id,
329 sizeof (GNUNET_HashCode)))) && 411 sizeof (GNUNET_HashCode)))) &&
@@ -341,16 +423,25 @@ handle_transmit_request (void *cls,
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "Broadcasting message to neighbour peers\n"); 424 "Broadcasting message to neighbour peers\n");
343#endif 425#endif
426 if (is_anon)
427 {
428 room_len = strlen (room);
429 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
430 msg_len + room_len);
431 p2p_rnmsg->header.size =
432 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
433 room_len);
434 p2p_rnmsg->room_name_len = htons (room_len);
435 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
436 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
437 }
438 else
439 {
344 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + 440 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
345 msg_len); 441 msg_len);
346 p2p_rnmsg->header.size = htons (sizeof (struct P2PReceiveNotificationMessage) + 442 p2p_rnmsg->header.size =
347 msg_len); 443 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
348 p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION); 444 if (is_priv)
349 p2p_rnmsg->msg_options = trmsg->msg_options;
350 p2p_rnmsg->sequence_number = trmsg->sequence_number;
351 memcpy (&p2p_rnmsg->sender, &rnmsg->sender, sizeof (GNUNET_HashCode));
352 p2p_rnmsg->target = trmsg->target;
353 if (priv_msg)
354 { 445 {
355 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len); 446 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
356 memcpy (&p2p_rnmsg->encrypted_key, 447 memcpy (&p2p_rnmsg->encrypted_key,
@@ -358,9 +449,17 @@ handle_transmit_request (void *cls,
358 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); 449 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
359 } 450 }
360 else 451 else
361 {
362 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len); 452 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
363 } 453 }
454 p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
455 p2p_rnmsg->msg_options = trmsg->msg_options;
456 p2p_rnmsg->sequence_number = trmsg->sequence_number;
457 p2p_rnmsg->timestamp = trmsg->timestamp;
458 p2p_rnmsg->reserved = 0;
459 p2p_rnmsg->sender = rnmsg->sender;
460 p2p_rnmsg->target = trmsg->target;
461 if (is_anon)
462 remember_anonymous_message (p2p_rnmsg);
364 GNUNET_CORE_iterate_peers (cfg, 463 GNUNET_CORE_iterate_peers (cfg,
365 &send_message_noficiation, 464 &send_message_noficiation,
366 p2p_rnmsg); 465 p2p_rnmsg);
@@ -591,9 +690,17 @@ transmit_confirmation_receipt_to_peer (void *cls,
591 "Transmitting P2P confirmation receipt to '%s'\n", 690 "Transmitting P2P confirmation receipt to '%s'\n",
592 GNUNET_h2s (&receipt->target)); 691 GNUNET_h2s (&receipt->target));
593#endif 692#endif
693 if (buf == NULL)
694 {
695 /* client disconnected */
696#if DEBUG_CHAT_SERVICE
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
698 "Buffer is NULL, dropping the message\n");
699#endif
700 return 0;
701 }
594 msg_size = sizeof (struct P2PConfirmationReceiptMessage); 702 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
595 GNUNET_assert (size >= msg_size); 703 GNUNET_assert (size >= msg_size);
596 GNUNET_assert (NULL != buf);
597 memcpy (buf, receipt, msg_size); 704 memcpy (buf, receipt, msg_size);
598 GNUNET_free (receipt); 705 GNUNET_free (receipt);
599 return msg_size; 706 return msg_size;
@@ -765,9 +872,17 @@ transmit_leave_notification_to_peer (void *cls,
765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
766 "Transmitting P2P leave notification\n"); 873 "Transmitting P2P leave notification\n");
767#endif 874#endif
875 if (buf == NULL)
876 {
877 /* client disconnected */
878#if DEBUG_CHAT_SERVICE
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Buffer is NULL, dropping the message\n");
881#endif
882 return 0;
883 }
768 msg_size = sizeof (struct P2PLeaveNotificationMessage); 884 msg_size = sizeof (struct P2PLeaveNotificationMessage);
769 GNUNET_assert (size >= msg_size); 885 GNUNET_assert (size >= msg_size);
770 GNUNET_assert (NULL != buf);
771 m = buf; 886 m = buf;
772 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION); 887 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
773 m->header.size = htons (msg_size); 888 m->header.size = htons (msg_size);
@@ -787,7 +902,6 @@ send_leave_noficiation (void *cls,
787 const struct GNUNET_TRANSPORT_ATS_Information *atsi) 902 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
788{ 903{
789 struct ChatClient *entry = cls; 904 struct ChatClient *entry = cls;
790 struct GNUNET_CORE_TransmitHandle *th;
791 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; 905 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
792 size_t msg_size; 906 size_t msg_size;
793 907
@@ -806,14 +920,15 @@ send_leave_noficiation (void *cls,
806 msg_size = sizeof (struct P2PLeaveNotificationMessage); 920 msg_size = sizeof (struct P2PLeaveNotificationMessage);
807 public_key = GNUNET_memdup (&entry->public_key, 921 public_key = GNUNET_memdup (&entry->public_key,
808 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); 922 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
809 th = GNUNET_CORE_notify_transmit_ready (core, 923 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
810 1, 924 1,
811 MAX_TRANSMIT_DELAY, 925 MAX_TRANSMIT_DELAY,
812 peer, 926 peer,
813 msg_size, 927 msg_size,
814 &transmit_leave_notification_to_peer, 928 &transmit_leave_notification_to_peer,
815 public_key); 929 public_key))
816 GNUNET_assert (NULL != th); 930 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
931 _("Failed to queue a leave notification\n"));
817 } 932 }
818} 933}
819 934
@@ -1108,8 +1223,12 @@ handle_p2p_message_notification (void *cls,
1108 struct ChatClient *sender; 1223 struct ChatClient *sender;
1109 struct ChatClient *pos; 1224 struct ChatClient *pos;
1110 static GNUNET_HashCode all_zeros; 1225 static GNUNET_HashCode all_zeros;
1111 int priv_msg; 1226 int is_priv;
1227 int is_anon;
1112 uint16_t msg_len; 1228 uint16_t msg_len;
1229 uint16_t room_name_len;
1230 char *room_name = NULL;
1231 char *text;
1113 1232
1114 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n"); 1233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1115 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage)) 1234 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
@@ -1119,6 +1238,37 @@ handle_p2p_message_notification (void *cls,
1119 return GNUNET_SYSERR; 1238 return GNUNET_SYSERR;
1120 } 1239 }
1121 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message; 1240 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1241 msg_len = ntohs (p2p_rnmsg->header.size) -
1242 sizeof (struct P2PReceiveNotificationMessage);
1243
1244 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1245 if (is_anon)
1246 {
1247 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1248 if (msg_len <= room_name_len)
1249 {
1250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1251 "Malformed message: wrong length of the room name\n");
1252 GNUNET_break_op (0);
1253 return GNUNET_SYSERR;
1254 }
1255 msg_len -= room_name_len;
1256 if (lookup_anonymous_message (p2p_rnmsg))
1257 {
1258#if DEBUG_CHAT_SERVICE
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260 "This anonymous message has already been handled.");
1261#endif
1262 return GNUNET_OK;
1263 }
1264 remember_anonymous_message (p2p_rnmsg);
1265 room_name = GNUNET_malloc (room_name_len + 1);
1266 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1267 room_name[room_name_len] = '\0';
1268 text = (char *) &p2p_rnmsg[1] + room_name_len;
1269 }
1270 else
1271 {
1122 sender = client_list_head; 1272 sender = client_list_head;
1123 while ((NULL != sender) && 1273 while ((NULL != sender) &&
1124 (0 != memcmp (&sender->id, 1274 (0 != memcmp (&sender->id,
@@ -1127,10 +1277,13 @@ handle_p2p_message_notification (void *cls,
1127 sender = sender->next; 1277 sender = sender->next;
1128 if (NULL == sender) 1278 if (NULL == sender)
1129 { 1279 {
1130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1280 /* not an error since the sender may have left before we got the
1281 message */
1282#if DEBUG_CHAT_SERVICE
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131 "Unknown source. Rejecting the message\n"); 1284 "Unknown source. Rejecting the message\n");
1132 GNUNET_break_op (0); 1285#endif
1133 return GNUNET_SYSERR; 1286 return GNUNET_OK;
1134 } 1287 }
1135 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number)) 1288 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1136 { 1289 {
@@ -1138,15 +1291,19 @@ handle_p2p_message_notification (void *cls,
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "This message has already been handled." 1292 "This message has already been handled."
1140 " Sequence numbers (msg/sender): %u/%u\n", 1293 " Sequence numbers (msg/sender): %u/%u\n",
1141 ntohl (p2p_rnmsg->sequence_number), sender->msg_sequence_number); 1294 ntohl (p2p_rnmsg->sequence_number),
1295 sender->msg_sequence_number);
1142#endif 1296#endif
1143 return GNUNET_OK; 1297 return GNUNET_OK;
1144 } 1298 }
1145 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number); 1299 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1146 msg_len = ntohs (p2p_rnmsg->header.size) - 1300 room_name = sender->room;
1147 sizeof (struct P2PReceiveNotificationMessage); 1301 text = (char *) &p2p_rnmsg[1];
1302 }
1303
1148#if DEBUG_CHAT_SERVICE 1304#if DEBUG_CHAT_SERVICE
1149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n"); 1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306 "Sending message to local room members\n");
1150#endif 1307#endif
1151 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); 1308 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1152 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) + 1309 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
@@ -1154,21 +1311,22 @@ handle_p2p_message_notification (void *cls,
1154 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); 1311 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1155 rnmsg->msg_options = p2p_rnmsg->msg_options; 1312 rnmsg->msg_options = p2p_rnmsg->msg_options;
1156 rnmsg->sequence_number = p2p_rnmsg->sequence_number; 1313 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1157 priv_msg = (0 != memcmp (&all_zeros, 1314 rnmsg->timestamp = p2p_rnmsg->timestamp;
1315 is_priv = (0 != memcmp (&all_zeros,
1158 &p2p_rnmsg->target, sizeof (GNUNET_HashCode))); 1316 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1159 if (priv_msg) 1317 if (is_priv)
1160 memcpy (&rnmsg->encrypted_key, 1318 memcpy (&rnmsg->encrypted_key,
1161 &p2p_rnmsg->encrypted_key, 1319 &p2p_rnmsg->encrypted_key,
1162 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); 1320 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1163 memcpy (&rnmsg->sender, &p2p_rnmsg->sender, sizeof (GNUNET_HashCode)); 1321 rnmsg->sender = p2p_rnmsg->sender;
1164 memcpy (&rnmsg[1], &p2p_rnmsg[1], msg_len); 1322 memcpy (&rnmsg[1], text, msg_len);
1165 pos = client_list_head; 1323 pos = client_list_head;
1166 while (NULL != pos) 1324 while (NULL != pos)
1167 { 1325 {
1168 if ((0 == strcmp (sender->room, pos->room)) && 1326 if ((0 == strcmp (room_name, pos->room)) &&
1169 (NULL != pos->client)) 1327 (NULL != pos->client))
1170 { 1328 {
1171 if (((!priv_msg) || 1329 if (((!is_priv) ||
1172 (0 == memcmp (&p2p_rnmsg->target, 1330 (0 == memcmp (&p2p_rnmsg->target,
1173 &pos->id, 1331 &pos->id,
1174 sizeof (GNUNET_HashCode)))) && 1332 sizeof (GNUNET_HashCode)))) &&
@@ -1182,6 +1340,8 @@ handle_p2p_message_notification (void *cls,
1182 } 1340 }
1183 pos = pos->next; 1341 pos = pos->next;
1184 } 1342 }
1343 if (is_anon)
1344 GNUNET_free (room_name);
1185#if DEBUG_CHAT_SERVICE 1345#if DEBUG_CHAT_SERVICE
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Broadcasting message notification to neighbour peers\n"); 1347 "Broadcasting message notification to neighbour peers\n");
@@ -1441,6 +1601,9 @@ static void
1441cleanup_task (void *cls, 1601cleanup_task (void *cls,
1442 const struct GNUNET_SCHEDULER_TaskContext *tc) 1602 const struct GNUNET_SCHEDULER_TaskContext *tc)
1443{ 1603{
1604 struct AnonymousMessage *next_msg;
1605 struct ChatClient *next_client;
1606
1444 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n"); 1607 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1445 if (NULL != core) 1608 if (NULL != core)
1446 { 1609 {
@@ -1452,6 +1615,20 @@ cleanup_task (void *cls,
1452 GNUNET_SERVER_notification_context_destroy (nc); 1615 GNUNET_SERVER_notification_context_destroy (nc);
1453 nc = NULL; 1616 nc = NULL;
1454 } 1617 }
1618 while (NULL != client_list_head)
1619 {
1620 next_client = client_list_head->next;
1621 GNUNET_free (client_list_head->room);
1622 GNUNET_free_non_null (client_list_head->member_info);
1623 GNUNET_free (client_list_head);
1624 client_list_head = next_client;
1625 }
1626 while (NULL != anonymous_list_head)
1627 {
1628 next_msg = anonymous_list_head->next;
1629 GNUNET_free (anonymous_list_head);
1630 anonymous_list_head = next_msg;
1631 }
1455} 1632}
1456 1633
1457 1634
diff --git a/src/core/core.h b/src/core/core.h
index acac7c407..7959e565b 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -30,7 +30,7 @@
30/** 30/**
31 * General core debugging. 31 * General core debugging.
32 */ 32 */
33#define DEBUG_CORE GNUNET_NO 33#define DEBUG_CORE GNUNET_YES
34 34
35/** 35/**
36 * Debugging interaction core-clients. 36 * Debugging interaction core-clients.
diff --git a/src/include/gnunet_chat_service.h b/src/include/gnunet_chat_service.h
index 059dff254..732d625f2 100644
--- a/src/include/gnunet_chat_service.h
+++ b/src/include/gnunet_chat_service.h
@@ -89,6 +89,14 @@ enum GNUNET_CHAT_MsgOptions
89struct GNUNET_CHAT_Room; 89struct GNUNET_CHAT_Room;
90 90
91/** 91/**
92 * Callback used for notification that we have joined the room.
93 *
94 * @param cls closure
95 * @return GNUNET_OK
96 */
97typedef int (*GNUNET_CHAT_JoinCallback) (void *cls);
98
99/**
92 * Callback used for notification about incoming messages. 100 * Callback used for notification about incoming messages.
93 * 101 *
94 * @param cls closure 102 * @param cls closure
@@ -96,6 +104,7 @@ struct GNUNET_CHAT_Room;
96 * @param sender what is the ID of the sender? (maybe NULL) 104 * @param sender what is the ID of the sender? (maybe NULL)
97 * @param member_info information about the joining member 105 * @param member_info information about the joining member
98 * @param message the message text 106 * @param message the message text
107 * @param timestamp when was the message sent?
99 * @param options options for the message 108 * @param options options for the message
100 * @return GNUNET_OK to accept the message now, GNUNET_NO to 109 * @return GNUNET_OK to accept the message now, GNUNET_NO to
101 * accept (but user is away), GNUNET_SYSERR to signal denied delivery 110 * accept (but user is away), GNUNET_SYSERR to signal denied delivery
@@ -105,11 +114,13 @@ typedef int (*GNUNET_CHAT_MessageCallback) (void *cls,
105 const GNUNET_HashCode *sender, 114 const GNUNET_HashCode *sender,
106 const struct GNUNET_CONTAINER_MetaData *member_info, 115 const struct GNUNET_CONTAINER_MetaData *member_info,
107 const char *message, 116 const char *message,
117 struct GNUNET_TIME_Absolute timestamp,
108 enum GNUNET_CHAT_MsgOptions options); 118 enum GNUNET_CHAT_MsgOptions options);
109 119
110/** 120/**
111 * Callback used for notification that another room member has joined or left. 121 * Callback used for notification that another room member has joined or left.
112 * 122 *
123 * @param cls closure
113 * @param member_info will be non-null if the member is joining, NULL if he is 124 * @param member_info will be non-null if the member is joining, NULL if he is
114 * leaving 125 * leaving
115 * @param member_id hash of public key of the user (for unique identification) 126 * @param member_id hash of public key of the user (for unique identification)
@@ -129,8 +140,6 @@ typedef int (*GNUNET_CHAT_MemberListCallback) (void *cls,
129 * @param orig_seq_number sequence number of the original message 140 * @param orig_seq_number sequence number of the original message
130 * @param timestamp when was the message received? 141 * @param timestamp when was the message received?
131 * @param receiver who is confirming the receipt? 142 * @param receiver who is confirming the receipt?
132 * @param msg_hash hash of the original message
133 * @param receipt signature confirming delivery
134 * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further 143 * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further
135 * confirmations from anyone for this message 144 * confirmations from anyone for this message
136 */ 145 */
@@ -138,9 +147,7 @@ typedef int (*GNUNET_CHAT_MessageConfirmation) (void *cls,
138 struct GNUNET_CHAT_Room *room, 147 struct GNUNET_CHAT_Room *room,
139 uint32_t orig_seq_number, 148 uint32_t orig_seq_number,
140 struct GNUNET_TIME_Absolute timestamp, 149 struct GNUNET_TIME_Absolute timestamp,
141 const GNUNET_HashCode *receiver, 150 const GNUNET_HashCode *receiver);
142 const GNUNET_HashCode *msg_hash,
143 const struct GNUNET_CRYPTO_RsaSignature *receipt);
144 151
145/** 152/**
146 * Join a chat room. 153 * Join a chat room.
@@ -153,6 +160,8 @@ typedef int (*GNUNET_CHAT_MessageConfirmation) (void *cls,
153 * @param member_info information about the joining member 160 * @param member_info information about the joining member
154 * @param room_name name of the room 161 * @param room_name name of the room
155 * @param msg_options message options of the joining user 162 * @param msg_options message options of the joining user
163 * @param joinCallback which function to call when we've joined the room
164 * @param join_cls argument to callback
156 * @param messageCallback which function to call if a message has 165 * @param messageCallback which function to call if a message has
157 * been received? 166 * been received?
158 * @param message_cls argument to callback 167 * @param message_cls argument to callback
@@ -170,6 +179,8 @@ GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg,
170 struct GNUNET_CONTAINER_MetaData *member_info, 179 struct GNUNET_CONTAINER_MetaData *member_info,
171 const char *room_name, 180 const char *room_name,
172 enum GNUNET_CHAT_MsgOptions msg_options, 181 enum GNUNET_CHAT_MsgOptions msg_options,
182 GNUNET_CHAT_JoinCallback joinCallback,
183 void *join_cls,
173 GNUNET_CHAT_MessageCallback messageCallback, 184 GNUNET_CHAT_MessageCallback messageCallback,
174 void *message_cls, 185 void *message_cls,
175 GNUNET_CHAT_MemberListCallback memberCallback, 186 GNUNET_CHAT_MemberListCallback memberCallback,