[sword-svn] r2475 - in trunk: bindings/java-jni bindings/java-jni/jni bindings/java-jni/src/org/crosswire/android/sword src/keys src/mgr src/utilfuns

scribe at crosswire.org scribe at crosswire.org
Tue Nov 17 23:29:35 MST 2009


Author: scribe
Date: 2009-11-17 23:29:35 -0700 (Tue, 17 Nov 2009)
New Revision: 2475

Added:
   trunk/bindings/java-jni/jni/org_crosswire_android_sword_InstallMgr.h
   trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWModule_SearchProgressReporter.h
   trunk/bindings/java-jni/src/org/crosswire/android/sword/InstallMgr.java
Modified:
   trunk/bindings/java-jni/Makefile
   trunk/bindings/java-jni/jni/Android.mk
   trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWMgr.h
   trunk/bindings/java-jni/jni/swordstub.cpp
   trunk/bindings/java-jni/src/org/crosswire/android/sword/SWMgr.java
   trunk/bindings/java-jni/src/org/crosswire/android/sword/SWModule.java
   trunk/src/keys/versekey.cpp
   trunk/src/mgr/ftplibftpt.cpp
   trunk/src/mgr/installmgr.cpp
   trunk/src/utilfuns/ftplib.c
   trunk/src/utilfuns/utilstr.cpp
Log:
updated logging
added latest android java-jni wrappers-- much more stable and featureful now.
added ability to parse jn.1.1f to jn.1.1-2 and jn.1.1ff to jn.1.1-51
made ftplib work on android and better from sword


