aboutsummaryrefslogtreecommitdiff
path: root/src/gnunet_chat_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnunet_chat_lib.c')
-rw-r--r--src/gnunet_chat_lib.c693
1 files changed, 693 insertions, 0 deletions
diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c
new file mode 100644
index 0000000..23c541d
--- /dev/null
+++ b/src/gnunet_chat_lib.c
@@ -0,0 +1,693 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 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 gnunet_chat_lib.c
23 */
24
25#include "gnunet_chat_lib.h"
26
27#include <limits.h>
28
29#include "gnunet_chat_config.h"
30#include "gnunet_chat_contact.h"
31#include "gnunet_chat_context.h"
32#include "gnunet_chat_file.h"
33#include "gnunet_chat_group.h"
34#include "gnunet_chat_handle.h"
35#include "gnunet_chat_invitation.h"
36#include "gnunet_chat_message.h"
37#include "gnunet_chat_util.h"
38
39#include "gnunet_chat_lib_intern.c"
40
41struct GNUNET_CHAT_Handle*
42GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
43 const char *name,
44 GNUNET_CHAT_WarningCallback warn_cb, void *warn_cls,
45 GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls)
46{
47 if (!cfg)
48 return NULL;
49
50 if (!name)
51 return NULL;
52
53 return handle_create_from_config(
54 cfg, name, msg_cb, msg_cls, warn_cb, warn_cls
55 );
56}
57
58void
59GNUNET_CHAT_stop (struct GNUNET_CHAT_Handle *handle)
60{
61 if (!handle)
62 return;
63
64 handle_destroy(handle);
65}
66
67int
68GNUNET_CHAT_update (struct GNUNET_CHAT_Handle *handle)
69{
70 if (!handle)
71 return GNUNET_SYSERR;
72
73 return GNUNET_MESSENGER_update(handle->messenger);
74}
75
76int
77GNUNET_CHAT_set_name (struct GNUNET_CHAT_Handle *handle,
78 const char *name)
79{
80 if (!handle)
81 return GNUNET_SYSERR;
82
83 if (!name)
84 return GNUNET_NO;
85
86 return GNUNET_MESSENGER_set_name(handle->messenger, name);
87}
88
89const char*
90GNUNET_CHAT_get_name (const struct GNUNET_CHAT_Handle *handle)
91{
92 if (!handle)
93 return NULL;
94
95 return GNUNET_MESSENGER_get_name(handle->messenger);
96}
97
98const struct GNUNET_IDENTITY_PublicKey*
99GNUNET_CHAT_get_key (const struct GNUNET_CHAT_Handle *handle)
100{
101 if (!handle)
102 return NULL;
103
104 return GNUNET_MESSENGER_get_key(handle->messenger);
105}
106
107int
108GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle,
109 GNUNET_CHAT_ContactCallback callback,
110 void *cls)
111{
112 if (!handle)
113 return GNUNET_SYSERR;
114
115 struct GNUNET_CHAT_HandleIterateContacts it;
116 it.handle = handle;
117 it.cb = callback;
118 it.cls = cls;
119
120 return GNUNET_CONTAINER_multishortmap_iterate(
121 handle->contacts, it_handle_iterate_contacts, &it
122 );
123}
124
125struct GNUNET_CHAT_Group *
126GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle,
127 const char* topic)
128{
129 if (!handle)
130 return NULL;
131
132 struct GNUNET_HashCode key;
133
134 if (topic)
135 GNUNET_CRYPTO_hash(topic, strlen(topic), &key);
136 else
137 GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, &key, sizeof(key));
138
139 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(
140 handle->contexts, &key))
141 return NULL;
142
143 struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room(
144 handle->messenger, &key
145 );
146
147 struct GNUNET_CHAT_Context *context = context_create_from_room(handle, room);
148
149 context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP;
150
151 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
152 handle->contexts, &key, context,
153 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
154 goto destroy_context;
155
156 struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context);
157
158 util_set_name_field(topic, &(group->topic));
159
160 if (group->topic)
161 group_publish(group);
162
163 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(
164 handle->groups, &key, group,
165 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
166 return group;
167
168 group_destroy(group);
169
170 GNUNET_CONTAINER_multihashmap_remove(handle->contexts, &key, context);
171
172destroy_context:
173 context_destroy(context);
174 return NULL;
175}
176
177int
178GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle,
179 GNUNET_CHAT_GroupCallback callback,
180 void *cls)
181{
182 if (!handle)
183 return GNUNET_SYSERR;
184
185 struct GNUNET_CHAT_HandleIterateGroups it;
186 it.handle = handle;
187 it.cb = callback;
188 it.cls = cls;
189
190 return GNUNET_CONTAINER_multihashmap_iterate(
191 handle->groups, it_handle_iterate_groups, &it
192 );
193}
194
195int
196GNUNET_CHAT_contact_delete (struct GNUNET_CHAT_Contact *contact)
197{
198 if (!contact)
199 return GNUNET_SYSERR;
200
201 struct GNUNET_ShortHashCode shorthash;
202 util_shorthash_from_member(contact->member, &shorthash);
203
204 GNUNET_CONTAINER_multishortmap_remove(
205 contact->handle->contacts, &shorthash, contact
206 );
207
208 const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(
209 contact->context->room
210 );
211
212 GNUNET_CONTAINER_multihashmap_remove(
213 contact->handle->contexts, key, contact->context
214 );
215
216 GNUNET_MESSENGER_close_room(contact->context->room);
217
218 context_destroy(contact->context);
219 contact_destroy(contact);
220 return GNUNET_OK;
221}
222
223void
224GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact,
225 const char *name)
226{
227 if (!contact)
228 return;
229
230 util_set_name_field(name, &(contact->context->nick));
231}
232
233
234const char*
235GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact)
236{
237 if (!contact)
238 return NULL;
239
240 if (contact->context->nick)
241 return contact->context->nick;
242
243 return GNUNET_MESSENGER_contact_get_name(contact->member);
244}
245
246
247const struct GNUNET_IDENTITY_PublicKey*
248GNUNET_CHAT_contact_get_key (const struct GNUNET_CHAT_Contact *contact)
249{
250 if (!contact)
251 return NULL;
252
253 return GNUNET_MESSENGER_contact_get_key(contact->member);
254}
255
256
257struct GNUNET_CHAT_Context*
258GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact)
259{
260 if (!contact)
261 return NULL;
262
263 return contact->context;
264}
265
266
267int
268GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group)
269{
270 if (!group)
271 return GNUNET_SYSERR;
272
273 const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(
274 group->context->room
275 );
276
277 GNUNET_CONTAINER_multihashmap_remove(
278 group->handle->groups, key, group
279 );
280
281 GNUNET_CONTAINER_multihashmap_remove(
282 group->handle->contexts, key, group->context
283 );
284
285 GNUNET_MESSENGER_close_room(group->context->room);
286
287 context_destroy(group->context);
288 group_destroy(group);
289 return GNUNET_OK;
290}
291
292
293void
294GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group,
295 const char *name)
296{
297 if (!group)
298 return;
299
300 util_set_name_field(name, &(group->context->nick));
301}
302
303
304const char*
305GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group)
306{
307 if (!group)
308 return NULL;
309
310 return group->context->nick;
311}
312
313
314void
315GNUNET_CHAT_group_invite_contact (struct GNUNET_CHAT_Group *group,
316 struct GNUNET_CHAT_Contact *contact)
317{
318 if ((!group) || (!contact))
319 return;
320
321 const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(
322 group->context->room
323 );
324
325 GNUNET_MESSENGER_open_room(group->handle->messenger, key);
326
327 struct GNUNET_MESSENGER_Message msg;
328 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE;
329 GNUNET_CRYPTO_get_peer_identity(group->handle->cfg, &(msg.body.invite.door));
330 GNUNET_memcpy(&(msg.body.invite.key), key, sizeof(msg.body.invite.key));
331
332 GNUNET_MESSENGER_send_message(contact->context->room, &msg, contact->member);
333}
334
335int
336GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group,
337 GNUNET_CHAT_GroupContactCallback callback,
338 void *cls)
339{
340 if (!group)
341 return GNUNET_SYSERR;
342
343 struct GNUNET_CHAT_GroupIterateContacts it;
344 it.group = group;
345 it.cb = callback;
346 it.cls = cls;
347
348 return GNUNET_MESSENGER_iterate_members(
349 group->context->room, it_group_iterate_contacts, &it
350 );
351}
352
353
354struct GNUNET_CHAT_Context*
355GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group)
356{
357 if (!group)
358 return NULL;
359
360 return group->context;
361}
362
363void
364GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context,
365 const char *text)
366{
367 if ((!context) || (!text))
368 return;
369
370 struct GNUNET_MESSENGER_Message msg;
371 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT;
372 msg.body.text.text = GNUNET_strdup(text);
373
374 GNUNET_MESSENGER_send_message(context->room, &msg, NULL);
375
376 GNUNET_free(msg.body.text.text);
377}
378
379
380void
381GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context,
382 const char *path)
383{
384 if ((!context) || (!path))
385 return;
386
387 // TODO: encrypt file, publish file, share file
388}
389
390
391void
392GNUNET_CHAT_context_send_uri (struct GNUNET_CHAT_Context *context,
393 const char *uri)
394{
395 if ((!context) || (!uri))
396 return;
397
398 struct GNUNET_FS_Uri *furi = GNUNET_FS_uri_parse(uri, NULL);
399
400 if (!furi)
401 return;
402
403 // TODO: download file, hash file, share file
404}
405
406
407void
408GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context,
409 const struct GNUNET_CHAT_File *file)
410{
411 if ((!context) || (!file) || (strlen(file->name) > NAME_MAX))
412 return;
413
414 struct GNUNET_MESSENGER_Message msg;
415 msg.header.kind = GNUNET_MESSENGER_KIND_FILE;
416 GNUNET_memcpy(&(msg.body.file.key), &(file->key), sizeof(file->key));
417 GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash));
418 GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX);
419 msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri);
420
421 GNUNET_MESSENGER_send_message(context->room, &msg, NULL);
422
423 GNUNET_free(msg.body.file.uri);
424}
425
426
427void
428GNUNET_CHAT_context_delete_message (const struct GNUNET_CHAT_Message *message,
429 struct GNUNET_TIME_Relative delay)
430{
431 if (!message)
432 return;
433
434 struct GNUNET_MESSENGER_Message msg;
435 msg.header.kind = GNUNET_MESSENGER_KIND_DELETE;
436 GNUNET_memcpy(&(msg.body.delete.hash), &(message->hash), sizeof(message->hash));
437 msg.body.delete.delay = GNUNET_TIME_relative_hton(delay);
438
439 GNUNET_MESSENGER_send_message(message->context->room, &msg, NULL);
440}
441
442
443
444int
445GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context,
446 GNUNET_CHAT_ContextMessageCallback callback,
447 void *cls)
448{
449 if (!context)
450 return GNUNET_SYSERR;
451
452 struct GNUNET_CHAT_ContextIterateMessages it;
453 it.context = context;
454 it.cb = callback;
455 it.cls = cls;
456
457 return GNUNET_CONTAINER_multihashmap_iterate(
458 context->messages, it_context_iterate_messages, &it
459 );
460}
461
462
463enum GNUNET_CHAT_MessageKind
464GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message)
465{
466 if (!message)
467 return GNUNET_CHAT_KIND_UNKNOWN;
468
469 switch (message->msg->header.kind)
470 {
471 case GNUNET_MESSENGER_KIND_INVITE:
472 return GNUNET_CHAT_KIND_INVITATION;
473 case GNUNET_MESSENGER_KIND_TEXT:
474 return GNUNET_CHAT_KIND_TEXT;
475 case GNUNET_MESSENGER_KIND_FILE:
476 return GNUNET_CHAT_KIND_FILE;
477 default:
478 return GNUNET_CHAT_KIND_UNKNOWN;
479 }
480}
481
482
483struct GNUNET_TIME_Absolute
484GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message)
485{
486 if (!message)
487 return GNUNET_TIME_absolute_get_zero_();
488
489 return GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp);
490}
491
492
493const struct GNUNET_CHAT_Contact*
494GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message)
495{
496 if (!message)
497 return NULL;
498
499 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender(
500 message->context->room, &(message->hash)
501 );
502
503 if (!sender)
504 return NULL;
505
506 struct GNUNET_ShortHashCode shorthash;
507 util_shorthash_from_member(sender, &shorthash);
508
509 return GNUNET_CONTAINER_multishortmap_get(
510 message->context->handle->contacts, &shorthash
511 );
512}
513
514
515int
516GNUNET_CHAT_message_get_read_receipt (const struct GNUNET_CHAT_Message *message,
517 GNUNET_CHAT_MessageReadReceiptCallback callback,
518 void *cls)
519{
520 if (!message)
521 return GNUNET_SYSERR;
522
523 // TODO: request read receipt? / check if newer message was received of sender?
524
525 return GNUNET_SYSERR;
526}
527
528
529const char*
530GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message)
531{
532 if (!message)
533 return NULL;
534
535 if (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind)
536 return NULL;
537
538 return message->msg->body.text.text;
539}
540
541
542struct GNUNET_CHAT_File*
543GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message)
544{
545 if (!message)
546 return NULL;
547
548 if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind)
549 return NULL;
550
551 return GNUNET_CONTAINER_multihashmap_get(
552 message->context->handle->files,
553 &(message->msg->body.file.hash)
554 );
555}
556
557
558struct GNUNET_CHAT_Invitation*
559GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message)
560{
561 if (!message)
562 return NULL;
563
564 if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind)
565 return NULL;
566
567 return GNUNET_CONTAINER_multihashmap_get(
568 message->context->invites,
569 &(message->hash)
570 );
571}
572
573
574const struct GNUNET_HashCode*
575GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file)
576{
577 if (!file)
578 return NULL;
579
580 return &(file->hash);
581}
582
583
584uint64_t
585GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file)
586{
587 if (!file)
588 return 0;
589
590 if (file->uri)
591 return GNUNET_FS_uri_chk_get_file_size(file->uri);
592
593 const char *path = ""; // TODO: path = download_directory + file->name
594
595 // TODO: check size through info or check locally?
596
597 return 0;
598}
599
600
601int
602GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file)
603{
604 if (!file)
605 return GNUNET_SYSERR;
606
607 const char *path = ""; // TODO: path = download_directory + file->name
608
609 // TODO: check locally?
610
611 return GNUNET_SYSERR;
612}
613
614
615int
616GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file,
617 GNUNET_CHAT_MessageFileDownloadCallback callback,
618 void *cls)
619{
620 if (!file)
621 return GNUNET_SYSERR;
622
623 // TODO: check if downloading?
624
625 const char *path = ""; // TODO: path = download_directory + file->name
626
627 file->download = GNUNET_FS_download_start(
628 file->handle->fs,
629 file->uri,
630 NULL,
631 path,
632 NULL,
633 0,
634 0,
635 0,
636 GNUNET_FS_DOWNLOAD_OPTION_NONE,
637 NULL,
638 NULL
639 );
640
641 return GNUNET_OK;
642}
643
644
645int
646GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file)
647{
648 if (!file)
649 return GNUNET_SYSERR;
650
651 GNUNET_FS_download_suspend(file->download);
652 return GNUNET_OK;
653}
654
655
656int
657GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file)
658{
659 if (!file)
660 return GNUNET_SYSERR;
661
662 GNUNET_FS_download_resume(file->download);
663 return GNUNET_OK;
664}
665
666
667int
668GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file)
669{
670 if (!file)
671 return GNUNET_SYSERR;
672
673 GNUNET_FS_download_stop(file->download, GNUNET_YES);
674 file->download = NULL;
675 return GNUNET_OK;
676}
677
678
679void
680GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation)
681{
682 if (!invitation)
683 return;
684
685 struct GNUNET_PeerIdentity door;
686 GNUNET_PEER_resolve(invitation->door, &door);
687
688 GNUNET_MESSENGER_enter_room(
689 invitation->context->handle->messenger,
690 &door, &(invitation->key)
691 );
692}
693