diff --git a/src/Makefile b/src/Makefile index e4f845d..a6c0cb6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -36,7 +36,7 @@ org_pEp_jniadapter_AbstractEngine.o: %.o: %.cc %.h throw_pEp_exception.hh jniuti org_pEp_jniadapter_Engine.o org_pEp_jniadapter_Message.o: %.o: %.cc %.h -$(LIBRARY): org_pEp_jniadapter_AbstractEngine.o org_pEp_jniadapter_Engine.o org_pEp_jniadapter_Message.o throw_pEp_exception.o jniutils.o +$(LIBRARY): org_pEp_jniadapter_AbstractEngine.o org_pEp_jniadapter_Engine.o org_pEp_jniadapter_Message.o throw_pEp_exception.o jniutils.o basic_api.o ar -r $@ *.o org/pEp/jniadapter/pEpException.java: pEp.yml2 gen_java_exceptions.ysl2 @@ -59,6 +59,8 @@ throw_pEp_exception.cc throw_pEp_exception.hh: pEp.yml2 gen_throw_pEp_exception. throw_pEp_exception.o: throw_pEp_exception.cc throw_pEp_exception.hh +basic_api.o: basic_api.cc jniutils.hh throw_pEp_exception.hh + .PHONY: clean clean: diff --git a/src/basic_api.cc b/src/basic_api.cc new file mode 100644 index 0000000..bdbaf8c --- /dev/null +++ b/src/basic_api.cc @@ -0,0 +1,94 @@ +#include + +#include "throw_pEp_exception.hh" +#include "jniutils.hh" + +extern "C" { + using namespace pEp::JNIAdapter; + +JNIEXPORT jobject JNICALL Java_org_pEp_jniadapter_Engine_trustwords( + JNIEnv *env, + jobject obj, + jobject ident + ) +{ + PEP_SESSION session = (PEP_SESSION) callLongMethod(env, obj, "getHandle"); + pEp_identity *_ident = to_identity(env, ident); + char *words; + size_t wsize; + + if (_ident->fpr == NULL || _ident->fpr[0] == 0) { + if (_ident->me) + ::myself(session, _ident); + else + ::update_identity(session, _ident); + } + + if (_ident->fpr == NULL || _ident->fpr[0] == 0) { + throw_pEp_Exception(env, PEP_CANNOT_FIND_IDENTITY); + return NULL; + } + + PEP_STATUS status = ::trustwords(session, _ident->fpr, _ident->lang, &words, &wsize, 10); + if (status != PEP_STATUS_OK) { + throw_pEp_Exception(env, status); + return NULL; + } + + return from_string(env, words); +} + +JNIEXPORT jobject JNICALL Java_org_pEp_jniadapter_Engine_myself( + JNIEnv *env, + jobject obj, + jobject ident + ) +{ + PEP_SESSION session = (PEP_SESSION) callLongMethod(env, obj, "getHandle"); + pEp_identity *_ident = to_identity(env, ident); + + ::myself(session, _ident); + + return from_identity(env, _ident); +} + +JNIEXPORT jobject JNICALL Java_org_pEp_jniadapter_Engine_updateIdentity( + JNIEnv *env, + jobject obj, + jobject ident + ) +{ + PEP_SESSION session = (PEP_SESSION) callLongMethod(env, obj, "getHandle"); + pEp_identity *_ident = to_identity(env, ident); + + ::update_identity(session, _ident); + + return from_identity(env, _ident); +} + +JNIEXPORT void JNICALL Java_org_pEp_jniadapter_Engine_keyCompromized( + JNIEnv *env, + jobject obj, + jobject ident + ) +{ + PEP_SESSION session = (PEP_SESSION) callLongMethod(env, obj, "getHandle"); + pEp_identity *_ident = to_identity(env, ident); + + if (_ident->fpr == NULL || _ident->fpr[0] == 0) { + if (_ident->me) + ::myself(session, _ident); + else + ::update_identity(session, _ident); + } + + if (_ident->fpr == NULL || _ident->fpr[0] == 0) { + throw_pEp_Exception(env, PEP_CANNOT_FIND_IDENTITY); + return; + } + + ::key_compromized(session, _ident->fpr); +} + +} // extern "C" + diff --git a/src/gen_cpp_Engine.ysl2 b/src/gen_cpp_Engine.ysl2 index 057ff8c..1356c7d 100644 --- a/src/gen_cpp_Engine.ysl2 +++ b/src/gen_cpp_Engine.ysl2 @@ -12,6 +12,7 @@ tstylesheet { #include #include #include "org_pEp_jniadapter_«@name».h" + #include "throw_pEp_exception.hh" #include "jniutils.hh" using namespace pEp::JNIAdapter; @@ -41,6 +42,11 @@ tstylesheet { `` apply "parm[creates|returns]", mode=out PEP_STATUS status = ::«@name»(session`apply "parm", mode=call``if "@name = 'encrypt_message'" > , PEP_enc_PEP`); + if ((status > PEP_STATUS_OK && status < PEP_UNENCRYPTED) |`> |` + status >= PEP_TRUSTWORD_NOT_FOUND) { + throw_pEp_Exception(env, status); + return NULL; + } || @@ -93,8 +99,16 @@ tstylesheet { const "name", "name(*[3])"; || jfieldID «$name»_field = getFieldID(env, "«$jtype»", - "«$name»", "«$sig»"); - env->SetObjectField(result_, «$name»_field, «$name»_); + "«$name»", "«$sig»"); + if («$name»_) + env->SetObjectField(result_, «$name»_field, «$name»_); + || + if "$name = 'dst'" + || + else + env->SetObjectField(result_, «$name»_field, src); + || + || || } @@ -120,20 +134,32 @@ tstylesheet { choose { when "$jnitype = 'jbyteArray'" || - jobject «$name»_ = from_stringlist(env, _«$retname»); + jobject «$name»_ = NULL; + if (_«$retname») + «$name»_ = from_stringlist(env, _«$retname»); || otherwise { - || - jclass clazz_«$name»_ = findClass(env, "org/pEp/jniadapter/«$jtype»"); - jmethodID constructor_«$name»_ = env->GetMethodID(clazz_«$name»_, "", "«$sig»"); - assert(constructor_«$name»_); - || - indent(0); - > jobject «$name»_ = env->NewObject(clazz_«$name»_, constructor_«$name»_ - if "$jnitype != ''" > , («$jnitype») _«$retname» - > );\n\n + | jobject «$name»_ = NULL; + indent(0); + if "$retname != 'result'" > if (_«$retname») + > {\n + || + jclass clazz_«$name»_ = findClass(env, "org/pEp/jniadapter/«$jtype»"); + jmethodID constructor_«$name»_ = env->GetMethodID(clazz_«$name»_, "", "«$sig»"); + assert(constructor_«$name»_); + || + + indent(1); + > «$name»_ = env->NewObject(clazz_«$name»_, constructor_«$name»_ + if "$jnitype != ''" > , («$jnitype») _«$retname» + > );\n + + || + } + + || } } } diff --git a/src/gen_java_Engine.ysl2 b/src/gen_java_Engine.ysl2 index 6366b4c..a93e3e4 100644 --- a/src/gen_java_Engine.ysl2 +++ b/src/gen_java_Engine.ysl2 @@ -18,11 +18,40 @@ tstylesheet { public «$cname»() throws pEpException { } `` apply "method", mode=plain + `` apply "basic" } || } + template "basic" { + const "itype" call "toIntermediate" with "type", "@type"; + const "jtype" call "toJava" with "type", "@type"; + const "ptype", "name(parm/*[1])"; + const "pitype" call "toIntermediate" with "type", "$ptype"; + const "pjtype" call "toJava" with "type", "$ptype"; + const "pname", "name(parm/*[2])"; + + || + private native «$itype» «@name»(«$pitype» «$pname»); + + public «$jtype» «@name»(«$pjtype» «$pname») { + «$pitype» _«$pname» = new «$pitype»(«$pname»); + || + choose { + when "@type = 'void'" + |> «@name»(_«$pname»); + when "@type = 'identity'" + |> return new Identity(«@name»(_«$pname»)); + otherwise + |> return AbstractEngine.toUTF16(«@name»(_«$pname»)); + } + || + } + + || + } + function "returnJava" { const "returning", "count(parm/creates|parm/returns)"; const "returntype" call "toJava" with "type", "name(parm[creates|returns]/*[2])"; @@ -47,6 +76,7 @@ tstylesheet { template "method", mode=plain { const "convert", "count(parm/stringlist|parm/string|parm/identity) > 0"; + const "convertreturn", "count(parm[returns]/stringlist|parm[returns]/string|parm[returns]/identity) > 0"; const "singlereturn", "count(parm/creates|parm/returns) = 1"; const "multireturn", "count(parm/creates|parm/returns) > 1"; @@ -85,7 +115,12 @@ tstylesheet { | { apply "parm", mode=convertIn; - if "$singlereturn" |> return _«@name»(`apply "parm[in]", mode=call;`); + if "$singlereturn" choose { + when "$convertreturn" + |> return AbstractEngine.toUTF16(_«@name»(`apply "parm[in]", mode=call;`)); + otherwise + |> return _«@name»(`apply "parm[in]", mode=call;`); + } if "$multireturn" || @@ -97,9 +132,11 @@ tstylesheet { || } - || } + || + + || } template "parm", mode=java { diff --git a/src/jniutils.cc b/src/jniutils.cc index 3f50b7b..30c3c4d 100644 --- a/src/jniutils.cc +++ b/src/jniutils.cc @@ -77,6 +77,7 @@ namespace pEp { return env->CallIntMethod(obj, method); } + jlong callLongMethod( JNIEnv *env, jobject obj, diff --git a/src/jniutils.hh b/src/jniutils.hh index 6dca348..b7598fd 100644 --- a/src/jniutils.hh +++ b/src/jniutils.hh @@ -1,11 +1,90 @@ #pragma once +#include +#include #include #include #include #include namespace pEp { + namespace utility { + using namespace std; + + class mutex { + pthread_mutex_t _mutex; + + public: + mutex() { + pthread_mutex_init(&_mutex, NULL); + } + ~mutex() { + pthread_mutex_destroy(&_mutex); + } + void lock() { + pthread_mutex_lock(&_mutex); + } + void unlock() { + pthread_mutex_unlock(&_mutex); + } + }; + + template class lock_guard { + T& _mtx; + + public: + lock_guard(T& mtx) : _mtx(mtx) { + _mtx.lock(); + } + ~lock_guard() { + _mtx.unlock(); + } + }; + + template class locked_queue + { + mutex _mtx; + list _q; + + public: + T& back() + { + lock_guard lg(_mtx); + return _q.back(); + } + T& front() + { + lock_guard lg(_mtx); + return _q.front(); + } + void pop_back() + { + lock_guard lg(_mtx); + _q.pop_back(); + } + void pop_front() + { + lock_guard lg(_mtx); + _q.pop_front(); + } + void push_back(const T& data) + { + lock_guard lg(_mtx); + _q.push_back(data); + } + void push_front(const T& data) + { + lock_guard lg(_mtx); + _q.push_front(data); + } + size_t size() + { + lock_guard lg(_mtx); + return _q.size(); + } + }; + } + namespace JNIAdapter { jclass findClass(JNIEnv *env, const char *classname); diff --git a/src/org/pEp/jniadapter/AbstractEngine.java b/src/org/pEp/jniadapter/AbstractEngine.java index 36905f7..1475aa6 100644 --- a/src/org/pEp/jniadapter/AbstractEngine.java +++ b/src/org/pEp/jniadapter/AbstractEngine.java @@ -27,6 +27,12 @@ abstract class AbstractEngine implements AutoCloseable { release(); } + private long keyserverThread; + private long queueThread; + + public native void startKeyserverLookup(); + public native void stopKeyserverLookup(); + public static byte[] toUTF8(String str) { try { String _str = Normalizer.normalize(str, Normalizer.Form.NFC); @@ -101,39 +107,5 @@ abstract class AbstractEngine implements AutoCloseable { return result; } - - public class _Identity { - public byte[] address; - public byte[] fpr; - public byte[] user_id; - public byte[] username; - CommType comm_type; - public byte[] lang; - public boolean me; - - public _Identity(Identity value) { - address = toUTF8(value.address); - fpr = toUTF8(value.fpr); - user_id = toUTF8(value.user_id); - username = toUTF8(value.username); - comm_type = value.comm_type; - lang = toUTF8(value.lang); - me = value.me; - } - - public Identity getIdentity() { - Identity ident = new Identity(me); - - ident.address = toUTF16(address); - ident.fpr = toUTF16(fpr); - ident.user_id = toUTF16(user_id); - ident.username = toUTF16(username); - ident.comm_type = comm_type; - ident.lang = toUTF16(lang); - ident.me = me; - - return ident; - } - } } diff --git a/src/org_pEp_jniadapter_AbstractEngine.cc b/src/org_pEp_jniadapter_AbstractEngine.cc index 26cdf16..98a3a5c 100644 --- a/src/org_pEp_jniadapter_AbstractEngine.cc +++ b/src/org_pEp_jniadapter_AbstractEngine.cc @@ -1,14 +1,17 @@ #include "org_pEp_jniadapter_AbstractEngine.h" #include +#include #include -#include +#include +#include #include "throw_pEp_exception.hh" #include "jniutils.hh" extern "C" { using namespace pEp::JNIAdapter; + using namespace pEp::utility; JNIEXPORT void JNICALL Java_org_pEp_jniadapter_Engine_init( JNIEnv *env, @@ -62,5 +65,118 @@ extern "C" { else env->SetLongField(me, handle, jlong(0)); } -} + + int examine_identity(pEp_identity *ident, void *arg) + { + locked_queue< pEp_identity * > *queue = (locked_queue< pEp_identity * > *) arg; + queue->push_back(identity_dup(ident)); + return 0; + } + + pEp_identity *retrieve_next_identity(void *arg) + { + locked_queue< pEp_identity * > *queue = (locked_queue< pEp_identity * > *) arg; + + while (!queue->size()) + usleep(100000); + + pEp_identity *ident = queue->front(); + queue->pop_front(); + return ident; + } + + static void *start_routine(void *arg) + { + PEP_STATUS status = do_keymanagement(retrieve_next_identity, arg); + + locked_queue< pEp_identity * > *queue = (locked_queue< pEp_identity * > *) arg; + + while (queue->size()) { + pEp_identity *ident = queue->front(); + queue->pop_front(); + free_identity(ident); + } + + delete queue; + + return (void *) status; + } + + JNIEXPORT void JNICALL Java_org_pEp_jniadapter_AbstractEngine_startKeyserverLookup( + JNIEnv *env, + jobject obj + ) + { + PEP_SESSION session = (PEP_SESSION) callLongMethod(env, obj, "getHandle"); + + pthread_t *thread = NULL; + locked_queue< pEp_identity * > *queue = NULL; + + jfieldID thread_handle; + jfieldID queue_handle; + + try { + thread_handle = getFieldID(env, "org/pEp/jniadapter/Engine", "keyserverThread", "J"); + queue_handle = getFieldID(env, "org/pEp/jniadapter/Engine", "queueThread", "J"); + } + catch (std::exception& ex) { + assert(0); + return; + } + + thread = (pthread_t *) env->GetLongField(obj, thread_handle); + if (thread) + return; + + thread = (pthread_t *) calloc(1, sizeof(pthread_t)); + assert(thread); + env->SetLongField(obj, thread_handle, (jlong) thread); + + queue = new locked_queue< pEp_identity * >(); + env->SetLongField(obj, queue_handle, (jlong) queue); + + pthread_create(thread, NULL, start_routine, (void *) queue); + register_examine_function(session, examine_identity, (void *) queue); + } + + JNIEXPORT void JNICALL Java_org_pEp_jniadapter_AbstractEngine_stopKeyserverLookup( + JNIEnv *env, + jobject obj + ) + { + PEP_SESSION session = (PEP_SESSION) callLongMethod(env, obj, "getHandle"); + + pthread_t *thread = NULL; + locked_queue< pEp_identity * > *queue = NULL; + + jfieldID thread_handle; + jfieldID queue_handle; + + try { + thread_handle = getFieldID(env, "org/pEp/jniadapter/Engine", "keyserverThread", "J"); + queue_handle = getFieldID(env, "org/pEp/jniadapter/Engine", "queueThread", "J"); + } + catch (std::exception& ex) { + assert(0); + return; + } + + thread = (pthread_t *) env->GetLongField(obj, thread_handle); + if (!thread) + return; + + queue = (locked_queue< pEp_identity * > *) env->GetLongField(obj, queue_handle); + + env->SetLongField(obj, queue_handle, (jlong) 0); + env->SetLongField(obj, thread_handle, (jlong) 0); + + register_examine_function(session, NULL, NULL); + + queue->push_front(NULL); + pthread_join(*thread, NULL); + free(thread); + } + +} // extern "C" + diff --git a/src/pEp.yml2 b/src/pEp.yml2 index c485127..383f3a6 100644 --- a/src/pEp.yml2 +++ b/src/pEp.yml2 @@ -4,6 +4,7 @@ decl interface @name; decl exception @name; decl method @name; decl struct @name; +decl basic @type @name; namespace pEp { exception pEp_status { @@ -86,6 +87,11 @@ namespace pEp { in message msg, returns Color color ); + + basic string trustwords(identity ident); + basic identity myself(identity ident); + basic identity updateIdentity(identity ident); + basic void keyCompromized(identity ident); }; struct message { diff --git a/src/types_java.ysl2 b/src/types_java.ysl2 index 5536dc3..e384728 100644 --- a/src/types_java.ysl2 +++ b/src/types_java.ysl2 @@ -12,6 +12,7 @@ function "toJava" { when "$type='bloblist'" > Vector when "$type='stringpairlist'" > ArrayList> when "$type='message'" > Message + when "$type='void'" > void otherwise call "CamelCase" with "text", "$type"; }