Modified: trunk/bindings/java-jni/Makefile
===================================================================
--- trunk/bindings/java-jni/Makefile	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/bindings/java-jni/Makefile	2009-11-18 06:29:35 UTC (rev 2475)
@@ -3,11 +3,13 @@
 	javac -d classes src/org/crosswire/android/sword/*.java
 	javah -d jni -classpath classes -jni org.crosswire.android.sword.SWMgr
 	javah -d jni -classpath classes -jni org.crosswire.android.sword.SWModule
+	javah -d jni -classpath classes -jni org.crosswire.android.sword.InstallMgr
 	javap -s -classpath classes/ org.crosswire.android.sword.SWMgr > SWMgr.txt
 	javap -s -classpath classes/ org.crosswire.android.sword.SWMgr.ModInfo > ModInfo.txt
 	javap -s -classpath classes/ org.crosswire.android.sword.SWModule > SWModule.txt
 	javap -s -classpath classes/ org.crosswire.android.sword.SWModule.SearchHit > SearchHit.txt
 	javap -s -classpath classes/ org.crosswire.android.sword.SWModule.SearchProgressReporter > SearchProgressReporter.txt
-	cp src/org/crosswire/android/sword/*.java /home/scribe/workspace/bishop/src/org/crosswire/android/sword/
+	javap -s -classpath classes/ org.crosswire.android.sword.InstallMgr > InstallMgr.txt
+	cp src/org/crosswire/android/sword/*.java /home/scribe/src/bishop/src/org/crosswire/android/sword/
 
 

Modified: trunk/bindings/java-jni/jni/Android.mk
===================================================================
--- trunk/bindings/java-jni/jni/Android.mk	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/bindings/java-jni/jni/Android.mk	2009-11-18 06:29:35 UTC (rev 2475)
@@ -31,7 +31,9 @@
 LOCAL_C_INCLUDES := ../sword/include
 LOCAL_CFLAGS	+= -I$(STLPORT_BASE)/stlport \
 		   -D__NEW__ \
+		   -D__unix__ \
 		   -D__SGI_STL_INTERNAL_PAIR_H \
+		   -D_FTPLIB_NO_COMPAT \
 		   -DANDROID \
 		   -DOS_ANDROID
 LOCAL_SRC_FILES := ../../../src/modules/comments/zcom/zcom.cpp \
@@ -149,10 +151,13 @@
 ../../../src/mgr/filemgr.cpp \
 ../../../src/mgr/versemgr.cpp \
 ../../../src/mgr/ftptrans.cpp \
+../../../src/mgr/ftplibftpt.cpp \
 ../../../src/utilfuns/swobject.cpp \
 ../../../src/utilfuns/roman.cpp \
 ../../../src/utilfuns/swbuf.cpp \
 ../../../src/utilfuns/utilstr.cpp \
+../../../src/utilfuns/ftplib.c \
+../../../src/utilfuns/ftpparse.c \
 ../../../src/utilfuns/url.cpp \
 ../../../src/utilfuns/swversion.cpp \
 ../../../src/utilfuns/utilxml.cpp \
@@ -166,9 +171,9 @@
 ../../../src/keys/treekey.cpp \
 ../../../src/keys/listkey.cpp \
 ../../../src/frontend/swdisp.cpp \
-../../../src/frontend/swlog.cpp
+../../../src/frontend/swlog.cpp \
+../../../src/utilfuns/zlib/untgz.c
 
-#../../../../../sword/src/mgr/ftplibftpt.cpp \
 #../../../../../sword/src/mgr/curlftpt.cpp \
 #../../../../../sword/src/mgr/curlhttpt.cpp \
 #../../../../../sword/src/utilfuns/win32/dirent.cpp \
@@ -194,7 +199,7 @@
 		   -DOS_ANDROID
 
 LOCAL_LDLIBS	+= -L$(STLPORT_BASE)/build/lib/obj/arm-linux-gcc/so \
-		   -lstlport -lz
+		   -lstlport -lz -llog
 
 LOCAL_SRC_FILES := swordstub.cpp
 

Added: trunk/bindings/java-jni/jni/org_crosswire_android_sword_InstallMgr.h
===================================================================
--- trunk/bindings/java-jni/jni/org_crosswire_android_sword_InstallMgr.h	                        (rev 0)
+++ trunk/bindings/java-jni/jni/org_crosswire_android_sword_InstallMgr.h	2009-11-18 06:29:35 UTC (rev 2475)
@@ -0,0 +1,85 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_crosswire_android_sword_InstallMgr */
+
+#ifndef _Included_org_crosswire_android_sword_InstallMgr
+#define _Included_org_crosswire_android_sword_InstallMgr
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    reInit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_crosswire_android_sword_InstallMgr_reInit
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    setUserDisclaimerConfirmed
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_crosswire_android_sword_InstallMgr_setUserDisclaimerConfirmed
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    syncConfig
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_syncConfig
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    uninstallModule
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_uninstallModule
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    getRemoteSources
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteSources
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    refreshRemoteSource
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_refreshRemoteSource
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    getRemoteModInfoList
+ * Signature: (Ljava/lang/String;)[Lorg/crosswire/android/sword/SWMgr/ModInfo;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteModInfoList
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    remoteInstallModule
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_remoteInstallModule
+  (JNIEnv *, jobject, jstring, jstring);
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    getRemoteModuleByName
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Lorg/crosswire/android/sword/SWModule;
+ */
+JNIEXPORT jobject JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteModuleByName
+  (JNIEnv *, jobject, jstring, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Modified: trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWMgr.h
===================================================================
--- trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWMgr.h	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWMgr.h	2009-11-18 06:29:35 UTC (rev 2475)
@@ -17,6 +17,14 @@
 
 /*
  * Class:     org_crosswire_android_sword_SWMgr
+ * Method:    reInit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_reInit
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_crosswire_android_sword_SWMgr
  * Method:    getModInfoList
  * Signature: ()[Lorg/crosswire/android/sword/SWMgr/ModInfo;
  */

Added: trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWModule_SearchProgressReporter.h
===================================================================
--- trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWModule_SearchProgressReporter.h	                        (rev 0)
+++ trunk/bindings/java-jni/jni/org_crosswire_android_sword_SWModule_SearchProgressReporter.h	2009-11-18 06:29:35 UTC (rev 2475)
@@ -0,0 +1,13 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_crosswire_android_sword_SWModule_SearchProgressReporter */
+
+#ifndef _Included_org_crosswire_android_sword_SWModule_SearchProgressReporter
+#define _Included_org_crosswire_android_sword_SWModule_SearchProgressReporter
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif

Modified: trunk/bindings/java-jni/jni/swordstub.cpp
===================================================================
--- trunk/bindings/java-jni/jni/swordstub.cpp	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/bindings/java-jni/jni/swordstub.cpp	2009-11-18 06:29:35 UTC (rev 2475)
@@ -1,99 +1,200 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
+ *	CrossWire Bible Society
+ *	P. O. Box 2528
+ *	Tempe, AZ  85280-2528
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
  */
-//#include "first.h"
+
 #include <iostream>
-
 #include <vector>
+#include <map>
 
 #include <jni.h>
+#include <android/log.h>
 
 #include <utilstr.h>
 #include <swversion.h>
 #include <swmgr.h>
+#include <swlog.h>
+#include <filemgr.h>
 #include <swmodule.h>
 #include <versekey.h>
 #include <localemgr.h>
 #include <treekeyidx.h>
+#include <installmgr.h>
 
 #include "webmgr.hpp"
 #include "org_crosswire_android_sword_SWMgr.h"
 #include "org_crosswire_android_sword_SWModule.h"
+#include "org_crosswire_android_sword_InstallMgr.h"
 
 
 using std::cerr;
+using std::map;
+using std::vector;
 
 using namespace sword;
 
-WebMgr *mgr;
 
+WebMgr *mgr = 0;
+InstallMgr *installMgr = 0;
+
+class AndroidLogger : public SWLog {
+	vector<int> levelMapping;
+public:
+	AndroidLogger() {
+		levelMapping.resize(10, 0);
+		levelMapping[SWLog::LOG_ERROR] = ANDROID_LOG_ERROR;
+		levelMapping[SWLog::LOG_WARN] = ANDROID_LOG_WARN;
+		levelMapping[SWLog::LOG_INFO] = ANDROID_LOG_INFO;
+		levelMapping[SWLog::LOG_TIMEDINFO] = ANDROID_LOG_INFO;
+		levelMapping[SWLog::LOG_DEBUG] = ANDROID_LOG_DEBUG;
+	}
+	virtual void logMessage(const char *message, int level) const {
+		SWBuf msg = message;
+		if (msg.size() > 512) msg.setSize(512);
+		__android_log_write(levelMapping[level], "libsword.so", msg.c_str());
+	}
+};
+
+
 static void init() {
-	if (!mgr) mgr = new WebMgr("/sdcard/sword");
+	if (!mgr) {
+		SWLog::setSystemLog(new AndroidLogger());
+		SWLog::getSystemLog()->setLogLevel(SWLog::LOG_DEBUG);
+		SWBuf baseDir  = "/sdcard/sword";
+		SWBuf confPath = baseDir + "/mods.d/globals.conf";
+		// be sure we have at least some config file already out there
+		if (!FileMgr::existsFile(confPath.c_str())) {
+			FileMgr::createParent(confPath.c_str());
+			remove(confPath.c_str());
+
+			SWConfig config(confPath.c_str());
+			config["Globals"]["HiAndroid"] = "weeee";
+			config.Save();
+		}
+		mgr = new WebMgr("/sdcard/sword");
+	}
 }
 
+
+static void initInstall() {
+
+	if (!installMgr) {
+		SWBuf baseDir  = "/sdcard/sword/InstallMgr";
+		SWBuf confPath = baseDir + "/InstallMgr.conf";
+		// be sure we have at least some config file already out there
+		if (!FileMgr::existsFile(confPath.c_str())) {
+			FileMgr::createParent(confPath.c_str());
+			remove(confPath.c_str());
+
+			SWConfig config(confPath.c_str());
+			config["General"]["PassiveFTP"] = "true";
+			config.Save();
+		}
+		installMgr = new InstallMgr(baseDir);
+	}
+}
+
+
+
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_version
   (JNIEnv *env, jobject me) {
+
+	init();
+
 	SWVersion v;
 	return env->NewStringUTF(v.currentVersion);
 }
 
 
+/*
+ * Class:     org_crosswire_android_sword_SWMgr
+ * Method:    reInit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_reInit
+  (JNIEnv *, jobject) {
+
+	delete mgr;
+	mgr = 0;
+}
+
+
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getPrefixPath
   (JNIEnv *env, jobject me) {
+
 	init();
+
 	return env->NewStringUTF(mgr->prefixPath);
 }
 
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getConfigPath
   (JNIEnv *env, jobject me) {
+
 	init();
+
 	return env->NewStringUTF(mgr->configPath);
 }
 
 
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getModInfoList
   (JNIEnv *env, jobject) {
+
 	init();
 
-	sword::SWModule *module = 0;
-
 	int size = 0;
 	for (sword::ModMap::iterator it = mgr->Modules.begin(); it != mgr->Modules.end(); it++) {
 		if ((!(it->second->getConfigEntry("CipherKey"))) || (*(it->second->getConfigEntry("CipherKey"))))
 			size++;
 	}
 
+SWLog::getSystemLog()->logDebug("getModInfoList returning %d length array\n", size);
+
 	jclass clazzModInfo = env->FindClass("org/crosswire/android/sword/SWMgr$ModInfo");
+	jfieldID nameID     = env->GetFieldID(clazzModInfo, "name",        "Ljava/lang/String;");
+	jfieldID descID     = env->GetFieldID(clazzModInfo, "description", "Ljava/lang/String;");
+	jfieldID catID      = env->GetFieldID(clazzModInfo, "category",    "Ljava/lang/String;");
+	jfieldID langID     = env->GetFieldID(clazzModInfo, "language",    "Ljava/lang/String;");
+	jfieldID versionID  = env->GetFieldID(clazzModInfo, "version",     "Ljava/lang/String;");
+	jfieldID deltaID    = env->GetFieldID(clazzModInfo, "delta",       "Ljava/lang/String;");
+
 	jobjectArray ret = (jobjectArray) env->NewObjectArray(size, clazzModInfo, NULL);
 
 	int i = 0;
 	for (sword::ModMap::iterator it = mgr->Modules.begin(); it != mgr->Modules.end(); it++) {
-		module = it->second;
+		SWModule *module = it->second;
+
 		if ((!(module->getConfigEntry("CipherKey"))) || (*(module->getConfigEntry("CipherKey")))) {
 			SWBuf type = module->Type();
 			SWBuf cat = module->getConfigEntry("Category");
+			SWBuf version = module->getConfigEntry("Version");
 			if (cat.length() > 0) type = cat;
-			jfieldID fieldID;
+
 			jobject modInfo = env->AllocObject(clazzModInfo); 
 
-			fieldID = env->GetFieldID(clazzModInfo, "name", "Ljava/lang/String;"); env->SetObjectField(modInfo, fieldID, env->NewStringUTF(module->Name()));
-			fieldID = env->GetFieldID(clazzModInfo, "description", "Ljava/lang/String;"); env->SetObjectField(modInfo, fieldID, env->NewStringUTF(module->Description()));
-			fieldID = env->GetFieldID(clazzModInfo, "category", "Ljava/lang/String;"); env->SetObjectField(modInfo, fieldID, env->NewStringUTF(type.c_str()));
-			fieldID = env->GetFieldID(clazzModInfo, "language", "Ljava/lang/String;"); env->SetObjectField(modInfo, fieldID, env->NewStringUTF(module->Lang()));
+			jstring val;
+			val = env->NewStringUTF(assureValidUTF8(module->Name()));        env->SetObjectField(modInfo, nameID   , val); env->DeleteLocalRef(val);
+			val = env->NewStringUTF(assureValidUTF8(module->Description())); env->SetObjectField(modInfo, descID   , val); env->DeleteLocalRef(val);
+			val = env->NewStringUTF(assureValidUTF8(type.c_str()));          env->SetObjectField(modInfo, catID    , val); env->DeleteLocalRef(val);
+			val = env->NewStringUTF(assureValidUTF8(module->Lang()));        env->SetObjectField(modInfo, langID   , val); env->DeleteLocalRef(val);
+			val = env->NewStringUTF(assureValidUTF8(version.c_str()));       env->SetObjectField(modInfo, versionID, val); env->DeleteLocalRef(val);
+			val = env->NewStringUTF(assureValidUTF8(""));                    env->SetObjectField(modInfo, deltaID  , val); env->DeleteLocalRef(val);
+
 			env->SetObjectArrayElement(ret, i++, modInfo);
+
+			env->DeleteLocalRef(modInfo);
+
 		}
 	}
 	return ret;
@@ -106,6 +207,9 @@
  */
 JNIEXPORT jobject JNICALL Java_org_crosswire_android_sword_SWMgr_getModuleByName
   (JNIEnv *env, jobject me, jstring modNameJS) {
+
+	init();
+
 	jobject retVal = 0;
 
      const char *modName = env->GetStringUTFChars(modNameJS, NULL);
@@ -119,9 +223,9 @@
 		jfieldID fieldID;
 		jclass clazzSWModule = env->FindClass("org/crosswire/android/sword/SWModule");
 		retVal = env->AllocObject(clazzSWModule); 
-		fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(module->Name()));
-		fieldID = env->GetFieldID(clazzSWModule, "description", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(module->Description()));
-		fieldID = env->GetFieldID(clazzSWModule, "category", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(type.c_str()));
+		fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->Name())));
+		fieldID = env->GetFieldID(clazzSWModule, "description", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->Description())));
+		fieldID = env->GetFieldID(clazzSWModule, "category", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(type.c_str())));
 	}
 	return retVal;
 }
