1 /******************************************************************************
2  *
3  *  swordstub.cpp -	JNI bindings
4  *
5  * $Id: swordstub.cpp 3524 2017-11-07 03:08:49Z scribe $
6  *
7  * Copyright 2009-2013 CrossWire Bible Society (http://www.crosswire.org)
8  *	CrossWire Bible Society
9  *	P. O. Box 2528
10  *	Tempe, AZ  85280-2528
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  */
22 
23 #include <iostream>
24 #include <vector>
25 #include <map>
26 
27 #include <jni.h>
28 #include <android/log.h>
29 
30 #include <utilstr.h>
31 #include <swversion.h>
32 #include <swmgr.h>
33 #include <swlog.h>
34 #include <filemgr.h>
35 #include <swmodule.h>
36 #include <versekey.h>
37 #include <localemgr.h>
38 #include <treekeyidx.h>
39 #include <installmgr.h>
40 #include <remotetrans.h>
41 #include <rtfhtml.h>
42 //#include <android/native_activity.h>
43 
44 
45 #ifdef BIBLESYNC
46 #include <biblesync.hh>
47 #endif
48 
49 #include "webmgr.hpp"
50 #include "org_crosswire_android_sword_SWMgr.h"
51 #include "org_crosswire_android_sword_SWModule.h"
52 #include "org_crosswire_android_sword_InstallMgr.h"
53 
54 
55 using std::cerr;
56 using std::map;
57 using std::vector;
58 
59 using namespace sword;
60 
61 namespace {
62 WebMgr *mgr = 0;
63 InstallMgr *installMgr = 0;
64 
65 #ifdef BIBLESYNC
66 BibleSync *bibleSync = 0;
67 using std::string;
68 jobject bibleSyncListener = 0;
69 JNIEnv *bibleSyncListenerEnv = 0;
70 #endif
71 static SWBuf STORAGE_BASE;
72 static char *SWORD_PATH = "/sdcard/sword";
73 static char *AND_BIBLE_MODULES_PATH = "/sdcard/Android/data/net.bible.android.activity/files";
74 //ANativeActivity *_activity;
75 
76 class InstallStatusReporter : public StatusReporter {
77 public:
78 	JNIEnv *env;
79 	jobject callback;
80 	unsigned long last;
81 
InstallStatusReporter()82 	InstallStatusReporter() : env(0), callback(0), last(0) {
83 	}
84 
init(JNIEnv * env,jobject callback)85 	void init(JNIEnv *env, jobject callback) {
86 		this->env = env;
87 		this->callback = callback;
88 		last = 0xffffffff;
89 	}
90 
update(unsigned long totalBytes,unsigned long completedBytes)91 	virtual void update(unsigned long totalBytes, unsigned long completedBytes) {
92 
93 		// assert we have a callback
94 		if (!callback) return;
95 
96 		if (completedBytes != last) {
97 			last = completedBytes;
98 			jclass cls = env->GetObjectClass(callback);
99 			jmethodID mid = env->GetMethodID(cls, "update", "(JJ)V");
100 			if (mid != 0) {
101 				env->CallVoidMethod(callback, mid, (jlong)totalBytes, (jlong)completedBytes);
102 			}
103 			env->DeleteLocalRef(cls);
104 		}
105 	}
106 
preStatus(long totalBytes,long completedBytes,const char * message)107 	virtual void preStatus(long totalBytes, long completedBytes, const char *message) {
108 
109 		// assert we have a callback
110 		if (!callback) return;
111 
112 		jclass cls = env->GetObjectClass(callback);
113 		jmethodID mid = env->GetMethodID(cls, "preStatus", "(JJLjava/lang/String;)V");
114 		if (mid != 0) {
115 			jstring msg = env->NewStringUTF(assureValidUTF8((const char *)message));
116 			env->CallVoidMethod(callback, mid, (jlong)totalBytes, (jlong)completedBytes, msg);
117 			env->DeleteLocalRef(msg);
118 		}
119 		env->DeleteLocalRef(cls);
120 	}
121 } *installStatusReporter = 0;
122 bool disclaimerConfirmed = false;
123 
124 class AndroidLogger : public SWLog {
125 	vector<int> levelMapping;
126 public:
AndroidLogger()127 	AndroidLogger() {
128 		levelMapping.resize(10, 0);
129 		levelMapping[SWLog::LOG_ERROR] = ANDROID_LOG_ERROR;
130 		levelMapping[SWLog::LOG_WARN] = ANDROID_LOG_WARN;
131 		levelMapping[SWLog::LOG_INFO] = ANDROID_LOG_INFO;
132 		levelMapping[SWLog::LOG_TIMEDINFO] = ANDROID_LOG_INFO;
133 		levelMapping[SWLog::LOG_DEBUG] = ANDROID_LOG_DEBUG;
134 	}
logMessage(const char * message,int level) const135 	virtual void logMessage(const char *message, int level) const {
136 		SWBuf msg = message;
137 		if (msg.size() > 512) msg.setSize(512);
138 		__android_log_write(levelMapping[level], "libsword.so", msg.c_str());
139 	}
140 };
141 
142 
init(JNIEnv * env)143 static void init(JNIEnv *env) {
144 	if (!mgr) {
145 		SWLog::setSystemLog(new AndroidLogger());
146 		SWLog::getSystemLog()->setLogLevel(SWLog::LOG_DEBUG);
147 SWLog::getSystemLog()->logDebug("libsword: init() begin");
148 		SWBuf baseDir  = SWORD_PATH;
149 		SWBuf confPath = baseDir + "/mods.d/globals.conf";
150 		// be sure we have at least some config file already out there
151 		if (!FileMgr::existsFile(confPath.c_str())) {
152 			SWLog::getSystemLog()->logDebug("libsword: init() sword config not found, attempting to create parent of: %s", confPath.c_str());
153 			FileMgr::createParent(confPath.c_str());
154 			remove(confPath.c_str());
155 
156 			SWLog::getSystemLog()->logDebug("libsword: init() saving basic: %s", confPath.c_str());
157 			SWConfig config(confPath.c_str());
158 			config["Globals"]["HiAndroid"] = "weeee";
159 			config.save();
160 		}
161 		if (!FileMgr::existsFile(confPath.c_str())) {
162 			baseDir = STORAGE_BASE;
163 			confPath = baseDir + "/mods.d/globals.conf";
164 SWLog::getSystemLog()->logDebug("libsword: init() sword config STILL not found, attempting to create parent of: %s", confPath.c_str());
165 			FileMgr::createParent(confPath.c_str());
166 			remove(confPath.c_str());
167 
168 SWLog::getSystemLog()->logDebug("libsword: init() saving basic: %s", confPath.c_str());
169 			SWConfig config(confPath.c_str());
170 			config["Globals"]["HiAndroid"] = "weeee";
171 			config.save();
172 		}
173 		confPath = STORAGE_BASE + "/extraConfig.conf";
174 		bool exists = FileMgr::existsFile(confPath.c_str());
175 SWLog::getSystemLog()->logDebug("libsword: extraConfig %s at path: %s", exists?"Exists":"Absent", confPath.c_str());
176 
177 SWLog::getSystemLog()->logDebug("libsword: init() creating WebMgr using path: %s", baseDir.c_str());
178 		mgr = new WebMgr(baseDir, exists?confPath.c_str():0);
179 
180 SWLog::getSystemLog()->logDebug("libsword: init() augmenting modules from: %s", AND_BIBLE_MODULES_PATH);
181 		// for And Bible modules
182 		mgr->augmentModules(AND_BIBLE_MODULES_PATH, true);
183 	}
184 }
185 
initInstall(JNIEnv * env,jobject progressReporter=0)186 static void initInstall(JNIEnv *env, jobject progressReporter = 0) {
187 
188 	if (!installStatusReporter) {
189 		installStatusReporter = new InstallStatusReporter();
190 	}
191 	installStatusReporter->init(env, progressReporter);
192 	if (!installMgr) {
193 SWLog::getSystemLog()->logDebug("initInstall: installMgr is null");
194 		SWBuf baseDir  = SWORD_PATH;
195 		baseDir += "/InstallMgr";
196 		SWBuf confPath = baseDir + "/InstallMgr.conf";
197 		// be sure we have at least some config file already out there
198 SWLog::getSystemLog()->logDebug("initInstall: confPath: %s", confPath.c_str());
199 		if (!FileMgr::existsFile(confPath.c_str())) {
200 			SWLog::getSystemLog()->logDebug("initInstall: file doesn't exist: %s", confPath.c_str());
201 			FileMgr::createParent(confPath.c_str());
202 			SWConfig config(confPath.c_str());
203 			config["General"]["PassiveFTP"] = "true";
204 			config.save();
205 		}
206 		if (!FileMgr::existsFile(confPath.c_str())) {
207 			baseDir = STORAGE_BASE;
208 			confPath = baseDir + "/InstallMgr.conf";
209 			SWLog::getSystemLog()->logDebug("initInstall: file STILL doesn't exist, attempting to create parent of: %s", confPath.c_str());
210 			FileMgr::createParent(confPath.c_str());
211 			SWConfig config(confPath.c_str());
212 			config["General"]["PassiveFTP"] = "true";
213 			config.save();
214 		}
215 		installMgr = new InstallMgr(baseDir, installStatusReporter);
216 		if (disclaimerConfirmed) installMgr->setUserDisclaimerConfirmed(true);
217 SWLog::getSystemLog()->logDebug("initInstall: instantiated InstallMgr with baseDir: %s", baseDir.c_str());
218 	}
219 }
220 
221 #ifdef BIBLESYNC
bibleSyncCallback(char cmd,string bible,string ref,string alt,string group,string domain,string info,string dump)222 void bibleSyncCallback(char cmd, string bible, string ref, string alt, string group, string domain, string info, string dump) {
223 SWLog::getSystemLog()->logDebug("bibleSync callback msg: %c; bible: %s; ref: %s; alt: %s; group: %s; domain: %s; info: %s; dump: %s", cmd, bible.c_str(), ref.c_str(), alt.c_str(), group.c_str(), domain.c_str(), info.c_str(), dump.c_str());
224 	if (::bibleSyncListener) {
225 SWLog::getSystemLog()->logDebug("bibleSync listener is true");
226 		jclass cls = bibleSyncListenerEnv->GetObjectClass(::bibleSyncListener);
227 		jmethodID mid = bibleSyncListenerEnv->GetMethodID(cls, "messageReceived", "(Ljava/lang/String;)V");
228 SWLog::getSystemLog()->logDebug("bibleSync listener mid: %ld", mid);
229 		if (mid) {
230 SWLog::getSystemLog()->logDebug("bibleSync listener mid is available");
231 			switch(cmd) {
232 			// error
233 			case 'E':
234 			// mismatch
235 			case 'M':
236 			// new speaker
237 			case 'S':
238 			// dead speaker
239 			case 'D':
240 			// announce
241 			case 'A':
242 				break;
243 			// navigation
244 			case 'N':
245 SWLog::getSystemLog()->logDebug("bibleSync Nav Received: %s", ref.c_str());
246 				jstring msg = bibleSyncListenerEnv->NewStringUTF(ref.c_str());
247 				bibleSyncListenerEnv->CallVoidMethod(::bibleSyncListener, mid, msg);
248 				bibleSyncListenerEnv->DeleteLocalRef(msg);
249 				break;
250 			}
251 		}
252 SWLog::getSystemLog()->logDebug("bibleSync listener deleting local ref to cls");
253 		bibleSyncListenerEnv->DeleteLocalRef(cls);
254 	}
255 }
256 #endif
257 
258 
initBibleSync()259 static void initBibleSync() {
260 #ifdef BIBLESYNC
261 	if (!bibleSync) {
262 SWLog::getSystemLog()->logDebug("bibleSync initializing c-tor");
263 		bibleSync = new BibleSync("SWORD", (const char *)SWVersion().currentVersion, "SwordUser");
264 SWLog::getSystemLog()->logDebug("bibleSync initializing setMode");
265 		bibleSync->setMode(BSP_MODE_PERSONAL, bibleSyncCallback, "passphrase");
266 	}
267 #endif
268 }
269 
270 }
271 
272 
Java_org_crosswire_android_sword_SWMgr_version(JNIEnv * env,jobject me)273 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_version
274 		(JNIEnv *env, jobject me) {
275 
276 	init(env);
277 
278 	SWVersion v;
279 	return env->NewStringUTF(v.currentVersion);
280 }
281 
282 
283 /*
284  * Class:     org_crosswire_android_sword_SWMgr
285  * Method:    reInit
286  * Signature: ()V
287  */
Java_org_crosswire_android_sword_SWMgr_reInit(JNIEnv * env,jobject me)288 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_reInit
289 		(JNIEnv *env, jobject me) {
290 
291 	jclass swmgrClass = env->GetObjectClass(me);
292 	jmethodID getStorageBasePath = env->GetMethodID(swmgrClass, "getStorageBasePath", "()Ljava/lang/String;");
293 	jstring basePathJS = (jstring)env->CallObjectMethod(me, getStorageBasePath, NULL);
294 
295 	const char *basePath = (basePathJS?env->GetStringUTFChars(basePathJS, NULL):0);
296 	STORAGE_BASE = basePath;
297 	SWLog::getSystemLog()->logDebug("setting STORAGE_BASE to: %s", STORAGE_BASE.c_str());
298 
299 	delete mgr;
300 	mgr = 0;
301 }
302 
303 
Java_org_crosswire_android_sword_SWMgr_getPrefixPath(JNIEnv * env,jobject me)304 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getPrefixPath
305 		(JNIEnv *env, jobject me) {
306 
307 	init(env);
308 
309 	return env->NewStringUTF(mgr->prefixPath);
310 }
311 
Java_org_crosswire_android_sword_SWMgr_getConfigPath(JNIEnv * env,jobject me)312 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getConfigPath
313 		(JNIEnv *env, jobject me) {
314 
315 	init(env);
316 
317 	return env->NewStringUTF(mgr->configPath);
318 }
319 
320 
Java_org_crosswire_android_sword_SWMgr_getModInfoList(JNIEnv * env,jobject)321 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getModInfoList
322 		(JNIEnv *env, jobject) {
323 
324 	init(env);
325 
326 	int size = 0;
327 	for (sword::ModMap::iterator it = mgr->Modules.begin(); it != mgr->Modules.end(); ++it) {
328 		if ((!(it->second->getConfigEntry("CipherKey"))) || (*(it->second->getConfigEntry("CipherKey"))))
329 			size++;
330 	}
331 
332 SWLog::getSystemLog()->logDebug("getModInfoList returning %d length array\n", size);
333 
334 	jclass clazzModInfo = env->FindClass("org/crosswire/android/sword/SWMgr$ModInfo");
335 	jfieldID nameID     = env->GetFieldID(clazzModInfo, "name",        "Ljava/lang/String;");
336 	jfieldID descID     = env->GetFieldID(clazzModInfo, "description", "Ljava/lang/String;");
337 	jfieldID catID      = env->GetFieldID(clazzModInfo, "category",    "Ljava/lang/String;");
338 	jfieldID langID     = env->GetFieldID(clazzModInfo, "language",    "Ljava/lang/String;");
339 	jfieldID versionID  = env->GetFieldID(clazzModInfo, "version",     "Ljava/lang/String;");
340 	jfieldID deltaID    = env->GetFieldID(clazzModInfo, "delta",       "Ljava/lang/String;");
341 
342 	jobjectArray ret = (jobjectArray) env->NewObjectArray(size, clazzModInfo, NULL);
343 
344 	int i = 0;
345 	for (sword::ModMap::iterator it = mgr->Modules.begin(); it != mgr->Modules.end(); ++it) {
346 		SWModule *module = it->second;
347 
348 		if ((!(module->getConfigEntry("CipherKey"))) || (*(module->getConfigEntry("CipherKey")))) {
349 			SWBuf type = module->getType();
350 			SWBuf cat = module->getConfigEntry("Category");
351 			SWBuf version = module->getConfigEntry("Version");
352 			if (cat.length() > 0) type = cat;
353 
354 			jobject modInfo = env->AllocObject(clazzModInfo);
355 
356 			jstring val;
357 			val = env->NewStringUTF(assureValidUTF8(module->getName()));        env->SetObjectField(modInfo, nameID   , val); env->DeleteLocalRef(val);
358 			val = env->NewStringUTF(assureValidUTF8(module->getDescription())); env->SetObjectField(modInfo, descID   , val); env->DeleteLocalRef(val);
359 			val = env->NewStringUTF(assureValidUTF8(type.c_str()));          env->SetObjectField(modInfo, catID    , val); env->DeleteLocalRef(val);
360 			val = env->NewStringUTF(assureValidUTF8(module->getLanguage()));        env->SetObjectField(modInfo, langID   , val); env->DeleteLocalRef(val);
361 			val = env->NewStringUTF(assureValidUTF8(version.c_str()));       env->SetObjectField(modInfo, versionID, val); env->DeleteLocalRef(val);
362 			val = env->NewStringUTF(assureValidUTF8(""));                    env->SetObjectField(modInfo, deltaID  , val); env->DeleteLocalRef(val);
363 
364 			env->SetObjectArrayElement(ret, i++, modInfo);
365 
366 			env->DeleteLocalRef(modInfo);
367 
368 		}
369 	}
370 	return ret;
371 }
372 
373 /*
374  * Class:     org_crosswire_android_sword_SWMgr
375  * Method:    getModuleByName
376  * Signature: (Ljava/lang/String;)Lorg/crosswire/android/sword/SWModule;
377  */
Java_org_crosswire_android_sword_SWMgr_getModuleByName(JNIEnv * env,jobject me,jstring modNameJS)378 JNIEXPORT jobject JNICALL Java_org_crosswire_android_sword_SWMgr_getModuleByName
379 		(JNIEnv *env, jobject me, jstring modNameJS) {
380 
381 	init(env);
382 
383 	jobject retVal = 0;
384 
385 	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
386 	sword::SWModule *module = mgr->getModule(modName);
387 	env->ReleaseStringUTFChars(modNameJS, modName);
388 
389 	if (module) {
390 		SWBuf type = module->getType();
391 		SWBuf cat = module->getConfigEntry("Category");
392 		if (cat.length() > 0) type = cat;
393 		jfieldID fieldID;
394 		jclass clazzSWModule = env->FindClass("org/crosswire/android/sword/SWModule");
395 		retVal = env->AllocObject(clazzSWModule);
396 		fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->getName())));
397 		fieldID = env->GetFieldID(clazzSWModule, "description", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->getDescription())));
398 		fieldID = env->GetFieldID(clazzSWModule, "category", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(type.c_str())));
399 	}
400 	return retVal;
401 }
402 
403 
404 /*
405  * Class:     org_crosswire_android_sword_SWMgr
406  * Method:    setGlobalOption
407  * Signature: (Ljava/lang/String;Ljava/lang/String;)V
408  */
Java_org_crosswire_android_sword_SWMgr_setGlobalOption(JNIEnv * env,jobject me,jstring optionJS,jstring valueJS)409 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setGlobalOption
410 		(JNIEnv *env, jobject me, jstring optionJS, jstring valueJS) {
411 
412 	init(env);
413 
414 	const char *option = env->GetStringUTFChars(optionJS, NULL);
415 	const char *value  = env->GetStringUTFChars(valueJS, NULL);
416 
417 	mgr->setGlobalOption(option, value);
418 
419 	env->ReleaseStringUTFChars(valueJS, value);
420 	env->ReleaseStringUTFChars(optionJS, option);
421 }
422 
423 
424 /*
425  * Class:     org_crosswire_android_sword_SWMgr
426  * Method:    getGlobalOption
427  * Signature: (Ljava/lang/String;)Ljava/lang/String;
428  */
Java_org_crosswire_android_sword_SWMgr_getGlobalOption(JNIEnv * env,jobject me,jstring optionJS)429 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOption
430 		(JNIEnv *env, jobject me, jstring optionJS) {
431 
432 	init(env);
433 
434 	const char *option = env->GetStringUTFChars(optionJS, NULL);
435 
436 	SWBuf value = mgr->getGlobalOption(option);
437 
438 	env->ReleaseStringUTFChars(optionJS, option);
439 
440 	return env->NewStringUTF(assureValidUTF8(value));
441 }
442 
443 
444 /*
445  * Class:     org_crosswire_android_sword_SWMgr
446  * Method:    getGlobalOptionTip
447  * Signature: (Ljava/lang/String;)Ljava/lang/String;
448  */
Java_org_crosswire_android_sword_SWMgr_getGlobalOptionTip(JNIEnv * env,jobject me,jstring optionJS)449 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOptionTip
450 		(JNIEnv *env, jobject me, jstring optionJS) {
451 
452 	init(env);
453 
454 	const char *option = env->GetStringUTFChars(optionJS, NULL);
455 
456 	SWBuf value = mgr->getGlobalOptionTip(option);
457 
458 	env->ReleaseStringUTFChars(optionJS, option);
459 
460 	return env->NewStringUTF(assureValidUTF8(value));
461 }
462 
463 
464 /*
465  * Class:     org_crosswire_android_sword_SWMgr
466  * Method:    filterText
467  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
468  */
Java_org_crosswire_android_sword_SWMgr_filterText(JNIEnv * env,jobject me,jstring filterNameJS,jstring textJS)469 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_filterText
470 		(JNIEnv *env, jobject me, jstring filterNameJS, jstring textJS) {
471 
472 	init(env);
473 
474 	const char *filterName = env->GetStringUTFChars(filterNameJS, NULL);
475 	const char *text  = env->GetStringUTFChars(textJS, NULL);
476 
477 	SWBuf buf = text;
478 	// hmmm, in the future, provide a param to specify filter value maybe?
479 	mgr->setGlobalOption("Greek Accents", "Off");
480 	char errStatus = mgr->filterText(filterName, buf);
481 
482 	env->ReleaseStringUTFChars(textJS, text);
483 	env->ReleaseStringUTFChars(filterNameJS, filterName);
484 
485 	return env->NewStringUTF(assureValidUTF8(buf));
486 }
487 
488 
489 /*
490  * Class:     org_crosswire_android_sword_SWMgr
491  * Method:    getGlobalOptions
492  * Signature: ()[Ljava/lang/String;
493  */
Java_org_crosswire_android_sword_SWMgr_getGlobalOptions(JNIEnv * env,jobject me)494 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOptions
495 		(JNIEnv *env, jobject me) {
496 
497 	init(env);
498 
499 	sword::StringList options = mgr->getGlobalOptions();
500 	int count = 0;
501 	for (sword::StringList::iterator it = options.begin(); it != options.end(); ++it) {
502 		count++;
503 	}
504 
505 	jclass clazzString = env->FindClass("java/lang/String");
506 	jobjectArray ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
507 
508 	count = 0;
509 	for (sword::StringList::iterator it = options.begin(); it != options.end(); ++it) {
510 		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(*it)));
511 	}
512 
513 	return ret;
514 }
515 
516 
517 /*
518  * Class:     org_crosswire_android_sword_SWMgr
519  * Method:    getExtraConfigSections
520  * Signature: ()[Ljava/lang/String;
521  */
Java_org_crosswire_android_sword_SWMgr_getExtraConfigSections(JNIEnv * env,jobject me)522 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getExtraConfigSections
523 		(JNIEnv *env, jobject me) {
524 
525 	init(env);
526 
527 	SWBuf baseDir = STORAGE_BASE;
528 	SWBuf confPath = baseDir + "/extraConfig.conf";
529 	int count = 0;
530 	bool exists = FileMgr::existsFile(confPath.c_str());
531 	jclass clazzString = env->FindClass("java/lang/String");
532 	jobjectArray ret;
533 	SWLog::getSystemLog()->logDebug("libsword: extraConfig %s at path: %s", exists?"Exists":"Absent", confPath.c_str());
534 	if (exists) {
535 		SWConfig config(confPath.c_str());
536 		SectionMap::const_iterator sit;
537 		for (sit = config.getSections().begin(); sit != config.getSections().end(); ++sit) {
538 			count++;
539 		}
540 		SWLog::getSystemLog()->logDebug("libsword: %d sections found in extraConfig", count);
541 		ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
542 		count = 0;
543 		for (sit = config.getSections().begin(); sit != config.getSections().end(); ++sit) {
544 			env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(sit->first.c_str())));
545 		}
546 	}
547 	else {
548 		ret = (jobjectArray) env->NewObjectArray(0, clazzString, NULL);
549 	}
550 
551 	return ret;
552 }
553 
554 
555 /*
556  * Class:     org_crosswire_android_sword_SWMgr
557  * Method:    getExtraConfigKeys
558  * Signature: (Ljava/lang/String;)[Ljava/lang/String;
559  */
Java_org_crosswire_android_sword_SWMgr_getExtraConfigKeys(JNIEnv * env,jobject me,jstring section)560 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getExtraConfigKeys
561 		(JNIEnv *env, jobject me, jstring section) {
562 
563 	init(env);
564 
565 	const char *s = env->GetStringUTFChars(section, NULL);
566 
567 	SWBuf mySection = s;
568 
569 	env->ReleaseStringUTFChars(section, s);
570 
571 	SWBuf baseDir = STORAGE_BASE;
572 	SWBuf confPath = baseDir + "/extraConfig.conf";
573 	int count = 0;
574 	bool exists = FileMgr::existsFile(confPath.c_str());
575 	jclass clazzString = env->FindClass("java/lang/String");
576 	jobjectArray ret;
577 	if (exists) {
578 		SWConfig config(confPath.c_str());
579 		SectionMap::const_iterator sit = config.getSections().find(mySection.c_str());
580 		if (sit != config.getSections().end()) {
581 			ConfigEntMap::const_iterator it;
582 			for (it = sit->second.begin(); it != sit->second.end(); ++it) {
583 				count++;
584 			}
585 			ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
586 			count = 0;
587 			for (it = sit->second.begin(); it != sit->second.end(); ++it) {
588 				env->SetObjectArrayElement(ret, count++,
589 				                           env->NewStringUTF(assureValidUTF8(it->first.c_str())));
590 			}
591 		}
592 		else {
593 			ret = (jobjectArray) env->NewObjectArray(0, clazzString, NULL);
594 		}
595 	}
596 	else {
597 		ret = (jobjectArray) env->NewObjectArray(0, clazzString, NULL);
598 	}
599 
600 	return ret;
601 }
602 
603 
604 /*
605  * Class:     org_crosswire_android_sword_SWMgr
606  * Method:    getExtraConfigValue
607  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
608  */
Java_org_crosswire_android_sword_SWMgr_getExtraConfigValue(JNIEnv * env,jobject me,jstring section,jstring key)609 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWMgr_getExtraConfigValue
610 		(JNIEnv *env, jobject me, jstring section, jstring key) {
611 
612 	init(env);
613 
614 	const char *s = env->GetStringUTFChars(section, NULL);
615 
616 	SWBuf mySection = s;
617 
618 	env->ReleaseStringUTFChars(section, s);
619 
620 	const char *k = env->GetStringUTFChars(key, NULL);
621 
622 	SWBuf myKey = k;
623 
624 	env->ReleaseStringUTFChars(key, k);
625 
626 	jstring ret = 0;
627 
628 	SWBuf baseDir = STORAGE_BASE;
629 	SWBuf confPath = baseDir + "/extraConfig.conf";
630 	bool exists = FileMgr::existsFile(confPath.c_str());
631 	if (exists) {
632 		SWConfig config(confPath.c_str());
633 		SectionMap::const_iterator sit = config.getSections().find(mySection.c_str());
634 		if (sit != config.getSections().end()) {
635 			ConfigEntMap::const_iterator it = sit->second.find(myKey.c_str());
636 			if (it != sit->second.end()) {
637 				ret = env->NewStringUTF(assureValidUTF8(it->second.c_str()));
638 			}
639 		}
640 	}
641 
642 	return ret;
643 }
644 
645 
646 /*
647  * Class:     org_crosswire_android_sword_SWMgr
648  * Method:    setExtraConfigValue
649  * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
650  */
Java_org_crosswire_android_sword_SWMgr_setExtraConfigValue(JNIEnv * env,jobject me,jstring section,jstring key,jstring value)651 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setExtraConfigValue
652 		(JNIEnv *env, jobject me, jstring section, jstring key, jstring value) {
653 
654 	init(env);
655 
656 	const char *s = env->GetStringUTFChars(section, NULL);
657 
658 	SWBuf mySection = s;
659 
660 	env->ReleaseStringUTFChars(section, s);
661 
662 	const char *k = env->GetStringUTFChars(key, NULL);
663 
664 	SWBuf myKey = k;
665 
666 	env->ReleaseStringUTFChars(key, k);
667 
668 	const char *v = env->GetStringUTFChars(value, NULL);
669 
670 	SWBuf myValue = v;
671 
672 	env->ReleaseStringUTFChars(value, v);
673 
674 	SWBuf baseDir = STORAGE_BASE;
675 	SWBuf confPath = baseDir + "/extraConfig.conf";
676 	SWConfig config(confPath.c_str());
677 	config[mySection][myKey] = myValue;
678 	config.save();
679 
680 	Java_org_crosswire_android_sword_SWMgr_reInit(env, me);
681 
682 }
683 
684 
685 /*
686  * Class:     org_crosswire_android_sword_SWMgr
687  * Method:    addExtraConfig
688  * Signature: (Ljava/lang/String;)[Ljava/lang/String;
689  */
Java_org_crosswire_android_sword_SWMgr_addExtraConfig(JNIEnv * env,jobject me,jstring blob)690 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_addExtraConfig
691 		(JNIEnv *env, jobject me, jstring blob) {
692 
693 	init(env);
694 
695 	const char *b = env->GetStringUTFChars(blob, NULL);
696 
697 	SWBuf myBlob = b;
698 
699 	env->ReleaseStringUTFChars(blob, b);
700 
701 	jobjectArray ret;
702 
703 	int count = 0;
704 	jclass clazzString = env->FindClass("java/lang/String");
705 
706 	SWBuf baseDir = STORAGE_BASE;
707 	SWBuf tmpConfPath = baseDir + "/tmpConfig.conf";
708 	FileMgr::removeFile(tmpConfPath.c_str());
709 	FileDesc *fd = FileMgr::getSystemFileMgr()->open(tmpConfPath.c_str(), FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
710 	fd->getFd();
711 	fd->write(myBlob.c_str(), myBlob.size());
712 	FileMgr::getSystemFileMgr()->close(fd);
713 
714 	SWConfig newConfig(tmpConfPath.c_str());
715 	FileMgr::removeFile(tmpConfPath.c_str());
716 	SectionMap::const_iterator sit;
717 	for (sit = newConfig.getSections().begin(); sit != newConfig.getSections().end(); ++sit) {
718 		count++;
719 	}
720 	ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
721 	count = 0;
722 	for (sit = newConfig.getSections().begin(); sit != newConfig.getSections().end(); ++sit) {
723 		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(sit->first.c_str())));
724 	}
725 
726 	SWBuf confPath = baseDir + "/extraConfig.conf";
727 	SWConfig config(confPath.c_str());
728 	config.augment(newConfig);
729 	config.save();
730 
731 	Java_org_crosswire_android_sword_SWMgr_reInit(env, me);
732 
733 	return ret;
734 }
735 
736 
737 /*
738  * Class:     org_crosswire_android_sword_SWMgr
739  * Method:    getGlobalOptionValues
740  * Signature: (Ljava/lang/String;)[Ljava/lang/String;
741  */
Java_org_crosswire_android_sword_SWMgr_getGlobalOptionValues(JNIEnv * env,jobject me,jstring optionJS)742 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getGlobalOptionValues
743 		(JNIEnv *env, jobject me, jstring optionJS) {
744 
745 	init(env);
746 
747 	const char *option = env->GetStringUTFChars(optionJS, NULL);
748 
749 	sword::StringList options = mgr->getGlobalOptionValues(option);
750 
751 	env->ReleaseStringUTFChars(optionJS, option);
752 
753 	int count = 0;
754 	for (sword::StringList::iterator it = options.begin(); it != options.end(); ++it) {
755 		count++;
756 	}
757 	jclass clazzString = env->FindClass("java/lang/String");
758 	jobjectArray ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
759 
760 	count = 0;
761 	for (sword::StringList::iterator it = options.begin(); it != options.end(); ++it) {
762 		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(*it)));
763 	}
764 
765 	return ret;
766 }
767 
768 
769 /*
770  * Class:     org_crosswire_android_sword_SWMgr
771  * Method:    setCipherKey
772  * Signature: (Ljava/lang/String;Ljava/lang/String;)V
773  */
Java_org_crosswire_android_sword_SWMgr_setCipherKey(JNIEnv * env,jobject me,jstring modNameJS,jstring keyJS)774 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setCipherKey
775 		(JNIEnv *env, jobject me , jstring modNameJS, jstring keyJS) {
776 
777 	init(env);
778 
779 	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
780 	const char *key     = env->GetStringUTFChars(keyJS, NULL);
781 
782 	mgr->setCipherKey(modName, key);
783 
784 	env->ReleaseStringUTFChars(keyJS, key);
785 	env->ReleaseStringUTFChars(modNameJS, modName);
786 }
787 
788 
789 /*
790  * Class:     org_crosswire_android_sword_SWMgr
791  * Method:    setJavascript
792  * Signature: (Z)V
793  */
Java_org_crosswire_android_sword_SWMgr_setJavascript(JNIEnv * env,jobject me,jboolean val)794 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setJavascript
795 		(JNIEnv *env, jobject me, jboolean val) {
796 
797 	init(env);
798 
799 	mgr->setJavascript(val == JNI_TRUE);
800 }
801 
802 
803 /*
804  * Class:     org_crosswire_android_sword_SWMgr
805  * Method:    getAvailableLocales
806  * Signature: ()[Ljava/lang/String;
807  */
Java_org_crosswire_android_sword_SWMgr_getAvailableLocales(JNIEnv * env,jobject me)808 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWMgr_getAvailableLocales
809 		(JNIEnv *env, jobject me) {
810 
811 	init(env);
812 
813 	sword::StringList localeNames = LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
814 	int count = 0;
815 	for (sword::StringList::iterator it = localeNames.begin(); it != localeNames.end(); ++it) {
816 		count++;
817 	}
818 
819 	jclass clazzString = env->FindClass("java/lang/String");
820 	jobjectArray ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
821 
822 	count = 0;
823 	for (sword::StringList::iterator it = localeNames.begin(); it != localeNames.end(); ++it) {
824 		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(*it)));
825 	}
826 	return ret;
827 }
828 
829 
830 /*
831  * Class:     org_crosswire_android_sword_SWMgr
832  * Method:    setDefaultLocale
833  * Signature: (Ljava/lang/String;)V
834  */
Java_org_crosswire_android_sword_SWMgr_setDefaultLocale(JNIEnv * env,jobject me,jstring localeNameJS)835 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_setDefaultLocale
836 		(JNIEnv *env, jobject me, jstring localeNameJS) {
837 
838 	init(env);
839 
840 	const char *localeName = env->GetStringUTFChars(localeNameJS, NULL);
841 
842 	LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName(localeName);
843 
844 	env->ReleaseStringUTFChars(localeNameJS, localeName);
845 }
846 
847 
848 
849 // SWModule methods ----------------------------------------------------------------------------------
850 
851 
getModule(JNIEnv * env,jobject me)852 SWModule *getModule
853 		(JNIEnv *env, jobject me) {
854 
855 	init(env);
856 
857 	SWModule *module = 0;
858 	jclass clazzSWModule = env->FindClass("org/crosswire/android/sword/SWModule");
859 	jfieldID fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;");
860 	jfieldID sourceFieldID = env->GetFieldID(clazzSWModule, "remoteSourceName", "Ljava/lang/String;");
861 	jstring modNameJS = (jstring)env->GetObjectField(me, fieldID);
862 	jstring sourceNameJS = (jstring)env->GetObjectField(me, sourceFieldID);
863 	const char *modName = (modNameJS?env->GetStringUTFChars(modNameJS, NULL):0);
864 	const char *sourceName = (sourceNameJS?env->GetStringUTFChars(sourceNameJS, NULL):0);
865 	if (sourceName && *sourceName) {
866 		initInstall(env);
867 		InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
868 		if (source == installMgr->sources.end()) {
869 			SWMgr *mgr = source->second->getMgr();
870 			module = mgr->getModule(modName);
871 		}
872 	}
873 	else module = mgr->getModule(modName);
874 	if (modName) env->ReleaseStringUTFChars(modNameJS, modName);
875 	if (sourceName) env->ReleaseStringUTFChars(sourceNameJS, sourceName);
876 	return module;
877 }
878 
879 /*
880  * Class:     org_crosswire_android_sword_SWModule
881  * Method:    setKeyText
882  * Signature: (Ljava/lang/String;)V
883  */
Java_org_crosswire_android_sword_SWModule_setKeyText(JNIEnv * env,jobject me,jstring keyTextJS)884 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_setKeyText
885 		(JNIEnv *env, jobject me, jstring keyTextJS) {
886 
887 	init(env);
888 
889 	SWModule *module = getModule(env, me);
890 
891 	if (module) {
892 		const char *keyText = env->GetStringUTFChars(keyTextJS, NULL);
893 SWLog::getSystemLog()->logDebug("setKeyText(%s, %s)", module->getName(), keyText);
894 		sword::SWKey *key = module->getKey();
895 		sword::VerseKey *vkey = SWDYNAMIC_CAST(VerseKey, key);
896 		if (vkey && (*keyText=='+' ||*keyText=='-')) {
897 			if (!stricmp(keyText+1, "book")) {
898 				int newBook = vkey->getBook() + ((*keyText=='+')?1:-1);
899 SWLog::getSystemLog()->logDebug("setting book to %d", newBook);
900 				vkey->setBook(newBook);
901 				env->ReleaseStringUTFChars(keyTextJS, keyText);
902 				return;
903 			}
904 			else if (!stricmp(keyText+1, "chapter")) {
905 				vkey->setChapter(vkey->getChapter() + ((*keyText=='+')?1:-1));
906 				env->ReleaseStringUTFChars(keyTextJS, keyText);
907 				return;
908 			}
909 		}
910 
911 		module->setKey(keyText);
912 		env->ReleaseStringUTFChars(keyTextJS, keyText);
913 	}
914 }
915 
916 
917 /*
918  * Class:     org_crosswire_android_sword_SWModule
919  * Method:    getKeyText
920  * Signature: ()Ljava/lang/String;
921  */
Java_org_crosswire_android_sword_SWModule_getKeyText(JNIEnv * env,jobject me)922 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getKeyText
923 		(JNIEnv *env, jobject me) {
924 
925 	init(env);
926 
927 	SWModule *module = getModule(env, me);
928 
929 	jstring retVal = 0;
930 	if (module) {
931 		retVal = env->NewStringUTF(assureValidUTF8(module->getKeyText()));
932 	}
933 	return retVal;
934 }
935 
936 
937 /*
938  * Class:     org_crosswire_android_sword_SWModule
939  * Method:    getRenderText
940  * Signature: ()Ljava/lang/String;
941  */
Java_org_crosswire_android_sword_SWModule_getRenderText(JNIEnv * env,jobject me)942 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getRenderText
943 		(JNIEnv *env, jobject me) {
944 
945 	init(env);
946 
947 	SWModule *module = getModule(env, me);
948 
949 	jstring retVal = 0;
950 	if (module) {
951 		retVal = env->NewStringUTF(assureValidUTF8(module->renderText()));
952 	}
953 	return retVal;
954 }
955 
956 
957 /*
958  * Class:     org_crosswire_android_sword_SWModule
959  * Method:    getRenderHeader
960  * Signature: ()Ljava/lang/String;
961  */
Java_org_crosswire_android_sword_SWModule_getRenderHeader(JNIEnv * env,jobject me)962 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getRenderHeader
963 		(JNIEnv *env, jobject me) {
964 
965 	init(env);
966 
967 	SWModule *module = getModule(env, me);
968 
969 	jstring retVal = 0;
970 	if (module) {
971 		retVal = env->NewStringUTF(assureValidUTF8(((const char *)(module->getRenderHeader() ? module->getRenderHeader():""))));
972 	}
973 	return retVal;
974 }
975 
976 
977 /*
978  * Class:     org_crosswire_android_sword_SWModule
979  * Method:    terminateSearch
980  * Signature: ()V
981  */
Java_org_crosswire_android_sword_SWModule_terminateSearch(JNIEnv * env,jobject me)982 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_terminateSearch
983 		(JNIEnv *env, jobject me) {
984 
985 	init(env);
986 
987 	SWModule *module = getModule(env, me);
988 
989 	if (module) {
990 		module->terminateSearch = true;
991 	}
992 }
993 
994 
995 /*
996  * Class:     org_crosswire_android_sword_SWModule
997  * Method:    error
998  * Signature: ()C
999  */
Java_org_crosswire_android_sword_SWModule_error(JNIEnv * env,jobject me)1000 JNIEXPORT jchar JNICALL Java_org_crosswire_android_sword_SWModule_error
1001 		(JNIEnv *env, jobject me) {
1002 
1003 	init(env);
1004 
1005 	SWModule *module = getModule(env, me);
1006 
1007 	int error = (module) ? module->popError() : -99;
1008 	return error;
1009 }
1010 
1011 
1012 /*
1013  * Class:     org_crosswire_android_sword_SWModule
1014  * Method:    getEntrySize
1015  * Signature: ()J
1016  */
Java_org_crosswire_android_sword_SWModule_getEntrySize(JNIEnv * env,jobject me)1017 JNIEXPORT jlong JNICALL Java_org_crosswire_android_sword_SWModule_getEntrySize
1018 		(JNIEnv *env, jobject me) {
1019 
1020 	init(env);
1021 
1022 	SWModule *module = getModule(env, me);
1023 
1024 	return (module) ? module->getEntrySize() : 0;
1025 }
1026 
1027 
1028 /*
1029  * Class:     org_crosswire_android_sword_SWModule
1030  * Method:    getEntryAttribute
1031  * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)[Ljava/lang/String;
1032  */
Java_org_crosswire_android_sword_SWModule_getEntryAttribute(JNIEnv * env,jobject me,jstring level1JS,jstring level2JS,jstring level3JS,jboolean filteredJS)1033 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_getEntryAttribute
1034 		(JNIEnv *env, jobject me, jstring level1JS, jstring level2JS, jstring level3JS, jboolean filteredJS) {
1035 
1036 	init(env);
1037 
1038 	const char *level1 = env->GetStringUTFChars(level1JS, NULL);
1039 	const char *level2 = env->GetStringUTFChars(level2JS, NULL);
1040 	const char *level3 = env->GetStringUTFChars(level3JS, NULL);
1041 	bool filtered = (filteredJS == JNI_TRUE);
1042 
1043 	jclass clazzString = env->FindClass("java/lang/String");
1044 	jobjectArray ret = 0;
1045 
1046 	SWModule *module = getModule(env, me);
1047 
1048 	if (module) {
1049 
1050 		module->renderText();	// force parse
1051 		vector<SWBuf> results;
1052 
1053 		sword::AttributeTypeList &entryAttribs = module->getEntryAttributes();
1054 		sword::AttributeTypeList::iterator i1Start, i1End;
1055 		sword::AttributeList::iterator i2Start, i2End;
1056 		sword::AttributeValue::iterator i3Start, i3End;
1057 
1058 		if ((level1) && (*level1) && *level1 != '-') {
1059 			i1Start = entryAttribs.find(level1);
1060 			i1End = i1Start;
1061 			if (i1End != entryAttribs.end())
1062 				++i1End;
1063 		}
1064 		else {
1065 			i1Start = entryAttribs.begin();
1066 			i1End   = entryAttribs.end();
1067 		}
1068 		for (;i1Start != i1End; ++i1Start) {
1069 			if (level1 && *level1 && *level1 == '-') {
1070 				results.push_back(i1Start->first);
1071 			}
1072 			else {
1073 				if (level2 && *level2 && *level2 != '-') {
1074 					i2Start = i1Start->second.find(level2);
1075 					i2End = i2Start;
1076 					if (i2End != i1Start->second.end())
1077 						++i2End;
1078 				}
1079 				else {
1080 					i2Start = i1Start->second.begin();
1081 					i2End   = i1Start->second.end();
1082 				}
1083 				for (;i2Start != i2End; ++i2Start) {
1084 					if (level2 && *level2 && *level2 == '-') {
1085 						results.push_back(i2Start->first);
1086 					}
1087 					else {
1088 						// allow '-' to get all keys; allow '*' to get all key=value
1089 						if (level3 && *level3 && *level3 != '-' && *level3 != '*') {
1090 							i3Start = i2Start->second.find(level3);
1091 							i3End = i3Start;
1092 							if (i3End != i2Start->second.end())
1093 								++i3End;
1094 						}
1095 						else {
1096 							i3Start = i2Start->second.begin();
1097 							i3End   = i2Start->second.end();
1098 						}
1099 						for (;i3Start != i3End; ++i3Start) {
1100 							if (level3 && *level3 && *level3 == '-') {
1101 								results.push_back(i3Start->first);
1102 							}
1103 							else if (level3 && *level3 && *level3 == '*') {
1104 								results.push_back(i3Start->first + "=" + i3Start->second);
1105 							}
1106 							else {
1107 								results.push_back(i3Start->second);
1108 							}
1109 						}
1110 						if (i3Start != i3End)
1111 							break;
1112 					}
1113 				}
1114 				if (i2Start != i2End)
1115 					break;
1116 			}
1117 		}
1118 
1119 		ret = (jobjectArray) env->NewObjectArray(results.size(), clazzString, NULL);
1120 
1121 SWLog::getSystemLog()->logDebug("getEntryAttributes: size returned: %d", results.size());
1122 
1123 		for (int i = 0; i < results.size(); i++) {
1124 			if (filtered) {
1125 				env->SetObjectArrayElement(ret, i, env->NewStringUTF(assureValidUTF8(module->renderText(results[i].c_str()))));
1126 			}
1127 			else {
1128 				env->SetObjectArrayElement(ret, i, env->NewStringUTF(assureValidUTF8(results[i].c_str())));
1129 			}
1130 		}
1131 	}
1132 
1133 	env->ReleaseStringUTFChars(level3JS, level3);
1134 	env->ReleaseStringUTFChars(level2JS, level2);
1135 	env->ReleaseStringUTFChars(level1JS, level1);
1136 
1137 	return (ret) ? ret : (jobjectArray) env->NewObjectArray(0, clazzString, NULL);
1138 }
1139 
1140 
1141 /*
1142  * Class:     org_crosswire_android_sword_SWModule
1143  * Method:    parseKeyList
1144  * Signature: (Ljava/lang/String;)[Ljava/lang/String;
1145  */
Java_org_crosswire_android_sword_SWModule_parseKeyList(JNIEnv * env,jobject me,jstring keyListTextJS)1146 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_parseKeyList
1147 		(JNIEnv *env, jobject me, jstring keyListTextJS) {
1148 
1149 	init(env);
1150 
1151 	const char *keyListText = env->GetStringUTFChars(keyListTextJS, NULL);
1152 
1153 	SWModule *module = getModule(env, me);
1154 	jclass clazzString = env->FindClass("java/lang/String");
1155 	jobjectArray ret;
1156 
1157 	if (module) {
1158 		sword::SWKey *k = module->getKey();
1159 		sword::VerseKey *parser = SWDYNAMIC_CAST(VerseKey, k);
1160 		if (parser) {
1161 			sword::ListKey result;
1162 			result = parser->parseVerseList(keyListText, *parser, true);
1163 			int count = 0;
1164 			for (result = sword::TOP; !result.popError(); result++) {
1165 				count++;
1166 			}
1167 			ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
1168 
1169 			count = 0;
1170 			for (result = sword::TOP; !result.popError(); result++) {
1171 				env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8((const char *)result)));
1172 			}
1173 		}
1174 		else	{
1175 			ret = (jobjectArray) env->NewObjectArray(1, clazzString, NULL);
1176 			env->SetObjectArrayElement(ret, 0, env->NewStringUTF(assureValidUTF8(keyListText)));
1177 		}
1178 	}
1179 
1180 	env->ReleaseStringUTFChars(keyListTextJS, keyListText);
1181 
1182 	return ret;
1183 }
1184 
1185 
1186 /*
1187  * Class:     org_crosswire_android_sword_SWModule
1188  * Method:    hasKeyChildren
1189  * Signature: ()Z
1190  */
Java_org_crosswire_android_sword_SWModule_hasKeyChildren(JNIEnv * env,jobject me)1191 JNIEXPORT jboolean JNICALL Java_org_crosswire_android_sword_SWModule_hasKeyChildren
1192 		(JNIEnv *env, jobject me) {
1193 
1194 	init(env);
1195 
1196 
1197 	SWModule *module = getModule(env, me);
1198 	jboolean retVal = JNI_FALSE;
1199 
1200 	if (module) {
1201 		sword::SWKey *key = module->getKey();
1202 
1203 		TreeKeyIdx *tkey = SWDYNAMIC_CAST(TreeKeyIdx, key);
1204 		if (tkey) {
1205 			retVal = (tkey->hasChildren())?JNI_TRUE:JNI_FALSE;
1206 		}
1207 	}
1208 	return retVal;
1209 }
1210 
1211 /*
1212  * Class:     org_crosswire_android_sword_SWModule
1213  * Method:    getKeyChildren
1214  * Signature: ()[Ljava/lang/String;
1215  */
Java_org_crosswire_android_sword_SWModule_getKeyChildren(JNIEnv * env,jobject me)1216 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_getKeyChildren
1217 		(JNIEnv *env, jobject me) {
1218 
1219 	init(env);
1220 
1221 
1222 	jclass clazzString = env->FindClass("java/lang/String");
1223 	jobjectArray ret;
1224 
1225 	SWModule *module = getModule(env, me);
1226 
1227 	if (module) {
1228 		sword::SWKey *key = module->getKey();
1229 		int count = 0;
1230 
1231 		sword::VerseKey *vkey = SWDYNAMIC_CAST(VerseKey, key);
1232 		if (vkey) {
1233 			ret = (jobjectArray) env->NewObjectArray(10, clazzString, NULL);
1234 			SWBuf num;
1235 			num.appendFormatted("%d", vkey->getTestament());
1236 			env->SetObjectArrayElement(ret, 0, env->NewStringUTF(assureValidUTF8(num.c_str())));
1237 			num = "";
1238 			num.appendFormatted("%d", vkey->getBook());
1239 			env->SetObjectArrayElement(ret, 1, env->NewStringUTF(assureValidUTF8(num.c_str())));
1240 			num = "";
1241 			num.appendFormatted("%d", vkey->getChapter());
1242 			env->SetObjectArrayElement(ret, 2, env->NewStringUTF(assureValidUTF8(num.c_str())));
1243 			num = "";
1244 			num.appendFormatted("%d", vkey->getVerse());
1245 			env->SetObjectArrayElement(ret, 3, env->NewStringUTF(assureValidUTF8(num.c_str())));
1246 			num = "";
1247 			num.appendFormatted("%d", vkey->getChapterMax());
1248 			env->SetObjectArrayElement(ret, 4, env->NewStringUTF(assureValidUTF8(num.c_str())));
1249 			num = "";
1250 			num.appendFormatted("%d", vkey->getVerseMax());
1251 			env->SetObjectArrayElement(ret, 5, env->NewStringUTF(assureValidUTF8(num.c_str())));
1252 			env->SetObjectArrayElement(ret, 6, env->NewStringUTF(assureValidUTF8(vkey->getBookName())));
1253 			env->SetObjectArrayElement(ret, 7, env->NewStringUTF(assureValidUTF8(vkey->getOSISRef())));
1254 			env->SetObjectArrayElement(ret, 8, env->NewStringUTF(assureValidUTF8(vkey->getShortText())));
1255 			env->SetObjectArrayElement(ret, 9, env->NewStringUTF(assureValidUTF8(vkey->getBookAbbrev())));
1256 		}
1257 		else {
1258 			TreeKeyIdx *tkey = SWDYNAMIC_CAST(TreeKeyIdx, key);
1259 			if (tkey) {
1260 				if (tkey->firstChild()) {
1261 					do {
1262 						count++;
1263 					}
1264 					while (tkey->nextSibling());
1265 					tkey->parent();
1266 				}
1267 				ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
1268 				count = 0;
1269 				if (tkey->firstChild()) {
1270 					do {
1271 						env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(tkey->getLocalName())));
1272 					}
1273 					while (tkey->nextSibling());
1274 					tkey->parent();
1275 				}
1276 			}
1277 		}
1278 	}
1279 	return ret;
1280 }
1281 
1282 
1283 /*
1284  * Class:     org_crosswire_android_sword_SWModule
1285  * Method:    getKeyParent
1286  * Signature: ()Ljava/lang/String;
1287  */
Java_org_crosswire_android_sword_SWModule_getKeyParent(JNIEnv * env,jobject me)1288 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getKeyParent
1289 		(JNIEnv *env, jobject me) {
1290 
1291 	init(env);
1292 
1293 
1294 	SWBuf retVal = "";
1295 
1296 	SWModule *module = getModule(env, me);
1297 
1298 	if (module) {
1299 
1300 		sword::SWKey *key = module->getKey();
1301 
1302 		TreeKeyIdx *tkey = SWDYNAMIC_CAST(TreeKeyIdx, key);
1303 		if (tkey) {
1304 			if (tkey->parent()) {
1305 				retVal = tkey->getText();
1306 			}
1307 		}
1308 	}
1309 	return env->NewStringUTF(assureValidUTF8(retVal));
1310 }
1311 
1312 
1313 /*
1314  * Class:     org_crosswire_android_sword_SWModule
1315  * Method:    previous
1316  * Signature: ()V
1317  */
Java_org_crosswire_android_sword_SWModule_previous(JNIEnv * env,jobject me)1318 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_previous
1319 		(JNIEnv *env, jobject me) {
1320 
1321 	init(env);
1322 
1323 
1324 	SWModule *module = getModule(env, me);
1325 
1326 	if (module) {
1327 		module->decrement();
1328 	}
1329 }
1330 
1331 
1332 /*
1333  * Class:     org_crosswire_android_sword_SWModule
1334  * Method:    next
1335  * Signature: ()V
1336  */
Java_org_crosswire_android_sword_SWModule_next(JNIEnv * env,jobject me)1337 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_next
1338 		(JNIEnv *env, jobject me) {
1339 
1340 	init(env);
1341 
1342 
1343 	SWModule *module = getModule(env, me);
1344 
1345 	if (module) {
1346 		module->increment();
1347 	}
1348 }
1349 
1350 
1351 /*
1352  * Class:     org_crosswire_android_sword_SWModule
1353  * Method:    begin
1354  * Signature: ()V
1355  */
Java_org_crosswire_android_sword_SWModule_begin(JNIEnv * env,jobject me)1356 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_begin
1357 		(JNIEnv *env, jobject me) {
1358 
1359 	init(env);
1360 
1361 
1362 	SWModule *module = getModule(env, me);
1363 
1364 	if (module) {
1365 		module->setPosition(sword::TOP);
1366 	}
1367 }
1368 
1369 
1370 /*
1371  * Class:     org_crosswire_android_sword_SWModule
1372  * Method:    getStripText
1373  * Signature: ()Ljava/lang/String;
1374  */
Java_org_crosswire_android_sword_SWModule_getStripText(JNIEnv * env,jobject me)1375 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getStripText
1376 		(JNIEnv *env, jobject me) {
1377 
1378 	init(env);
1379 
1380 
1381 	SWBuf retVal = "";
1382 
1383 	SWModule *module = getModule(env, me);
1384 
1385 	if (module) {
1386 		retVal = module->stripText();
1387 	}
1388 
1389 	return env->NewStringUTF(assureValidUTF8(retVal));
1390 }
1391 
1392 
1393 /*
1394  * Class:     org_crosswire_android_sword_SWModule
1395  * Method:    getRawEntry
1396  * Signature: ()Ljava/lang/String;
1397  */
Java_org_crosswire_android_sword_SWModule_getRawEntry(JNIEnv * env,jobject me)1398 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getRawEntry
1399 		(JNIEnv *env, jobject me) {
1400 
1401 	init(env);
1402 
1403 
1404 	SWBuf retVal = "";
1405 
1406 	SWModule *module = getModule(env, me);
1407 
1408 	if (module) {
1409 		retVal = module->getRawEntry();
1410 	}
1411 
1412 	return env->NewStringUTF(assureValidUTF8(retVal));
1413 }
1414 
1415 
1416 /*
1417  * Class:     org_crosswire_android_sword_SWModule
1418  * Method:    setRawEntry
1419  * Signature: (Ljava/lang/String;)V
1420  */
Java_org_crosswire_android_sword_SWModule_setRawEntry(JNIEnv * env,jobject me,jstring newEntryTextJS)1421 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_setRawEntry
1422 		(JNIEnv *env, jobject me, jstring newEntryTextJS) {
1423 
1424 	init(env);
1425 
1426 
1427 	const char *newEntryText = env->GetStringUTFChars(newEntryTextJS, NULL);
1428 
1429 	SWModule *module = getModule(env, me);
1430 
1431 	if (module) {
1432 		module->setEntry(newEntryText);
1433 	}
1434 
1435 	env->ReleaseStringUTFChars(newEntryTextJS, newEntryText);
1436 }
1437 
1438 
1439 /*
1440  * Class:     org_crosswire_android_sword_SWModule
1441  * Method:    getConfigEntry
1442  * Signature: (Ljava/lang/String;)Ljava/lang/String;
1443  */
Java_org_crosswire_android_sword_SWModule_getConfigEntry(JNIEnv * env,jobject me,jstring configKeyJS)1444 JNIEXPORT jstring JNICALL Java_org_crosswire_android_sword_SWModule_getConfigEntry
1445 		(JNIEnv *env, jobject me, jstring configKeyJS) {
1446 
1447 	init(env);
1448 
1449 
1450 	jstring retVal = 0;
1451 
1452 	const char *configKey = env->GetStringUTFChars(configKeyJS, NULL);
1453 SWLog::getSystemLog()->logDebug("getConfigEntry(%s)\n", configKey);
1454 
1455 	SWModule *module = getModule(env, me);
1456 
1457 	if (module) {
1458 		SWBuf confValue = module->getConfigEntry(configKey);
1459 		// special processing if we're requesting About-- kindof cheese
1460 		if (!strcmp("About", configKey)) {
1461 			RTFHTML().processText(confValue);
1462 		}
1463 		SWBuf assuredBuf = assureValidUTF8(confValue.c_str());
1464 		retVal = env->NewStringUTF(assuredBuf.c_str());
1465 	}
1466 
1467 	env->ReleaseStringUTFChars(configKeyJS, configKey);
1468 
1469 	return retVal;
1470 }
1471 
1472 
1473 /*
1474  * Class:     org_crosswire_android_sword_SWModule
1475  * Method:    deleteSearchFramework
1476  * Signature: ()V
1477  */
Java_org_crosswire_android_sword_SWModule_deleteSearchFramework(JNIEnv * env,jobject me)1478 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWModule_deleteSearchFramework
1479 		(JNIEnv *env, jobject me) {
1480 
1481 	init(env);
1482 
1483 
1484 	SWModule *module = getModule(env, me);
1485 
1486 	if (module) {
1487 		module->deleteSearchFramework();
1488 	}
1489 }
1490 
1491 
1492 /*
1493  * Class:     org_crosswire_android_sword_SWModule
1494  * Method:    hasSearchFramework
1495  * Signature: ()Z
1496  */
Java_org_crosswire_android_sword_SWModule_hasSearchFramework(JNIEnv * env,jobject me)1497 JNIEXPORT jboolean JNICALL Java_org_crosswire_android_sword_SWModule_hasSearchFramework
1498 		(JNIEnv *env, jobject me) {
1499 
1500 	init(env);
1501 
1502 
1503 	SWModule *module = getModule(env, me);
1504 
1505 	return (module && module->hasSearchFramework()) ? JNI_TRUE : JNI_FALSE;
1506 }
1507 
1508 
1509 struct pu {
pupu1510 	pu(JNIEnv *env, jobject pr) : env(env), progressReporter(pr), last(0) {}
1511 	JNIEnv *env;
1512 	jobject progressReporter;
1513 	char last;
1514 };
1515 
1516 
percentUpdate(char percent,void * userData)1517 void percentUpdate(char percent, void *userData) {
1518 	struct pu *p = (struct pu *)userData;
1519 
1520 	// assert we've actually been given a progressReporter
1521 	if (!p->progressReporter) return;
1522 
1523 	if (percent != p->last) {
1524 		p->last = percent;
1525 		jclass cls = p->env->GetObjectClass(p->progressReporter);
1526 		jmethodID mid = p->env->GetMethodID(cls, "progressReport", "(I)V");
1527 		if (mid != 0) {
1528 			p->env->CallVoidMethod(p->progressReporter, mid, (jint)percent);
1529 		}
1530 		p->env->DeleteLocalRef(cls);
1531 	}
1532 }
1533 
1534 
1535 /*
1536  * Class:     org_crosswire_android_sword_SWModule
1537  * Method:    search
1538  * Signature: (Ljava/lang/String;IJLjava/lang/String;Lorg/crosswire/android/sword/SWModule/SearchProgressReporter;)[Lorg/crosswire/android/sword/SWModule/SearchHit;
1539  */
Java_org_crosswire_android_sword_SWModule_search(JNIEnv * env,jobject me,jstring expressionJS,jint srchType,jlong flags,jstring scopeJS,jobject progressReporter)1540 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_SWModule_search
1541 		(JNIEnv *env, jobject me, jstring expressionJS, jint srchType, jlong flags, jstring scopeJS, jobject progressReporter) {
1542 
1543 	init(env);
1544 
1545 	const int MAX_RETURN_COUNT = 999999;
1546 
1547 	const char *expression = env->GetStringUTFChars(expressionJS, NULL);
1548 	const char *scope = scopeJS ? env->GetStringUTFChars(scopeJS, NULL) : 0;
1549 
1550 	jclass clazzSearchHit = env->FindClass("org/crosswire/android/sword/SWModule$SearchHit");
1551 	jobjectArray ret = 0;
1552 
1553 	SWModule *module = getModule(env, me);
1554 
1555 	// TODO: remove this from the stack
1556 	pu *peeuuu = new pu(env, progressReporter);
1557 
1558 	if (module) {
1559 		sword::ListKey lscope;
1560 		sword::ListKey result;
1561 
1562 		if ((scope) && (strlen(scope)) > 0) {
1563 			sword::SWKey *p = module->createKey();
1564 			sword::VerseKey *parser = SWDYNAMIC_CAST(VerseKey, p);
1565 			if (!parser) {
1566 				delete p;
1567 				parser = new VerseKey();
1568 			}
1569 			*parser = module->getKeyText();
1570 			lscope = parser->parseVerseList(scope, *parser, true);
1571 			result = module->search(expression, srchType, flags, &lscope, 0, &percentUpdate, peeuuu);
1572 			delete parser;
1573 		}
1574 		else	result = module->search(expression, srchType, flags, 0, 0, &percentUpdate, peeuuu);
1575 
1576 		delete peeuuu;
1577 
1578 		int count = 0;
1579 		for (result = sword::TOP; !result.popError(); result++) count++;
1580 
1581 		if (count > MAX_RETURN_COUNT) count = MAX_RETURN_COUNT;
1582 
1583 		ret = (jobjectArray) env->NewObjectArray(count, clazzSearchHit, NULL);
1584 
1585 		// if we're sorted by score, let's re-sort by verse, because Java can always re-sort by score
1586 		result = sword::TOP;
1587 		if ((count) && (long)result.getElement()->userData)
1588 			result.sort();
1589 
1590 		int i = 0;
1591 		jstring modName = env->NewStringUTF(assureValidUTF8(module->getName()));
1592 		jfieldID fieldIDModName = env->GetFieldID(clazzSearchHit, "modName", "Ljava/lang/String;");
1593 		jfieldID fieldIDKey     = env->GetFieldID(clazzSearchHit, "key"    , "Ljava/lang/String;");
1594 		jfieldID fieldIDScore   = env->GetFieldID(clazzSearchHit, "score"  , "J");
1595 		for (result = sword::TOP; !result.popError(); result++) {
1596 			jfieldID fieldID;
1597 			jobject searchHit = env->AllocObject(clazzSearchHit);
1598 
1599 			env->SetObjectField(searchHit, fieldIDModName, modName);
1600 			jstring key = env->NewStringUTF(assureValidUTF8((const char *)result));
1601 			env->SetObjectField(searchHit, fieldIDKey, key);
1602 			env->DeleteLocalRef(key);
1603 			env->SetLongField(searchHit, fieldIDScore, (long)result.getElement()->userData);
1604 
1605 			env->SetObjectArrayElement(ret, i++, searchHit);
1606 			env->DeleteLocalRef(searchHit);
1607 			if (i >= MAX_RETURN_COUNT) break;
1608 		}
1609 		env->DeleteLocalRef(modName);
1610 	}
1611 
1612 	if (scope) env->ReleaseStringUTFChars(scopeJS, scope);
1613 	env->ReleaseStringUTFChars(expressionJS, expression);
1614 
1615 	return (ret) ? ret : (jobjectArray) env->NewObjectArray(0, clazzSearchHit, NULL);
1616 }
1617 
1618 
1619 
1620 // InstallMgr methods ----------------------------------------------------------------------------------
1621 
1622 
1623 /*
1624  * Class:     org_crosswire_android_sword_InstallMgr
1625  * Method:    reInit
1626  * Signature: ()V
1627  */
Java_org_crosswire_android_sword_InstallMgr_reInit(JNIEnv * env,jobject me)1628 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_InstallMgr_reInit
1629 		(JNIEnv *env, jobject me) {
1630 
1631 	delete installMgr;
1632 	installMgr = 0;
1633 }
1634 
1635 
1636 /*
1637  * Class:     org_crosswire_android_sword_InstallMgr
1638  * Method:    syncConfig
1639  * Signature: ()I
1640  */
Java_org_crosswire_android_sword_InstallMgr_syncConfig(JNIEnv * env,jobject me)1641 JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_syncConfig
1642 		(JNIEnv *env, jobject me) {
1643 
1644 	initInstall(env);
1645 
1646 	return installMgr->refreshRemoteSourceConfiguration();
1647 }
1648 
1649 
1650 /*
1651  * Class:     org_crosswire_android_sword_InstallMgr
1652  * Method:    uninstallModule
1653  * Signature: (Ljava/lang/String;)I
1654  */
Java_org_crosswire_android_sword_InstallMgr_uninstallModule(JNIEnv * env,jobject me,jstring modNameJS)1655 JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_uninstallModule
1656 		(JNIEnv *env, jobject me, jstring modNameJS) {
1657 
1658 	init(env);
1659 	initInstall(env);
1660 
1661 	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
1662 
1663 SWLog::getSystemLog()->logDebug("uninstallModule %s\n", modName);
1664 
1665 	SWModule *module;
1666 	ModMap::iterator it = mgr->Modules.find(modName);
1667 	if (it == mgr->Modules.end()) {
1668 		return -2;
1669 	}
1670 	module = it->second;
1671 	int retVal = installMgr->removeModule(mgr, module->getName());
1672 
1673 	env->ReleaseStringUTFChars(modNameJS, modName);
1674 
1675 	return retVal;
1676 }
1677 
1678 
1679 /*
1680  * Class:     org_crosswire_android_sword_InstallMgr
1681  * Method:    getRemoteSources
1682  * Signature: ()[Ljava/lang/String;
1683  */
Java_org_crosswire_android_sword_InstallMgr_getRemoteSources(JNIEnv * env,jobject me)1684 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteSources
1685 		(JNIEnv *env, jobject me) {
1686 
1687 	initInstall(env);
1688 
1689 	jclass clazzString = env->FindClass("java/lang/String");
1690 	jobjectArray ret;
1691 
1692 	int count = 0;
1693 	for (InstallSourceMap::iterator it = installMgr->sources.begin(); it != installMgr->sources.end(); ++it) {
1694 		count++;
1695 	}
1696 SWLog::getSystemLog()->logDebug("getRemoteSources: count: %d\n", count);
1697 	ret = (jobjectArray) env->NewObjectArray(count, clazzString, NULL);
1698 	count = 0;
1699 	for (InstallSourceMap::iterator it = installMgr->sources.begin(); it != installMgr->sources.end(); ++it) {
1700 		env->SetObjectArrayElement(ret, count++, env->NewStringUTF(assureValidUTF8(it->second->caption.c_str())));
1701 	}
1702 
1703 	return ret;
1704 }
1705 
1706 
1707 /*
1708  * Class:     org_crosswire_android_sword_InstallMgr
1709  * Method:    refreshRemoteSource
1710  * Signature: (Ljava/lang/String;)I
1711  */
Java_org_crosswire_android_sword_InstallMgr_refreshRemoteSource(JNIEnv * env,jobject me,jstring sourceNameJS)1712 JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_refreshRemoteSource
1713 		(JNIEnv *env, jobject me, jstring sourceNameJS) {
1714 
1715 	initInstall(env);
1716 
1717 	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
1718 
1719 	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
1720 	if (source == installMgr->sources.end()) {
1721 		return -3;
1722 	}
1723 
1724 	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
1725 
1726 	return installMgr->refreshRemoteSource(source->second);
1727 }
1728 
1729 
1730 /*
1731  * Class:     org_crosswire_android_sword_InstallMgr
1732  * Method:    getRemoteModInfoList
1733  * Signature: (Ljava/lang/String;)[Lorg/crosswire/android/sword/SWMgr/ModInfo;
1734  */
Java_org_crosswire_android_sword_InstallMgr_getRemoteModInfoList(JNIEnv * env,jobject me,jstring sourceNameJS)1735 JNIEXPORT jobjectArray JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteModInfoList
1736 		(JNIEnv *env, jobject me, jstring sourceNameJS) {
1737 
1738 SWLog::getSystemLog()->logDebug("getRemoteModInfoList\n");
1739 	init(env);
1740 	initInstall(env);
1741 
1742 	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
1743 SWLog::getSystemLog()->logDebug("sourceName: %s\n", sourceName);
1744 
1745 	jclass clazzModInfo = env->FindClass("org/crosswire/android/sword/SWMgr$ModInfo");
1746 	jfieldID nameID     = env->GetFieldID(clazzModInfo, "name",        "Ljava/lang/String;");
1747 	jfieldID descID     = env->GetFieldID(clazzModInfo, "description", "Ljava/lang/String;");
1748 	jfieldID catID      = env->GetFieldID(clazzModInfo, "category",    "Ljava/lang/String;");
1749 	jfieldID langID     = env->GetFieldID(clazzModInfo, "language",    "Ljava/lang/String;");
1750 	jfieldID versionID  = env->GetFieldID(clazzModInfo, "version",     "Ljava/lang/String;");
1751 	jfieldID deltaID    = env->GetFieldID(clazzModInfo, "delta",       "Ljava/lang/String;");
1752 
1753 	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
1754 	if (source == installMgr->sources.end()) {
1755 SWLog::getSystemLog()->logDebug("remoteListModules returning 0 length array\n");
1756 		return (jobjectArray) env->NewObjectArray(0, clazzModInfo, NULL);
1757 	}
1758 SWLog::getSystemLog()->logDebug("found source: %s\n", sourceName);
1759 
1760 	map<SWModule *, int> modStats = installMgr->getModuleStatus(*mgr, *source->second->getMgr());
1761 
1762 	int size = 0;
1763 	for (map<SWModule *, int>::iterator it = modStats.begin(); it != modStats.end(); ++it) {
1764 		size++;
1765 	}
1766 
1767 SWLog::getSystemLog()->logDebug("remoteListModules returning %d length array\n", size);
1768 	jobjectArray ret = (jobjectArray) env->NewObjectArray(size, clazzModInfo, NULL);
1769 
1770 	int i = 0;
1771 	for (map<SWModule *, int>::iterator it = modStats.begin(); it != modStats.end(); ++it) {
1772 		SWModule *module = it->first;
1773 		int status = it->second;
1774 
1775 		SWBuf version = module->getConfigEntry("Version");
1776 		SWBuf statusString = " ";
1777 		if (status & InstallMgr::MODSTAT_NEW) statusString = "*";
1778 		if (status & InstallMgr::MODSTAT_OLDER) statusString = "-";
1779 		if (status & InstallMgr::MODSTAT_UPDATED) statusString = "+";
1780 
1781 		SWBuf type = module->getType();
1782 		SWBuf cat = module->getConfigEntry("Category");
1783 		if (cat.length() > 0) type = cat;
1784 		jobject modInfo = env->AllocObject(clazzModInfo);
1785 
1786 		jstring val;
1787 		val = env->NewStringUTF(assureValidUTF8(module->getName()));        env->SetObjectField(modInfo, nameID   , val); env->DeleteLocalRef(val);
1788 		val = env->NewStringUTF(assureValidUTF8(module->getDescription())); env->SetObjectField(modInfo, descID   , val); env->DeleteLocalRef(val);
1789 		val = env->NewStringUTF(assureValidUTF8(type.c_str()));          env->SetObjectField(modInfo, catID    , val); env->DeleteLocalRef(val);
1790 		val = env->NewStringUTF(assureValidUTF8(module->getLanguage()));        env->SetObjectField(modInfo, langID   , val); env->DeleteLocalRef(val);
1791 		val = env->NewStringUTF(assureValidUTF8(version.c_str()));       env->SetObjectField(modInfo, versionID, val); env->DeleteLocalRef(val);
1792 		val = env->NewStringUTF(assureValidUTF8(statusString.c_str()));  env->SetObjectField(modInfo, deltaID  , val); env->DeleteLocalRef(val);
1793 
1794 		env->SetObjectArrayElement(ret, i++, modInfo);
1795 
1796 		env->DeleteLocalRef(modInfo);
1797 	}
1798 
1799 	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
1800 
1801 	return ret;
1802 }
1803 
1804 /*
1805  * Class:     org_crosswire_android_sword_InstallMgr
1806  * Method:    remoteInstallModule
1807  * Signature: (Ljava/lang/String;Ljava/lang/String;)I
1808  */
Java_org_crosswire_android_sword_InstallMgr_remoteInstallModule(JNIEnv * env,jobject me,jstring sourceNameJS,jstring modNameJS,jobject progressReporter)1809 JNIEXPORT jint JNICALL Java_org_crosswire_android_sword_InstallMgr_remoteInstallModule
1810 		(JNIEnv *env, jobject me, jstring sourceNameJS, jstring modNameJS, jobject progressReporter) {
1811 
1812 	init(env);
1813 	initInstall(env, progressReporter);
1814 
1815 	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
1816 SWLog::getSystemLog()->logDebug("remoteInstallModule: sourceName: %s\n", sourceName);
1817 	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
1818 	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
1819 
1820 	if (source == installMgr->sources.end()) {
1821 		return -3;
1822 	}
1823 
1824 	InstallSource *is = source->second;
1825 	SWMgr *rmgr = is->getMgr();
1826 	SWModule *module;
1827 
1828 	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
1829 SWLog::getSystemLog()->logDebug("remoteInstallModule: modName: %s\n", modName);
1830 	ModMap::iterator it = rmgr->Modules.find(modName);
1831 	env->ReleaseStringUTFChars(modNameJS, modName);
1832 
1833 	if (it == rmgr->Modules.end()) {
1834 		return -4;
1835 	}
1836 
1837 	module = it->second;
1838 
1839 	int error = installMgr->installModule(mgr, 0, module->getName(), is);
1840 
1841 	if (progressReporter) {
1842 		jclass cls = env->GetObjectClass(progressReporter);
1843 		jmethodID mid = env->GetMethodID(cls, "preStatus", "(JJLjava/lang/String;)V");
1844 		if (mid != 0) {
1845 			jstring msg = env->NewStringUTF("Complete");
1846 			env->CallVoidMethod(progressReporter, mid, (jlong)0, (jlong)0, msg);
1847 			env->DeleteLocalRef(msg);
1848 		}
1849 		env->DeleteLocalRef(cls);
1850 	}
1851 
1852 	return error;
1853 }
1854 
1855 
1856 /*
1857  * Class:     org_crosswire_android_sword_InstallMgr
1858  * Method:    getRemoteModuleByName
1859  * Signature: (Ljava/lang/String;Ljava/lang/String;)Lorg/crosswire/android/sword/SWModule;
1860  */
Java_org_crosswire_android_sword_InstallMgr_getRemoteModuleByName(JNIEnv * env,jobject me,jstring sourceNameJS,jstring modNameJS)1861 JNIEXPORT jobject JNICALL Java_org_crosswire_android_sword_InstallMgr_getRemoteModuleByName
1862 		(JNIEnv *env, jobject me, jstring sourceNameJS, jstring modNameJS) {
1863 
1864 	jobject retVal = 0;
1865 
1866 	initInstall(env);
1867 
1868 	const char *sourceName = env->GetStringUTFChars(sourceNameJS, NULL);
1869 SWLog::getSystemLog()->logDebug("getRemoteModuleByName: sourceName: %s\n", sourceName);
1870 	InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
1871 	env->ReleaseStringUTFChars(sourceNameJS, sourceName);
1872 
1873 	if (source == installMgr->sources.end()) {
1874 SWLog::getSystemLog()->logDebug("Couldn't find remote source [%s]\n", sourceName);
1875 		return 0;
1876 	}
1877 
1878 	SWMgr *mgr = source->second->getMgr();
1879 
1880 	const char *modName = env->GetStringUTFChars(modNameJS, NULL);
1881 	sword::SWModule *module = mgr->getModule(modName);
1882 	env->ReleaseStringUTFChars(modNameJS, modName);
1883 
1884 	if (module) {
1885 		SWBuf type = module->getType();
1886 		SWBuf cat = module->getConfigEntry("Category");
1887 		if (cat.length() > 0) type = cat;
1888 		jfieldID fieldID;
1889 		jclass clazzSWModule = env->FindClass("org/crosswire/android/sword/SWModule");
1890 		retVal = env->AllocObject(clazzSWModule);
1891 		fieldID = env->GetFieldID(clazzSWModule, "name", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->getName())));
1892 		fieldID = env->GetFieldID(clazzSWModule, "description", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(module->getDescription())));
1893 		fieldID = env->GetFieldID(clazzSWModule, "category", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, env->NewStringUTF(assureValidUTF8(type.c_str())));
1894 		fieldID = env->GetFieldID(clazzSWModule, "remoteSourceName", "Ljava/lang/String;"); env->SetObjectField(retVal, fieldID, sourceNameJS);
1895 	}
1896 
1897 	return retVal;
1898 
1899 }
1900 
1901 
1902 /*
1903  * Class:     org_crosswire_android_sword_InstallMgr
1904  * Method:    setUserDisclaimerConfirmed
1905  * Signature: ()V
1906  */
Java_org_crosswire_android_sword_InstallMgr_setUserDisclaimerConfirmed(JNIEnv * env,jobject me)1907 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_InstallMgr_setUserDisclaimerConfirmed
1908 		(JNIEnv *env, jobject me) {
1909 
1910 	initInstall(env);
1911 
1912 	disclaimerConfirmed = true;
1913 	installMgr->setUserDisclaimerConfirmed(true);
1914 }
1915 
1916 
1917 /*
1918  * Class:     org_crosswire_android_sword_SWMgr
1919  * Method:    sendBibleSyncMessage
1920  * Signature: (Ljava/lang/String;)V
1921  */
Java_org_crosswire_android_sword_SWMgr_sendBibleSyncMessage(JNIEnv * env,jobject me,jstring osisRefJS)1922 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_sendBibleSyncMessage
1923 		(JNIEnv *env, jobject me, jstring osisRefJS) {
1924 
1925 	initBibleSync();
1926 	const char *osisRef = env->GetStringUTFChars(osisRefJS, NULL);
1927 
1928 #ifdef BIBLESYNC
1929 	BibleSync_xmit_status retval = bibleSync->Transmit(BSP_SYNC, "Bible", osisRef);
1930 #endif
1931 
1932 	env->ReleaseStringUTFChars(osisRefJS, osisRef);
1933 }
1934 
1935 
1936 /*
1937  * NOTE: this method blocks and should be called in a new thread
1938  * Class:     org_crosswire_android_sword_SWMgr
1939  * Method:    registerBibleSyncListener
1940  * Signature: (Ljava/lang/Object;)V
1941  */
Java_org_crosswire_android_sword_SWMgr_registerBibleSyncListener(JNIEnv * env,jobject me,jobject bibleSyncListener)1942 JNIEXPORT void JNICALL Java_org_crosswire_android_sword_SWMgr_registerBibleSyncListener
1943 		(JNIEnv *env, jobject me, jobject bibleSyncListener) {
1944 
1945 #ifdef BIBLESYNC
1946 SWLog::getSystemLog()->logDebug("registerBibleSyncListener");
1947 	::bibleSyncListener = bibleSyncListener;
1948 	::bibleSyncListenerEnv = env;
1949 SWLog::getSystemLog()->logDebug("registerBibleSyncListener - calling init");
1950 	initBibleSync();
1951 SWLog::getSystemLog()->logDebug("registerBibleSyncListener - starting while listener");
1952 	while(::bibleSyncListener) {
1953 SWLog::getSystemLog()->logDebug("bibleSyncListener - while loop iteration");
1954 		BibleSync::Receive(bibleSync);
1955 SWLog::getSystemLog()->logDebug("bibleSyncListener - sleeping for 2 seconds");
1956 		sleep(2);
1957 	}
1958 #endif
1959 }
1960 
1961