diff --git a/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt b/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt index 9557a7abaf..3e17f9f835 100644 --- a/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt +++ b/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt @@ -49,8 +49,69 @@ class InstrumentedTests { @Test fun jni_contacts() { val contacts = Contacts.newInstance(keyPair.secretKey) - val definitelyRealId = Hex.fromStringCondensed("050000000000000000000000000000000000000000000000000000000000000000") + val definitelyRealId = "050000000000000000000000000000000000000000000000000000000000000000" + assertNull(contacts.get(definitelyRealId)) + // Should be an uninitialized contact apart from ID + val c = contacts.getOrCreate(definitelyRealId) + assertEquals(definitelyRealId, c.id) + assertNull(c.name) + assertNull(c.nickname) + assertFalse(c.approved) + assertFalse(c.approvedMe) + assertFalse(c.blocked) + assertNull(c.profilePicture) + + assertFalse(contacts.needsPush()) + assertFalse(contacts.needsDump()) + assertEquals(0, contacts.push().seqNo) + + c.name = "Joe" + c.nickname = "Joey" + c.approved = true + c.approvedMe = true + + contacts.set(c) + + val cSaved = contacts.get(definitelyRealId)!! + assertEquals("Joe", cSaved.name) + assertEquals("Joey", cSaved.nickname) + assertTrue(cSaved.approved) + assertTrue(cSaved.approvedMe) + assertFalse(cSaved.blocked) + assertNull(cSaved.profilePicture) + + val push1 = contacts.push() + + assertEquals(1, push1.seqNo) + contacts.confirmPushed(push1.seqNo) + assertFalse(contacts.needsPush()) + assertTrue(contacts.needsDump()) + + val contacts2 = Contacts.newInstance(keyPair.secretKey, contacts.dump()) + assertFalse(contacts.needsDump()) + assertFalse(contacts2.needsPush()) + assertFalse(contacts2.needsDump()) + + val anotherId = "051111111111111111111111111111111111111111111111111111111111111111" + val c2 = contacts2.getOrCreate(anotherId) + contacts2.set(c2) + val push2 = contacts2.push() + assertEquals(2, push2.seqNo) + contacts2.confirmPushed(push2.seqNo) + assertFalse(contacts2.needsPush()) + + contacts.merge(push2.config) + + + assertFalse(contacts.needsPush()) + assertEquals(push2.seqNo, contacts.push().seqNo) + + val contactList = contacts.all().toList() + assertEquals(definitelyRealId, contactList[0].id) + assertEquals(anotherId, contactList[1].id) + assertEquals("Joey", contactList[0].nickname) + assertNull(contactList[1].nickname) } @Test diff --git a/libsession-util/src/main/cpp/contacts.cpp b/libsession-util/src/main/cpp/contacts.cpp index 1113e83062..f57ee1e2a3 100644 --- a/libsession-util/src/main/cpp/contacts.cpp +++ b/libsession-util/src/main/cpp/contacts.cpp @@ -27,7 +27,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_set(JNIEnv *env, jobject t jobject contact) { auto contacts = ptrToContacts(env, thiz); auto contact_info = deserialize_contact(env, contact); - contacts->set(contact_info); + contacts->set(*contact_info); } extern "C" @@ -68,4 +68,18 @@ Java_network_loki_messenger_libsession_1util_Contacts_00024Companion_newInstance return newConfig; } -#pragma clang diagnostic pop \ No newline at end of file +#pragma clang diagnostic pop +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_Contacts_all(JNIEnv *env, jobject thiz) { + auto contacts = ptrToContacts(env, thiz); + jclass stack = env->FindClass("java/util/Stack"); + jmethodID init = env->GetMethodID(stack, "", "()V"); + jobject our_stack = env->NewObject(stack, init); + jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;"); + for (const auto& contact : *contacts) { + auto contact_obj = serialize_contact(env, contact); + env->CallObjectMethod(our_stack, push, contact_obj); + } + return our_stack; +} \ No newline at end of file diff --git a/libsession-util/src/main/cpp/contacts.h b/libsession-util/src/main/cpp/contacts.h index 8f8fd097b7..c8cfb0778b 100644 --- a/libsession-util/src/main/cpp/contacts.h +++ b/libsession-util/src/main/cpp/contacts.h @@ -3,6 +3,7 @@ #include #include "session/config/contacts.hpp" +#include "util.h" inline session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) { jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts"); @@ -14,18 +15,84 @@ inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact"); jmethodID constructor = env->GetMethodID(contactClass, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;)V"); - // val id: String, - // val name: String, - // val nickname: String, - // val approved: Boolean, - // val approvedMe: Boolean, - // val blocked: Boolean, - // val profilePicture: UserPic - return nullptr; + jstring id = env->NewStringUTF(info.session_id.data()); + jstring name = nullptr; + jstring nickname = nullptr; + if (info.name) { + name = env->NewStringUTF(info.name->data()); + } + if (info.nickname) { + nickname = env->NewStringUTF(info.nickname->data()); + } + jboolean approved, approvedMe, blocked; + approved = info.approved; + approvedMe = info.approved_me; + blocked = info.blocked; + jobject profilePic = util::serialize_user_pic(env, info.profile_picture); + jobject returnObj = env->NewObject(contactClass, constructor, id, name, nickname, approved, approvedMe, blocked, profilePic); + return returnObj; } -inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject info) { +inline session::config::contact_info* deserialize_contact(JNIEnv *env, jobject info) { + jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact"); + jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic; + getId = env->GetFieldID(contactClass, "id", "Ljava/lang/String;"); + getName = env->GetFieldID(contactClass, "name", "Ljava/lang/String;"); + getNick = env->GetFieldID(contactClass, "nickname", "Ljava/lang/String;"); + getApproved = env->GetFieldID(contactClass, "approved", "Z"); + getApprovedMe = env->GetFieldID(contactClass, "approvedMe", "Z"); + getBlocked = env->GetFieldID(contactClass, "blocked", "Z"); + getUserPic = env->GetFieldID(contactClass, "profilePicture", "Lnetwork/loki/messenger/libsession_util/util/UserPic;"); + jstring name, nickname, session_id; + session_id = static_cast(env->GetObjectField(info, getId)); + name = static_cast(env->GetObjectField(info, getName)); + nickname = static_cast(env->GetObjectField(info, getNick)); + bool approved, approvedMe, blocked; + approved = env->GetBooleanField(info, getApproved); + approvedMe = env->GetBooleanField(info, getApprovedMe); + blocked = env->GetBooleanField(info, getBlocked); + jobject user_pic = env->GetObjectField(info, getUserPic); + + std::string url; + session::ustring key; + + if (user_pic != nullptr) { + auto deserialized_pic = util::deserialize_user_pic(env, user_pic); + auto url_jstring = deserialized_pic.first; + auto url_bytes = env->GetStringUTFChars(url_jstring, nullptr); + url = std::string(url_bytes); + env->ReleaseStringUTFChars(url_jstring, url_bytes); + key = util::ustring_from_bytes(env, deserialized_pic.second); + } + + auto session_id_bytes = env->GetStringUTFChars(session_id, nullptr); + auto name_bytes = name ? env->GetStringUTFChars(name, nullptr) : nullptr; + auto nickname_bytes = nickname ? env->GetStringUTFChars(nickname, nullptr) : nullptr; + + auto contact_info = new session::config::contact_info(session_id_bytes); + if (name_bytes) { + contact_info->name = name_bytes; + } + if (nickname_bytes) { + contact_info->nickname = nickname_bytes; + } + contact_info->approved = approved; + contact_info->approved_me = approvedMe; + contact_info->blocked = blocked; + if (!url.empty() && !key.empty()) { + contact_info->profile_picture = session::config::profile_pic(url, key); + } + + env->ReleaseStringUTFChars(session_id, session_id_bytes); + if (name_bytes) { + env->ReleaseStringUTFChars(name, name_bytes); + } + if (nickname_bytes) { + env->ReleaseStringUTFChars(nickname, nickname_bytes); + } + + return contact_info; } diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt index 6b4ee80dc1..5487aa1161 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt @@ -36,6 +36,7 @@ class Contacts(pointer: Long) : ConfigBase(pointer) { external fun get(sessionId: String): Contact? external fun getOrCreate(sessionId: String): Contact + external fun all(): List external fun set(contact: Contact) external fun erase(sessionId: String): Boolean } diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt index 5497dd9817..71e67555c1 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Contact.kt @@ -2,10 +2,10 @@ package network.loki.messenger.libsession_util.util data class Contact( val id: String, - val name: String, - val nickname: String, - val approved: Boolean, - val approvedMe: Boolean, - val blocked: Boolean, - val profilePicture: UserPic + var name: String?, + var nickname: String?, + var approved: Boolean, + var approvedMe: Boolean, + var blocked: Boolean, + var profilePicture: UserPic? ) \ No newline at end of file