@@ -134,6 +238,9 @@
  */
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setGlobalOption
   (JNIEnv *env, jobject me, jstring optionJS, jstring valueJS) {
+
+	init();
+
      const char *option = env->GetStringUTFChars(optionJS, NULL);
      const char *value  = env->GetStringUTFChars(valueJS, NULL);
 
@@ -151,13 +258,16 @@
  */
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOption
   (JNIEnv *env, jobject me, jstring optionJS) {
+
+	init();
+
      const char *option = env->GetStringUTFChars(optionJS, NULL);
 
 	SWBuf value = mgr->getGlobalOption(option);
 
      env->ReleaseStringUTFChars(optionJS, option);
 
-	return env->NewStringUTF(value);
+	return env->NewStringUTF(assureValidUTF8(value));
 }
 
 
@@ -168,13 +278,16 @@
  */
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOptionTip
   (JNIEnv *env, jobject me, jstring optionJS) {
+
+	init();
+
      const char *option = env->GetStringUTFChars(optionJS, NULL);
 
 	SWBuf value = mgr->getGlobalOptionTip(option);
 
      env->ReleaseStringUTFChars(optionJS, option);
 
-	return env->NewStringUTF(value);
+	return env->NewStringUTF(assureValidUTF8(value));
 }
 
 
@@ -185,6 +298,9 @@
  */
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_filterText
   (JNIEnv *env, jobject me, jstring filterNameJS, jstring textJS) {
+
+	init();
+
      const char *filterName = env->GetStringUTFChars(filterNameJS, NULL);
      const char *text  = env->GetStringUTFChars(textJS, NULL);
 
@@ -196,7 +312,7 @@
      env->ReleaseStringUTFChars(textJS, text);
      env->ReleaseStringUTFChars(filterNameJS, filterName);
 
-	return env->NewStringUTF(buf);
+	return env->NewStringUTF(assureValidUTF8(buf));
 }
 
 
@@ -207,6 +323,9 @@
  */
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOptions
   (JNIEnv *env, jobject me) {
+
+	init();
+
 	sword::StringList options = mgr->getGlobalOptions();
 	int count = 0;
 	for (sword::StringList::iterator it = options.begin(); it != options.end(); it++) {
@@ -218,7 +337,7 @@
 
 	count = 0;
 	for (sword::StringList::iterator it = options.begin(); it != options.end(); it++) {
-		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(*it));
+		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(*it)));
 	}
 
 	return ret;
@@ -232,6 +351,9 @@
  */
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOptionValues
   (JNIEnv *env, jobject me, jstring optionJS) {
+
+	init();
+
      const char *option = env->GetStringUTFChars(optionJS, NULL);
 
 	sword::StringList options = mgr->getGlobalOptionValues(option);
@@ -247,7 +369,7 @@
 
 	count = 0;
 	for (sword::StringList::iterator it = options.begin(); it != options.end(); it++) {
-		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(*it));
+		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(*it)));
 	}
 
 	return ret;
@@ -261,6 +383,9 @@
  */
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setCipherKey
   (JNIEnv *env, jobject me , jstring modNameJS, jstring keyJS) {
+
+	init();
+
      const char *modName = env->GetStringUTFChars(modNameJS, NULL);
      const char *key     = env->GetStringUTFChars(keyJS, NULL);
 
@@ -278,6 +403,9 @@
  */
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setJavascript
   (JNIEnv *env, jobject me, jboolean val) {
+
+	init();
+
 	mgr->setJavascript(val == JNI_TRUE);
 }
 
@@ -289,6 +417,9 @@
  */
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getAvailableLocales
   (JNIEnv *env, jobject me) {
+
+	init();
+
 	sword::StringList localeNames = LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
 	int count = 0;
 	for (sword::StringList::iterator it = localeNames.begin(); it != localeNames.end(); it++) {
@@ -300,7 +431,7 @@
 
 	count = 0;
 	for (sword::StringList::iterator it = localeNames.begin(); it != localeNames.end(); it++) {
-		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(*it));
+		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(*it)));
 	}
 	return ret;
 }
