
101 changed files with 3295 additions and 2670 deletions
@ -0,0 +1,55 @@ |
|||||
|
# Copyright 2018, pEp Foundation
|
||||
|
# This file is part of pEp JNI Adapter
|
||||
|
# This file may be used under the terms of the GNU General Public License version 3
|
||||
|
# see LICENSE.txt
|
||||
|
|
||||
|
include ../../Makefile.conf |
||||
|
|
||||
|
MARKER_DIR=../../build/marker/ |
||||
|
|
||||
|
PEP_HEADER:=$(shell $(CXX) $(CXXFLAGS) -E -M ../cxx/get_header.cc | grep -oe '[^[:space:]]*pEpEngine\.h' | head -1) |
||||
|
|
||||
|
# Every ysl2 file that needs to be "compiled" separately, needs to generate a "marker" file
|
||||
|
# The marker serves as the make target.
|
||||
|
# If the marker file is older than its corresponding ysl2 file, or not exsiting, the ysl2 file will be "compiled"
|
||||
|
# Naming:
|
||||
|
# For a ysl2 file called "gen_example_stuff.ysl2", a marker file called "gen_example_stuff.marker" is expected.
|
||||
|
YML2_MARKERS= \
|
||||
|
$(MARKER_DIR)/gen_java_Engine.marker \
|
||||
|
$(MARKER_DIR)/gen_java_Message.marker \
|
||||
|
$(MARKER_DIR)/gen_cpp_Engine.marker \
|
||||
|
$(MARKER_DIR)/gen_cpp_Message.marker \
|
||||
|
$(MARKER_DIR)/gen_throw_pEp_exception.marker |
||||
|
|
||||
|
# All code genration will be done upon change of these files
|
||||
|
YML2_INCLUDES= \
|
||||
|
textutils.ysl2 \
|
||||
|
types_c.ysl2 \
|
||||
|
types_java.ysl2 |
||||
|
|
||||
|
|
||||
|
.PHONY: all codegen gen-status-codes create-dirs remove-dirs clean |
||||
|
|
||||
|
all: codegen |
||||
|
|
||||
|
# ------------- YML2 CodeGen --------------
|
||||
|
codegen: create-dirs gen-status-codes $(YML2_MARKERS) |
||||
|
|
||||
|
$(YML2_MARKERS): $(MARKER_DIR)/%.marker : %.ysl2 pEp.yml2 $(YML2_INCLUDES) |
||||
|
$(YML2_PROC) -y $< pEp.yml2 |
||||
|
|
||||
|
gen-status-codes: pEp.yml2 |
||||
|
bash ../../utils/gen_status_codes.sh "$(PEP_HEADER)" |
||||
|
|
||||
|
# ------------- Housekeeping ---------------
|
||||
|
create-dirs: |
||||
|
mkdir -p $(MARKER_DIR) |
||||
|
|
||||
|
#rm -rf is too dangerous for vars
|
||||
|
remove-dirs: |
||||
|
rm -rf ../../build/marker |
||||
|
|
||||
|
clean: remove-dirs |
||||
|
rm -f status_list.yml2 |
||||
|
rm -f passphrase_status_list.yml2 |
||||
|
|
@ -0,0 +1,368 @@ |
|||||
|
include yslt.yml2 |
||||
|
|
||||
|
tstylesheet { |
||||
|
include ./textutils.ysl2 |
||||
|
include ./types_java.ysl2 |
||||
|
|
||||
|
template "/namespace[@name='pEp']" { |
||||
|
apply "struct|enum|exception", 0; |
||||
|
document "../java/foundation/pEp/jniadapter/exceptions/pEpException.java", "text" { |
||||
|
|| |
||||
|
package foundation.pEp.jniadapter.exceptions; |
||||
|
|
||||
|
public class pEpException extends RuntimeException { |
||||
|
public pEpException(String message) { |
||||
|
super(message); |
||||
|
} |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
document("../../build/marker/gen_java_Message.marker", "text") > "" |
||||
|
} |
||||
|
|
||||
|
template "struct" { |
||||
|
const "cname" call "toJava" with "type", "@name"; |
||||
|
document("../java/foundation/pEp/jniadapter/{$cname}.java", "text") |
||||
|
|| |
||||
|
package foundation.pEp.jniadapter; |
||||
|
|
||||
|
import foundation.pEp.jniadapter.interfaces.*; |
||||
|
import foundation.pEp.jniadapter.exceptions.*; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Vector; |
||||
|
import java.util.Date; |
||||
|
import java.util.HashMap; |
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
public class «$cname» implements MessageInterface, AutoCloseable, Serializable { |
||||
|
private static final long serialVersionUID = 2119420428331150924L; |
||||
|
private long handle; |
||||
|
|
||||
|
native long init(); |
||||
|
native void release(long handle); |
||||
|
|
||||
|
public «$cname»() { |
||||
|
handle = init(); |
||||
|
} |
||||
|
|
||||
|
private native long _«$cname»( |
||||
|
byte[] mime_text |
||||
|
) throws pEpException; |
||||
|
|
||||
|
public «$cname»(String mime_text) { |
||||
|
byte[] _mime_text = Utils.toUTF8(mime_text); |
||||
|
handle = _«$cname»(_mime_text); |
||||
|
} |
||||
|
|
||||
|
private native byte[] _encodeMIME() throws pEpException; |
||||
|
|
||||
|
public String encodeMIME() { |
||||
|
return Utils.toUTF16(_encodeMIME()); |
||||
|
} |
||||
|
|
||||
|
private «$cname»(long h) { |
||||
|
handle = h; |
||||
|
} |
||||
|
|
||||
|
public final void close() { |
||||
|
release(handle); |
||||
|
} |
||||
|
|
||||
|
final protected long getHandle() { |
||||
|
return handle; |
||||
|
} |
||||
|
|
||||
|
`` apply "enum", mode=inner |
||||
|
`` apply "*[name(.)!='enum']", mode=entry |
||||
|
} |
||||
|
|| |
||||
|
document("../java/foundation/pEp/jniadapter/interfaces/{$cname}Interface.java", "text") |
||||
|
|| |
||||
|
package foundation.pEp.jniadapter.interfaces; |
||||
|
|
||||
|
import foundation.pEp.jniadapter.*; |
||||
|
import foundation.pEp.jniadapter.Message.*; |
||||
|
import java.util.Date; |
||||
|
import java.util.Vector; |
||||
|
import java.util.ArrayList; |
||||
|
|
||||
|
public interface «$cname»Interface { |
||||
|
public String encodeMIME(); |
||||
|
|
||||
|
`` apply "*[name(.)!='enum']", mode=interface |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
template "enum" { |
||||
|
const "jname" call "toJava" with "type", "@name"; |
||||
|
document("../java/foundation/pEp/jniadapter/{$jname}.java", "text") |
||||
|
|| |
||||
|
// CodeGen template enum |
||||
|
package foundation.pEp.jniadapter; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
|
||||
|
`` apply ".", 0, mode=inner |
||||
|
|| |
||||
|
|
||||
|
} |
||||
|
|
||||
|
template "enum", mode=inner { |
||||
|
const "jname" call "CamelCase" with "text", "@name"; |
||||
|
|| |
||||
|
// CodeGen template enum, mode=inner |
||||
|
public enum «$jname» { |
||||
|
`` apply "enumitem" |
||||
|
; |
||||
|
|
||||
|
public final int value; |
||||
|
|
||||
|
private static HashMap<Integer, «$jname»> intMap; |
||||
|
|
||||
|
private «$jname»(int value) { |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
public static «$jname» getByInt(int value){ |
||||
|
if (intMap == null) { |
||||
|
intMap = new HashMap<Integer, «$jname»>(); |
||||
|
for («$jname» s : «$jname».values()) { |
||||
|
intMap.put(s.value, s); |
||||
|
} |
||||
|
} |
||||
|
if (intMap.containsKey(value)) { |
||||
|
return intMap.get(value); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
|| |
||||
|
choose { |
||||
|
when "@has_int_str_val = 'true'" { |
||||
|
|| |
||||
|
public String getInternalStringValue() { |
||||
|
return "Unimplemented"; |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
function "exception" { |
||||
|
param "name"; |
||||
|
|
||||
|
document "../java/foundation/pEp/jniadapter/exceptions/{$name}.java", "text" { |
||||
|
| package foundation.pEp.jniadapter.exceptions; |
||||
|
| |
||||
|
| public class «$name» extends pEpException { |
||||
|
| public «$name»(String message) { |
||||
|
| super(message); |
||||
|
| } |
||||
|
| } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template "exception" for "*[text()!=0]" call "exception" |
||||
|
with "name" call "CamelCase" with "text", "name(.)"; |
||||
|
|
||||
|
|
||||
|
template "*", mode=entry { |
||||
|
const "ctype", "name(.)"; |
||||
|
const "type" call "toJava" with "type", "name(.)"; |
||||
|
const "itype" call "toIntermediate" with "type", "name(.)"; |
||||
|
const "name" call "toJava" with "type", "name(*[position()=1])"; |
||||
|
|
||||
|
|| |
||||
|
// CodeGen template * mode=entry |
||||
|
|| |
||||
|
choose { |
||||
|
when "$ctype = 'identity'" { |
||||
|
|| |
||||
|
// Property type: Identity. [java: «$type», intermediate: «$itype», ctype: «$ctype»] |
||||
|
public «$type» get«$name»() { |
||||
|
«$itype» res = _get«$name»(); |
||||
|
if (res != null) { |
||||
|
return new «$type»(_get«$name»()); |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
private native «$itype» _get«$name»(); |
||||
|
|
||||
|
public void set«$name»(«$type» value) { |
||||
|
if (value != null) { |
||||
|
_set«$name»(new «$itype»(value)); |
||||
|
} else { |
||||
|
_set«$name»(null); |
||||
|
} |
||||
|
} |
||||
|
private native void _set«$name»(«$itype» value); |
||||
|
|
||||
|
|
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
when "$ctype = 'identitylist' or $ctype = 'bloblist' or $ctype = 'stringlist' or $ctype = 'stringpairlist'" { |
||||
|
const "ename", "substring-after(substring($type,1,string-length($type)-1), '<')"; |
||||
|
const "iename" choose { |
||||
|
when "$ctype = 'stringlist'" > byte[] |
||||
|
when "$ctype = 'stringpairlist'" > Pair<byte[],byte[]> |
||||
|
otherwise > _«$ename» |
||||
|
} |
||||
|
const "convget" choose { |
||||
|
when "$ctype = 'stringlist'" > Utils.toUTF16(i) |
||||
|
when "$ctype = 'stringpairlist'" > new Pair<String, String>(Utils.toUTF16(i.first), Utils.toUTF16(i.second)) |
||||
|
otherwise > new «$ename»(i) |
||||
|
} |
||||
|
const "convset" choose { |
||||
|
when "$ctype = 'stringlist'" > Utils.toUTF8(i) |
||||
|
when "$ctype = 'stringpairlist'" > new Pair<byte[],byte[]>(Utils.toUTF8(i.first), Utils.toUTF8(i.second)) |
||||
|
otherwise > new _«$ename»(i) |
||||
|
} |
||||
|
|| |
||||
|
// Property type: list type. [java: «$type», intermediate: «$itype», ctype: «$ctype»] |
||||
|
public «$type» get«$name»() { |
||||
|
«$itype» glist = _get«$name»(); |
||||
|
if (glist != null) { |
||||
|
«$type» list = new «$type»(); |
||||
|
for («$iename» i : glist) { |
||||
|
list.add(«$convget»); |
||||
|
} |
||||
|
return list; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
private native «$itype» _get«$name»(); |
||||
|
|
||||
|
public void set«$name»(«$type» value) { |
||||
|
if (value != null) { |
||||
|
«$itype» list = new «$itype»(); |
||||
|
for («$ename» i : value) { |
||||
|
list.add(«$convset»); |
||||
|
} |
||||
|
_set«$name»(list); |
||||
|
} else { |
||||
|
_set«$name»(null); |
||||
|
} |
||||
|
} |
||||
|
private native void _set«$name»(«$itype» value); |
||||
|
|
||||
|
|
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
when "$itype != $type" { |
||||
|
|| |
||||
|
// Property type: differs from intermediate. [java: «$type», intermediate: «$itype», ctype: «$ctype»] |
||||
|
public «$type» get«$name»() { |
||||
|
«$itype» res = _get«$name»(); |
||||
|
if (res != null) { |
||||
|
return Utils.toUTF16(res); |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
private native «$itype» _get«$name»(); |
||||
|
|
||||
|
public void set«$name»(«$type» value) { |
||||
|
if (value != null) { |
||||
|
_set«$name»(Utils.toUTF8(value)); |
||||
|
} else { |
||||
|
_set«$name»(new byte[0]); |
||||
|
} |
||||
|
} |
||||
|
private native void _set«$name»(«$itype» value); |
||||
|
|
||||
|
|
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
when "../enum[@name=$ctype]" { |
||||
|
|| |
||||
|
// Property type: enum type. [java: «$type», intermediate: «$itype», ctype: «$ctype»] |
||||
|
public «$type» get«$name»() { |
||||
|
return «$type».getByInt(_get«$name»()); |
||||
|
} |
||||
|
private native int _get«$name»(); |
||||
|
public void set«$name»(«$type» value) { |
||||
|
if(value != null) |
||||
|
_set«$name»(value.value); |
||||
|
else |
||||
|
_set«$name»(0); |
||||
|
} |
||||
|
private native void _set«$name»(int value); |
||||
|
|
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
otherwise { |
||||
|
|| |
||||
|
// Property type: no intermediate type [java: «$type», intermediate: «$itype», ctype: «$ctype»] |
||||
|
public «$type» get«$name»() { |
||||
|
return get«$name»(); |
||||
|
} |
||||
|
private native «$type» _get«$name»(); |
||||
|
|
||||
|
public void set«$name»(«$type» value) { |
||||
|
_set«$name»(value); |
||||
|
} |
||||
|
private native void _set«$name»(«$type» value); |
||||
|
|
||||
|
|
||||
|
|| |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template "*", mode=interface { |
||||
|
const "type" call "toJava" with "type", "name(.)"; |
||||
|
const "name" call "toJava" with "type", "name(*[position()=1])"; |
||||
|
|
||||
|
|| |
||||
|
public «$type» get«$name»(); |
||||
|
|
||||
|
public void set«$name»(«$type» value); |
||||
|
|
||||
|
|| |
||||
|
} |
||||
|
|
||||
|
|
||||
|
template "enumitem" { |
||||
|
const "name_hyphenized" call "hyphenize" with "text", "@name"; |
||||
|
const "javaname" call "toJava" with "type", "$name_hyphenized"; |
||||
|
const "enum_index", "."; |
||||
|
|| |
||||
|
«$javaname» («$enum_index») { |
||||
|
public String toString() { |
||||
|
|| |
||||
|
choose { |
||||
|
when "@toString" { |
||||
|
|| |
||||
|
return "«@toString»"; |
||||
|
|| |
||||
|
} otherwise { |
||||
|
|| |
||||
|
return "«$javaname»"; |
||||
|
|| |
||||
|
} |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
|| |
||||
|
choose { |
||||
|
when "@int_str_val" { |
||||
|
|| |
||||
|
public String getInternalStringValue() { |
||||
|
return "«@int_str_val»"; |
||||
|
} |
||||
|
|| |
||||
|
} |
||||
|
} |
||||
|
| }`if "position()!=last()" > , ` |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,65 @@ |
|||||
|
include yslt.yml2 |
||||
|
|
||||
|
tstylesheet { |
||||
|
include ./textutils.ysl2 |
||||
|
|
||||
|
template "/" { |
||||
|
apply "namespace", 0; |
||||
|
document "../cxx/throw_pEp_exception.hh", "text" |
||||
|
|| |
||||
|
#pragma once |
||||
|
|
||||
|
#include <jni.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace JNIAdapter { |
||||
|
jint throw_pEp_Exception(JNIEnv *env, PEP_STATUS status); |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
|| |
||||
|
document("../../build/marker/gen_throw_pEp_exception.marker", "text") > "" |
||||
|
} |
||||
|
|
||||
|
template "namespace" |
||||
|
document("../cxx/throw_pEp_exception.cc", "text") |
||||
|
|| |
||||
|
#include <assert.h> |
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include "throw_pEp_exception.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace JNIAdapter { |
||||
|
jint throw_pEp_Exception(JNIEnv *env, PEP_STATUS status) |
||||
|
{ |
||||
|
jclass ex; |
||||
|
const char *ex_name; |
||||
|
|
||||
|
switch (status) { |
||||
|
`` apply "exception/*[text()!=0]", 4, mode=case |
||||
|
default: |
||||
|
assert(0); |
||||
|
ex_name = "Exception"; |
||||
|
} |
||||
|
|
||||
|
ex = env->FindClass(ex_name); |
||||
|
assert(ex); |
||||
|
|
||||
|
if (ex == NULL) { |
||||
|
ex = env->FindClass("java/lang/NoClassDefFoundError"); |
||||
|
assert(ex); |
||||
|
} |
||||
|
|
||||
|
return env->ThrowNew(ex, ex_name); |
||||
|
} |
||||
|
}; |
||||
|
}; |
||||
|
|| |
||||
|
|
||||
|
template "*", mode=case { |
||||
|
| case `call "UCASE" with "text", "name(.)"`: |
||||
|
| ex_name = "foundation/pEp/jniadapter/exceptions/`call "CamelCase" with "text", "name(.)"`"; |
||||
|
| break; |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,795 @@ |
|||||
|
#include <cassert> |
||||
|
#include "jniutils.hh" |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
|
||||
|
#ifndef __LP64__ |
||||
|
|
||||
|
#include <time64.h> |
||||
|
|
||||
|
#define time_t time64_t |
||||
|
#define timegm timegm64 |
||||
|
#define gmtime_r gmtime64_r |
||||
|
#else |
||||
|
#include <string.h> |
||||
|
#endif |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace JNIAdapter { |
||||
|
|
||||
|
std::mutex global_mutex; |
||||
|
std::unordered_map<long, std::mutex *> engine_objid_mutex; |
||||
|
|
||||
|
std::mutex *get_engine_java_object_mutex(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
long engine_obj_id = static_cast<long>(callLongMethod(env, obj, "getId")); |
||||
|
assert(engine_obj_id); |
||||
|
pEpLog("for java object id: " << engine_obj_id); |
||||
|
std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); |
||||
|
pEpLog("found mutex: " << engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle()); |
||||
|
assert(engine_obj_mutex); |
||||
|
return engine_obj_mutex; |
||||
|
} |
||||
|
|
||||
|
void create_engine_java_object_mutex(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
long engine_obj_id = static_cast<long>(callLongMethod(env, obj, "getId")); |
||||
|
assert(engine_obj_id); |
||||
|
std::mutex *engine_obj_mutex = new std::mutex(); |
||||
|
pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); |
||||
|
assert(engine_obj_mutex); |
||||
|
if (engine_objid_mutex.count(engine_obj_id) > 0) { |
||||
|
pEpLog("Fatal: mutex already existing for object id: " << engine_obj_id); |
||||
|
assert(0); |
||||
|
} |
||||
|
engine_objid_mutex.insert(std::make_pair(engine_obj_id, engine_obj_mutex)); |
||||
|
} |
||||
|
|
||||
|
void release_engine_java_object_mutex(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
long engine_obj_id = static_cast<long>(callLongMethod(env, obj, "getId")); |
||||
|
assert(engine_obj_id); |
||||
|
std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); |
||||
|
pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); |
||||
|
assert(engine_obj_mutex); |
||||
|
engine_objid_mutex.erase(engine_obj_id); |
||||
|
delete engine_obj_mutex; |
||||
|
} |
||||
|
|
||||
|
jclass findClass(JNIEnv *env, |
||||
|
const char *classname) |
||||
|
{ |
||||
|
jclass clazz = env->FindClass(classname); |
||||
|
if (!clazz) { |
||||
|
fprintf(stderr, "class not found: %s\n", classname); |
||||
|
} |
||||
|
assert(clazz); |
||||
|
|
||||
|
if (clazz == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoClassDefFoundError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, classname); |
||||
|
throw std::bad_cast(); |
||||
|
} |
||||
|
|
||||
|
return clazz; |
||||
|
} |
||||
|
|
||||
|
jfieldID getFieldID(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
const char *fieldname, |
||||
|
const char *signature) |
||||
|
{ |
||||
|
jclass clazz = findClass(env, classname); |
||||
|
assert(clazz); |
||||
|
|
||||
|
jfieldID field = env->GetFieldID(clazz, fieldname, signature); |
||||
|
assert(field); |
||||
|
|
||||
|
if (field == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoSuchFieldError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, fieldname); |
||||
|
throw std::invalid_argument(std::string(fieldname)); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
return field; |
||||
|
} |
||||
|
|
||||
|
//TODO: fix/generalize/clean patch added to make keysync work using globalref to class
|
||||
|
jfieldID getFieldID(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
const char *fieldname, |
||||
|
const char *signature, |
||||
|
const jclass clazz) |
||||
|
{ |
||||
|
jfieldID field = env->GetFieldID(clazz, fieldname, signature); |
||||
|
assert(field); |
||||
|
|
||||
|
if (field == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoSuchFieldError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, fieldname); |
||||
|
throw std::invalid_argument(std::string(fieldname)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
return field; |
||||
|
} |
||||
|
|
||||
|
jint callIntMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname) |
||||
|
{ |
||||
|
jclass clazz = env->GetObjectClass(obj); |
||||
|
assert(clazz); |
||||
|
|
||||
|
jmethodID method = env->GetMethodID(clazz, methodname, "()I"); |
||||
|
if (method == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, methodname); |
||||
|
throw std::invalid_argument(std::string(methodname)); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
jint result = env->CallIntMethod(obj, method); |
||||
|
env->ExceptionCheck(); // handle exception in Java
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
jlong callLongMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname) |
||||
|
{ |
||||
|
jclass clazz = env->GetObjectClass(obj); |
||||
|
assert(clazz); |
||||
|
|
||||
|
jmethodID method = env->GetMethodID(clazz, methodname, "()J"); |
||||
|
if (method == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, methodname); |
||||
|
throw std::invalid_argument(std::string(methodname)); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
jlong result = env->CallLongMethod(obj, method); |
||||
|
env->ExceptionCheck(); // handle exception in Java
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
jobject callObjectMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname, |
||||
|
jint index) |
||||
|
{ |
||||
|
jclass clazz = env->GetObjectClass(obj); |
||||
|
assert(clazz); |
||||
|
|
||||
|
jmethodID method = env->GetMethodID(clazz, methodname, "(I)Ljava/lang/Object;"); |
||||
|
if (method == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, methodname); |
||||
|
throw std::invalid_argument(std::string(methodname)); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
jobject result = env->CallObjectMethod(obj, method, index); |
||||
|
env->ExceptionCheck(); // handle exception in Java
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
jboolean callBooleanMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname, |
||||
|
jobject o) |
||||
|
{ |
||||
|
jclass clazz = env->GetObjectClass(obj); |
||||
|
assert(clazz); |
||||
|
|
||||
|
jmethodID method = env->GetMethodID(clazz, methodname, "(Ljava/lang/Object;)Z"); |
||||
|
if (method == NULL) { |
||||
|
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
||||
|
assert(ex); |
||||
|
env->ThrowNew(ex, methodname); |
||||
|
throw std::invalid_argument(std::string(methodname)); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
jboolean result = env->CallBooleanMethod(obj, method, o); |
||||
|
env->ExceptionCheck(); // handle exception in Java
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
jint outOfMemory(JNIEnv *env) |
||||
|
{ |
||||
|
jclass ex; |
||||
|
const char *ex_name = "java/lang/OutOfMemoryError"; |
||||
|
|
||||
|
ex = env->FindClass(ex_name); |
||||
|
assert(ex); |
||||
|
return env->ThrowNew(ex, ex_name); |
||||
|
} |
||||
|
|
||||
|
jobject from_Integer(JNIEnv *env, |
||||
|
int val) |
||||
|
{ |
||||
|
assert(env); |
||||
|
jclass clazz = findClass(env, "java/lang/Integer"); |
||||
|
|
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(I)V"); |
||||
|
assert(constructor); |
||||
|
|
||||
|
jobject obj = env->NewObject(clazz, constructor, val); |
||||
|
assert(obj); |
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
int to_Integer(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
assert(env && obj); |
||||
|
int _val = callIntMethod(env, obj, "intValue"); |
||||
|
return _val; |
||||
|
} |
||||
|
|
||||
|
jbyteArray from_string(JNIEnv *env, |
||||
|
const char *str) |
||||
|
{ |
||||
|
if (str && str[0]) { |
||||
|
jboolean isCopy; |
||||
|
size_t l = strlen(str); |
||||
|
jbyteArray _str = env->NewByteArray(l); |
||||
|
env->SetByteArrayRegion(_str, 0, l, (jbyte *) str); |
||||
|
return _str; |
||||
|
} else if (str) { |
||||
|
return env->NewByteArray(0); |
||||
|
} else { |
||||
|
return (jbyteArray) NULL; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
char *to_string(JNIEnv *env, |
||||
|
jbyteArray str) |
||||
|
{ |
||||
|
if (str == NULL) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
size_t l = env->GetArrayLength(str); |
||||
|
char *_str = static_cast<char *>(calloc(1, l + 1)); |
||||
|
assert(_str); |
||||
|
env->GetByteArrayRegion(str, 0, l, (jbyte *) _str); |
||||
|
return _str; |
||||
|
} |
||||
|
|
||||
|
jobject from_stringlist(JNIEnv *env, |
||||
|
stringlist_t *sl) |
||||
|
{ |
||||
|
if (!sl) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
jclass clazz = findClass(env, "java/util/Vector"); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jobject obj = env->NewObject(clazz, constructor); |
||||
|
assert(obj); |
||||
|
|
||||
|
stringlist_t *_sl; |
||||
|
for (_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
||||
|
jobject o = from_string(env, _sl->value); |
||||
|
callBooleanMethod(env, obj, "add", o); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
stringlist_t *to_stringlist(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
if (!obj) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
jint size = callIntMethod(env, obj, "size"); |
||||
|
if (size == 0) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
stringlist_t *sl = new_stringlist(NULL); |
||||
|
stringlist_t *_sl; |
||||
|
jint i; |
||||
|
for (_sl = sl, i = 0; i < (int) size; i++) { |
||||
|
jobject o = callObjectMethod(env, obj, "get", i); |
||||
|
jbyteArray a = static_cast<jbyteArray>(o); |
||||
|
char *str = to_string(env, a); |
||||
|
_sl = stringlist_add(_sl, str); |
||||
|
env->DeleteLocalRef(o); |
||||
|
free(str); |
||||
|
} |
||||
|
|
||||
|
return sl; |
||||
|
} |
||||
|
|
||||
|
jobject from_stringpairlist(JNIEnv *env, |
||||
|
stringpair_list_t *sl) |
||||
|
{ |
||||
|
if (!sl) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
jclass clazz = findClass(env, "java/util/ArrayList"); |
||||
|
jclass clazz_pair = findClass(env, "foundation/pEp/jniadapter/Pair"); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jmethodID constructor_pair = env->GetMethodID(clazz_pair, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V"); |
||||
|
assert(constructor_pair); |
||||
|
|
||||
|
jobject obj = env->NewObject(clazz, constructor); |
||||
|
assert(obj); |
||||
|
|
||||
|
stringpair_list_t *_sl; |
||||
|
for (_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
||||
|
assert(_sl->value->key); |
||||
|
assert(_sl->value->value); |
||||
|
|
||||
|
jbyteArray first = from_string(env, _sl->value->key); |
||||
|
jbyteArray second = from_string(env, _sl->value->value); |
||||
|
jobject pair = env->NewObject(clazz_pair, constructor_pair, first, second); |
||||
|
callBooleanMethod(env, obj, "add", pair); |
||||
|
|
||||
|
env->DeleteLocalRef(first); |
||||
|
env->DeleteLocalRef(second); |
||||
|
env->DeleteLocalRef(pair); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
env->DeleteLocalRef(clazz_pair); |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
stringpair_list_t *to_stringpairlist(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
if (!obj) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
jint size = callIntMethod(env, obj, "size"); |
||||
|
if (size == 0) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
jfieldID first_id = getFieldID(env, "foundation/pEp/jniadapter/Pair", "first", "Ljava/lang/Object;"); |
||||
|
jfieldID second_id = getFieldID(env, "foundation/pEp/jniadapter/Pair", "second", "Ljava/lang/Object;"); |
||||
|
|
||||
|
stringpair_list_t *sl = new_stringpair_list(NULL); |
||||
|
stringpair_list_t *_sl; |
||||
|
jint i; |
||||
|
|
||||
|
for (_sl = sl, i = 0; i < (int) size; i++) { |
||||
|
jobject pair = callObjectMethod(env, obj, "get", i); |
||||
|
jbyteArray first = static_cast<jbyteArray>(env->GetObjectField(pair, first_id)); |
||||
|
jbyteArray second = static_cast<jbyteArray>(env->GetObjectField(pair, second_id)); |
||||
|
|
||||
|
char *first_str = to_string(env, first); |
||||
|
char *second_str = to_string(env, second); |
||||
|
stringpair_t *sp = new_stringpair(first_str, second_str); |
||||
|
env->DeleteLocalRef(pair); |
||||
|
free(first_str); |
||||
|
free(second_str); |
||||
|
|
||||
|
_sl = stringpair_list_add(_sl, sp); |
||||
|
} |
||||
|
|
||||
|
return sl; |
||||
|
} |
||||
|
|
||||
|
jobject from_timestamp(JNIEnv *env, |
||||
|
timestamp *ts) |
||||
|
{ |
||||
|
if (!ts) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
//LOGD("/* Seconds (0-60) */ FROM :%d", ts->tm_sec);
|
||||
|
//LOGD("/* Minutes (0-59) */ :%d", ts->tm_min);
|
||||
|
//LOGD("/* Hours (0-23) */ :%d", ts->tm_hour);
|
||||
|
//LOGD("/* Day of the month (1-31) */:%d", ts->tm_mday);
|
||||
|
//LOGD("/* Month (0-11) */ :%d", ts->tm_mon);
|
||||
|
//LOGD("/* Year - 1900 */ :%d", ts->tm_year);
|
||||
|
|
||||
|
time_t t = timegm(ts) * 1000; |
||||
|
//LOGD( "TimeGM returns : %lld", t);
|
||||
|
jclass clazz = findClass(env, "java/util/Date"); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(J)V"); |
||||
|
assert(constructor); |
||||
|
|
||||
|
jobject result = env->NewObject(clazz, constructor, (jlong) t); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
timestamp *to_timestamp(JNIEnv *env, |
||||
|
jobject date) |
||||
|
{ |
||||
|
if (!date) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
jlong t = callLongMethod(env, date, "getTime"); |
||||
|
//LOGD( "Set Time to : %lld", t);
|
||||
|
timestamp *ts = static_cast<timestamp *>(calloc(1, sizeof(timestamp))); |
||||
|
assert(ts); |
||||
|
if (ts == NULL) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
if (t) { |
||||
|
time_t clock = t / 1000; |
||||
|
gmtime_r(&clock, ts); |
||||
|
|
||||
|
//LOGD("/* Seconds (0-60) */ TO :%d", ts->tm_sec);
|
||||
|
//LOGD("/* Minutes (0-59) */ :%d", ts->tm_min);
|
||||
|
//LOGD("/* Hours (0-23) */ :%d", ts->tm_hour);
|
||||
|
//LOGD("/* Day of the month (1-31) */:%d", ts->tm_mday);
|
||||
|
//LOGD("/* Month (0-11) */ :%d", ts->tm_mon);
|
||||
|
//LOGD("/* Year - 1900 */ :%d", ts->tm_year);
|
||||
|
} |
||||
|
|
||||
|
return ts; |
||||
|
} |
||||
|
|
||||
|
static void _setStringField(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
jobject obj, |
||||
|
const char *name, |
||||
|
const char *value) |
||||
|
{ |
||||
|
if (value) { |
||||
|
jfieldID fieldID = getFieldID(env, classname, name, "[B"); |
||||
|
env->SetObjectField(obj, fieldID, static_cast<jobject>(from_string(env, value))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//TODO: fix/generalize/clean patch added to make keysync work using globalref to class
|
||||
|
static void _setStringField(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
jobject obj, |
||||
|
const char *name, |
||||
|
const char *value, |
||||
|
const jclass clazz) |
||||
|
{ |
||||
|
if (value) { |
||||
|
jfieldID fieldID = getFieldID(env, classname, name, "[B", clazz); |
||||
|
env->SetObjectField(obj, fieldID, static_cast<jobject>(from_string(env, value))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
jobject from_identity(JNIEnv *env, |
||||
|
pEp_identity *ident) |
||||
|
{ |
||||
|
if (!ident) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
static const char *classname = "foundation/pEp/jniadapter/_Identity"; |
||||
|
jclass clazz = findClass(env, classname); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jobject obj = env->NewObject(clazz, constructor); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
if (ident) { |
||||
|
_setStringField(env, classname, obj, "address", ident->address); |
||||
|
_setStringField(env, classname, obj, "fpr", ident->fpr); |
||||
|
_setStringField(env, classname, obj, "user_id", ident->user_id); |
||||
|
_setStringField(env, classname, obj, "username", ident->username); |
||||
|
|
||||
|
jfieldID comm_type_id = getFieldID(env, classname, "comm_type", "I"); |
||||
|
env->SetIntField(obj, comm_type_id, static_cast<jint>(ident->comm_type)); |
||||
|
|
||||
|
_setStringField(env, classname, obj, "lang", ident->lang); |
||||
|
|
||||
|
jfieldID me_id = getFieldID(env, classname, "me", "Z"); |
||||
|
env->SetBooleanField(obj, me_id, static_cast<jboolean>(ident->me)); |
||||
|
|
||||
|
jfieldID flags_id = getFieldID(env, classname, "flags", "I"); |
||||
|
env->SetIntField(obj, flags_id, static_cast<jint>(ident->flags)); |
||||
|
} |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
//TODO: fix/generalize/clean patch added to make keysync work using globalref to class
|
||||
|
jobject from_identity(JNIEnv *env, |
||||
|
pEp_identity *ident, |
||||
|
jclass identityClass) |
||||
|
{ |
||||
|
if (!ident) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
static const char *classname = "foundation/pEp/jniadapter/_Identity"; |
||||
|
jmethodID constructor = env->GetMethodID(identityClass, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jobject obj = env->NewObject(identityClass, constructor); |
||||
|
|
||||
|
if (ident) { |
||||
|
_setStringField(env, classname, obj, "address", ident->address, identityClass); |
||||
|
_setStringField(env, classname, obj, "fpr", ident->fpr, identityClass); |
||||
|
_setStringField(env, classname, obj, "user_id", ident->user_id, identityClass); |
||||
|
_setStringField(env, classname, obj, "username", ident->username, identityClass); |
||||
|
|
||||
|
jfieldID comm_type_id = getFieldID(env, classname, "comm_type", "I", identityClass); |
||||
|
env->SetIntField(obj, comm_type_id, static_cast<jint>(ident->comm_type)); |
||||
|
|
||||
|
_setStringField(env, classname, obj, "lang", ident->lang, identityClass); |
||||
|
|
||||
|
jfieldID me_id = getFieldID(env, classname, "me", "Z", identityClass); |
||||
|
env->SetBooleanField(obj, me_id, static_cast<jboolean>(ident->me)); |
||||
|
|
||||
|
jfieldID flags_id = getFieldID(env, classname, "flags", "I", identityClass); |
||||
|
env->SetIntField(obj, flags_id, static_cast<jint>(ident->flags)); |
||||
|
} |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
char *_getStringField(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
jobject obj, |
||||
|
const char *name) |
||||
|
{ |
||||
|
jfieldID fieldID = getFieldID(env, classname, name, "[B"); |
||||
|
jobject fobj = env->GetObjectField(obj, fieldID); |
||||
|
|
||||
|
char *res = to_string(env, static_cast<jbyteArray>(fobj)); |
||||
|
|
||||
|
env->DeleteLocalRef(fobj); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
pEp_identity *to_identity(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
if (!obj) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
static const char *classname = "foundation/pEp/jniadapter/_Identity"; |
||||
|
pEp_identity *ident = new_identity(NULL, NULL, NULL, NULL); |
||||
|
|
||||
|
ident->address = _getStringField(env, classname, obj, "address"); |
||||
|
ident->fpr = _getStringField(env, classname, obj, "fpr"); |
||||
|
ident->user_id = _getStringField(env, classname, obj, "user_id"); |
||||
|
ident->username = _getStringField(env, classname, obj, "username"); |
||||
|
|
||||
|
jfieldID comm_type_id = getFieldID(env, classname, "comm_type", "I"); |
||||
|
ident->comm_type = static_cast<PEP_comm_type>(env->GetIntField(obj, comm_type_id)); |
||||
|
|
||||
|
char *lang = _getStringField(env, classname, obj, "lang"); |
||||
|
if (lang && lang[0]) { |
||||
|
ident->lang[0] = lang[0]; |
||||
|
ident->lang[1] = lang[1]; |
||||
|
} |
||||
|
free(lang); |
||||
|
|
||||
|
jfieldID me_id = getFieldID(env, classname, "me", "Z"); |
||||
|
ident->me = static_cast<bool>(env->GetBooleanField(obj, me_id)); |
||||
|
|
||||
|
jfieldID flags_id = getFieldID(env, classname, "flags", "I"); |
||||
|
ident->flags = static_cast<identity_flags_t>(env->GetIntField(obj, flags_id)); |
||||
|
|
||||
|
return ident; |
||||
|
} |
||||
|
|
||||
|
jobject from_identitylist(JNIEnv *env, |
||||
|
identity_list *il) |
||||
|
{ |
||||
|
if (!il) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
jclass clazz = findClass(env, "java/util/Vector"); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jobject obj = env->NewObject(clazz, constructor); |
||||
|
assert(obj); |
||||
|
|
||||
|
identity_list *_il; |
||||
|
for (_il = il; _il && _il->ident; _il = _il->next) { |
||||
|
jobject o = from_identity(env, _il->ident); |
||||
|
callBooleanMethod(env, obj, "add", o); |
||||
|
} |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
identity_list *to_identitylist(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
if (!obj) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
jint size = callIntMethod(env, obj, "size"); |
||||
|
if (size == 0) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
identity_list *il = new_identity_list(NULL); |
||||
|
identity_list *_il; |
||||
|
jint i; |
||||
|
for (_il = il, i = 0; i < (int) size; i++) { |
||||
|
jobject o = callObjectMethod(env, obj, "get", i); |
||||
|
pEp_identity *ident = to_identity(env, o); |
||||
|
_il = identity_list_add(_il, ident); |
||||
|
env->DeleteLocalRef(o); |
||||
|
} |
||||
|
|
||||
|
return il; |
||||
|
} |
||||
|
|
||||
|
jobject _from_blob(JNIEnv *env, |
||||
|
bloblist_t *b) |
||||
|
{ |
||||
|
if (!b) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
static const char *classname = "foundation/pEp/jniadapter/_Blob"; |
||||
|
jclass clazz = findClass(env, classname); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jobject obj = env->NewObject(clazz, constructor); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
jfieldID fieldID = getFieldID(env, classname, "data", "[B"); |
||||
|
jbyteArray _data = env->NewByteArray(static_cast<jsize>(b->size)); |
||||
|
env->SetByteArrayRegion(_data, 0, b->size, reinterpret_cast<jbyte *>(b->value)); |
||||
|
env->SetObjectField(obj, fieldID, static_cast<jobject>(_data)); |
||||
|
_setStringField(env, classname, obj, "mime_type", b->mime_type); |
||||
|
_setStringField(env, classname, obj, "filename", b->filename); |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
jobject from_bloblist(JNIEnv *env, |
||||
|
bloblist_t *bl) |
||||
|
{ |
||||
|
if (!bl) { |
||||
|
return (jobject) NULL; |
||||
|
} |
||||
|
|
||||
|
jclass clazz = findClass(env, "java/util/Vector"); |
||||
|
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
||||
|
assert(constructor); |
||||
|
jobject obj = env->NewObject(clazz, constructor); |
||||
|
assert(obj); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz); |
||||
|
|
||||
|
bloblist_t *_bl; |
||||
|
for (_bl = bl; _bl && _bl->value; _bl = _bl->next) { |
||||
|
jobject o = _from_blob(env, _bl); |
||||
|
if (o) { |
||||
|
callBooleanMethod(env, obj, "add", o); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
bloblist_t *to_blob(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
if (!obj) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
static const char *classname = "foundation/pEp/jniadapter/_Blob"; |
||||
|
jclass clazz = findClass(env, classname); |
||||
|
|
||||
|
char *mime_type = _getStringField(env, classname, obj, "mime_type"); |
||||
|
char *filename = _getStringField(env, classname, obj, "filename"); |
||||
|
|
||||
|
jfieldID data_id = getFieldID(env, classname, "data", "[B"); |
||||
|
jbyteArray _data = static_cast<jbyteArray>(env->GetObjectField(obj, data_id)); |
||||
|
size_t size = static_cast<size_t>(env->GetArrayLength(_data)); |
||||
|
char *b = static_cast<char *>(malloc(size)); |
||||
|
assert(b); |
||||
|
|
||||
|
env->GetByteArrayRegion(_data, 0, size, reinterpret_cast<jbyte *>(b)); |
||||
|
bloblist_t *bl = new_bloblist(b, size, mime_type, filename); |
||||
|
|
||||
|
free(mime_type); |
||||
|
free(filename); |
||||
|
return bl; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bloblist_t *to_bloblist(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
if (!obj) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
jint size = callIntMethod(env, obj, "size"); |
||||
|
if (size == 0) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL); |
||||
|
bloblist_t *_bl; |
||||
|
_bl = bl; |
||||
|
jint i; |
||||
|
for (i = 0; i < (int) size; i++) { |
||||
|
jobject o = callObjectMethod(env, obj, "get", i); |
||||
|
bloblist_t *b = to_blob(env, o); |
||||
|
_bl = bloblist_add(_bl, b->value, b->size, b->mime_type, b->filename); |
||||
|
env->DeleteLocalRef(o); |
||||
|
} |
||||
|
|
||||
|
return bl; |
||||
|
} |
||||
|
|
||||
|
PEP_enc_format to_EncFormat(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
static const char *classname = "foundation/pEp/jniadapter/Message$EncFormat"; |
||||
|
jclass clazz_enc_format = findClass(env, classname); |
||||
|
jfieldID field_value = env->GetFieldID(clazz_enc_format, "value", "I"); |
||||
|
assert(field_value); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz_enc_format); |
||||
|
return static_cast<PEP_enc_format>(env->GetIntField(obj, field_value)); |
||||
|
} |
||||
|
|
||||
|
PEP_CIPHER_SUITE to_CipherSuite(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
static const char *classname = "foundation/pEp/jniadapter/CipherSuite"; |
||||
|
jclass clazz_enc_format = findClass(env, classname); |
||||
|
jfieldID field_value = env->GetFieldID(clazz_enc_format, "value", "I"); |
||||
|
assert(field_value); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz_enc_format); |
||||
|
return static_cast<PEP_CIPHER_SUITE>(env->GetIntField(obj, field_value)); |
||||
|
} |
||||
|
|
||||
|
sync_handshake_result to_SyncHandshakeResult(JNIEnv *env, |
||||
|
jobject obj) |
||||
|
{ |
||||
|
static const char *classname = "foundation/pEp/jniadapter/SyncHandshakeResult"; |
||||
|
jclass clazz_enc_format = findClass(env, classname); |
||||
|
jfieldID field_value = env->GetFieldID(clazz_enc_format, "value", "I"); |
||||
|
assert(field_value); |
||||
|
|
||||
|
env->DeleteLocalRef(clazz_enc_format); |
||||
|
return static_cast<sync_handshake_result>(env->GetIntField(obj, field_value)); |
||||
|
} |
||||
|
}; |
||||
|
}; |
||||
|
|
@ -0,0 +1,147 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <unordered_map> |
||||
|
#include <thread> |
||||
|
#include <mutex> |
||||
|
#include <jni.h> |
||||
|
#include <pEp/stringpair.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/bloblist.h> |
||||
|
#include <pEp/message.h> |
||||
|
#include <pEp/sync_api.h> |
||||
|
#include <pEp/passphrase_cache.hh> |
||||
|
|
||||
|
#if 0 // Enable if log needed
|
||||
|
#include <android/log.h> |
||||
|
#define LOG_TAG "pEpJNIAdapter" |
||||
|
#define LOGD(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) |
||||
|
#else |
||||
|
#define LOGD(...) do{}while(0) |
||||
|
#endif |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace JNIAdapter { |
||||
|
// Global mutex needs to be locked in all constructors which insert their own mutex object
|
||||
|
// into the unordered_map (which is thread safe for read, but not for write)
|
||||
|
extern std::mutex global_mutex; |
||||
|
|
||||
|
// Stores mutex per java object
|
||||
|
extern std::unordered_map<long, std::mutex *> engine_objid_mutex; |
||||
|
|
||||
|
// needs to be called after create_engine_java_object_mutex()
|
||||
|
// and before release_engine_java_object_mutex()
|
||||
|
// Thread safe
|
||||
|
std::mutex *get_engine_java_object_mutex(JNIEnv *env, |
||||
|
jobject me); |
||||
|
|
||||
|
// Needs to be called exactly once per obj, in the constructor of the obj
|
||||
|
// You need to lock a global mutex before calling this function (write to unordered_map)
|
||||
|
void create_engine_java_object_mutex(JNIEnv *env, |
||||
|
jobject me); |
||||
|
|
||||
|
// Needs to be called exactly once per obj, in the destructor of this obj
|
||||
|
// You need to lock a global mutex before calling this function (write to unordered_map)
|
||||
|
void release_engine_java_object_mutex(JNIEnv *env, |
||||
|
jobject me); |
||||
|
|
||||
|
|
||||
|
jclass findClass(JNIEnv *env, |
||||
|
const char *classname); |
||||
|
|
||||
|
jfieldID getFieldID(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
const char *fieldname, |
||||
|
const char *signature); |
||||
|
|
||||
|
jfieldID getFieldID(JNIEnv *env, |
||||
|
const char *classname, |
||||
|
const char *fieldname, |
||||
|
const char *signature, |
||||
|
const jclass clazz); |
||||
|
|
||||
|
jint callIntMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname); |
||||
|
|
||||
|
jlong callLongMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname); |
||||
|
|
||||
|
jobject callObjectMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname, |
||||
|
jint index); |
||||
|
|
||||
|
jboolean callBooleanMethod(JNIEnv *env, |
||||
|
jobject obj, |
||||
|
const char *methodname, |
||||
|
jobject o); |
||||
|
|
||||
|
jint outOfMemory(JNIEnv *env); |
||||
|
|
||||
|
jobject from_Integer(JNIEnv *env, |
||||
|
int val); |
||||
|
|
||||
|
int to_Integer(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
jbyteArray from_string(JNIEnv *env, |
||||
|
const char *str); |
||||
|
|
||||
|
char *to_string(JNIEnv *env, |
||||
|
jbyteArray str); |
||||
|
|
||||
|
jobject from_stringlist(JNIEnv *env, |
||||
|
stringlist_t *sl); |
||||
|
|
||||
|
stringlist_t *to_stringlist(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
jobject from_stringpairlist(JNIEnv *env, |
||||
|
stringpair_list_t *sl); |
||||
|
|
||||
|
stringpair_list_t *to_stringpairlist(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
jobject from_timestamp(JNIEnv *env, |
||||
|
timestamp *ts); |
||||
|
|
||||
|
timestamp *to_timestamp(JNIEnv *env, |
||||
|
jobject date); |
||||
|
|
||||
|
jobject from_identity(JNIEnv *env, |
||||
|
pEp_identity *ident); |
||||
|
|
||||
|
jobject from_identity(JNIEnv *env, |
||||
|
pEp_identity *ident, |
||||
|
jclass identityClass); |
||||
|
|
||||
|
pEp_identity *to_identity(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
jobject from_identitylist(JNIEnv *env, |
||||
|
identity_list *il); |
||||
|
|
||||
|
identity_list *to_identitylist(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
jobject from_bloblist(JNIEnv *env, |
||||
|
bloblist_t *bl); |
||||
|
|
||||
|
bloblist_t *to_blob(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
bloblist_t *to_bloblist(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
PEP_enc_format to_EncFormat(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
PEP_CIPHER_SUITE to_CipherSuite(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
|
||||
|
sync_handshake_result to_SyncHandshakeResult(JNIEnv *env, |
||||
|
jobject obj); |
||||
|
}; |
||||
|
}; |
||||
|
|
@ -0,0 +1,15 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <pEp/passphrase_cache.hh> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace JNIAdapter { |
||||
|
|
||||
|
char *passphraseRequiredCallback(const PEP_STATUS status); |
||||
|
template<typename... A> PEP_STATUS passphraseWrap(PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#include "passphrase_callback.hxx" |
@ -0,0 +1,42 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include "passphrase_callback.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace JNIAdapter { |
||||
|
|
||||
|
template<typename... A> PEP_STATUS passphraseWrap(PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a) { |
||||
|
pEpLog("cached passphrase mode"); |
||||
|
bool retryAgain = false; |
||||
|
int maxRetries = 3; |
||||
|
int retryCount = 0; |
||||
|
PEP_STATUS status; |
||||
|
do { |
||||
|
// the actual target function
|
||||
|
pEpLog("calling passphrase_cache.api from basic_api"); |
||||
|
status = passphrase_cache.api(f, session, a...); |
||||
|
pEpLog("PEP_STATUS:" << status); |
||||
|
if (status == PEP_PASSPHRASE_REQUIRED || |
||||
|
status == PEP_WRONG_PASSPHRASE || |
||||
|
status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED) |
||||
|
{ |
||||
|
pEpLog("none of the cached passphrases worked"); |
||||
|
if (retryCount < maxRetries) { |
||||
|
// call the app
|
||||
|
char *_passphrase = passphraseRequiredCallback(status); |
||||
|
pEpLog("callback returned, config_passphrase() with new passphrase"); |
||||
|
PEP_STATUS status = ::config_passphrase(session, passphrase_cache.add(_passphrase)); |
||||
|
retryAgain = true; |
||||
|
retryCount++; |
||||
|
} else { |
||||
|
pEpLog("max retries reached:" << maxRetries); |
||||
|
retryAgain = false; |
||||
|
} |
||||
|
} else { |
||||
|
retryAgain = false; |
||||
|
} |
||||
|
} while (retryAgain); |
||||
|
return status; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,28 +0,0 @@ |
|||||
package foundation.pEp.jniadapter; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.Vector; |
|
||||
|
|
||||
final public class Engine extends AbstractEngine { |
|
||||
public Engine() throws pEpException { } |
|
||||
|
|
||||
public native Message encrypt_message( |
|
||||
Message src, |
|
||||
ArrayList<String> extra, |
|
||||
Message.EncFormat enc_format |
|
||||
) throws pEpException; |
|
||||
|
|
||||
public class DecryptResult { |
|
||||
public Message dst; |
|
||||
public Color color; |
|
||||
} |
|
||||
|
|
||||
public native DecryptResult decrypt_message( |
|
||||
Message src, |
|
||||
ArrayList<String> keylist |
|
||||
) throws pEpException; |
|
||||
|
|
||||
public native Color outgoing_message_color( |
|
||||
Message msg |
|
||||
) throws pEpException; |
|
||||
} |
|
@ -1,218 +0,0 @@ |
|||||
package foundation.pEp.jniadapter; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.Vector; |
|
||||
import java.util.Date; |
|
||||
import java.util.HashMap; |
|
||||
|
|
||||
public class Message implements AutoCloseable { |
|
||||
private final long handle; |
|
||||
|
|
||||
native long init(); |
|
||||
native void release(long handle); |
|
||||
|
|
||||
public Message() { |
|
||||
handle = init(); |
|
||||
} |
|
||||
|
|
||||
public final void close() { |
|
||||
release(handle); |
|
||||
} |
|
||||
|
|
||||
public enum TextFormat { |
|
||||
Plain (0), |
|
||||
Html (1), |
|
||||
Other (255) |
|
||||
; |
|
||||
|
|
||||
static class Management { |
|
||||
public static final HashMap<Integer, TextFormat> tag = |
|
||||
new HashMap<Integer, TextFormat>(); |
|
||||
} |
|
||||
|
|
||||
public final int value; |
|
||||
|
|
||||
TextFormat(int value) { |
|
||||
this.value = value; |
|
||||
fill(value); |
|
||||
} |
|
||||
|
|
||||
private void fill(int value) { |
|
||||
Management.tag.put(value, this); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public enum Direction { |
|
||||
Incoming (0), |
|
||||
Outgoing (1) |
|
||||
; |
|
||||
|
|
||||
static class Management { |
|
||||
public static final HashMap<Integer, Direction> tag = |
|
||||
new HashMap<Integer, Direction>(); |
|
||||
} |
|
||||
|
|
||||
public final int value; |
|
||||
|
|
||||
Direction(int value) { |
|
||||
this.value = value; |
|
||||
fill(value); |
|
||||
} |
|
||||
|
|
||||
private void fill(int value) { |
|
||||
Management.tag.put(value, this); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public enum EncFormat { |
|
||||
None (0), |
|
||||
Pieces (1), |
|
||||
SMIME (2), |
|
||||
PGPMIME (3), |
|
||||
PEP (4) |
|
||||
; |
|
||||
|
|
||||
static class Management { |
|
||||
public static final HashMap<Integer, EncFormat> tag = |
|
||||
new HashMap<Integer, EncFormat>(); |
|
||||
} |
|
||||
|
|
||||
public final int value; |
|
||||
|
|
||||
EncFormat(int value) { |
|
||||
this.value = value; |
|
||||
fill(value); |
|
||||
} |
|
||||
|
|
||||
private void fill(int value) { |
|
||||
Management.tag.put(value, this); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private native int _getDir(); |
|
||||
private native void _setDir(int value); |
|
||||
public Direction getDir() { |
|
||||
return Direction.tag.get(_getDir()); |
|
||||
} |
|
||||
public void setDir(Direction value) { |
|
||||
_setDir(value.value); |
|
||||
} |
|
||||
|
|
||||
private native byte[] _getId(); |
|
||||
private native void _setId(byte[] value); |
|
||||
public String getId() { |
|
||||
return AbstractEngine.toUTF16(_getId()); |
|
||||
} |
|
||||
public void setId(String value) { |
|
||||
_setId(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native byte[] _getShortmsg(); |
|
||||
private native void _setShortmsg(byte[] value); |
|
||||
public String getShortmsg() { |
|
||||
return AbstractEngine.toUTF16(_getShortmsg()); |
|
||||
} |
|
||||
public void setShortmsg(String value) { |
|
||||
_setShortmsg(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native byte[] _getLongmsg(); |
|
||||
private native void _setLongmsg(byte[] value); |
|
||||
public String getLongmsg() { |
|
||||
return AbstractEngine.toUTF16(_getLongmsg()); |
|
||||
} |
|
||||
public void setLongmsg(String value) { |
|
||||
_setLongmsg(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native byte[] _getLongmsgFormatted(); |
|
||||
private native void _setLongmsgFormatted(byte[] value); |
|
||||
public String getLongmsgFormatted() { |
|
||||
return AbstractEngine.toUTF16(_getLongmsgFormatted()); |
|
||||
} |
|
||||
public void setLongmsgFormatted(String value) { |
|
||||
_setLongmsgFormatted(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
public native ArrayList<Blob> getAttachments(); |
|
||||
public native void setAttachments(ArrayList<Blob> value); |
|
||||
|
|
||||
public native Date getSent(); |
|
||||
public native void setSent(Date value); |
|
||||
|
|
||||
public native Date getRecv(); |
|
||||
public native void setRecv(Date value); |
|
||||
|
|
||||
private native AbstractEngine._Identity _getFrom(); |
|
||||
private native void _setFrom(AbstractEngine._Identity value); |
|
||||
public Identity getFrom() { |
|
||||
return new _getFrom().getIdentity(); |
|
||||
} |
|
||||
public void setFrom(Identity value) { |
|
||||
_setFrom(new AbstractEngine._Identity(value)); |
|
||||
} |
|
||||
|
|
||||
public native ArrayList<Identity> getTo(); |
|
||||
public native void setTo(ArrayList<Identity> value); |
|
||||
|
|
||||
public native Identity getRecvBy(); |
|
||||
public native void setRecvBy(Identity value); |
|
||||
|
|
||||
public native ArrayList<Identity> getCc(); |
|
||||
public native void setCc(ArrayList<Identity> value); |
|
||||
|
|
||||
public native ArrayList<Identity> getBcc(); |
|
||||
public native void setBcc(ArrayList<Identity> value); |
|
||||
|
|
||||
public native ArrayList<Identity> getReplyTo(); |
|
||||
public native void setReplyTo(ArrayList<Identity> value); |
|
||||
|
|
||||
private native ArrayList<byte[]> _getInReplyTo(); |
|
||||
private native void _setInReplyTo(ArrayList<byte[]> value); |
|
||||
public ArrayList<String> getInReplyTo() { |
|
||||
return AbstractEngine.toUTF16(_getInReplyTo()); |
|
||||
} |
|
||||
public void setInReplyTo(ArrayList<String> value) { |
|
||||
_setInReplyTo(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native ArrayList<byte[]> _getReferences(); |
|
||||
private native void _setReferences(ArrayList<byte[]> value); |
|
||||
public ArrayList<String> getReferences() { |
|
||||
return AbstractEngine.toUTF16(_getReferences()); |
|
||||
} |
|
||||
public void setReferences(ArrayList<String> value) { |
|
||||
_setReferences(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native ArrayList<byte[]> _getKeywords(); |
|
||||
private native void _setKeywords(ArrayList<byte[]> value); |
|
||||
public ArrayList<String> getKeywords() { |
|
||||
return AbstractEngine.toUTF16(_getKeywords()); |
|
||||
} |
|
||||
public void setKeywords(ArrayList<String> value) { |
|
||||
_setKeywords(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native byte[] _getComments(); |
|
||||
private native void _setComments(byte[] value); |
|
||||
public String getComments() { |
|
||||
return AbstractEngine.toUTF16(_getComments()); |
|
||||
} |
|
||||
public void setComments(String value) { |
|
||||
_setComments(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
private native Vector<Pair<byte[], byte[]>> _getOptFields(); |
|
||||
private native void _setOptFields(Vector<Pair<byte[], byte[]>> value); |
|
||||
public Vector<Pair<String, String>> getOptFields() { |
|
||||
return AbstractEngine.toUTF16(_getOptFields()); |
|
||||
} |
|
||||
public void setOptFields(Vector<Pair<String, String>> value) { |
|
||||
_setOptFields(AbstractEngine.toUTF8(value)); |
|
||||
} |
|
||||
|
|
||||
public native Message.EncFormat getEncFormat(); |
|
||||
public native void setEncFormat(Message.EncFormat value); |
|
||||
|
|
||||
} |
|
@ -1,11 +0,0 @@ |
|||||
package foundation.pEp.jniadapter; |
|
||||
import java.util.concurrent.atomic.AtomicLong; |
|
||||
|
|
||||
abstract class UniquelyIdentifiable { |
|
||||
static final AtomicLong NEXT_ID = new AtomicLong(1); |
|
||||
final long id = NEXT_ID.getAndIncrement(); |
|
||||
|
|
||||
public long getId() { |
|
||||
return id; |
|
||||
} |
|
||||
} |
|
@ -1,252 +0,0 @@ |
|||||
include yslt.yml2 |
|
||||
|
|
||||
tstylesheet { |
|
||||
include ./textutils.ysl2 |
|
||||
include ./types_java.ysl2 |
|
||||
|
|
||||
template "/namespace[@name='pEp']" apply "struct|enum|exception", 0; |
|
||||
|
|
||||
template "struct" { |
|
||||
const "cname" call "toJava" with "type", "@name"; |
|
||||
document("foundation/pEp/jniadapter/{$cname}.java", "text") |
|
||||
|| |
|
||||
package foundation.pEp.jniadapter; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.Vector; |
|
||||
import java.util.Date; |
|
||||
import java.util.HashMap; |
|
||||
import java.io.Serializable; |
|
||||
|
|
||||
public class «$cname» implements AutoCloseable, Serializable { |
|
||||
private static final long serialVersionUID = 2119420428331150924L; |
|
||||
private long handle; |
|
||||
|
|
||||
native long init(); |
|
||||
native void release(long handle); |
|
||||
|
|
||||
public «$cname»() { |
|
||||
handle = init(); |
|
||||
} |
|
||||
|
|
||||
private native long _«$cname»( |
|
||||
byte[] mime_text |
|
||||
) throws pEpException; |
|
||||
|
|
||||
public «$cname»(String mime_text) { |
|
||||
byte[] _mime_text = AbstractEngine.toUTF8(mime_text); |
|
||||
handle = _«$cname»(_mime_text); |
|
||||
} |
|
||||
|
|
||||
public native byte[] _encodeMIME() throws pEpException; |
|
||||
|
|
||||
public String encodeMIME() { |
|
||||
return AbstractEngine.toUTF16(_encodeMIME()); |
|
||||
} |
|
||||
|
|
||||
private «$cname»(long h) { |
|
||||
handle = h; |
|
||||
} |
|
||||
|
|
||||
public final void close() { |
|
||||
release(handle); |
|
||||
} |
|
||||
|
|
||||
final protected long getHandle() { |
|
||||
return handle; |
|
||||
} |
|
||||
|
|
||||
`` apply "enum", mode=inner |
|
||||
`` apply "*[name(.)!='enum']", mode=entry |
|
||||
} |
|
||||
|| |
|
||||
} |
|
||||
|
|
||||
template "enum|exception" { |
|
||||
const "jname" call "toJava" with "type", "@name"; |
|
||||
document("foundation/pEp/jniadapter/{$jname}.java", "text") |
|
||||
|| |
|
||||
package foundation.pEp.jniadapter; |
|
||||
|
|
||||
import java.util.HashMap; |
|
||||
|
|
||||
`` apply ".", 0, mode=inner |
|
||||
|| |
|
||||
} |
|
||||
|
|
||||
template "enum|exception", mode=inner { |
|
||||
const "jname" call "CamelCase" with "text", "@name"; |
|
||||
|| |
|
||||
public enum «$jname» { |
|
||||
`` apply "*", mode=value |
|
||||
; |
|
||||
|
|
||||
public final int value; |
|
||||
|
|
||||
private static HashMap<Integer, «$jname»> intMap; |
|
||||
|
|
||||
private «$jname»(int value) { |
|
||||
this.value = value; |
|
||||
} |
|
||||
|
|
||||
public static «$jname» getByInt(int value){ |
|
||||
if (intMap == null) { |
|
||||
intMap = new HashMap<Integer, «$jname»>(); |
|
||||
for («$jname» s : «$jname».values()) { |
|
||||
intMap.put(s.value, s); |
|
||||
} |
|
||||
} |
|
||||
if (intMap.containsKey(value)) { |
|
||||
return intMap.get(value); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
|| |
|
||||
} |
|
||||
|
|
||||
template "*", mode=entry { |
|
||||
const "ctype", "name(.)"; |
|
||||
const "type" call "toJava" with "type", "name(.)"; |
|
||||
const "itype" call "toIntermediate" with "type", "name(.)"; |
|
||||
const "name" call "toJava" with "type", "name(*[position()=1])"; |
|
||||
|
|
||||
choose { |
|
||||
when "$ctype = 'identity'" |
|
||||
|| |
|
||||
private native «$itype» _get«$name»(); |
|
||||
private native void _set«$name»(«$itype» value); |
|
||||
public «$type» get«$name»() { |
|
||||
«$itype» res = _get«$name»(); |
|
||||
if(res != null){ |
|
||||
return new «$type»(_get«$name»()); |
|
||||
}else{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
public void set«$name»(«$type» value) { |
|
||||
if(value != null) |
|
||||
_set«$name»(new «$itype»(value)); |
|
||||
else |
|
||||
_set«$name»(null); |
|
||||
} |
|
||||
|
|
||||
|| |
|
||||
|
|
||||
when "$ctype = 'identitylist' or $ctype = 'bloblist' or $ctype = 'stringlist' or $ctype = 'stringpairlist'" |
|
||||
{ |
|
||||
|
|
||||
const "ename", "substring-after(substring($type,1,string-length($type)-1), '<')"; |
|
||||
const "iename" choose { |
|
||||
when "$ctype = 'stringlist'" > byte[] |
|
||||
when "$ctype = 'stringpairlist'" > Pair<byte[],byte[]> |
|
||||
otherwise > _«$ename» |
|
||||
} |
|
||||
const "convget" choose { |
|
||||
when "$ctype = 'stringlist'" > AbstractEngine.toUTF16(i) |
|
||||
when "$ctype = 'stringpairlist'" > new Pair<String, String>(AbstractEngine.toUTF16(i.first), AbstractEngine.toUTF16(i.second)) |
|
||||
otherwise > new «$ename»(i) |
|
||||
} |
|
||||
const "convset" choose { |
|
||||
when "$ctype = 'stringlist'" > AbstractEngine.toUTF8(i) |
|
||||
when "$ctype = 'stringpairlist'" > new Pair<byte[],byte[]>(AbstractEngine.toUTF8(i.first), AbstractEngine.toUTF8(i.second)) |
|
||||
otherwise > new _«$ename»(i) |
|
||||
} |
|
||||
|| |
|
||||
private native «$itype» _get«$name»(); |
|
||||
private native void _set«$name»(«$itype» value); |
|
||||
public «$type» get«$name»() { |
|
||||
«$itype» glist = _get«$name»(); |
|
||||
if(glist != null){ |
|
||||
«$type» list = new «$type»(); |
|
||||
for («$iename» i : glist) |
|
||||
list.add(«$convget»); |
|
||||
return list; |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
public void set«$name»(«$type» value) { |
|
||||
if(value != null){ |
|
||||
«$itype» list = new «$itype»(); |
|
||||
for («$ename» i : value) |
|
||||
list.add(«$convset»); |
|
||||
_set«$name»(list); |
|
||||
}else{ |
|
||||
_set«$name»(null); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|| |
|
||||
} |
|
||||
|
|
||||
when "$itype != $type" |
|
||||
|| |
|
||||
private native «$itype» _get«$name»(); |
|
||||
private native void _set«$name»(«$itype» value); |
|
||||
public «$type» get«$name»() { |
|
||||
«$itype» res = _get«$name»(); |
|
||||
if(res != null) |
|
||||
return AbstractEngine.toUTF16(res); |
|
||||
else |
|
||||
return null; |
|
||||
} |
|
||||
public void set«$name»(«$type» value) { |
|
||||
if(value != null) |
|
||||
_set«$name»(AbstractEngine.toUTF8(value)); |
|
||||
else |
|
||||
_set«$name»(new byte[0]); |
|
||||
} |
|
||||
|
|
||||
|| |
|
||||
|
|
||||
when "$itype != $type" |
|
||||
|| |
|
||||
private native «$itype» _get«$name»(); |
|
||||
private native void _set«$name»(«$itype» value); |
|
||||
public «$type» get«$name»() { |
|
||||
«$itype» res = _get«$name»(); |
|
||||
if(res != null) |
|
||||
return AbstractEngine.toUTF16(res); |
|
||||
else |
|
||||
return null; |
|
||||
} |
|
||||
public void set«$name»(«$type» value) { |
|
||||
if(value != null) |
|
||||
_set«$name»(AbstractEngine.toUTF8(value)); |
|
||||
else |
|
||||
_set«$name»(null); |
|
||||
} |
|
||||
|
|
||||
|| |
|
||||
|
|
||||
when "../enum[@name=$ctype]" |
|
||||
|| |
|
||||
private native int _get«$name»(); |
|
||||
public «$itype» get«$name»() { |
|
||||
return «$itype».getByInt(_get«$name»()); |
|
||||
} |
|
||||
private native void _set«$name»(int value); |
|
||||
public void set«$name»(«$itype» value) { |
|
||||
if(value != null) |
|
||||
_set«$name»(value.value); |
|
||||
else |
|
||||
_set«$name»(0); |
|
||||
} |
|
||||
|
|
||||
|| |
|
||||
|
|
||||
otherwise |
|
||||
|| |
|
||||
public native «$itype» get«$name»(); |
|
||||
public native void set«$name»(«$itype» value); |
|
||||
|
|
||||
|| |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
template "*", mode=value { |
|
||||
const "name" call "toJava" with "type", "name(.)"; |
|
||||
| «$name» («.»)`if "position()!=last()" > , ` |
|
||||
} |
|
||||
} |
|
||||
|
|
@ -1,35 +0,0 @@ |
|||||
include yslt.yml2 |
|
||||
|
|
||||
tstylesheet { |
|
||||
include ./textutils.ysl2 |
|
||||
|
|
||||
template "/" { |
|
||||
| package foundation.pEp.jniadapter; |
|
||||
| |
|
||||
| public class pEpException extends RuntimeException { |
|
||||
| public pEpException(String message) { |
|
||||
| super(message); |
|
||||
| } |
|
||||
| } |
|
||||
|
|
||||
apply "namespace/exception[@name='Status']", 0; |
|
||||
} |
|
||||
|
|
||||
function "exception" { |
|
||||
param "name"; |
|
||||
|
|
||||
document "foundation/pEp/jniadapter/{$name}.java", "text" { |
|
||||
| package foundation.pEp.jniadapter; |
|
||||
| |
|
||||
| public class «$name» extends pEpException { |
|
||||
| public «$name»(String message) { |
|
||||
| super(message); |
|
||||
| } |
|
||||
| } |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
template "exception" for "*[text()!=0]" call "exception" |
|
||||
with "name" call "CamelCase" with "text", "name(.)"; |
|
||||
} |
|
||||
|
|
@ -1,64 +0,0 @@ |
|||||
include yslt.yml2 |
|
||||
|
|
||||
tstylesheet { |
|
||||
include ./textutils.ysl2 |
|
||||
|
|
||||
template "/" { |
|
||||
apply "namespace", 0; |
|
||||
document "throw_pEp_exception.hh", "text" |
|
||||
|| |
|
||||
#pragma once |
|
||||
|
|
||||
#include <jni.h> |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace JNIAdapter { |
|
||||
jint throw_pEp_Exception(JNIEnv *env, PEP_STATUS status); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
|| |
|
||||
|
|
||||
} |
|
||||
|
|
||||
template "namespace" |
|
||||
|| |
|
||||
#include <assert.h> |
|
||||
#include <pEp/pEpEngine.h> |
|
||||
#include "throw_pEp_exception.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace JNIAdapter { |
|
||||
jint throw_pEp_Exception(JNIEnv *env, PEP_STATUS status) |
|
||||
{ |
|
||||
jclass ex; |
|
||||
const char *ex_name; |
|
||||
|
|
||||
switch (status) { |
|
||||
`` apply "exception/*[text()!=0]", 4, mode=case |
|
||||
default: |
|
||||
assert(0); |
|
||||
ex_name = "Exception"; |
|
||||
} |
|
||||
|
|
||||
ex = env->FindClass(ex_name); |
|
||||
assert(ex); |
|
||||
|
|
||||
if (ex == NULL) { |
|
||||
ex = env->FindClass("java/lang/NoClassDefFoundError"); |
|
||||
assert(ex); |
|
||||
} |
|
||||
|
|
||||
return env->ThrowNew(ex, ex_name); |
|
||||
} |
|
||||
}; |
|
||||
}; |
|
||||
|| |
|
||||
|
|
||||
template "*", mode=case { |
|
||||
| case `call "UCASE" with "text", "name(.)"`: |
|
||||
| ex_name = "foundation/pEp/jniadapter/`call "CamelCase" with "text", "name(.)"`"; |
|
||||
| break; |
|
||||
} |
|
||||
} |
|
||||
|
|
@ -0,0 +1,12 @@ |
|||||
|
package foundation.pEp.jniadapter; |
||||
|
import java.util.concurrent.atomic.AtomicLong; |
||||
|
|
||||
|
// Abstract here so you can only inherit from, but not instantiate
|
||||
|
abstract public class UniquelyIdentifiable { |
||||
|
private static final AtomicLong NEXT_ID = new AtomicLong(1); |
||||
|
private final long id = NEXT_ID.getAndIncrement(); |
||||
|
|
||||
|
protected long getId() { |
||||
|
return id; |
||||
|
} |
||||
|
} |
@ -0,0 +1,115 @@ |
|||||
|
package foundation.pEp.jniadapter; |
||||
|
|
||||
|
import java.io.UnsupportedEncodingException; |
||||
|
import java.text.Normalizer; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Vector; |
||||
|
|
||||
|
public class Utils { |
||||
|
private Utils() { } |
||||
|
|
||||
|
public static byte[] toUTF8(String str) { |
||||
|
if (str == null) |
||||
|
return null; |
||||
|
|
||||
|
try { |
||||
|
String _str = Normalizer.normalize(str, Normalizer.Form.NFC); |
||||
|
byte _buf[] = _str.getBytes("UTF-8"); |
||||
|
byte _cpy[] = new byte[_buf.length]; |
||||
|
System.arraycopy(_buf,0,_cpy,0,_buf.length); |
||||
|
return _cpy; |
||||
|
} |
||||
|
catch (UnsupportedEncodingException e) { |
||||
|
assert false; |
||||
|
return new byte[0]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static Vector<byte[]> toUTF8(Vector<String> list) { |
||||
|
if (list == null) |
||||
|
return null; |
||||
|
|
||||
|
Vector<byte[]> result = new Vector<byte[]>(list.size()); |
||||
|
|
||||
|
for (int i=0; i<list.size(); i++) |
||||
|
result.add(toUTF8(list.get(i))); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static Pair<byte[], byte[]> toUTF8(Pair<String, String> pair) { |
||||
|
if (pair == null) |
||||
|
return null; |
||||
|
|
||||
|
Pair<byte[], byte[]> result = new Pair<byte[], byte[]>(); |
||||
|
|
||||
|
result.first = toUTF8(pair.first); |
||||
|
result.second = toUTF8(pair.second); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static ArrayList<Pair<byte[], byte[]>> toUTF8(ArrayList<Pair<String, String>> list) { |
||||
|
if (list == null) |
||||
|
return null; |
||||
|
|
||||
|
ArrayList<Pair<byte[], byte[]>> result = new ArrayList<Pair<byte[], byte[]>>(list.size()); |
||||
|
|
||||
|
for (int i=0; i<list.size(); i++) |
||||
|
result.set(i, toUTF8(list.get(i))); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static String toUTF16(byte[] utf8) { |
||||
|
if (utf8 == null) |
||||
|
return null; |
||||
|
|
||||
|
try { |
||||
|
byte newUtf8[] = new byte[utf8.length]; |
||||
|
System.arraycopy(utf8,0,newUtf8,0,utf8.length); |
||||
|
|
||||
|
return new String(newUtf8, "UTF-8"); |
||||
|
} |
||||
|
catch (UnsupportedEncodingException e) { |
||||
|
assert false; |
||||
|
return new String(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static Vector<String> toUTF16(Vector<byte[]> list) { |
||||
|
if (list == null) |
||||
|
return null; |
||||
|
|
||||
|
Vector<String> result = new Vector<String>(list.size()); |
||||
|
|
||||
|
for (int i=0; i<list.size(); i++) |
||||
|
result.add(toUTF16(list.get(i))); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static Pair<String, String> toUTF16(Pair<byte[], byte[]> pair) { |
||||
|
if (pair == null) |
||||
|
return null; |
||||
|
|
||||
|
Pair<String, String> result = new Pair<String,String>(); |
||||
|
|
||||
|
result.first = toUTF16(pair.first); |
||||
|
result.second = toUTF16(pair.second); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static ArrayList<Pair<String, String>> toUTF16(ArrayList<Pair<byte[], byte[]>> list) { |
||||
|
if (list == null) |
||||
|
return null; |
||||
|
|
||||
|
ArrayList<Pair<String, String>> result = new ArrayList<Pair<String, String>>(list.size()); |
||||
|
|
||||
|
for (int i=0; i<list.size(); i++) |
||||
|
result.set(i, toUTF16(list.get(i))); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
package foundation.pEp.jniadapter; |
||||
|
|
||||
|
public class decrypt_message_Return { |
||||
|
public Message dst; |
||||
|
public Rating rating; |
||||
|
public int flags; |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package foundation.pEp.jniadapter.interfaces; |
||||
|
|
||||
|
import foundation.pEp.jniadapter.Message; |
||||
|
import foundation.pEp.jniadapter.Sync; |
||||
|
|
||||
|
public interface AbstractEngineInterface extends AutoCloseable { |
||||
|
public String getVersion(); |
||||
|
|
||||
|
public String getProtocolVersion(); |
||||
|
|
||||
|
public void startKeyserverLookup(); |
||||
|
|
||||
|
public void stopKeyserverLookup(); |
||||
|
|
||||
|
public void startSync(); |
||||
|
|
||||
|
public void stopSync(); |
||||
|
|
||||
|
public boolean isSyncRunning(); |
||||
|
|
||||
|
public void setMessageToSendCallback(Sync.MessageToSendCallback messageToSendCallback); |
||||
|
|
||||
|
public void setNotifyHandshakeCallback(Sync.NotifyHandshakeCallback notifyHandshakeCallback); |
||||
|
|
||||
|
public void setNeedsFastPollCallback(Sync.NeedsFastPollCallback needsFastPollCallback); |
||||
|
|
||||
|
public void setPassphraseRequiredCallback(Sync.PassphraseRequiredCallback passphraseRequiredCallback); |
||||
|
|
||||
|
public Message incomingMessageFromPGPText(String pgpText, Message.EncFormat encFormat); |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package foundation.pEp.jniadapter.interfaces; |
||||
|
|
||||
|
public interface BlobInterface { |
||||
|
|
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
package foundation.pEp.jniadapter.interfaces; |
||||
|
|
||||
|
import foundation.pEp.jniadapter.Rating; |
||||
|
|
||||
|
public interface IdentityInterface { |
||||
|
public Rating getRating(); |
||||
|
} |
@ -1,772 +0,0 @@ |
|||||
#include <cassert> |
|
||||
#include "jniutils.hh" |
|
||||
#include <pEp/pEpLog.hh> |
|
||||
#ifndef __LP64__ |
|
||||
#include <time64.h> |
|
||||
#define time_t time64_t |
|
||||
#define timegm timegm64 |
|
||||
#define gmtime_r gmtime64_r |
|
||||
#else |
|
||||
#include <string.h> |
|
||||
#endif |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace JNIAdapter { |
|
||||
std::mutex global_mutex; |
|
||||
std::unordered_map<long, std::mutex*> engine_objid_mutex; |
|
||||
|
|
||||
std::mutex* get_engine_java_object_mutex( |
|
||||
JNIEnv *env, |
|
||||
jobject obj |
|
||||
) |
|
||||
{ |
|
||||
long engine_obj_id = (long)callLongMethod(env, obj, "getId"); |
|
||||
assert(engine_obj_id); |
|
||||
pEpLog("for java object id: " << engine_obj_id); |
|
||||
std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); |
|
||||
pEpLog("found mutex: " << engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle()); |
|
||||
assert(engine_obj_mutex); |
|
||||
return engine_obj_mutex; |
|
||||
} |
|
||||
|
|
||||
void create_engine_java_object_mutex( |
|
||||
JNIEnv *env, |
|
||||
jobject obj |
|
||||
) |
|
||||
{ |
|
||||
long engine_obj_id = (long)callLongMethod(env, obj, "getId"); |
|
||||
assert(engine_obj_id); |
|
||||
std::mutex *engine_obj_mutex = new std::mutex(); |
|
||||
pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); |
|
||||
assert(engine_obj_mutex); |
|
||||
if(engine_objid_mutex.count(engine_obj_id) > 0) { |
|
||||
pEpLog("Fatal: mutex already existing for object id: " << engine_obj_id); |
|
||||
assert(0); |
|
||||
} |
|
||||
engine_objid_mutex.insert(std::make_pair(engine_obj_id, engine_obj_mutex )); |
|
||||
} |
|
||||
|
|
||||
void release_engine_java_object_mutex( |
|
||||
JNIEnv *env, |
|
||||
jobject obj |
|
||||
) |
|
||||
{ |
|
||||
long engine_obj_id = (long)callLongMethod(env, obj, "getId"); |
|
||||
assert(engine_obj_id); |
|
||||
std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); |
|
||||
pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); |
|
||||
assert(engine_obj_mutex); |
|
||||
engine_objid_mutex.erase(engine_obj_id); |
|
||||
delete engine_obj_mutex; |
|
||||
} |
|
||||
|
|
||||
jclass findClass(JNIEnv *env, const char *classname) |
|
||||
{ |
|
||||
jclass clazz = env->FindClass(classname); |
|
||||
if (!clazz) |
|
||||
fprintf(stderr, "class not found: %s\n", classname); |
|
||||
assert(clazz); |
|
||||
|
|
||||
if (clazz == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoClassDefFoundError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, classname); |
|
||||
throw std::bad_cast(); |
|
||||
} |
|
||||
|
|
||||
return clazz; |
|
||||
} |
|
||||
|
|
||||
jfieldID getFieldID( |
|
||||
JNIEnv *env, |
|
||||
const char *classname, |
|
||||
const char *fieldname, |
|
||||
const char *signature |
|
||||
) |
|
||||
{ |
|
||||
jclass clazz = findClass(env, classname); |
|
||||
assert(clazz); |
|
||||
|
|
||||
jfieldID field = env->GetFieldID(clazz, fieldname, signature); |
|
||||
assert(field); |
|
||||
|
|
||||
if (field == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoSuchFieldError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, fieldname); |
|
||||
throw std::invalid_argument(std::string(fieldname)); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
return field; |
|
||||
} |
|
||||
|
|
||||
//TODO: fix/generalize/clean patch added to make keysync work using globalref to class
|
|
||||
jfieldID getFieldID( |
|
||||
JNIEnv *env, |
|
||||
const char *classname, |
|
||||
const char *fieldname, |
|
||||
const char *signature, |
|
||||
const jclass clazz |
|
||||
) |
|
||||
{ |
|
||||
|
|
||||
jfieldID field = env->GetFieldID(clazz, fieldname, signature); |
|
||||
assert(field); |
|
||||
|
|
||||
if (field == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoSuchFieldError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, fieldname); |
|
||||
throw std::invalid_argument(std::string(fieldname)); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
return field; |
|
||||
} |
|
||||
|
|
||||
jint callIntMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname |
|
||||
) |
|
||||
{ |
|
||||
jclass clazz = env->GetObjectClass(obj); |
|
||||
assert(clazz); |
|
||||
|
|
||||
jmethodID method = env->GetMethodID(clazz, methodname, "()I"); |
|
||||
if (method == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, methodname); |
|
||||
throw std::invalid_argument(std::string(methodname)); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
jint result = env->CallIntMethod(obj, method); |
|
||||
env->ExceptionCheck(); // handle exception in Java
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
jlong callLongMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname |
|
||||
) |
|
||||
{ |
|
||||
jclass clazz = env->GetObjectClass(obj); |
|
||||
assert(clazz); |
|
||||
|
|
||||
jmethodID method = env->GetMethodID(clazz, methodname, "()J"); |
|
||||
if (method == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, methodname); |
|
||||
throw std::invalid_argument(std::string(methodname)); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
jlong result = env->CallLongMethod(obj, method); |
|
||||
env->ExceptionCheck(); // handle exception in Java
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
jobject callObjectMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname, |
|
||||
jint index |
|
||||
) |
|
||||
{ |
|
||||
jclass clazz = env->GetObjectClass(obj); |
|
||||
assert(clazz); |
|
||||
|
|
||||
jmethodID method = env->GetMethodID(clazz, methodname, |
|
||||
"(I)Ljava/lang/Object;"); |
|
||||
if (method == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, methodname); |
|
||||
throw std::invalid_argument(std::string(methodname)); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
jobject result = env->CallObjectMethod(obj, method, index); |
|
||||
env->ExceptionCheck(); // handle exception in Java
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
jboolean callBooleanMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname, |
|
||||
jobject o |
|
||||
) |
|
||||
{ |
|
||||
jclass clazz = env->GetObjectClass(obj); |
|
||||
assert(clazz); |
|
||||
|
|
||||
jmethodID method = env->GetMethodID(clazz, methodname, |
|
||||
"(Ljava/lang/Object;)Z"); |
|
||||
if (method == NULL) { |
|
||||
jclass ex = env->FindClass("java/lang/NoSuchMethodError"); |
|
||||
assert(ex); |
|
||||
env->ThrowNew(ex, methodname); |
|
||||
throw std::invalid_argument(std::string(methodname)); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
jboolean result = env->CallBooleanMethod(obj, method, o); |
|
||||
env->ExceptionCheck(); // handle exception in Java
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
jint outOfMemory(JNIEnv *env) |
|
||||
{ |
|
||||
jclass ex; |
|
||||
const char *ex_name = "java/lang/OutOfMemoryError"; |
|
||||
|
|
||||
ex = env->FindClass(ex_name); |
|
||||
assert(ex); |
|
||||
return env->ThrowNew(ex, ex_name); |
|
||||
} |
|
||||
|
|
||||
jobject from_Integer(JNIEnv *env, int val) |
|
||||
{ |
|
||||
assert(env); |
|
||||
jclass clazz = findClass(env, "java/lang/Integer"); |
|
||||
|
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(I)V"); |
|
||||
assert(constructor); |
|
||||
|
|
||||
jobject obj = env->NewObject(clazz, constructor, val); |
|
||||
assert(obj); |
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
int to_Integer(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
assert(env && obj); |
|
||||
int _val = callIntMethod(env, obj, "intValue"); |
|
||||
return _val; |
|
||||
} |
|
||||
|
|
||||
jbyteArray from_string(JNIEnv *env, const char *str) |
|
||||
{ |
|
||||
if (str && str[0]) { |
|
||||
jboolean isCopy; |
|
||||
size_t l = strlen(str); |
|
||||
jbyteArray _str = env->NewByteArray(l); |
|
||||
env->SetByteArrayRegion(_str, 0, l, (jbyte*)str); |
|
||||
return _str; |
|
||||
} |
|
||||
else if (str) { |
|
||||
return env->NewByteArray(0); |
|
||||
} else { |
|
||||
return (jbyteArray) NULL; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
char *to_string(JNIEnv *env, jbyteArray str) |
|
||||
{ |
|
||||
if (str == NULL) |
|
||||
return NULL; |
|
||||
|
|
||||
size_t l = env->GetArrayLength(str); |
|
||||
char *_str = (char *) calloc(1,l+1); |
|
||||
assert(_str); |
|
||||
env->GetByteArrayRegion(str, 0, l, (jbyte*)_str); |
|
||||
return _str; |
|
||||
} |
|
||||
|
|
||||
jobject from_stringlist(JNIEnv *env, stringlist_t *sl) |
|
||||
{ |
|
||||
if (!sl) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
jclass clazz = findClass(env, "java/util/Vector"); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jobject obj = env->NewObject(clazz, constructor); |
|
||||
assert(obj); |
|
||||
|
|
||||
stringlist_t *_sl; |
|
||||
for (_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
|
||||
jobject o = from_string(env, _sl->value); |
|
||||
callBooleanMethod(env, obj, "add", o); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
stringlist_t *to_stringlist(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return NULL; |
|
||||
|
|
||||
jint size = callIntMethod(env, obj, "size"); |
|
||||
if (size == 0) |
|
||||
return NULL; |
|
||||
|
|
||||
stringlist_t *sl = new_stringlist(NULL); |
|
||||
stringlist_t *_sl; |
|
||||
jint i; |
|
||||
for (_sl = sl, i = 0; i < (int) size; i++) { |
|
||||
jobject o = callObjectMethod(env, obj, "get", i); |
|
||||
jbyteArray a = reinterpret_cast<jbyteArray>(o); |
|
||||
char * str = to_string(env, a); |
|
||||
_sl = stringlist_add(_sl, str); |
|
||||
env->DeleteLocalRef(o); |
|
||||
free(str); |
|
||||
} |
|
||||
|
|
||||
return sl; |
|
||||
} |
|
||||
|
|
||||
jobject from_stringpairlist(JNIEnv *env, stringpair_list_t *sl) |
|
||||
{ |
|
||||
if (!sl) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
jclass clazz = findClass(env, "java/util/ArrayList"); |
|
||||
jclass clazz_pair = findClass(env, "foundation/pEp/jniadapter/Pair"); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jmethodID constructor_pair = env->GetMethodID(clazz_pair, "<init>", |
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)V"); |
|
||||
assert(constructor_pair); |
|
||||
|
|
||||
jobject obj = env->NewObject(clazz, constructor); |
|
||||
assert(obj); |
|
||||
|
|
||||
stringpair_list_t *_sl; |
|
||||
for (_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
|
||||
assert(_sl->value->key); |
|
||||
assert(_sl->value->value); |
|
||||
|
|
||||
jbyteArray first = from_string(env, _sl->value->key); |
|
||||
jbyteArray second = from_string(env, _sl->value->value); |
|
||||
jobject pair = env->NewObject(clazz_pair, constructor_pair, |
|
||||
first, second); |
|
||||
callBooleanMethod(env, obj, "add", pair); |
|
||||
|
|
||||
env->DeleteLocalRef(first); |
|
||||
env->DeleteLocalRef(second); |
|
||||
env->DeleteLocalRef(pair); |
|
||||
|
|
||||
|
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
env->DeleteLocalRef(clazz_pair); |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
stringpair_list_t *to_stringpairlist(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return NULL; |
|
||||
|
|
||||
jint size = callIntMethod(env, obj, "size"); |
|
||||
if (size == 0) |
|
||||
return NULL; |
|
||||
|
|
||||
jfieldID first_id = getFieldID(env, "foundation/pEp/jniadapter/Pair", |
|
||||
"first", "Ljava/lang/Object;"); |
|
||||
jfieldID second_id = getFieldID(env, "foundation/pEp/jniadapter/Pair", |
|
||||
"second", "Ljava/lang/Object;"); |
|
||||
|
|
||||
stringpair_list_t *sl = new_stringpair_list(NULL); |
|
||||
stringpair_list_t *_sl; |
|
||||
jint i; |
|
||||
|
|
||||
for (_sl = sl, i = 0; i < (int) size; i++) { |
|
||||
jobject pair = callObjectMethod(env, obj, "get", i); |
|
||||
jbyteArray first = |
|
||||
reinterpret_cast<jbyteArray>(env->GetObjectField(pair, |
|
||||
first_id)); |
|
||||
jbyteArray second = |
|
||||
reinterpret_cast<jbyteArray>(env->GetObjectField(pair, |
|
||||
second_id)); |
|
||||
|
|
||||
char *first_str = to_string(env, first); |
|
||||
char *second_str = to_string(env, second); |
|
||||
stringpair_t *sp = new_stringpair(first_str, second_str); |
|
||||
env->DeleteLocalRef(pair); |
|
||||
free(first_str); |
|
||||
free(second_str); |
|
||||
|
|
||||
_sl = stringpair_list_add(_sl, sp); |
|
||||
} |
|
||||
|
|
||||
return sl; |
|
||||
} |
|
||||
|
|
||||
jobject from_timestamp(JNIEnv *env, timestamp *ts) |
|
||||
{ |
|
||||
if (!ts) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
//LOGD("/* Seconds (0-60) */ FROM :%d", ts->tm_sec);
|
|
||||
//LOGD("/* Minutes (0-59) */ :%d", ts->tm_min);
|
|
||||
//LOGD("/* Hours (0-23) */ :%d", ts->tm_hour);
|
|
||||
//LOGD("/* Day of the month (1-31) */:%d", ts->tm_mday);
|
|
||||
//LOGD("/* Month (0-11) */ :%d", ts->tm_mon);
|
|
||||
//LOGD("/* Year - 1900 */ :%d", ts->tm_year);
|
|
||||
|
|
||||
time_t t = timegm(ts)*1000; |
|
||||
//LOGD( "TimeGM returns : %lld", t);
|
|
||||
jclass clazz = findClass(env, "java/util/Date"); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(J)V"); |
|
||||
assert(constructor); |
|
||||
|
|
||||
jobject result = env->NewObject(clazz, constructor, (jlong) t); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
return result; |
|
||||
|
|
||||
} |
|
||||
|
|
||||
timestamp *to_timestamp(JNIEnv *env, jobject date) |
|
||||
{ |
|
||||
if (!date) |
|
||||
return NULL; |
|
||||
|
|
||||
jlong t = callLongMethod(env, date, "getTime"); |
|
||||
//LOGD( "Set Time to : %lld", t);
|
|
||||
timestamp *ts = (timestamp*)calloc(1, sizeof(timestamp)); |
|
||||
assert(ts); |
|
||||
if (ts == NULL) |
|
||||
return NULL; |
|
||||
|
|
||||
if (t){ |
|
||||
time_t clock = t/1000; |
|
||||
gmtime_r(&clock, ts); |
|
||||
|
|
||||
//LOGD("/* Seconds (0-60) */ TO :%d", ts->tm_sec);
|
|
||||
//LOGD("/* Minutes (0-59) */ :%d", ts->tm_min);
|
|
||||
//LOGD("/* Hours (0-23) */ :%d", ts->tm_hour);
|
|
||||
//LOGD("/* Day of the month (1-31) */:%d", ts->tm_mday);
|
|
||||
//LOGD("/* Month (0-11) */ :%d", ts->tm_mon);
|
|
||||
//LOGD("/* Year - 1900 */ :%d", ts->tm_year);
|
|
||||
} |
|
||||
|
|
||||
return ts; |
|
||||
} |
|
||||
|
|
||||
static void _setStringField(JNIEnv *env, const char *classname, |
|
||||
jobject obj, const char *name, const char *value) |
|
||||
{ |
|
||||
if (value) { |
|
||||
jfieldID fieldID = getFieldID(env, classname, name, "[B"); |
|
||||
env->SetObjectField(obj, fieldID, |
|
||||
reinterpret_cast<jobject>(from_string(env, value))); |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//TODO: fix/generalize/clean patch added to make keysync work using globalref to class
|
|
||||
static void _setStringField(JNIEnv *env, const char *classname, |
|
||||
jobject obj, const char *name, const char *value, const jclass clazz) |
|
||||
{ |
|
||||
if (value) { |
|
||||
jfieldID fieldID = getFieldID(env, classname, name, "[B", clazz); |
|
||||
env->SetObjectField(obj, fieldID, |
|
||||
reinterpret_cast<jobject>(from_string(env, value))); |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
jobject from_identity(JNIEnv *env, pEp_identity *ident) |
|
||||
{ |
|
||||
if (!ident) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
static const char *classname = "foundation/pEp/jniadapter/_Identity"; |
|
||||
jclass clazz = findClass(env, classname); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jobject obj = env->NewObject(clazz, constructor); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
if (ident) { |
|
||||
_setStringField(env, classname, obj, "address", ident->address); |
|
||||
_setStringField(env, classname, obj, "fpr", ident->fpr); |
|
||||
_setStringField(env, classname, obj, "user_id", ident->user_id); |
|
||||
_setStringField(env, classname, obj, "username", ident->username); |
|
||||
|
|
||||
jfieldID comm_type_id = getFieldID(env, classname, "comm_type", "I"); |
|
||||
env->SetIntField(obj, comm_type_id, (jint) (int) ident->comm_type); |
|
||||
|
|
||||
_setStringField(env, classname, obj, "lang", ident->lang); |
|
||||
|
|
||||
jfieldID me_id = getFieldID(env, classname, "me", "Z"); |
|
||||
env->SetBooleanField(obj, me_id, (jboolean) ident->me); |
|
||||
|
|
||||
jfieldID flags_id = getFieldID(env, classname, "flags", "I"); |
|
||||
env->SetIntField(obj, flags_id, (jint) (int) ident->flags); |
|
||||
} |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
//TODO: fix/generalize/clean patch added to make keysync work using globalref to class
|
|
||||
jobject from_identity(JNIEnv *env, pEp_identity *ident, jclass identityClass) |
|
||||
{ |
|
||||
if (!ident) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
static const char *classname = "foundation/pEp/jniadapter/_Identity"; |
|
||||
jmethodID constructor = env->GetMethodID(identityClass, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jobject obj = env->NewObject(identityClass, constructor); |
|
||||
|
|
||||
if (ident) { |
|
||||
_setStringField(env, classname, obj, "address", ident->address, identityClass); |
|
||||
_setStringField(env, classname, obj, "fpr", ident->fpr, identityClass); |
|
||||
_setStringField(env, classname, obj, "user_id", ident->user_id, identityClass); |
|
||||
_setStringField(env, classname, obj, "username", ident->username, identityClass); |
|
||||
|
|
||||
jfieldID comm_type_id = getFieldID(env, classname, "comm_type", "I", identityClass); |
|
||||
env->SetIntField(obj, comm_type_id, (jint) (int) ident->comm_type); |
|
||||
|
|
||||
_setStringField(env, classname, obj, "lang", ident->lang, identityClass); |
|
||||
|
|
||||
jfieldID me_id = getFieldID(env, classname, "me", "Z", identityClass); |
|
||||
env->SetBooleanField(obj, me_id, (jboolean) ident->me); |
|
||||
|
|
||||
jfieldID flags_id = getFieldID(env, classname, "flags", "I", identityClass); |
|
||||
env->SetIntField(obj, flags_id, (jint) (int) ident->flags); |
|
||||
} |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
char *_getStringField(JNIEnv *env, const char *classname, jobject obj, |
|
||||
const char *name) |
|
||||
{ |
|
||||
jfieldID fieldID = getFieldID(env, classname, name, "[B"); |
|
||||
jobject fobj = env->GetObjectField(obj, fieldID); |
|
||||
|
|
||||
char *res = to_string(env, reinterpret_cast<jbyteArray>(fobj)); |
|
||||
|
|
||||
env->DeleteLocalRef(fobj); |
|
||||
return res; |
|
||||
} |
|
||||
|
|
||||
pEp_identity *to_identity(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return NULL; |
|
||||
|
|
||||
static const char *classname = "foundation/pEp/jniadapter/_Identity"; |
|
||||
pEp_identity *ident = new_identity(NULL, NULL, NULL, NULL); |
|
||||
|
|
||||
ident->address = _getStringField(env, classname, obj, "address"); |
|
||||
ident->fpr = _getStringField(env, classname, obj, "fpr"); |
|
||||
ident->user_id = _getStringField(env, classname, obj, "user_id"); |
|
||||
ident->username = _getStringField(env, classname, obj, "username"); |
|
||||
|
|
||||
jfieldID comm_type_id = getFieldID(env, classname, "comm_type", "I"); |
|
||||
ident->comm_type = (PEP_comm_type) (int) env->GetIntField(obj, comm_type_id); |
|
||||
|
|
||||
char *lang = _getStringField(env, classname, obj, "lang"); |
|
||||
if (lang && lang[0]) { |
|
||||
ident->lang[0] = lang[0]; |
|
||||
ident->lang[1] = lang[1]; |
|
||||
} |
|
||||
free(lang); |
|
||||
|
|
||||
jfieldID me_id = getFieldID(env, classname, "me", "Z"); |
|
||||
ident->me = (bool) env->GetBooleanField(obj, me_id); |
|
||||
|
|
||||
jfieldID flags_id = getFieldID(env, classname, "flags", "I"); |
|
||||
ident->flags = (identity_flags_t) (int) env->GetIntField(obj, flags_id); |
|
||||
|
|
||||
return ident; |
|
||||
} |
|
||||
|
|
||||
jobject from_identitylist(JNIEnv *env, identity_list *il) |
|
||||
{ |
|
||||
if (!il) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
jclass clazz = findClass(env, "java/util/Vector"); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jobject obj = env->NewObject(clazz, constructor); |
|
||||
assert(obj); |
|
||||
|
|
||||
identity_list *_il; |
|
||||
for (_il = il; _il && _il->ident; _il = _il->next) { |
|
||||
jobject o = from_identity(env, _il->ident); |
|
||||
callBooleanMethod(env, obj, "add", o); |
|
||||
} |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
identity_list *to_identitylist(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return NULL; |
|
||||
|
|
||||
jint size = callIntMethod(env, obj, "size"); |
|
||||
if (size == 0) |
|
||||
return NULL; |
|
||||
|
|
||||
identity_list *il = new_identity_list(NULL); |
|
||||
identity_list *_il; |
|
||||
jint i; |
|
||||
for (_il = il, i = 0; i < (int) size; i++) { |
|
||||
jobject o = callObjectMethod(env, obj, "get", i); |
|
||||
pEp_identity* ident = to_identity(env, o); |
|
||||
_il = identity_list_add(_il, ident); |
|
||||
env->DeleteLocalRef(o); |
|
||||
} |
|
||||
|
|
||||
return il; |
|
||||
} |
|
||||
|
|
||||
jobject _from_blob(JNIEnv *env, bloblist_t *b) |
|
||||
{ |
|
||||
if (!b) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
static const char *classname = "foundation/pEp/jniadapter/_Blob"; |
|
||||
jclass clazz = findClass(env, classname); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jobject obj = env->NewObject(clazz, constructor); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
jfieldID fieldID = getFieldID(env, classname, "data", "[B"); |
|
||||
jbyteArray _data = env->NewByteArray((jsize) b->size); |
|
||||
env->SetByteArrayRegion(_data, 0, b->size, (jbyte*)b->value); |
|
||||
env->SetObjectField(obj, fieldID, reinterpret_cast<jobject>(_data)); |
|
||||
_setStringField(env, classname, obj, "mime_type", b->mime_type); |
|
||||
_setStringField(env, classname, obj, "filename", b->filename); |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
jobject from_bloblist(JNIEnv *env, bloblist_t *bl) |
|
||||
{ |
|
||||
if (!bl) |
|
||||
return (jobject) NULL; |
|
||||
|
|
||||
jclass clazz = findClass(env, "java/util/Vector"); |
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); |
|
||||
assert(constructor); |
|
||||
jobject obj = env->NewObject(clazz, constructor); |
|
||||
assert(obj); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz); |
|
||||
|
|
||||
bloblist_t *_bl; |
|
||||
for (_bl = bl; _bl && _bl->value; _bl = _bl->next) { |
|
||||
jobject o = _from_blob(env, _bl); |
|
||||
if(o) |
|
||||
callBooleanMethod(env, obj, "add", o); |
|
||||
} |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
bloblist_t *to_blob(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return NULL; |
|
||||
|
|
||||
static const char *classname = "foundation/pEp/jniadapter/_Blob"; |
|
||||
jclass clazz = findClass(env, classname); |
|
||||
|
|
||||
char *mime_type = _getStringField(env, classname, obj, "mime_type"); |
|
||||
char *filename = _getStringField(env, classname, obj, "filename"); |
|
||||
|
|
||||
jfieldID data_id = getFieldID(env, classname, "data", "[B"); |
|
||||
jbyteArray _data = reinterpret_cast<jbyteArray>(env->GetObjectField(obj, data_id)); |
|
||||
size_t size = (size_t) env->GetArrayLength(_data); |
|
||||
char *b = (char *) malloc(size); |
|
||||
assert(b); |
|
||||
|
|
||||
env->GetByteArrayRegion(_data, 0, size, (jbyte*)b); |
|
||||
bloblist_t *bl = new_bloblist( b, size, mime_type, filename); |
|
||||
|
|
||||
free(mime_type); |
|
||||
free(filename); |
|
||||
return bl; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
bloblist_t *to_bloblist(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return NULL; |
|
||||
|
|
||||
jint size = callIntMethod(env, obj, "size"); |
|
||||
if (size == 0) |
|
||||
return NULL; |
|
||||
|
|
||||
bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL); |
|
||||
bloblist_t *_bl; |
|
||||
_bl = bl; |
|
||||
jint i; |
|
||||
for (i = 0; i < (int) size; i++) { |
|
||||
jobject o = callObjectMethod(env, obj, "get", i); |
|
||||
bloblist_t *b = to_blob(env, o); |
|
||||
_bl = bloblist_add(_bl, b->value, b->size, b->mime_type, b->filename); |
|
||||
env->DeleteLocalRef(o); |
|
||||
} |
|
||||
|
|
||||
return bl; |
|
||||
} |
|
||||
|
|
||||
PEP_enc_format to_EncFormat(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
static const char *classname = "foundation/pEp/jniadapter/Message$EncFormat"; |
|
||||
jclass clazz_enc_format = findClass(env, classname); |
|
||||
jfieldID field_value = env->GetFieldID(clazz_enc_format, "value", "I"); |
|
||||
assert(field_value); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz_enc_format); |
|
||||
return (PEP_enc_format) env->GetIntField(obj, field_value); |
|
||||
} |
|
||||
|
|
||||
PEP_CIPHER_SUITE to_CipherSuite(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
static const char *classname = "foundation/pEp/jniadapter/CipherSuite"; |
|
||||
jclass clazz_enc_format = findClass(env, classname); |
|
||||
jfieldID field_value = env->GetFieldID(clazz_enc_format, "value", "I"); |
|
||||
assert(field_value); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz_enc_format); |
|
||||
return (PEP_CIPHER_SUITE) env->GetIntField(obj, field_value); |
|
||||
} |
|
||||
|
|
||||
sync_handshake_result to_SyncHandshakeResult(JNIEnv *env, jobject obj) |
|
||||
{ |
|
||||
static const char *classname = "foundation/pEp/jniadapter/SyncHandshakeResult"; |
|
||||
jclass clazz_enc_format = findClass(env, classname); |
|
||||
jfieldID field_value = env->GetFieldID(clazz_enc_format, "value", "I"); |
|
||||
assert(field_value); |
|
||||
|
|
||||
env->DeleteLocalRef(clazz_enc_format); |
|
||||
return (sync_handshake_result) env->GetIntField(obj, field_value); |
|
||||
} |
|
||||
}; |
|
||||
}; |
|
||||
|
|
@ -1,130 +0,0 @@ |
|||||
#pragma once |
|
||||
#include <unordered_map> |
|
||||
#include <thread> |
|
||||
#include <mutex> |
|
||||
#include <jni.h> |
|
||||
#include <pEp/stringpair.h> |
|
||||
#include <pEp/identity_list.h> |
|
||||
#include <pEp/bloblist.h> |
|
||||
#include <pEp/message.h> |
|
||||
#include <pEp/sync_api.h> |
|
||||
#include <pEp/passphrase_cache.hh> |
|
||||
|
|
||||
#if 0 // Enable if log needed
|
|
||||
#include <android/log.h> |
|
||||
#define LOG_TAG "pEpJNIAdapter" |
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) |
|
||||
#else |
|
||||
#define LOGD(...) do{}while(0) |
|
||||
#endif |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace JNIAdapter { |
|
||||
// Global mutex needs to be locked in all constructors which insert their own mutex object
|
|
||||
// into the unordered_map (which is thread safe for read, but not for write)
|
|
||||
extern std::mutex global_mutex; |
|
||||
|
|
||||
// Stores mutex per java object
|
|
||||
extern std::unordered_map<long, std::mutex*> engine_objid_mutex; |
|
||||
|
|
||||
// needs to be called after create_engine_java_object_mutex()
|
|
||||
// and before release_engine_java_object_mutex()
|
|
||||
// Thread safe
|
|
||||
std::mutex* get_engine_java_object_mutex( |
|
||||
JNIEnv *env, |
|
||||
jobject me |
|
||||
); |
|
||||
|
|
||||
// Needs to be called exactly once per obj, in the constructor of the obj
|
|
||||
// You need to lock a global mutex before calling this function (write to unordered_map)
|
|
||||
void create_engine_java_object_mutex( |
|
||||
JNIEnv *env, |
|
||||
jobject me |
|
||||
); |
|
||||
|
|
||||
// Needs to be called exactly once per obj, in the destructor of this obj
|
|
||||
// You need to lock a global mutex before calling this function (write to unordered_map)
|
|
||||
void release_engine_java_object_mutex( |
|
||||
JNIEnv *env, |
|
||||
jobject me |
|
||||
); |
|
||||
|
|
||||
|
|
||||
jclass findClass(JNIEnv *env, const char *classname); |
|
||||
|
|
||||
jfieldID getFieldID( |
|
||||
JNIEnv *env, |
|
||||
const char *classname, |
|
||||
const char *fieldname, |
|
||||
const char *signature |
|
||||
); |
|
||||
|
|
||||
jfieldID getFieldID( |
|
||||
JNIEnv *env, |
|
||||
const char *classname, |
|
||||
const char *fieldname, |
|
||||
const char *signature, |
|
||||
const jclass clazz |
|
||||
); |
|
||||
|
|
||||
jint callIntMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname |
|
||||
); |
|
||||
|
|
||||
jlong callLongMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname |
|
||||
); |
|
||||
|
|
||||
jobject callObjectMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname, |
|
||||
jint index |
|
||||
); |
|
||||
|
|
||||
jboolean callBooleanMethod( |
|
||||
JNIEnv *env, |
|
||||
jobject obj, |
|
||||
const char *methodname, |
|
||||
jobject o |
|
||||
); |
|
||||
|
|
||||
jint outOfMemory(JNIEnv *env); |
|
||||
|
|
||||
jobject from_Integer(JNIEnv *env, int val); |
|
||||
int to_Integer(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
jbyteArray from_string(JNIEnv *env, const char *str); |
|
||||
char *to_string(JNIEnv *env, jbyteArray str); |
|
||||
|
|
||||
jobject from_stringlist(JNIEnv *env, stringlist_t *sl); |
|
||||
stringlist_t *to_stringlist(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
jobject from_stringpairlist(JNIEnv *env, stringpair_list_t *sl); |
|
||||
stringpair_list_t *to_stringpairlist(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
jobject from_timestamp(JNIEnv *env, timestamp *ts); |
|
||||
timestamp *to_timestamp(JNIEnv *env, jobject date); |
|
||||
|
|
||||
jobject from_identity(JNIEnv *env, pEp_identity *ident); |
|
||||
jobject from_identity(JNIEnv *env, pEp_identity *ident, jclass identityClass); |
|
||||
pEp_identity *to_identity(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
jobject from_identitylist(JNIEnv *env, identity_list *il); |
|
||||
identity_list *to_identitylist(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
jobject from_bloblist(JNIEnv *env, bloblist_t *bl); |
|
||||
bloblist_t *to_blob(JNIEnv *env, jobject obj); |
|
||||
bloblist_t *to_bloblist(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
PEP_enc_format to_EncFormat(JNIEnv *env, jobject obj); |
|
||||
PEP_CIPHER_SUITE to_CipherSuite(JNIEnv *env, jobject obj); |
|
||||
|
|
||||
sync_handshake_result to_SyncHandshakeResult(JNIEnv *env, jobject obj); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
@ -1,14 +0,0 @@ |
|||||
#pragma once |
|
||||
#include <pEp/passphrase_cache.hh> |
|
||||
|
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace JNIAdapter { |
|
||||
|
|
||||
char* passphraseRequiredCallback(const PEP_STATUS status); |
|
||||
|
|
||||
template<typename... A> PEP_STATUS passphraseWrap(PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
#include "passphrase_callback.hxx" |
|
@ -1,42 +0,0 @@ |
|||||
#pragma once |
|
||||
|
|
||||
#include "passphrase_callback.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace JNIAdapter { |
|
||||
|
|
||||
template<typename... A> PEP_STATUS passphraseWrap(PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a) { |
|
||||
pEpLog("cached passphrase mode"); |
|
||||
bool retryAgain = false; |
|
||||
int maxRetries = 3; |
|
||||
int retryCount = 0; |
|
||||
PEP_STATUS status; |
|
||||
do { |
|
||||
// the actual target function
|
|
||||
pEpLog("calling passphrase_cache.api from basic_api"); |
|
||||
status = passphrase_cache.api(f, session, a...); |
|
||||
pEpLog("PEP_STATUS:" << status); |
|
||||
if (status == PEP_PASSPHRASE_REQUIRED || |
|
||||
status == PEP_WRONG_PASSPHRASE || |
|
||||
status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED) |
|
||||
{ |
|
||||
pEpLog("none of the cached passphrases worked"); |
|
||||
if (retryCount < maxRetries) { |
|
||||
// call the app
|
|
||||
char *_passphrase = passphraseRequiredCallback(status); |
|
||||
pEpLog("callback returned, config_passphrase() with new passphrase"); |
|
||||
PEP_STATUS status = ::config_passphrase(session, passphrase_cache.add(_passphrase)); |
|
||||
retryAgain = true; |
|
||||
retryCount++; |
|
||||
} else { |
|
||||
pEpLog("max retries reached:" << maxRetries); |
|
||||
retryAgain = false; |
|
||||
} |
|
||||
} else { |
|
||||
retryAgain = false; |
|
||||
} |
|
||||
} while (retryAgain); |
|
||||
return status; |
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,37 @@ |
|||||
|
include ../../../../../../../Makefile.conf |
||||
|
include ../Makefile.conf |
||||
|
|
||||
|
TEST_UNIT_NAME=jni117 |
||||
|
|
||||
|
JAVA_CLASSES = \
|
||||
|
TestAlice.class \
|
||||
|
../utils/AdapterBaseTestContext.class \
|
||||
|
../utils/AdapterTestUtils.class \
|
||||
|
../utils/TestCallbacks.class |
||||
|
|
||||
|
.PHONY: pitytest compile alice test clean |
||||
|
|
||||
|
all: alice compile |
||||
|
|
||||
|
pitytest: |
||||
|
$(MAKE) -C $(PITYTEST_DIR) |
||||
|
|
||||
|
alice: compile clean-pep-home-alice |
||||
|
cd $(JAVA_CWD);pwd;HOME=$(JAVA_PEP_HOME_DIR_ALICE) $(JAVA) $(JAVA_PKG_BASENAME).$(TEST_UNIT_NAME).TestAlice |
||||
|
|
||||
|
compile: $(JAVA_CLASSES) pitytest |
||||
|
|
||||
|
%.class: %.java |
||||
|
cd $(JAVA_CWD);$(JAVAC_CMD) -cp $(CLASSPATH) $(JAVA_PKG_BASEPATH)/$(TEST_UNIT_NAME)/$< |
||||
|
|
||||
|
clean: |
||||
|
rm -f $(JAVA_CLASSES) |
||||
|
rm -f *.class |
||||
|
rm -f *.log |
||||
|
rm -Rf .gnupg |
||||
|
rm -Rf .lldb |
||||
|
|
||||
|
clean-pep-home: clean-pep-home-alice |
||||
|
|
||||
|
clean-pep-home-alice: |
||||
|
rm -rf $(PEP_HOME_DIR_ALICE)/.pEp |
@ -0,0 +1,34 @@ |
|||||
|
package foundation.pEp.jniadapter.test.jni117; |
||||
|
import foundation.pEp.jniadapter.test.utils.AdapterBaseTestContext; |
||||
|
import foundation.pEp.pitytest.TestSuite; |
||||
|
import foundation.pEp.pitytest.TestUnit; |
||||
|
import foundation.pEp.pitytest.utils.TestUtils; |
||||
|
|
||||
|
import static foundation.pEp.pitytest.TestLogger.log; |
||||
|
|
||||
|
// Test for JNI-117 - Key Export
|
||||
|
|
||||
|
// Tests: For an ad-hoc generated identity "alice" using myself()"
|
||||
|
// - export_key is not throwing
|
||||
|
// - keydata returned is longer than 100 bytes
|
||||
|
// - keydata contains header: "-----BEGIN PGP PBLIC KEY BLOCK-----"
|
||||
|
|
||||
|
class TestAlice { |
||||
|
public static void main(String[] args) throws Exception { |
||||
|
TestSuite.getDefault().setVerbose(true); |
||||
|
TestSuite.getDefault().setTestColor(TestUtils.TermColor.GREEN); |
||||
|
|
||||
|
new TestUnit<AdapterBaseTestContext>("Test Alice",new AdapterBaseTestContext() , ctx -> { |
||||
|
ctx.alice = ctx.engine.myself(ctx.alice); |
||||
|
byte[] keydata = ctx.engine.export_key(ctx.alice.fpr); |
||||
|
String keydataStr = new String(keydata); |
||||
|
log(keydataStr); |
||||
|
assert keydata.length > 100: "returned keydata is too short"; |
||||
|
assert keydataStr.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----") : "Keydata doesnt contain: -----BEGIN PGP PBLIC KEY BLOCK-----"; |
||||
|
}); |
||||
|
|
||||
|
TestSuite.getDefault().run(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
include ../../../../../../../Makefile.conf |
||||
|
include ../Makefile.conf |
||||
|
|
||||
|
TEST_UNIT_NAME=jni118 |
||||
|
|
||||
|
JAVA_CLASSES = \
|
||||
|
TestAlice.class \
|
||||
|
../utils/AdapterBaseTestContext.class \
|
||||
|
../utils/AdapterTestUtils.class \
|
||||
|
../utils/TestCallbacks.class |
||||
|
|
||||
|
.PHONY: pitytest compile alice test clean |
||||
|
|
||||
|
all: alice compile |
||||
|
|
||||
|
pitytest: |
||||
|
$(MAKE) -C $(PITYTEST_DIR) |
||||
|
|
||||
|
alice: compile clean-pep-home-alice |
||||
|
cd $(JAVA_CWD);pwd;HOME=$(JAVA_PEP_HOME_DIR_ALICE) $(JAVA) $(JAVA_PKG_BASENAME).$(TEST_UNIT_NAME).TestAlice |
||||
|
|
||||
|
compile: $(JAVA_CLASSES) pitytest |
||||
|
|
||||
|
%.class: %.java |
||||
|
cd $(JAVA_CWD);$(JAVAC_CMD) -cp $(CLASSPATH) $(JAVA_PKG_BASEPATH)/$(TEST_UNIT_NAME)/$< |
||||
|
|
||||
|
clean: |
||||
|
rm -f $(JAVA_CLASSES) |
||||
|
rm -f *.class |
||||
|
rm -f *.log |
||||
|
rm -Rf .gnupg |
||||
|
rm -Rf .lldb |
||||
|
|
||||
|
clean-pep-home: clean-pep-home-alice |
||||
|
|
||||
|
clean-pep-home-alice: |
||||
|
rm -rf $(PEP_HOME_DIR_ALICE)/.pEp |
@ -0,0 +1,107 @@ |
|||||
|
package foundation.pEp.jniadapter.test.jni118; |
||||
|
|
||||
|
import static foundation.pEp.pitytest.TestLogger.*; |
||||
|
|
||||
|
import foundation.pEp.jniadapter.*; |
||||
|
import foundation.pEp.pitytest.*; |
||||
|
import foundation.pEp.pitytest.utils.TestUtils; |
||||
|
import foundation.pEp.jniadapter.test.utils.*; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Vector; |
||||
|
|
||||
|
// re_evaluate_message_rating(Message m)
|
||||
|
// needs a msg that holds the OptFields:
|
||||
|
// * X-EncStatus - containing the pEpEngine internal string value of the rating
|
||||
|
// * X-KeyList - containing the FPR's of all the receivers of the msg
|
||||
|
//
|
||||
|
// Handling of PEP_Rating
|
||||
|
// When app needs to add optional fields like X-EncStatus, the value has to be the string rep for a rating.
|
||||
|
// These internal string representations can be obtained with the method:
|
||||
|
// * Rating.getInternalStringValue() - returning the pEpEngine internal string value
|
||||
|
// For human readable description of all the enums, use:
|
||||
|
// * Rating.toString()
|
||||
|
//
|
||||
|
// A convenience method Message.addRatingToOptFields(Rating r) would be desirable
|
||||
|
//
|
||||
|
// X-KeyList
|
||||
|
// New method to generate X-Keylist formatted FPR list:
|
||||
|
// * String Identity.toXKeyList(List<Identity> ids)
|
||||
|
//
|
||||
|
// A convenience method for adding X-KeyList for a message would be desirable
|
||||
|
// * method Message.addIdentitiesToOptFields()
|
||||
|
|
||||
|
// Test objectives
|
||||
|
// re_evaluate_message_rating() equal to decrypt_message_result.rating when Message has correct OptFields
|
||||
|
// re_evaluate_message_rating() equal to decrypt_message_result.rating when Message has random rating string on XEncStatus
|
||||
|
|
||||
|
|
||||
|
|
||||
|
class JNI1118Context extends AdapterBaseTestContext { |
||||
|
public Message msgToBobEncrypted; |
||||
|
public Message msgToBobDecrypted; |
||||
|
public decrypt_message_Return msgToBobDecryptResult; |
||||
|
|
||||
|
@Override |
||||
|
public JNI1118Context init() throws Throwable { |
||||
|
super.init(); |
||||
|
alice = engine.myself(alice); |
||||
|
engine.importKey(keyBobPub); |
||||
|
|
||||
|
Vector<Identity> msgToBobRcpts = new Vector<>(); |
||||
|
msgToBobRcpts.add(bob); |
||||
|
msgToBob.setTo(msgToBobRcpts); |
||||
|
|
||||
|
msgToBobEncrypted = engine.encrypt_message(msgToBob, null, Message.EncFormat.PEP); |
||||
|
msgToBobDecrypted = msgToBobEncrypted; |
||||
|
msgToBobDecryptResult = engine.decrypt_message(msgToBobDecrypted, new Vector<String>(), 0); |
||||
|
if (msgToBobEncrypted == null) { |
||||
|
throw new RuntimeException("Context failure, error decrypting message"); |
||||
|
} |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public void addRatingToOptFields(Message msg, String ratingStr) { |
||||
|
ArrayList<Pair<String, String>> opts = msg.getOptFields(); |
||||
|
opts.add(new Pair<String, String>("X-EncStatus",ratingStr)); |
||||
|
msg.setOptFields(opts); |
||||
|
} |
||||
|
|
||||
|
public void addRcptsToOptFields(Message msg, String fprs) { |
||||
|
ArrayList<Pair<String, String>> opts = msg.getOptFields(); |
||||
|
opts.add(new Pair<String, String>("X-KeyList", fprs)); |
||||
|
msg.setOptFields(opts); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
class TestAlice { |
||||
|
public static void main(String[] args) throws Throwable { |
||||
|
TestSuite.getDefault().setVerbose(true); |
||||
|
TestSuite.getDefault().setTestColor(TestUtils.TermColor.GREEN); |
||||
|
|
||||
|
new TestUnit<JNI1118Context>("re_evaluate_message_rating() equal to decrypt_message_result.rating when Message has correct OptFields", new JNI1118Context(), ctx -> { |
||||
|
ctx.addRatingToOptFields(ctx.msgToBobDecrypted,ctx.msgToBobDecryptResult.rating.getInternalStringValue()); |
||||
|
ctx.addRcptsToOptFields(ctx.msgToBobDecrypted,Identity.toXKeyList(ctx.msgToBobDecrypted.getTo())); |
||||
|
log("running re_evaluate_message_rating() on:\n" + AdapterTestUtils.msgToString(ctx.msgToBobDecrypted, false)); |
||||
|
Rating rat = ctx.engine.re_evaluate_message_rating(ctx.msgToBobDecrypted); |
||||
|
log("re_evaluate_message_rating() result: " + rat.toString()); |
||||
|
assert rat == ctx.msgToBobDecryptResult.rating : "Rating is " + rat.toString() + ",but should be " + ctx.msgToBobDecryptResult.rating.toString(); |
||||
|
}); |
||||
|
|
||||
|
new TestUnit<JNI1118Context>("re_evaluate_message_rating() equal to decrypt_message_result.rating when Message has random rating string on XEncStatus", new JNI1118Context(), ctx -> { |
||||
|
ctx.addRatingToOptFields(ctx.msgToBobDecrypted, TestUtils.randomASCIIString(TestUtils.CharClass.Unbounded, TestUtils.randomInt(0,42))); |
||||
|
ctx.addRcptsToOptFields(ctx.msgToBobDecrypted,Identity.toXKeyList(ctx.msgToBobDecrypted.getTo())); |
||||
|
log("running re_evaluate_message_rating() on:\n" + AdapterTestUtils.msgToString(ctx.msgToBobDecrypted, false)); |
||||
|
Rating rat = ctx.engine.re_evaluate_message_rating(ctx.msgToBobDecrypted); |
||||
|
log("re_evaluate_message_rating() result: " + rat.toString()); |
||||
|
assert rat == ctx.msgToBobDecryptResult.rating : "Rating is " + rat.toString() + ",but should be " + ctx.msgToBobDecryptResult.rating.toString(); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
|
||||
|
TestSuite.getDefault().run(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
include ../../../../../../../Makefile.conf |
||||
|
include ../Makefile.conf |
||||
|
|
||||
|
TEST_UNIT_NAME=jni119 |
||||
|
|
||||
|
JAVA_CLASSES = \
|
||||
|
TestAlice.class \
|
||||
|
../utils/AdapterBaseTestContext.class \
|
||||
|
../utils/AdapterTestUtils.class \
|
||||
|
../utils/TestCallbacks.class |
||||
|
|
||||
|
.PHONY: pitytest compile alice test clean |
||||
|
|
||||
|
all: alice compile |
||||
|
|
||||
|
pitytest: |
||||
|
$(MAKE) -C $(PITYTEST_DIR) |
||||
|
|
||||
|
alice: compile clean-pep-home-alice |
||||
|
cd $(JAVA_CWD);pwd;HOME=$(JAVA_PEP_HOME_DIR_ALICE) $(JAVA) $(JAVA_PKG_BASENAME).$(TEST_UNIT_NAME).TestAlice |
||||
|
|
||||
|
compile: $(JAVA_CLASSES) pitytest |
||||
|
|
||||
|
%.class: %.java |
||||
|
cd $(JAVA_CWD);$(JAVAC_CMD) -cp $(CLASSPATH) $(JAVA_PKG_BASEPATH)/$(TEST_UNIT_NAME)/$< |
||||
|
|
||||
|
clean: |
||||
|
rm -f $(JAVA_CLASSES) |
||||
|
rm -f *.class |
||||
|
rm -f *.log |
||||
|
rm -Rf .gnupg |
||||
|
rm -Rf .lldb |
||||
|
|
||||
|
clean-pep-home: clean-pep-home-alice |
||||
|
|
||||
|
clean-pep-home-alice: |
||||
|
rm -rf $(PEP_HOME_DIR_ALICE)/.pEp |
@ -0,0 +1,37 @@ |
|||||
|
package foundation.pEp.jniadapter.test.jni119; |
||||
|
|
||||
|
import foundation.pEp.jniadapter.Identity; |
||||
|
import foundation.pEp.jniadapter.test.utils.AdapterBaseTestContext; |
||||
|
import foundation.pEp.pitytest.TestSuite; |
||||
|
import foundation.pEp.pitytest.TestUnit; |
||||
|
import foundation.pEp.pitytest.utils.TestUtils; |
||||
|
|
||||
|
import java.util.Vector; |
||||
|
|
||||
|
|
||||
|
class TestAlice { |
||||
|
public static void main(String[] args) throws Throwable { |
||||
|
TestSuite.getDefault().setVerbose(true); |
||||
|
TestSuite.getDefault().setTestColor(TestUtils.TermColor.GREEN); |
||||
|
|
||||
|
new TestUnit<AdapterBaseTestContext>("enter_device_group() no exception with no identities", new AdapterBaseTestContext(), ctx -> { |
||||
|
ctx.alice = ctx.engine.myself(ctx.alice); |
||||
|
ctx.engine.enter_device_group(new Vector<Identity>()); |
||||
|
}); |
||||
|
|
||||
|
new TestUnit<AdapterBaseTestContext>("enter_device_group() no exception with 2 identities", new AdapterBaseTestContext(), ctx -> { |
||||
|
ctx.alice = ctx.engine.myself(ctx.alice); |
||||
|
ctx.bob = ctx.engine.myself(ctx.bob); |
||||
|
|
||||
|
Vector<Identity> grpIdents = new Vector<Identity>(); |
||||
|
grpIdents.add(ctx.alice); |
||||
|
grpIdents.add(ctx.bob); |
||||
|
|
||||
|
ctx.engine.enter_device_group(grpIdents); |
||||
|
}); |
||||
|
|
||||
|
TestSuite.getDefault().run(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
@ -1,11 +1,17 @@ |
|||||
package foundation.pEp.pitytest; |
package foundation.pEp.pitytest; |
||||
|
|
||||
public interface TestContextInterface { |
public interface TestContextInterface { |
||||
void init() throws Throwable; |
TestContextInterface init() throws Throwable; |
||||
|
|
||||
boolean isInitialized(); |
boolean isInitialized(); |
||||
|
|
||||
void setInitialized(boolean initialized); |
void setInitialized(boolean initialized); |
||||
|
|
||||
boolean isUninitializable(); |
boolean isUninitializable(); |
||||
|
|
||||
void setUninitializable(boolean uninitializable); |
void setUninitializable(boolean uninitializable); |
||||
|
|
||||
String getTestContextName(); |
String getTestContextName(); |
||||
|
|
||||
void setTestContextName(String name); |
void setTestContextName(String name); |
||||
} |
} |
||||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue