From d6c39f88b66ad613915b7c9475451f9bbe010046 Mon Sep 17 00:00:00 2001 From: "Hoa V. DINH" Date: Wed, 10 Dec 2014 23:43:01 -0800 Subject: Android: Implemented MCMainThread, implemented certificate verification --- build-android/build.sh | 5 +- build-android/jni/Android.mk | 9 +- src/core/basetypes/MCData.cpp | 35 +++++- src/core/basetypes/MCLog.cpp | 12 +- src/core/basetypes/MCMainThreadAndroid.cpp | 136 +++++++++++++++++++++ src/core/basetypes/MCMainThreadAndroid.h | 17 +++ src/core/basetypes/MCOperationQueue.cpp | 8 ++ src/core/basetypes/MCString.cpp | 4 +- .../basetypes/com_libmailcore_MainThreadUtils.h | 37 ++++++ src/core/security/MCCertificateUtils.cpp | 24 ++++ tests/test-all.cpp | 8 +- 11 files changed, 282 insertions(+), 13 deletions(-) create mode 100644 src/core/basetypes/MCMainThreadAndroid.cpp create mode 100644 src/core/basetypes/MCMainThreadAndroid.h create mode 100644 src/core/basetypes/com_libmailcore_MainThreadUtils.h diff --git a/build-android/build.sh b/build-android/build.sh index c2e14c32..bb41aba3 100755 --- a/build-android/build.sh +++ b/build-android/build.sh @@ -5,6 +5,7 @@ ANDROID_PLATFORM=android-21 archs="armeabi armeabi-v7a x86 x86_64" package_name=mailcore2-android ctemplate_build_version=1 +cyrus_sasl_build_version=1 icu4c_build_version=1 libetpan_build_version=1 libxml2_build_version=1 @@ -44,7 +45,8 @@ function build { LIBXML2_PATH=$current_dir/third-party/libxml2-android-1 \ UCHARDET_PATH=$current_dir/third-party/uchardet-android-1 \ TIDY_HTML5_PATH=$current_dir/third-party/tidy-html5-android-1 \ - OPENSSL_PATH=$current_dir/third-party/openssl-android-1 + OPENSSL_PATH=$current_dir/third-party/openssl-android-1 \ + CYRUS_SASL_PATH=$current_dir/third-party/cyrus-sasl-android-1 mkdir -p "$current_dir/$package_name-$build_version/libs/$TARGET_ARCH_ABI" cp "$current_dir/libs/$TARGET_ARCH_ABI/libMailCore.so" "$current_dir/$package_name-$build_version/libs/$TARGET_ARCH_ABI" @@ -70,6 +72,7 @@ download_dep "libxml2-android" $libxml2_build_version download_dep "uchardet-android" $uchardet_build_version download_dep "tidy-html5-android" $tidy_html5_build_version download_dep "openssl-android" $openssl_build_version +download_dep "cyrus-sasl-android" $cyrus_sasl_build_version # Start building. for arch in $archs ; do diff --git a/build-android/jni/Android.mk b/build-android/jni/Android.mk index 7f3b4aa0..d3eddf13 100644 --- a/build-android/jni/Android.mk +++ b/build-android/jni/Android.mk @@ -101,6 +101,11 @@ LOCAL_MODULE := ctemplate LOCAL_SRC_FILES := $(CTEMPLATE_PATH)/libs/$(TARGET_ARCH_ABI)/libctemplate.a include $(PREBUILT_STATIC_LIBRARY) +include $(CLEAR_VARS) +LOCAL_MODULE := sasl2 +LOCAL_SRC_FILES := $(CYRUS_SASL_PATH)/libs/$(TARGET_ARCH_ABI)/libsasl2.a +include $(PREBUILT_STATIC_LIBRARY) + include $(CLEAR_VARS) LOCAL_MODULE := MailCore LOCAL_C_INCLUDES := $(includes) @@ -110,7 +115,7 @@ LOCAL_SRC_FILES := $(core_src_files) $(abstract_src_files) $(imap_src_files) $(n $(async_imap_src_files) $(async_nntp_src_files) $(async_pop_src_files) $(async_smtp_src_files) LOCAL_CPPFLAGS := -frtti LOCAL_CFLAGS := -DNOCRYPT -LOCAL_LDLIBS := -lz \ +LOCAL_LDLIBS := -lz -llog \ -lc++_shared -L$(ANDROID_NDK)/sources/cxx-stl/llvm-libc++/libs/$(TARGET_ARCH_ABI) -LOCAL_STATIC_LIBRARIES := etpan ssl crypto icu4c xml2 uchardet tidy ctemplate +LOCAL_STATIC_LIBRARIES := etpan sasl2 ssl crypto icu4c xml2 uchardet tidy ctemplate include $(BUILD_SHARED_LIBRARY) diff --git a/src/core/basetypes/MCData.cpp b/src/core/basetypes/MCData.cpp index 3a042e46..d1feac48 100644 --- a/src/core/basetypes/MCData.cpp +++ b/src/core/basetypes/MCData.cpp @@ -809,7 +809,7 @@ static int lepIConv(const char * tocode, const char * fromcode, goto err; } - out_size = length * 6; + out_size = * result_len; old_out_size = out_size; p_result = result; @@ -861,6 +861,9 @@ static int lepCFConv(const char * tocode, const char * fromcode, unsigned int len; len = (unsigned int) CFDataGetLength(resultData); + if (len > * result_len) { + len = (unsigned int) * result_len; + } CFDataGetBytes(resultData, CFRangeMake(0, len), (UInt8 *) result); * result_len = len; result[len] = 0; @@ -894,6 +897,34 @@ static int lepMixedConv(const char * tocode, const char * fromcode, } #endif +#if defined(__ANDROID__) || defined(ANDROID) + +static int lepMixedConv(const char * tocode, const char * fromcode, + const char * str, size_t length, + char * result, size_t * result_len) +{ + Data * data = Data::dataWithBytes(str, length); + String * ustr = data->stringWithCharset(fromcode); + if (ustr == NULL) { + return MAIL_CHARCONV_ERROR_CONV; + } + data = ustr->dataUsingEncoding(tocode); + if (data == NULL) { + return MAIL_CHARCONV_ERROR_CONV; + } + size_t len = data->length(); + if (len > * result_len) { + len = * result_len; + } + memcpy(result, data->bytes(), len); + result[len] = 0; + * result_len = len; + + return MAIL_CHARCONV_NO_ERROR; +} + +#endif + static void * createObject() { return new Data(); @@ -902,7 +933,7 @@ static void * createObject() INITIALIZE(Data) { Object::registerObjectConstructor("mailcore::Data", &createObject); -#if __APPLE__ +#if __APPLE__ || defined(__ANDROID__) || defined(ANDROID) extended_charconv = lepMixedConv; #endif } diff --git a/src/core/basetypes/MCLog.cpp b/src/core/basetypes/MCLog.cpp index ceb1b93c..952229ec 100644 --- a/src/core/basetypes/MCLog.cpp +++ b/src/core/basetypes/MCLog.cpp @@ -16,6 +16,10 @@ #include #endif +#if defined(ANDROID) || defined(__ANDROID__) +#include +#endif + static pid_t sPid = -1; int MCLogEnabled = 0; @@ -61,7 +65,11 @@ static void logInternalv(FILE * file, struct timeval tv; struct tm tm_value; pthread_t thread_id = pthread_self(); - + +#if defined(ANDROID) || defined(__ANDROID__) + __android_log_vprint(ANDROID_LOG_INFO, filename, format, argp); +#else + gettimeofday(&tv, NULL); time_t timevalue_sec = tv.tv_sec; localtime_r(&timevalue_sec, &tm_value); @@ -103,5 +111,5 @@ static void logInternalv(FILE * file, #endif // TODO: other platforms implemented needed. } - +#endif } diff --git a/src/core/basetypes/MCMainThreadAndroid.cpp b/src/core/basetypes/MCMainThreadAndroid.cpp new file mode 100644 index 00000000..425558ca --- /dev/null +++ b/src/core/basetypes/MCMainThreadAndroid.cpp @@ -0,0 +1,136 @@ +// +// MCMainThreadAndroid.cpp +// mailcore2 +// +// Created by Hoa Dinh on 11/11/14. +// Copyright (c) 2014 MailCore. All rights reserved. +// + +#include "MCMainThread.h" +#include "MCMainThreadAndroid.h" +#include "com_libmailcore_MainThreadUtils.h" + +#include +#include +#include + +#include "MCDefines.h" +#include "MCAssert.h" +#include "MCLog.h" +#include "MCAutoreleasePool.h" + +#include "test-all.h" + +using namespace mailcore; + +struct main_thread_call_data { + void (* function)(void *); + void * context; + struct mailsem * sem; +}; + +static jobject s_mainThreadUtils = NULL; +static jclass s_mainThreadUtilsClass = NULL; +static JavaVM * s_jvm = NULL; +static jint s_version = 0; + +void mailcore::androidSetupThread(void) +{ + JNIEnv * env = NULL; + s_jvm->AttachCurrentThread(&env, NULL); +} + +void mailcore::androidUnsetupThread() +{ + s_jvm->DetachCurrentThread(); +} + +JNIEXPORT void JNICALL Java_com_libmailcore_MainThreadUtils_setupNative(JNIEnv * env, jobject object) +{ + AutoreleasePool * pool = new AutoreleasePool(); + + env->GetJavaVM(&s_jvm); + s_version = env->GetVersion(); + s_mainThreadUtils = reinterpret_cast(env->NewGlobalRef(object)); + jclass localClass = env->FindClass("com/libmailcore/MainThreadUtils"); + s_mainThreadUtilsClass = reinterpret_cast(env->NewGlobalRef(localClass)); + MCAssert(s_mainThreadUtilsClass != NULL); + + pool->release(); +} + +JNIEXPORT void JNICALL Java_com_libmailcore_MainThreadUtils_runIdentifier(JNIEnv * env, jobject object, jlong identifier) +{ + AutoreleasePool * pool = new AutoreleasePool(); + struct main_thread_call_data * data = (struct main_thread_call_data *) identifier; + data->function(data->context); + free(data); + pool->release(); +} + +JNIEXPORT void JNICALL Java_com_libmailcore_MainThreadUtils_runIdentifierAndNotify(JNIEnv * env, jobject object, jlong identifier) +{ + AutoreleasePool * pool = new AutoreleasePool(); + struct main_thread_call_data * data = (struct main_thread_call_data *) identifier; + data->function(data->context); + mailsem_up(data->sem); + pool->release(); +} + +void mailcore::callOnMainThread(void (* function)(void *), void * context) +{ + struct main_thread_call_data * data = (struct main_thread_call_data *) malloc(sizeof(* data)); + data->function = function; + data->context = context; + data->sem = NULL; + + JNIEnv * env = NULL; + s_jvm->GetEnv((void **)&env, s_version); + jmethodID mid = env->GetMethodID(s_mainThreadUtilsClass, "runOnMainThread", "(J)V"); + MCAssert(mid != NULL); + env->CallVoidMethod(s_mainThreadUtils, mid, (jlong) data); +} + +void mailcore::callOnMainThreadAndWait(void (* function)(void *), void * context) +{ + struct main_thread_call_data * data = (struct main_thread_call_data *) malloc(sizeof(* data)); + data->function = function; + data->context = context; + data->sem = mailsem_new(); + + JNIEnv * env = NULL; + s_jvm->GetEnv((void **)&env, s_version); + jmethodID mid = env->GetMethodID(s_mainThreadUtilsClass, "runOnMainThreadAndWait", "(J)V"); + MCAssert(mid != NULL); + env->CallVoidMethod(s_mainThreadUtils, mid, (jlong) data); + + // Wait. + mailsem_down(data->sem); + + mailsem_free(data->sem); + free(data); +} + +void * mailcore::callAfterDelay(void (* function)(void *), void * context, double time) +{ + struct main_thread_call_data * data = (struct main_thread_call_data *) malloc(sizeof(* data)); + data->function = function; + data->context = context; + data->sem = NULL; + + JNIEnv * env = NULL; + s_jvm->GetEnv((void **)&env, s_version); + jmethodID mid = env->GetMethodID(s_mainThreadUtilsClass, "runAfterDelay", "(JI)V"); + MCAssert(mid != NULL); + env->CallVoidMethod(s_mainThreadUtils, mid, (jlong) data, (jint) (time * 1000)); + return data; +} + +void mailcore::cancelDelayedCall(void * delayedCall) +{ + JNIEnv * env = NULL; + s_jvm->GetEnv((void **)&env, s_version); + jmethodID mid = env->GetMethodID(s_mainThreadUtilsClass, "cancelDelayedRun", "(J)V"); + MCAssert(mid != NULL); + env->CallVoidMethod(s_mainThreadUtils, mid, (jlong) delayedCall); +} diff --git a/src/core/basetypes/MCMainThreadAndroid.h b/src/core/basetypes/MCMainThreadAndroid.h new file mode 100644 index 00000000..8dfa1078 --- /dev/null +++ b/src/core/basetypes/MCMainThreadAndroid.h @@ -0,0 +1,17 @@ +#ifndef MAILCORE_MCMAINTHREADANDROID_H + +#define MAILCORE_MCMAINTHREADANDROID_H + +#if defined(__ANDROID) || defined(ANDROID) + +#ifdef __cplusplus + +namespace mailcore { + extern void androidSetupThread(void); + extern void androidUnsetupThread(void); +} +#endif + +#endif + +#endif diff --git a/src/core/basetypes/MCOperationQueue.cpp b/src/core/basetypes/MCOperationQueue.cpp index 7783a978..b9e8d779 100644 --- a/src/core/basetypes/MCOperationQueue.cpp +++ b/src/core/basetypes/MCOperationQueue.cpp @@ -10,6 +10,7 @@ #include "MCArray.h" #include "MCLog.h" #include "MCAutoreleasePool.h" +#include "MCMainThreadAndroid.h" using namespace mailcore; @@ -72,6 +73,10 @@ void OperationQueue::runOperationsOnThread(OperationQueue * queue) void OperationQueue::runOperations() { +#if defined(__ANDROID) || defined(ANDROID) + androidSetupThread(); +#endif + MCLog("start thread"); mailsem_up(mStartSem); @@ -142,6 +147,9 @@ void OperationQueue::runOperations() pool->release(); } MCLog("cleanup thread %p", this); +#if defined(__ANDROID) || defined(ANDROID) + androidUnsetupThread(); +#endif } void OperationQueue::performOnCallbackThread(Operation * op, Method method, void * context, bool waitUntilDone) diff --git a/src/core/basetypes/MCString.cpp b/src/core/basetypes/MCString.cpp index 90d7b227..d1115c40 100644 --- a/src/core/basetypes/MCString.cpp +++ b/src/core/basetypes/MCString.cpp @@ -1388,7 +1388,7 @@ String * String::extractedSubjectAndKeepBracket(bool keepBracket) String * String::uuidString() { - char buffer[38]; + char buffer[40]; FILE * f = fopen("/proc/sys/kernel/random/uuid", "r"); if (f == NULL) { return NULL; @@ -1397,7 +1397,7 @@ String * String::uuidString() fclose(f); return NULL; } - buffer[38] = 0; + buffer[36] = 0; fclose(f); return String::stringWithUTF8Characters(buffer); } diff --git a/src/core/basetypes/com_libmailcore_MainThreadUtils.h b/src/core/basetypes/com_libmailcore_MainThreadUtils.h new file mode 100644 index 00000000..327d9910 --- /dev/null +++ b/src/core/basetypes/com_libmailcore_MainThreadUtils.h @@ -0,0 +1,37 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_libmailcore_MainThreadUtils */ + +#ifndef _Included_com_libmailcore_MainThreadUtils +#define _Included_com_libmailcore_MainThreadUtils +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_libmailcore_MainThreadUtils + * Method: setupNative + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_libmailcore_MainThreadUtils_setupNative + (JNIEnv *, jobject); + +/* + * Class: com_libmailcore_MainThreadUtils + * Method: runIdentifier + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_libmailcore_MainThreadUtils_runIdentifier + (JNIEnv *, jobject, jlong); + +/* + * Class: com_libmailcore_MainThreadUtils + * Method: runIdentifierAndNotify + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_libmailcore_MainThreadUtils_runIdentifierAndNotify + (JNIEnv *, jobject, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/core/security/MCCertificateUtils.cpp b/src/core/security/MCCertificateUtils.cpp index f2345e90..2130714b 100644 --- a/src/core/security/MCCertificateUtils.cpp +++ b/src/core/security/MCCertificateUtils.cpp @@ -19,6 +19,8 @@ #include #endif +#include + #include "MCLog.h" bool mailcore::checkCertificate(mailstream * stream, String * hostname) @@ -97,6 +99,9 @@ err: X509_STORE * store = NULL; X509_STORE_CTX * storectx = NULL; STACK_OF(X509) * certificates = NULL; + DIR * dir = NULL; + struct dirent * ent = NULL; + FILE * f = NULL; int status; carray * cCerts = mailstream_get_certificate_chain(stream); @@ -127,6 +132,25 @@ err: previousCert = nextCert; } CertCloseStore(systemStore, 0); +#elif defined(ANDROID) || defined(__ANDROID__) + dir = opendir("/system/etc/security/cacerts"); + while (ent = readdir(dir)) { + if (ent->d_name[0] == '.') { + continue; + } + char filename[1024]; + snprintf(filename, sizeof(filename), "/system/etc/security/cacerts/%s", ent->d_name); + f = fopen(filename, "rb"); + if (f != NULL) { + X509 * cert = PEM_read_X509(f, NULL, NULL, NULL); + if (cert != NULL) { + X509_STORE_add_cert(store, cert); + X509_free(cert); + } + fclose(f); + } + } + closedir(dir); #endif status = X509_STORE_set_default_paths(store); diff --git a/tests/test-all.cpp b/tests/test-all.cpp index 3372811d..9b506792 100644 --- a/tests/test-all.cpp +++ b/tests/test-all.cpp @@ -12,7 +12,7 @@ #if __APPLE__ #include #endif -#if __linux__ +#if __linux__ && !defined(ANDROID) && !defined(__ANDROID__) #include #endif #ifdef _MSC_VER @@ -22,7 +22,7 @@ static mailcore::String * password = NULL; static mailcore::String * displayName = NULL; static mailcore::String * email = NULL; -#if __linux +#if __linux__ && !defined(ANDROID) && !defined(__ANDROID__) static GMainLoop * s_main_loop = NULL; #endif @@ -42,7 +42,7 @@ static void mainLoop(void) { #if __APPLE__ CFRunLoopRun(); -#elif __linux__ +#elif __linux__ && !defined(ANDROID) && !defined(__ANDROID__) g_main_loop_run(s_main_loop); #elif defined(_MSC_VER) win32MainLoop(); @@ -360,7 +360,7 @@ void testAll() password = MCSTR("MyP4ssw0rd"); displayName = MCSTR("My Email"); -#if __linux__ +#if __linux__ && !defined(ANDROID) && !defined(__ANDROID__) s_main_loop = g_main_loop_new (NULL, FALSE); #endif -- cgit v1.2.3