@@ -313,6 +444,9 @@
  */
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setDefaultLocale
   (JNIEnv *env, jobject me, jstring localeNameJS) {
+
+	init();
+
      const char *localeName = env->GetStringUTFChars(localeNameJS, NULL);
 
 	LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName(localeName);
@@ -324,13 +458,41 @@
 
 // SWModule methods ----------------------------------------------------------------------------------
 
+
 SWModule *getModule(JNIEnv *env, jobject me) {
+SWLog::getSystemLog()->logDebug("getModule start");
+
+	init(); 
+
+	SWModule *module = 0;
 	jclass clazzSWModule = env->FindClass("org/crosswire/android/sword/SWModule");
+SWLog::getSystemLog()->logDebug("getModule got SWModule clazz");
 	jfieldID fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;");
+SWLog::getSystemLog()->logDebug("getModule got SWModule::name fid");
+	jfieldID sourceFieldID = env->GetFieldID(clazzSWModule, "remoteSourceName", "Ljava/lang/String;");
+SWLog::getSystemLog()->logDebug("getModule got SWModule::remoteSourceName fid");
 	jstring modNameJS = (jstring)env->GetObjectField(me, fieldID);
-     const char *modName = env->GetStringUTFChars(modNameJS, NULL);
-	sword::SWModule *module = mgr->getModule(modName);
-     env->ReleaseStringUTFChars(modNameJS, modName);
+SWLog::getSystemLog()->logDebug("getModule got SWModule::name");
+	jstring sourceNameJS = (jstring)env->GetObjectField(me, sourceFieldID);
+SWLog::getSystemLog()->logDebug("getModule got SWModule::remoteSourceName");
+     const char *modName = (modNameJS?env->GetStringUTFChars(modNameJS, NULL):0);
+SWLog::getSystemLog()->logDebug("getModule got SWModule::modName const char *");
+     const char *sourceName = (sourceNameJS?env->GetStringUTFChars(sourceNameJS, NULL):0);
+SWLog::getSystemLog()->logDebug("getModule got SWModule::sourceName const char *");
+SWLog::getSystemLog()->logDebug("getModule %s %s", (sourceName?sourceName:"null"), (modName?modName:"null"));
+	if (sourceName && *sourceName) {
+SWLog::getSystemLog()->logDebug("getModule remote");
+		initInstall();
+		InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+		if (source == installMgr->sources.end()) {
+			SWMgr *mgr = source->second->getMgr();
+			module = mgr->getModule(modName);
+		}
+	}
+	else module = mgr->getModule(modName);
+     if (modName) env->ReleaseStringUTFChars(modNameJS, modName);
+     if (sourceName) env->ReleaseStringUTFChars(sourceNameJS, sourceName);
+SWLog::getSystemLog()->logDebug("getModule end");
 	return module;
 }
 
@@ -342,10 +504,13 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_setKeyText
   (JNIEnv *env, jobject me, jstring keyTextJS) {
 
+	init();
+
 	SWModule *module = getModule(env, me);
 
 	if (module) {
 		const char *keyText = env->GetStringUTFChars(keyTextJS, NULL);
+SWLog::getSystemLog()->logDebug("setKeyText(%s, %s)", module->Name(), keyText);
 		sword::SWKey *key = module->getKey();
 		sword::VerseKey *vkey = SWDYNAMIC_CAST(VerseKey, key);
 		if (vkey && (*keyText=='+' ||*keyText=='-')) {
@@ -375,11 +540,13 @@
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getKeyText
   (JNIEnv *env, jobject me) {
 
+	init();
+
 	SWModule *module = getModule(env, me);
 
 	jstring retVal = 0;
 	if (module) {
-		retVal = env->NewStringUTF(module->getKeyText());
+		retVal = env->NewStringUTF(assureValidUTF8(module->getKeyText()));
 	}
 	return retVal;
 }
@@ -393,11 +560,13 @@
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getRenderText
   (JNIEnv *env, jobject me) {
 
+	init();
+
 	SWModule *module = getModule(env, me);
 
 	jstring retVal = 0;
 	if (module) {
-		retVal = env->NewStringUTF(module->RenderText());
+		retVal = env->NewStringUTF(assureValidUTF8(module->RenderText()));
 	}
 	return retVal;
 }
@@ -411,6 +580,8 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_terminateSearch
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
 	SWModule *module = getModule(env, me);
 
 	if (module) {
@@ -427,6 +598,8 @@
 JNIEXPORT jchar JNICALL Java_org_crosswire_android_sword_SWModule_error
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
 	SWModule *module = getModule(env, me);
 	
 	return (module) ? module->Error() : -99;
@@ -441,6 +614,8 @@
 JNIEXPORT jlong JNICALL Java_org_crosswire_android_sword_SWModule_getEntrySize
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
 	SWModule *module = getModule(env, me);
 
 	return (module) ? module->getEntrySize() : 0;
@@ -454,20 +629,23 @@
  */
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_getEntryAttribute
   (JNIEnv *env, jobject me, jstring level1JS, jstring level2JS, jstring level3JS, jboolean filteredJS) {
+
+	init(); 
+
 	const char *level1 = env->GetStringUTFChars(level1JS, NULL);
 	const char *level2 = env->GetStringUTFChars(level2JS, NULL);
 	const char *level3 = env->GetStringUTFChars(level3JS, NULL);
 	bool filtered = (filteredJS == JNI_TRUE);
 
 	jclass clazzString = env->FindClass("java/lang/String");
-	jobjectArray ret = (jobjectArray) env->NewObjectArray(0, clazzString, NULL);
+	jobjectArray ret = 0;
 
 	SWModule *module = getModule(env, me);
 
 	if (module) {
 
 		module->RenderText();	// force parse
-		std::vector<SWBuf> results;
+		vector<SWBuf> results;
 
 		sword::AttributeTypeList &entryAttribs = module->getEntryAttributes();
 		sword::AttributeTypeList::iterator i1Start, i1End;
@@ -520,10 +698,10 @@
 
 		for (int i = 0; i < results.size(); i++) {
 			if (filtered) {
-				env->SetObjectArrayElement(ret, i, env->NewStringUTF(module->RenderText(results[i].c_str())));
+				env->SetObjectArrayElement(ret, i, env->NewStringUTF(assureValidUTF8(module->RenderText(results[i].c_str()))));
 			}
 			else {
-				env->SetObjectArrayElement(ret, i, env->NewStringUTF(results[i].c_str()));
+				env->SetObjectArrayElement(ret, i, env->NewStringUTF(assureValidUTF8(results[i].c_str())));
 			}
 		}
 	}
@@ -532,7 +710,7 @@
 	env->ReleaseStringUTFChars(level2JS, level2);
 	env->ReleaseStringUTFChars(level1JS, level1);
 
-	return ret;
+	return (ret) ? ret : (jobjectArray) env->NewObjectArray(0, clazzString, NULL);
 }
 
 
@@ -544,6 +722,8 @@
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_parseKeyList
   (JNIEnv *env, jobject me, jstring keyListTextJS) {
 
+	init(); 
+
 	const char *keyListText = env->GetStringUTFChars(keyListTextJS, NULL);
 
 	SWModule *module = getModule(env, me);
@@ -564,12 +744,12 @@
 
 			count = 0;
 			for (result = sword::TOP; !result.Error(); result++) {
-				env->SetObjectArrayElement(ret, count++, env->NewStringUTF((const char *)result));
+				env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8((const char *)result)));
 			}
 		}
 		else	{
 			ret = (jobjectArray) env->NewObjectArray(1, clazzString, NULL);
-			env->SetObjectArrayElement(ret, 0, env->NewStringUTF(keyListText));
+			env->SetObjectArrayElement(ret, 0, env->NewStringUTF(assureValidUTF8(keyListText)));
 		}
 	}
 
@@ -587,6 +767,9 @@
 JNIEXPORT jboolean JNICALL Java_org_crosswire_android_sword_SWModule_hasKeyChildren
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWModule *module = getModule(env, me);
 	jboolean retVal = JNI_FALSE;
 
@@ -609,6 +792,9 @@
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_getKeyChildren
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	jclass clazzString = env->FindClass("java/lang/String");
 	jobjectArray ret;
 
@@ -623,23 +809,23 @@
 			ret = (jobjectArray) env->NewObjectArray(7, clazzString, NULL);
 			SWBuf num;
 			num.appendFormatted("%d", vkey->getTestament());
-			env->SetObjectArrayElement(ret, 0, env->NewStringUTF(num.c_str()));
+			env->SetObjectArrayElement(ret, 0, env->NewStringUTF(assureValidUTF8(num.c_str())));
 			num = "";
 			num.appendFormatted("%d", vkey->getBook());
-			env->SetObjectArrayElement(ret, 1, env->NewStringUTF(num.c_str()));
+			env->SetObjectArrayElement(ret, 1, env->NewStringUTF(assureValidUTF8(num.c_str())));
 			num = "";
 			num.appendFormatted("%d", vkey->getChapter());
-			env->SetObjectArrayElement(ret, 2, env->NewStringUTF(num.c_str()));
+			env->SetObjectArrayElement(ret, 2, env->NewStringUTF(assureValidUTF8(num.c_str())));
 			num = "";
 			num.appendFormatted("%d", vkey->getVerse());
-			env->SetObjectArrayElement(ret, 3, env->NewStringUTF(num.c_str()));
+			env->SetObjectArrayElement(ret, 3, env->NewStringUTF(assureValidUTF8(num.c_str())));
 			num = "";
 			num.appendFormatted("%d", vkey->getChapterMax());
-			env->SetObjectArrayElement(ret, 4, env->NewStringUTF(num.c_str()));
+			env->SetObjectArrayElement(ret, 4, env->NewStringUTF(assureValidUTF8(num.c_str())));
 			num = "";
 			num.appendFormatted("%d", vkey->getVerseMax());
-			env->SetObjectArrayElement(ret, 5, env->NewStringUTF(num.c_str()));
-			env->SetObjectArrayElement(ret, 6, env->NewStringUTF(vkey->getBookName()));
+			env->SetObjectArrayElement(ret, 5, env->NewStringUTF(assureValidUTF8(num.c_str())));
+			env->SetObjectArrayElement(ret, 6, env->NewStringUTF(assureValidUTF8(vkey->getBookName())));
 		}
 		else {
 			TreeKeyIdx *tkey = SWDYNAMIC_CAST(TreeKeyIdx, key);
@@ -655,7 +841,7 @@
 				count = 0;
 				if (tkey->firstChild()) {
 					do {
-						env->SetObjectArrayElement(ret, count++, env->NewStringUTF(tkey->getLocalName()));
+						env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(tkey->getLocalName())));
 					}
 					while (tkey->nextSibling());
 					tkey->parent();
@@ -675,6 +861,9 @@
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getKeyParent
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWBuf retVal = "";
 
 	SWModule *module = getModule(env, me);
@@ -690,7 +879,7 @@
 			}
 		}
 	}
