aboutsummaryrefslogtreecommitdiff
path: root/src/service/messenger/messenger_api_room.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/messenger/messenger_api_room.c')
-rw-r--r--src/service/messenger/messenger_api_room.c913
1 files changed, 913 insertions, 0 deletions
diff --git a/src/service/messenger/messenger_api_room.c b/src/service/messenger/messenger_api_room.c
new file mode 100644
index 000000000..cddd43b22
--- /dev/null
+++ b/src/service/messenger/messenger_api_room.c
@@ -0,0 +1,913 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_room.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_room.h"
27
28#include "gnunet_common.h"
29#include "gnunet_messenger_service.h"
30#include "messenger_api_contact_store.h"
31#include "messenger_api_handle.h"
32#include "messenger_api_message.h"
33#include "messenger_api_message_control.h"
34#include <string.h>
35
36struct GNUNET_MESSENGER_Room*
37create_room (struct GNUNET_MESSENGER_Handle *handle,
38 const struct GNUNET_HashCode *key)
39{
40 GNUNET_assert ((handle) && (key));
41
42 struct GNUNET_MESSENGER_Room *room = GNUNET_new (struct
43 GNUNET_MESSENGER_Room);
44
45 room->handle = handle;
46 GNUNET_memcpy (&(room->key), key, sizeof(*key));
47
48 memset (&(room->last_message), 0, sizeof(room->last_message));
49
50 room->opened = GNUNET_NO;
51 room->use_handle_name = GNUNET_YES;
52 room->wait_for_sync = GNUNET_NO;
53
54 room->sender_id = NULL;
55
56 init_list_tunnels (&(room->entries));
57
58 room->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
59 room->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
60 room->links = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
61
62 init_queue_messages (&(room->queue));
63
64 room->control = create_message_control (room);
65
66 return room;
67}
68
69
70static enum GNUNET_GenericReturnValue
71iterate_destroy_message (void *cls,
72 const struct GNUNET_HashCode *key,
73 void *value)
74{
75 struct GNUNET_MESSENGER_RoomMessageEntry *entry = value;
76
77 destroy_message (entry->message);
78 GNUNET_free (entry);
79
80 return GNUNET_YES;
81}
82
83
84static enum GNUNET_GenericReturnValue
85iterate_destroy_link (void *cls,
86 const struct GNUNET_HashCode *key,
87 void *value)
88{
89 struct GNUNET_HashCode *hash = value;
90 GNUNET_free (hash);
91 return GNUNET_YES;
92}
93
94
95void
96destroy_room (struct GNUNET_MESSENGER_Room *room)
97{
98 GNUNET_assert (room);
99
100 destroy_message_control (room->control);
101
102 clear_queue_messages (&(room->queue));
103 clear_list_tunnels (&(room->entries));
104
105 if (room->messages)
106 {
107 GNUNET_CONTAINER_multihashmap_iterate (room->messages,
108 iterate_destroy_message, NULL);
109
110 GNUNET_CONTAINER_multihashmap_destroy (room->messages);
111 }
112
113 if (room->members)
114 GNUNET_CONTAINER_multishortmap_destroy (room->members);
115
116 if (room->links)
117 {
118 GNUNET_CONTAINER_multihashmap_iterate (room->links,
119 iterate_destroy_link, NULL);
120
121 GNUNET_CONTAINER_multihashmap_destroy (room->links);
122 }
123
124 if (room->sender_id)
125 GNUNET_free (room->sender_id);
126
127 GNUNET_free (room);
128}
129
130
131enum GNUNET_GenericReturnValue
132is_room_available (const struct GNUNET_MESSENGER_Room *room)
133{
134 GNUNET_assert (room);
135
136 if (! get_room_sender_id (room))
137 return GNUNET_NO;
138
139 if ((GNUNET_YES == room->opened) || (room->entries.head))
140 return GNUNET_YES;
141 else
142 return GNUNET_NO;
143}
144
145
146struct GNUNET_MESSENGER_Handle*
147get_room_handle (struct GNUNET_MESSENGER_Room *room)
148{
149 GNUNET_assert (room);
150
151 return room->handle;
152}
153
154
155const struct GNUNET_ShortHashCode*
156get_room_sender_id (const struct GNUNET_MESSENGER_Room *room)
157{
158 GNUNET_assert (room);
159
160 return room->sender_id;
161}
162
163
164void
165set_room_sender_id (struct GNUNET_MESSENGER_Room *room,
166 const struct GNUNET_ShortHashCode *id)
167{
168 GNUNET_assert (room);
169
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set member id for room: %s\n",
171 GNUNET_h2s (&(room->key)));
172
173 if (! id)
174 {
175 if (room->sender_id)
176 GNUNET_free (room->sender_id);
177
178 room->sender_id = NULL;
179 return;
180 }
181
182 if (! room->sender_id)
183 room->sender_id = GNUNET_new (struct GNUNET_ShortHashCode);
184
185 GNUNET_memcpy (room->sender_id, id, sizeof(struct GNUNET_ShortHashCode));
186}
187
188
189const struct GNUNET_MESSENGER_Message*
190get_room_message (const struct GNUNET_MESSENGER_Room *room,
191 const struct GNUNET_HashCode *hash)
192{
193 GNUNET_assert ((room) && (hash));
194
195 struct GNUNET_MESSENGER_RoomMessageEntry *entry =
196 GNUNET_CONTAINER_multihashmap_get (
197 room->messages, hash);
198
199 if ((! entry) || (GNUNET_YES != entry->completed))
200 return NULL;
201
202 return entry->message;
203}
204
205
206struct GNUNET_MESSENGER_Contact*
207get_room_sender (const struct GNUNET_MESSENGER_Room *room,
208 const struct GNUNET_HashCode *hash)
209{
210 GNUNET_assert ((room) && (hash));
211
212 struct GNUNET_MESSENGER_RoomMessageEntry *entry =
213 GNUNET_CONTAINER_multihashmap_get (
214 room->messages, hash);
215
216 if ((! entry) || (GNUNET_YES != entry->completed))
217 return NULL;
218
219 return entry->sender;
220}
221
222
223struct GNUNET_MESSENGER_Contact*
224get_room_recipient (const struct GNUNET_MESSENGER_Room *room,
225 const struct GNUNET_HashCode *hash)
226{
227 GNUNET_assert ((room) && (hash));
228
229 struct GNUNET_MESSENGER_RoomMessageEntry *entry =
230 GNUNET_CONTAINER_multihashmap_get (
231 room->messages, hash);
232
233 if ((! entry) || (GNUNET_YES != entry->completed))
234 return NULL;
235
236 return entry->recipient;
237}
238
239
240void
241callback_room_message (struct GNUNET_MESSENGER_Room *room,
242 const struct GNUNET_HashCode *hash)
243{
244 GNUNET_assert ((room) && (hash));
245
246 struct GNUNET_MESSENGER_Handle *handle = room->handle;
247
248 if (! handle)
249 return;
250
251 struct GNUNET_MESSENGER_RoomMessageEntry *entry;
252 entry = GNUNET_CONTAINER_multihashmap_get (room->messages, hash);
253
254 if (! entry)
255 return;
256
257 if (handle->msg_callback)
258 handle->msg_callback (handle->msg_cls, room,
259 entry->sender,
260 entry->recipient,
261 entry->message,
262 hash,
263 entry->flags);
264
265 if (entry->flags & GNUNET_MESSENGER_FLAG_UPDATE)
266 entry->flags ^= GNUNET_MESSENGER_FLAG_UPDATE;
267}
268
269
270static void
271handle_message (struct GNUNET_MESSENGER_Room *room,
272 const struct GNUNET_HashCode *hash,
273 struct GNUNET_MESSENGER_RoomMessageEntry *entry);
274
275
276void
277handle_join_message (struct GNUNET_MESSENGER_Room *room,
278 const struct GNUNET_HashCode *hash,
279 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
280{
281 GNUNET_assert ((room) && (hash) && (entry));
282
283 if (! entry->sender)
284 {
285 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
286 room->handle);
287 struct GNUNET_HashCode context;
288
289 get_context_from_member (&(room->key), &(entry->message->header.sender_id),
290 &context);
291
292 entry->sender = get_store_contact (store, &context,
293 &(entry->message->body.join.key));
294 }
295
296 if ((GNUNET_YES != GNUNET_CONTAINER_multishortmap_contains_value (
297 room->members, &(entry->message->header.sender_id), entry->sender)) &&
298 (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put (room->members,
299 &(entry->message->header
300 .sender_id),
301 entry->sender,
302 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)))
303
304 increase_contact_rc (entry->sender);
305}
306
307
308static void
309handle_leave_message (struct GNUNET_MESSENGER_Room *room,
310 const struct GNUNET_HashCode *hash,
311 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
312{
313 GNUNET_assert ((room) && (hash) && (entry));
314
315 if ((! entry->sender) ||
316 (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->members,
317 &(entry->message->
318 header.sender_id),
319 entry->sender)))
320 return;
321
322 if (GNUNET_YES == decrease_contact_rc (entry->sender))
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "A contact does not share any room with you anymore!\n");
325}
326
327
328static void
329handle_name_message (struct GNUNET_MESSENGER_Room *room,
330 const struct GNUNET_HashCode *hash,
331 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
332{
333 GNUNET_assert ((room) && (hash) && (entry));
334
335 if (GNUNET_MESSENGER_FLAG_SENT & entry->flags)
336 {
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Set rule for using handle name in room: %s\n",
339 GNUNET_h2s (&(room->key)));
340
341 const char *handle_name = get_handle_name (room->handle);
342
343 if ((handle_name) && (0 == strcmp (handle_name,
344 entry->message->body.name.name)))
345 room->use_handle_name = GNUNET_YES;
346 }
347
348 if (! entry->sender)
349 return;
350
351 set_contact_name (entry->sender, entry->message->body.name.name);
352}
353
354
355static void
356handle_key_message (struct GNUNET_MESSENGER_Room *room,
357 const struct GNUNET_HashCode *hash,
358 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
359{
360 GNUNET_assert ((room) && (hash) && (entry));
361
362 if (! entry->sender)
363 return;
364
365 struct GNUNET_HashCode context;
366 get_context_from_member (&(room->key), &(entry->message->header.sender_id),
367 &context);
368
369 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
370 room->handle);
371
372 update_store_contact (store, entry->sender, &context, &context,
373 &(entry->message->body.key.key));
374}
375
376
377static void
378handle_id_message (struct GNUNET_MESSENGER_Room *room,
379 const struct GNUNET_HashCode *hash,
380 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
381{
382 GNUNET_assert ((room) && (hash) && (entry));
383
384 if (GNUNET_MESSENGER_FLAG_SENT & entry->flags)
385 set_room_sender_id (room, &(entry->message->body.id.id));
386
387 if ((! entry->sender) ||
388 (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->members,
389 &(entry->message->
390 header.sender_id),
391 entry->sender)) ||
392 (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put (room->members,
393 &(entry->message->body.
394 id.id),
395 entry->sender,
396 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)))
397
398 return;
399
400 struct GNUNET_HashCode context, next_context;
401 get_context_from_member (&(room->key), &(entry->message->header.sender_id),
402 &context);
403 get_context_from_member (&(room->key), &(entry->message->body.id.id),
404 &next_context);
405
406 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
407 room->handle);
408
409 update_store_contact (store, entry->sender, &context, &next_context,
410 get_contact_key (entry->sender));
411}
412
413
414static void
415handle_miss_message (struct GNUNET_MESSENGER_Room *room,
416 const struct GNUNET_HashCode *hash,
417 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
418{
419 GNUNET_assert ((room) && (hash) && (entry));
420
421 if (0 == (GNUNET_MESSENGER_FLAG_SENT & entry->flags))
422 return;
423
424 struct GNUNET_MESSENGER_ListTunnel *match = find_list_tunnels (
425 &(room->entries), &(entry->message->body.miss.peer), NULL);
426
427 if (match)
428 remove_from_list_tunnels (&(room->entries), match);
429}
430
431
432static void
433handle_private_message (struct GNUNET_MESSENGER_Room *room,
434 const struct GNUNET_HashCode *hash,
435 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
436{
437 GNUNET_assert ((room) && (hash) && (entry));
438
439 struct GNUNET_MESSENGER_Message *private_message = copy_message (
440 entry->message);
441
442 if (! private_message)
443 return;
444
445 if (GNUNET_YES != decrypt_message (private_message,
446 get_handle_key (room->handle)))
447 {
448 destroy_message (private_message);
449 private_message = NULL;
450 }
451
452 if (! private_message)
453 return;
454
455 destroy_message (entry->message);
456
457 entry->recipient = get_handle_contact (room->handle, &(room->key));
458
459 entry->message = private_message;
460 entry->flags |= GNUNET_MESSENGER_FLAG_PRIVATE;
461
462 if ((entry->sender) && (entry->recipient))
463 handle_message (room, hash, entry);
464}
465
466
467extern void
468delete_message_in_room (struct GNUNET_MESSENGER_Room *room,
469 const struct GNUNET_HashCode *hash,
470 const struct GNUNET_TIME_Relative delay);
471
472
473static void
474handle_delete_message (struct GNUNET_MESSENGER_Room *room,
475 const struct GNUNET_HashCode *hash,
476 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
477{
478 GNUNET_assert ((room) && (hash) && (entry));
479
480 const struct GNUNET_HashCode *target_hash =
481 &(entry->message->body.deletion.hash);
482
483 if (get_handle_contact (room->handle, &(room->key)) == entry->sender)
484 {
485 struct GNUNET_TIME_Relative delay;
486 struct GNUNET_TIME_Absolute action;
487
488 delay = GNUNET_TIME_relative_ntoh (entry->message->body.deletion.delay);
489
490 action = GNUNET_TIME_absolute_ntoh (entry->message->header.timestamp);
491 action = GNUNET_TIME_absolute_add (action, delay);
492
493 delay = GNUNET_TIME_absolute_get_difference (GNUNET_TIME_absolute_get (),
494 action);
495
496 link_room_deletion (room, target_hash, delay, delete_message_in_room);
497 }
498
499 struct GNUNET_MESSENGER_RoomMessageEntry *target =
500 GNUNET_CONTAINER_multihashmap_get (room->messages, target_hash);
501
502 if (! target)
503 return;
504
505 if (((target->sender != entry->sender) &&
506 (get_handle_contact (room->handle, &(room->key)) != entry->sender)))
507 return;
508
509 target->flags |= GNUNET_MESSENGER_FLAG_DELETE;
510 callback_room_message (room, target_hash);
511
512 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (room->messages,
513 target_hash,
514 target))
515 {
516 destroy_message (target->message);
517 GNUNET_free (target);
518 }
519}
520
521
522static void
523handle_transcript_message (struct GNUNET_MESSENGER_Room *room,
524 const struct GNUNET_HashCode *hash,
525 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
526{
527 GNUNET_assert ((room) && (hash) && (entry));
528
529 if (get_handle_contact (room->handle, &(room->key)) != entry->sender)
530 return;
531
532 const struct GNUNET_HashCode *original_hash =
533 &(entry->message->body.transcript.hash);
534 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
535 room->handle);
536
537 struct GNUNET_MESSENGER_RoomMessageEntry *original =
538 GNUNET_CONTAINER_multihashmap_get (room->messages, original_hash);
539 struct GNUNET_MESSENGER_Message *original_message;
540
541 if (original)
542 goto read_transcript;
543
544 original = GNUNET_new (struct GNUNET_MESSENGER_RoomMessageEntry);
545
546 if (! original)
547 return;
548
549 original->sender = NULL;
550 original->recipient = NULL;
551
552 original->message = NULL;
553 original->flags = GNUNET_MESSENGER_FLAG_NONE;
554 original->completed = GNUNET_NO;
555
556 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages,
557 original_hash,
558 original,
559 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
560 {
561 GNUNET_free (original);
562 return;
563 }
564
565read_transcript:
566 original_message = copy_message (entry->message);
567
568 if (! original_message)
569 return;
570
571 if (GNUNET_YES != read_transcript_message (original_message))
572 {
573 destroy_message (original_message);
574 return;
575 }
576
577 original->recipient = get_store_contact (store,
578 NULL,
579 &(entry->message->body.transcript.key
580 ));
581
582 if (original->message)
583 {
584 if (GNUNET_MESSENGER_KIND_PRIVATE == original->message->header.kind)
585 original->flags |= GNUNET_MESSENGER_FLAG_PRIVATE;
586
587 copy_message_header (original_message, &(original->message->header));
588 destroy_message (original->message);
589 }
590
591 original->message = original_message;
592
593 link_room_message (room, hash, original_hash);
594 link_room_message (room, original_hash, hash);
595
596 if ((original->sender) && (original->recipient))
597 {
598 original->flags |= GNUNET_MESSENGER_FLAG_UPDATE;
599 handle_message (room, original_hash, original);
600 }
601}
602
603
604static void
605handle_message (struct GNUNET_MESSENGER_Room *room,
606 const struct GNUNET_HashCode *hash,
607 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
608{
609 GNUNET_assert ((room) && (hash) && (entry));
610
611 switch (entry->message->header.kind)
612 {
613 case GNUNET_MESSENGER_KIND_JOIN:
614 handle_join_message (room, hash, entry);
615 break;
616 case GNUNET_MESSENGER_KIND_LEAVE:
617 handle_leave_message (room, hash, entry);
618 break;
619 case GNUNET_MESSENGER_KIND_NAME:
620 handle_name_message (room, hash, entry);
621 break;
622 case GNUNET_MESSENGER_KIND_KEY:
623 handle_key_message (room, hash, entry);
624 break;
625 case GNUNET_MESSENGER_KIND_ID:
626 handle_id_message (room, hash, entry);
627 break;
628 case GNUNET_MESSENGER_KIND_MISS:
629 handle_miss_message (room, hash, entry);
630 break;
631 case GNUNET_MESSENGER_KIND_PRIVATE:
632 handle_private_message (room, hash, entry);
633 break;
634 case GNUNET_MESSENGER_KIND_DELETE:
635 handle_delete_message (room, hash, entry);
636 break;
637 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
638 handle_transcript_message (room, hash, entry);
639 break;
640 default:
641 break;
642 }
643
644 if (entry->flags & GNUNET_MESSENGER_FLAG_UPDATE)
645 callback_room_message (room, hash);
646}
647
648
649void
650handle_room_message (struct GNUNET_MESSENGER_Room *room,
651 struct GNUNET_MESSENGER_Contact *sender,
652 const struct GNUNET_MESSENGER_Message *message,
653 const struct GNUNET_HashCode *hash,
654 enum GNUNET_MESSENGER_MessageFlags flags)
655{
656 GNUNET_assert ((room) && (message) && (hash));
657
658 struct GNUNET_MESSENGER_RoomMessageEntry *entry;
659 entry = GNUNET_CONTAINER_multihashmap_get (room->messages, hash);
660
661 if (entry)
662 goto update_entry;
663
664 entry = GNUNET_new (struct GNUNET_MESSENGER_RoomMessageEntry);
665
666 if (! entry)
667 return;
668
669 entry->sender = NULL;
670 entry->recipient = NULL;
671
672 entry->message = NULL;
673 entry->flags = GNUNET_MESSENGER_FLAG_NONE;
674 entry->completed = GNUNET_NO;
675
676 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages, hash,
677 entry,
678 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
679 {
680 GNUNET_free (entry);
681 return;
682 }
683
684update_entry:
685 entry->sender = sender;
686 entry->flags = flags;
687
688 if (entry->message)
689 {
690 if (GNUNET_MESSENGER_KIND_PRIVATE == message->header.kind)
691 entry->flags |= GNUNET_MESSENGER_FLAG_PRIVATE;
692
693 copy_message_header (entry->message, &(message->header));
694 }
695 else
696 entry->message = copy_message (message);
697
698 entry->completed = GNUNET_YES;
699
700 handle_message (room, hash, entry);
701}
702
703
704void
705update_room_last_message (struct GNUNET_MESSENGER_Room *room,
706 const struct GNUNET_HashCode *hash)
707{
708 GNUNET_assert ((room) && (hash));
709
710 GNUNET_memcpy (&(room->last_message), hash, sizeof(room->last_message));
711}
712
713
714struct GNUNET_MESSENGER_MemberCall
715{
716 struct GNUNET_MESSENGER_Room *room;
717 GNUNET_MESSENGER_MemberCallback callback;
718 void *cls;
719};
720
721static enum GNUNET_GenericReturnValue
722iterate_local_members (void *cls,
723 const struct GNUNET_ShortHashCode *key,
724 void *value)
725{
726 struct GNUNET_MESSENGER_MemberCall *call = cls;
727 struct GNUNET_MESSENGER_Contact *contact = value;
728
729 return call->callback (call->cls, call->room, contact);
730}
731
732
733int
734iterate_room_members (struct GNUNET_MESSENGER_Room *room,
735 GNUNET_MESSENGER_MemberCallback callback,
736 void *cls)
737{
738 GNUNET_assert (room);
739
740 if (! callback)
741 return GNUNET_CONTAINER_multishortmap_iterate (room->members, NULL, NULL);
742
743 struct GNUNET_MESSENGER_MemberCall call;
744
745 call.room = room;
746 call.callback = callback;
747 call.cls = cls;
748
749 GNUNET_assert (callback);
750
751 return GNUNET_CONTAINER_multishortmap_iterate (room->members,
752 iterate_local_members,
753 &call);
754}
755
756
757struct GNUNET_MESSENGER_MemberFind
758{
759 const struct GNUNET_MESSENGER_Contact *contact;
760 enum GNUNET_GenericReturnValue result;
761};
762
763static enum GNUNET_GenericReturnValue
764iterate_find_member (void *cls,
765 const struct GNUNET_ShortHashCode *key,
766 void *value)
767{
768 struct GNUNET_MESSENGER_MemberFind *find = cls;
769 struct GNUNET_MESSENGER_Contact *contact = value;
770
771 if (contact == find->contact)
772 {
773 find->result = GNUNET_YES;
774 return GNUNET_NO;
775 }
776
777 return GNUNET_YES;
778}
779
780
781enum GNUNET_GenericReturnValue
782find_room_member (const struct GNUNET_MESSENGER_Room *room,
783 const struct GNUNET_MESSENGER_Contact *contact)
784{
785 GNUNET_assert (room);
786
787 struct GNUNET_MESSENGER_MemberFind find;
788
789 find.contact = contact;
790 find.result = GNUNET_NO;
791
792 GNUNET_CONTAINER_multishortmap_iterate (room->members, iterate_find_member,
793 &find);
794
795 return find.result;
796}
797
798
799static enum GNUNET_GenericReturnValue
800find_linked_hash (void *cls,
801 const struct GNUNET_HashCode *key,
802 void *value)
803{
804 const struct GNUNET_HashCode **result = cls;
805 struct GNUNET_HashCode *hash = value;
806
807 if (0 == GNUNET_CRYPTO_hash_cmp (hash, *result))
808 {
809 *result = NULL;
810 return GNUNET_NO;
811 }
812
813 return GNUNET_YES;
814}
815
816
817void
818link_room_message (struct GNUNET_MESSENGER_Room *room,
819 const struct GNUNET_HashCode *hash,
820 const struct GNUNET_HashCode *other)
821{
822 GNUNET_assert ((room) && (hash) && (other));
823
824 const struct GNUNET_HashCode **result = &other;
825 GNUNET_CONTAINER_multihashmap_get_multiple (room->links, hash,
826 find_linked_hash, result);
827
828 if (! *result)
829 return;
830
831 struct GNUNET_HashCode *value = GNUNET_memdup (other, sizeof(struct
832 GNUNET_HashCode))
833 ;
834 if (! value)
835 return;
836
837 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->links, hash, value,
838 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
839
840 GNUNET_free (value);
841}
842
843
844struct GNUNET_MESSENGER_RoomLinkDeletionInfo
845{
846 struct GNUNET_MESSENGER_Room *room;
847 struct GNUNET_TIME_Relative delay;
848 GNUNET_MESSENGER_RoomLinkDeletion deletion;
849};
850
851
852static enum GNUNET_GenericReturnValue
853clear_linked_hash (void *cls,
854 const struct GNUNET_HashCode *key,
855 void *value)
856{
857 struct GNUNET_HashCode **linked = cls;
858 struct GNUNET_HashCode *hash = value;
859
860 if (0 != GNUNET_CRYPTO_hash_cmp (*linked, hash))
861 return GNUNET_YES;
862
863 *linked = hash;
864 return GNUNET_NO;
865}
866
867
868static enum GNUNET_GenericReturnValue
869delete_linked_hash (void *cls,
870 const struct GNUNET_HashCode *key,
871 void *value)
872{
873 struct GNUNET_MESSENGER_RoomLinkDeletionInfo *info = cls;
874 struct GNUNET_HashCode *hash = value;
875
876 struct GNUNET_HashCode key_value;
877 GNUNET_memcpy (&key_value, key, sizeof (key_value));
878
879 struct GNUNET_HashCode *linked = &key_value;
880
881 GNUNET_CONTAINER_multihashmap_get_multiple (info->room->links, hash,
882 clear_linked_hash, &linked);
883
884 if ((linked != &key_value) &&
885 (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (info->room->links,
886 hash, linked)))
887 GNUNET_free (linked);
888
889 if (info->deletion)
890 info->deletion (info->room, hash, info->delay);
891
892 GNUNET_free (hash);
893 return GNUNET_YES;
894}
895
896
897void
898link_room_deletion (struct GNUNET_MESSENGER_Room *room,
899 const struct GNUNET_HashCode *hash,
900 const struct GNUNET_TIME_Relative delay,
901 GNUNET_MESSENGER_RoomLinkDeletion deletion)
902{
903 GNUNET_assert ((room) && (hash));
904
905 struct GNUNET_MESSENGER_RoomLinkDeletionInfo info;
906 info.room = room;
907 info.delay = delay;
908 info.deletion = deletion;
909
910 GNUNET_CONTAINER_multihashmap_get_multiple (room->links, hash,
911 delete_linked_hash, &info);
912 GNUNET_CONTAINER_multihashmap_remove_all (room->links, hash);
913}