-	return env->NewStringUTF(retVal);
+	return env->NewStringUTF(assureValidUTF8(retVal));
 }
 
 
@@ -702,6 +891,9 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_previous
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWModule *module = getModule(env, me);
 
 	if (module) {
@@ -718,6 +910,9 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_next
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWModule *module = getModule(env, me);
 
 	if (module) {
@@ -734,6 +929,9 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_begin
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWModule *module = getModule(env, me);
 
 	if (module) {
@@ -750,6 +948,9 @@
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getStripText
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWBuf retVal = "";
 
 	SWModule *module = getModule(env, me);
@@ -758,7 +959,7 @@
 		retVal = module->StripText();
 	}
 
-	return env->NewStringUTF(retVal);
+	return env->NewStringUTF(assureValidUTF8(retVal));
 }
 
 
@@ -770,6 +971,9 @@
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getRawEntry
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWBuf retVal = "";
 
 	SWModule *module = getModule(env, me);
@@ -778,7 +982,7 @@
 		retVal = module->getRawEntry();
 	}
 
-	return env->NewStringUTF(retVal);
+	return env->NewStringUTF(assureValidUTF8(retVal));
 }
 
 
@@ -790,6 +994,9 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_setRawEntry
   (JNIEnv *env, jobject me, jstring newEntryTextJS) {
 
+	init(); 
+
+
 	const char *newEntryText = env->GetStringUTFChars(newEntryTextJS, NULL);
 
 	SWModule *module = getModule(env, me);
@@ -802,6 +1009,25 @@
 }
 
 
+jstring newBigString(JNIEnv *env, const char *buf) {
+	SWBuf str = assureValidUTF8(buf);
+     jclass stringClass = env->FindClass("java/lang/String");
+     jmethodID ctorID = env->GetMethodID(stringClass, "<init>", "([B)V");
+
+	jstring result;
+SWLog::getSystemLog()->logDebug("newBigString: making byte array size: %d", str.size());
+	jbyteArray bytes = env->NewByteArray(str.size());
+SWLog::getSystemLog()->logDebug("newBigString: setting array region");
+
+	env->SetByteArrayRegion(bytes, 0, str.size(), (jbyte *)str.c_str());
+SWLog::getSystemLog()->logDebug("newBigString: newing string");
+	result = (jstring)env->NewObject(stringClass, ctorID, bytes);
+	env->DeleteLocalRef(bytes);
+SWLog::getSystemLog()->logDebug("newBigString: returning");
+	return result;
+}
+
+
 /*
  * Class:     org_crosswire_android_sword_SWModule
  * Method:    getConfigEntry
@@ -810,14 +1036,20 @@
 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getConfigEntry
   (JNIEnv *env, jobject me, jstring configKeyJS) {
 
+	init(); 
+
+
 	jstring retVal = 0;
 
 	const char *configKey = env->GetStringUTFChars(configKeyJS, NULL);
+SWLog::getSystemLog()->logDebug("getConfigEntry(%s)\n", configKey);
 
 	SWModule *module = getModule(env, me);
 
-	if (module && module->getConfigEntry(configKey)) {
-		retVal = env->NewStringUTF(module->getConfigEntry(configKey));
+	if (module) {
+		SWBuf about = module->getConfigEntry(configKey);
+		SWBuf assuredBuf = assureValidUTF8(about.c_str());
+		retVal = env->NewStringUTF(assuredBuf.c_str());
 	}
 
 	env->ReleaseStringUTFChars(configKeyJS, configKey);
@@ -834,6 +1066,9 @@
 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_deleteSearchFramework
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWModule *module = getModule(env, me);
 
 	if (module) {
@@ -850,6 +1085,9 @@
 JNIEXPORT jboolean JNICALL Java_org_crosswire_android_sword_SWModule_hasSearchFramework
   (JNIEnv *env, jobject me) {
 
+	init(); 
+
+
 	SWModule *module = getModule(env, me);
 
 	return (module && module->hasSearchFramework()) ? JNI_TRUE : JNI_FALSE;
@@ -886,11 +1124,14 @@
 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_search
   (JNIEnv *env, jobject me, jstring expressionJS, jint srchType, jlong flags, jstring scopeJS, jobject progressReporter) {
 
+	init(); 
+
+
 	const char *expression = env->GetStringUTFChars(expressionJS, NULL);
 	const char *scope = env->GetStringUTFChars(scopeJS, NULL);
 
 	jclass clazzSearchHit = env->FindClass("org/crosswire/android/sword/SWModule$SearchHit");
-	jobjectArray ret = (jobjectArray) env->NewObjectArray(0, clazzSearchHit, NULL);
+	jobjectArray ret = 0;
 
 	SWModule *module = getModule(env, me);
 
@@ -929,8 +1170,8 @@
 			jfieldID fieldID;
 			jobject searchHit = env->AllocObject(clazzSearchHit); 
 
-			fieldID = env->GetFieldID(clazzSearchHit, "modName", "Ljava/lang/String;"); env->SetObjectField(searchHit, fieldID, env->NewStringUTF(module->Name()));
-			fieldID = env->GetFieldID(clazzSearchHit, "key", "Ljava/lang/String;"); env->SetObjectField(searchHit, fieldID, env->NewStringUTF((const char *)result));
+			fieldID = env->GetFieldID(clazzSearchHit, "modName", "Ljava/lang/String;"); env->SetObjectField(searchHit, fieldID, env->NewStringUTF(assureValidUTF8(module->Name())));
+			fieldID = env->GetFieldID(clazzSearchHit, "key", "Ljava/lang/String;"); env->SetObjectField(searchHit, fieldID, env->NewStringUTF(assureValidUTF8((const char *)result)));
 			fieldID = env->GetFieldID(clazzSearchHit, "score", "J"); env->SetLongField(searchHit, fieldID, (long)result.getElement()->userData);
 
 			env->SetObjectArrayElement(ret, i++, searchHit);
@@ -940,7 +1181,291 @@
 	env->ReleaseStringUTFChars(scopeJS, scope);
 	env->ReleaseStringUTFChars(expressionJS, expression);
 
+	return (ret) ? ret : (jobjectArray) env->NewObjectArray(0, clazzSearchHit, NULL);
+}
+
+
+
+// InstallMgr methods ----------------------------------------------------------------------------------
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    reInit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_crosswire_android_sword_InstallMgr_reInit
+  (JNIEnv *env, jobject me) {
+
+	delete installMgr;
+	installMgr = 0;
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    syncConfig
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_syncConfig
+  (JNIEnv *env, jobject me) {
+
+	initInstall();
+
+	return installMgr->refreshRemoteSourceConfiguration();
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    uninstallModule
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_uninstallModule
+  (JNIEnv *env, jobject me, jstring modNameJS) {
+
+	init();
+	initInstall();
+
+	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
+
+SWLog::getSystemLog()->logDebug("uninstallModule %s\n", modName);
+
+	SWModule *module;
+	ModMap::iterator it = mgr->Modules.find(modName);
+	if (it == mgr->Modules.end()) {
+		return -2;
+	}
+	module = it->second;
+	installMgr->removeModule(mgr, module->Name());
+
+	env->ReleaseStringUTFChars(modNameJS, modName);
+
+	return 0;
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    getRemoteSources
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteSources
+  (JNIEnv *env, jobject me) {
+
+	initInstall();
+
+	jclass clazzString = env->FindClass("java/lang/String");
+	jobjectArray ret;
+
+	int count = 0;
+	for (InstallSourceMap::iterator it = installMgr->sources.begin(); it != installMgr->sources.end(); it++) {
+		count++;
+	}
+	ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
+	count = 0;
+	for (InstallSourceMap::iterator it = installMgr->sources.begin(); it != installMgr->sources.end(); it++) {
+		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(it->second->caption.c_str())));
+	}
+
 	return ret;
 }
 
 
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    refreshRemoteSource
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_refreshRemoteSource
+  (JNIEnv *env, jobject me, jstring sourceNameJS) {
+
+	initInstall();
+
+	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
+
+	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+	if (source == installMgr->sources.end()) {
+		return -3;
+	}
+
+	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
+
+	return installMgr->refreshRemoteSource(source->second);
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    getRemoteModInfoList
+ * Signature: (Ljava/lang/String;)[Lorg/crosswire/android/sword/SWMgr/ModInfo;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteModInfoList
+  (JNIEnv *env, jobject me, jstring sourceNameJS) {
+
+SWLog::getSystemLog()->logDebug("getRemoteModInfoList\n");
+	init();
+	initInstall();
+
+	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
+SWLog::getSystemLog()->logDebug("sourceName: %s\n", sourceName);
+
+	jclass clazzModInfo = env->FindClass("org/crosswire/android/sword/SWMgr$ModInfo");
+	jfieldID nameID     = env->GetFieldID(clazzModInfo, "name",        "Ljava/lang/String;");
+	jfieldID descID     = env->GetFieldID(clazzModInfo, "description", "Ljava/lang/String;");
+	jfieldID catID      = env->GetFieldID(clazzModInfo, "category",    "Ljava/lang/String;");
+	jfieldID langID     = env->GetFieldID(clazzModInfo, "language",    "Ljava/lang/String;");
+	jfieldID versionID  = env->GetFieldID(clazzModInfo, "version",     "Ljava/lang/String;");
+	jfieldID deltaID    = env->GetFieldID(clazzModInfo, "delta",       "Ljava/lang/String;");
+
+	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+	if (source == installMgr->sources.end()) {
+SWLog::getSystemLog()->logDebug("remoteListModules returning 0 length array\n");
+		return (jobjectArray) env->NewObjectArray(0, clazzModInfo, NULL);
+	}
+SWLog::getSystemLog()->logDebug("found source: %s\n", sourceName);
+
+	map<SWModule *, int> modStats = installMgr->getModuleStatus(*mgr, *source->second->getMgr());
+
+	int size = 0;
+	for (map<SWModule *, int>::iterator it = modStats.begin(); it != modStats.end(); it++) {
+		size++;
+	}
+
+SWLog::getSystemLog()->logDebug("remoteListModules returning %d length array\n", size);
+	jobjectArray ret = (jobjectArray) env->NewObjectArray(size, clazzModInfo, NULL);
+
+	int i = 0;
+	for (map<SWModule *, int>::iterator it = modStats.begin(); it != modStats.end(); it++) {
+		SWModule *module = it->first;
+		int status = it->second;
+
+		SWBuf version = module->getConfigEntry("Version");
+		SWBuf statusString = " ";
+		if (it->second & InstallMgr::MODSTAT_NEW) statusString = "*";
+		if (it->second & InstallMgr::MODSTAT_OLDER) statusString = "-";
+		if (it->second & InstallMgr::MODSTAT_UPDATED) statusString = "+";
+
+		SWBuf type = module->Type();
+		SWBuf cat = module->getConfigEntry("Category");
+		if (cat.length() > 0) type = cat;
+		jobject modInfo = env->AllocObject(clazzModInfo); 
+
+		jstring val;
+		val = env->NewStringUTF(assureValidUTF8(module->Name()));        env->SetObjectField(modInfo, nameID   , val); env->DeleteLocalRef(val);
+		val = env->NewStringUTF(assureValidUTF8(module->Description())); env->SetObjectField(modInfo, descID   , val); env->DeleteLocalRef(val);
+		val = env->NewStringUTF(assureValidUTF8(type.c_str()));          env->SetObjectField(modInfo, catID    , val); env->DeleteLocalRef(val);
+		val = env->NewStringUTF(assureValidUTF8(module->Lang()));        env->SetObjectField(modInfo, langID   , val); env->DeleteLocalRef(val);
+		val = env->NewStringUTF(assureValidUTF8(version.c_str()));       env->SetObjectField(modInfo, versionID, val); env->DeleteLocalRef(val);
+		val = env->NewStringUTF(assureValidUTF8(statusString.c_str()));  env->SetObjectField(modInfo, deltaID  , val); env->DeleteLocalRef(val);
+
+		env->SetObjectArrayElement(ret, i++, modInfo);
+
+		env->DeleteLocalRef(modInfo);
+	}
+
+	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
+
+	return ret;
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    remoteInstallModule
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_remoteInstallModule
+  (JNIEnv *env, jobject me, jstring sourceNameJS, jstring modNameJS) {
+
+	initInstall();
+
+	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
+SWLog::getSystemLog()->logDebug("remoteInstallModule: sourceName: %s\n", sourceName);
+	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
+
+	if (source == installMgr->sources.end()) {
+		return -3;
+	}
+
+	InstallSource *is = source->second;
+	SWMgr *rmgr = is->getMgr();
+	SWModule *module;
+
+	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
+SWLog::getSystemLog()->logDebug("remoteInstallModule: modName: %s\n", modName);
+	ModMap::iterator it = rmgr->Modules.find(modName);
+	env->ReleaseStringUTFChars(modNameJS, modName);
+
+	if (it == rmgr->Modules.end()) {
+		return -4;
+	}
+
+	module = it->second;
+
+	int error = installMgr->installModule(mgr, 0, module->Name(), is);
+
+	return error;
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    getRemoteModuleByName
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Lorg/crosswire/android/sword/SWModule;
+ */
+JNIEXPORT jobject JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteModuleByName
+  (JNIEnv *env, jobject me, jstring sourceNameJS, jstring modNameJS) {
+
+	jobject retVal = 0;
+
+	initInstall();
+
+	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
+SWLog::getSystemLog()->logDebug("getRemoteModuleByName: sourceName: %s\n", sourceName);
+	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
+
+	if (source == installMgr->sources.end()) {
+SWLog::getSystemLog()->logDebug("Couldn't find remote source [%s]\n", sourceName);
+		return 0;
+	}
+
+	SWMgr *mgr = source->second->getMgr();
+
+     const char *modName = env->GetStringUTFChars(modNameJS, NULL);
+	sword::SWModule *module = mgr->getModule(modName);
+     env->ReleaseStringUTFChars(modNameJS, modName);
+
+	if (module) {
+		SWBuf type = module->Type();
+		SWBuf cat = module->getConfigEntry("Category");
+		if (cat.length() > 0) type = cat;
+		jfieldID fieldID;
+		jclass clazzSWModule = env->FindClass("org/crosswire/android/sword/SWModule");
+		retVal = env->AllocObject(clazzSWModule); 
+		fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->Name())));
+		fieldID = env->GetFieldID(clazzSWModule, "description", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->Description())));
+		fieldID = env->GetFieldID(clazzSWModule, "category", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(type.c_str())));
+		fieldID = env->GetFieldID(clazzSWModule, "remoteSourceName", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, sourceNameJS);
+	}
+
+	return retVal;
+
+}
+
+
+/*
+ * Class:     org_crosswire_android_sword_InstallMgr
+ * Method:    setUserDisclaimerConfirmed
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_crosswire_android_sword_InstallMgr_setUserDisclaimerConfirmed
+  (JNIEnv *env, jobject me) {
+
+	initInstall();
+
+	installMgr->setUserDisclaimerConfirmed(true);
+}
+

Added: trunk/bindings/java-jni/src/org/crosswire/android/sword/InstallMgr.java
===================================================================
--- trunk/bindings/java-jni/src/org/crosswire/android/sword/InstallMgr.java	                        (rev 0)
+++ trunk/bindings/java-jni/src/org/crosswire/android/sword/InstallMgr.java	2009-11-18 06:29:35 UTC (rev 2475)
@@ -0,0 +1,17 @@
+package org.crosswire.android.sword;
+
+public class InstallMgr {
+
+	public native void reInit();
+
+	public native void             setUserDisclaimerConfirmed();
+	public native int              syncConfig();
+	public native int              uninstallModule(String modName);
+	public native String []        getRemoteSources();
+	public native int              refreshRemoteSource(String sourceName);
+	public native SWMgr.ModInfo [] getRemoteModInfoList(String sourceName);
+	public native int              remoteInstallModule(String sourceName, String modName);
+	public native SWModule         getRemoteModuleByName(String source, String name);
+
+}
+

Modified: trunk/bindings/java-jni/src/org/crosswire/android/sword/SWMgr.java
===================================================================
--- trunk/bindings/java-jni/src/org/crosswire/android/sword/SWMgr.java	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/bindings/java-jni/src/org/crosswire/android/sword/SWMgr.java	2009-11-18 06:29:35 UTC (rev 2475)
@@ -11,10 +11,13 @@
 		public String description;
 		public String category;
 		public String language;
+		public String version;
+		public String delta;
 	}
 
 
 	public native String version();
+	public native void reInit();
 
 	public native ModInfo[]   getModInfoList();
 	public native SWModule    getModuleByName(String name);

Modified: trunk/bindings/java-jni/src/org/crosswire/android/sword/SWModule.java
===================================================================
--- trunk/bindings/java-jni/src/org/crosswire/android/sword/SWModule.java	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/bindings/java-jni/src/org/crosswire/android/sword/SWModule.java	2009-11-18 06:29:35 UTC (rev 2475)
@@ -1,10 +1,13 @@
 package org.crosswire.android.sword;
 
 public class SWModule {
-	
+
 	private String name;
 	private String description;
 	private String category;
+	
+	// if this is a shell module from a remote source...
+	private String remoteSourceName;
 
 
 	public static final int SEARCHTYPE_REGEX     =  1;

Modified: trunk/src/keys/versekey.cpp
===================================================================
--- trunk/src/keys/versekey.cpp	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/src/keys/versekey.cpp	2009-11-18 06:29:35 UTC (rev 2475)
@@ -491,6 +491,7 @@
 	char lastPartial = 0;
 	bool inTerm = true;
 	int notAllDigits = 0;
+	bool doubleF = false;
 
 	// assert we have a buffer
 	if (!buf) return internalListKey;
@@ -693,7 +694,14 @@
 							tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str()));
 						}
 						else {
+							bool f = false;
+							if (curKey->getSuffix() == 'f') {
+								curKey->setSuffix(0);
+								f = true;
+							}
 							lastKey->LowerBound(*curKey);
+							if (f && doubleF) (*curKey) = MAXVERSE;
+							else if (f) (*curKey)++;
 							lastKey->UpperBound(*curKey);
 							*lastKey = TOP;
 							tmpListKey << *lastKey;
@@ -763,6 +771,7 @@
 				default:
 					// suffixes (and oddly 'f'-- ff.)
 					if ((*buf >= 'a' && *buf <= 'z') && (chap >=0)) {
+						doubleF = (*buf == 'f' && suffix == 'f');
 						suffix = *buf;
 					}
 					else {
@@ -901,11 +910,17 @@
 					tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str()));
 				}
 				else {
+					bool f = false;
+					if (curKey->getSuffix() == 'f') {
+						curKey->setSuffix(0);
+						f = true;
+					}
 					lastKey->LowerBound(*curKey);
+					if (f && doubleF) (*curKey) = MAXVERSE;
+					else if (f) (*curKey)++;
 					lastKey->UpperBound(*curKey);
 					*lastKey = TOP;
 					tmpListKey << *lastKey;
-//					tmpListKey << curKey->getText();
 					tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str()));
 				}
 			}

Modified: trunk/src/mgr/ftplibftpt.cpp
===================================================================
--- trunk/src/mgr/ftplibftpt.cpp	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/src/mgr/ftplibftpt.cpp	2009-11-18 06:29:35 UTC (rev 2475)
@@ -58,15 +58,18 @@
 char FTPLibFTPTransport::assureLoggedIn() {
 	char retVal = 0;
 	if (ftpConnection == 0) {
-		SWLog::getSystemLog()->logDebug("connecting to host %s\n", host.c_str());
-		if (FtpConnect(host, &ftpConnection))
+		SWLog::getSystemLog()->logDebug("connecting to host: %s...\n", host.c_str());
+		if (FtpConnect(host, &ftpConnection)) {
+			SWLog::getSystemLog()->logDebug("connected. logging in...\n");
 			if (FtpLogin(u.c_str(), p.c_str(), ftpConnection)) {
+				SWLog::getSystemLog()->logDebug("logged in.\n");
 				retVal = 0;
 			}
 			else {
 				SWLog::getSystemLog()->logError("Failed to login to %s\n", host.c_str());
 				retVal = -2;
 			}
+		}
 		else {
 			SWLog::getSystemLog()->logError("Failed to connect to %s\n", host.c_str());
 			retVal = -1;
@@ -80,12 +83,28 @@
 
 	char retVal = 0;
 
+	SWLog::getSystemLog()->logDebug("FTPLibFTPTransport::getURL(%s, %s, ...);\n", (destPath)?destPath:"(null)", sourceURL);
 	// assert we can login
 	retVal = assureLoggedIn();
 	if (retVal) return retVal;
+	SWLog::getSystemLog()->logDebug("FTPLibFTPTransport - logged in.\n");
 
 	SWBuf sourcePath = sourceURL;
-	SWBuf outFile = (!destBuf) ? destPath : "swftplib.tmp";
+
+	SWBuf outFile;
+	if (!destBuf) {
+		outFile = destPath;
+	}
+	else {
+#ifdef ANDROID
+		outFile = "/sdcard/sword/InstallMgr/swtmpbuf.out";
+#else
+		char tmpName[128];
+		tmpnam(tmpName);
+		outFile = tmpName;
+#endif
+	}
+
 	sourcePath << (6 + host.length()); // shift << "ftp://hostname";
 	SWLog::getSystemLog()->logDebug("getting file %s to %s\n", sourcePath.c_str(), outFile.c_str());
 	if (passive)
@@ -98,6 +117,7 @@
 		FtpDir(NULL, sourcePath, ftpConnection);
 		SWLog::getSystemLog()->logDebug("getting real directory %s\n", sourcePath.c_str());
 		retVal = FtpDir(outFile.c_str(), sourcePath, ftpConnection) - 1;
+		SWLog::getSystemLog()->logDebug("got real directory %s to %s\n", sourcePath.c_str(), outFile.c_str());
 	}
 	else {
 		SWLog::getSystemLog()->logDebug("getting file %s\n", sourcePath.c_str());
@@ -108,15 +128,17 @@
 	// If not, we probably want to add x-platform way to open a tmp file with FileMgr
 	// This wreaks and will easily fail if a user's CWD is not writable.
 	if (destBuf) {
-		FileDesc *fd = FileMgr::getSystemFileMgr()->open("swftplib.tmp", FileMgr::RDONLY);
+		SWLog::getSystemLog()->logDebug("filling destBuf\n");
+		FileDesc *fd = FileMgr::getSystemFileMgr()->open(outFile.c_str(), FileMgr::RDONLY);
 		long size = fd->seek(0, SEEK_END);
 		fd->seek(0, SEEK_SET);
 		destBuf->size(size);
 		fd->read(destBuf->getRawData(), size);
 		FileMgr::getSystemFileMgr()->close(fd);
-		FileMgr::removeFile("swftplib.tmp");
+		FileMgr::removeFile(outFile.c_str());
 	}
 
+	SWLog::getSystemLog()->logDebug("FTPLibFTPTransport - returning: %d\n", retVal);
 	return retVal;
 }
 

Modified: trunk/src/mgr/installmgr.cpp
===================================================================
--- trunk/src/mgr/installmgr.cpp	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/src/mgr/installmgr.cpp	2009-11-18 06:29:35 UTC (rev 2475)
@@ -271,6 +271,7 @@
 
 // TODO: rename to netCopy
 int InstallMgr::ftpCopy(InstallSource *is, const char *src, const char *dest, bool dirTransfer, const char *suffix) {
+SWLog::getSystemLog()->logDebug("netCopy: %s, %s, %s, %c, %s", (is?is->source.c_str():"null"), src, (dest?dest:"null"), (dirTransfer?'t':'f'), (suffix?suffix:"null"));
 
 	// assert user disclaimer has been confirmed
 	if (!isUserDisclaimerConfirmed()) return -1;

Modified: trunk/src/utilfuns/ftplib.c
===================================================================
--- trunk/src/utilfuns/ftplib.c	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/src/utilfuns/ftplib.c	2009-11-18 06:29:35 UTC (rev 2475)
@@ -80,6 +80,41 @@
 #define FTPLIB_DEFMODE FTPLIB_PASSIVE
 #endif
 
+#ifdef ANDROID
+#include <android/log.h>
+#define perror(M) __android_log_write(ANDROID_LOG_DEBUG, "perror_ftplib", M)
+#define lllog(M) __android_log_write(ANDROID_LOG_DEBUG, "ftplib", M)
+#else
+#define lllog(M) fprintf(stderr, M);
+#endif
+void *mymemccpy(void *dst, const void *src, int c, size_t n)
+{
+    char*        q     = dst;
+    const char*  p     = src;
+    const char*  p_end = p + n;
+    char         ch    = ~(char)c;  /* ensure ch != c */
+
+    for (;;) {
+        if (ch == c || p >= p_end) break;
+        *q++ = ch = *p++;
+
+        if (ch == c || p >= p_end) break;
+        *q++ = ch = *p++;
+
+        if (ch == c || p >= p_end) break;
+        *q++ = ch = *p++;
+
+        if (ch == c || p >= p_end) break;
+        *q++ = ch = *p++;
+    }
+
+    if (p >= p_end && ch != c)
+        return NULL;
+
+    return q;
+}
+
+
 struct NetBuf {
     char *cput,*cget;
     int handle;
@@ -208,9 +243,10 @@
           if (ctl->cavail > 0)
             {
                 x = (max >= ctl->cavail) ? ctl->cavail : max-1;
-                end = memccpy(bp,ctl->cget,'\n',x);
-                if (end != NULL)
+                end = mymemccpy(bp,ctl->cget,'\n',x);
+                if (end != NULL) {
                     x = end - bp;
+			 }
                 retval += x;
                 bp += x;
                 *bp = '\0';
@@ -254,7 +290,7 @@
                 retval = -1;
                 break;
             }
-          if (x == 0)
+          if (x == 0) //< ctl->cleft)
               eof = 1;
           ctl->cleft -= x;
           ctl->cavail += x;
@@ -411,7 +447,7 @@
     pnum = strchr(lhost,':');
     if (pnum == NULL)
       {
-#if defined(VMS)
+#if defined(VMS) || defined(ANDROID)
           sin.sin_port = htons(21);
 #else
           if ((pse = getservbyname("ftp","tcp")) == NULL)

Modified: trunk/src/utilfuns/utilstr.cpp
===================================================================
--- trunk/src/utilfuns/utilstr.cpp	2009-11-10 06:40:04 UTC (rev 2474)
+++ trunk/src/utilfuns/utilstr.cpp	2009-11-18 06:29:35 UTC (rev 2475)
@@ -264,7 +264,7 @@
 		}
 	}
 	if (invalidChar) {
-		SWLog::getSystemLog()->logWarning("Changing invalid UTF-8 string (%s) to (%s)\n", buf, myCopy.c_str());
+//		SWLog::getSystemLog()->logWarning("Changing invalid UTF-8 string (%s) to (%s)\n", buf, myCopy.c_str());
 	}
 	return myCopy;
 }




More information about the sword-cvs mailing list