1 /*
2  * Xiphos Bible Study Tool
3  * sword.cc - glue
4  *
5  * Copyright (C) 2000-2020 Xiphos Developer Team
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <gtk/gtk.h>
27 #include <glib.h>
28 #include <glib/gstdio.h>
29 
30 #include <swmgr.h>
31 #include <swmodule.h>
32 #include <stringmgr.h>
33 #include <localemgr.h>
34 
35 extern "C" {
36 #include "gui/bibletext.h"
37 #include "main/gtk_compat.h"
38 }
39 
40 #include <ctype.h>
41 #include <time.h>
42 
43 #include "gui/main_window.h"
44 #include "gui/font_dialog.h"
45 #include "gui/widgets.h"
46 #include "gui/commentary.h"
47 #include "gui/dialog.h"
48 #include "gui/parallel_dialog.h"
49 #include "gui/parallel_tab.h"
50 #include "gui/parallel_view.h"
51 #include "gui/tabbed_browser.h"
52 #include "gui/xiphos.h"
53 #include "gui/sidebar.h"
54 #include "gui/utilities.h"
55 #include "gui/cipher_key_dialog.h"
56 #include "gui/main_menu.h"
57 
58 #include "main/biblesync_glue.h"
59 #include "main/display.hh"
60 #include "main/lists.h"
61 #include "main/navbar.h"
62 #include "main/navbar_book.h"
63 #include "main/search_sidebar.h"
64 #include "main/previewer.h"
65 #include "main/settings.h"
66 #include "main/sidebar.h"
67 #include "main/sword.h"
68 #include "main/url.hh"
69 #include "main/xml.h"
70 #include "main/parallel_view.h"
71 #include "main/modulecache.hh"
72 
73 #include "backend/sword_main.hh"
74 #include "backend/gs_stringmgr.h"
75 
76 #include "biblesync/biblesync.hh"
77 
78 #include "gui/debug_glib_null.h"
79 
80 #ifdef HAVE_DBUS
81 #include "gui/ipc.h"
82 #endif
83 
84 extern BibleSync *biblesync;
85 
86 using namespace sword;
87 
88 char *sword_locale = NULL;
89 gboolean companion_activity = FALSE;
90 
91 /* Unicode collation necessities. */
92 UCollator* collator;
93 UErrorCode collator_status;
94 
95 extern gboolean valid_scripture_key;
96 
97 // these track together.  when one changes, so does the other.
98 static std::map<string, string> abbrev_name2abbrev, abbrev_abbrev2name;
99 typedef std::map<string, string>::iterator abbrev_iter;
100 
101 /******************************************************************************
102  * Name
103  *   main_add_abbreviation
104  *
105  * Synopsis
106  *   #include "main/sword.h"
107  *
108  *   void main_add_abbreviation(char *name, char *abbreviation)
109  *
110  * Description
111  *   adds an element to each of the abbreviation maps.
112  *
113  * Return value
114  *   void
115  */
116 
main_add_abbreviation(const char * name,const char * abbreviation)117 void main_add_abbreviation(const char *name, const char *abbreviation)
118 {
119 	// let's not be stupid about abbreviations chosen, ok?
120 	if (!strchr(abbreviation, '(')) {
121 		abbrev_name2abbrev[name] = abbreviation;
122 		abbrev_abbrev2name[abbreviation] = name;
123 	}
124 }
125 
126 /******************************************************************************
127  * Name
128  *   main_get_abbreviation
129  *
130  * Synopsis
131  *   #include "main/sword.h"
132  *
133  *   const char * main_get_abbreviation(const char *name)
134  *
135  * Description
136  *   gets abbreviation from real module, if available.
137  *
138  * Return value
139  *   const char *
140  */
141 
main_get_abbreviation(const char * name)142 const char *main_get_abbreviation(const char *name)
143 {
144 	if (name == NULL)
145 		return NULL;
146 	abbrev_iter it = abbrev_name2abbrev.find(name);
147 	if (it != abbrev_name2abbrev.end()) {
148 		return it->second.c_str();
149 	}
150 	return NULL;
151 }
152 
153 /******************************************************************************
154  * Name
155  *   main_get_name
156  *
157  * Synopsis
158  *   #include "main/sword.h"
159  *
160  *   const char * main_get_name(const char *abbreviation)
161  *
162  * Description
163  *   gets real module name from abbreviation, if available.
164  *
165  * Return value
166  *   const char *
167  */
168 
main_get_name(const char * abbreviation)169 const char *main_get_name(const char *abbreviation)
170 {
171 	if (abbreviation == NULL)
172 		return NULL;
173 	abbrev_iter it = abbrev_abbrev2name.find(abbreviation);
174 	if (it != abbrev_abbrev2name.end()) {
175 		return it->second.c_str();
176 	}
177 	return NULL;
178 }
179 
180 /******************************************************************************
181  * Name
182  *   main_book_heading
183  *
184  * Synopsis
185  *   #include "main/sword.h"
186  *
187  *   void main_book_heading(char * mod_name)
188  *
189  * Description
190  *
191  *
192  * Return value
193  *   void
194  */
195 
main_book_heading(char * mod_name)196 void main_book_heading(char *mod_name)
197 {
198 	VerseKey *vkey;
199 	SWMgr *mgr = backend->get_mgr();
200 
201 	backend->display_mod = mgr->Modules[mod_name];
202 	vkey = (VerseKey *)(SWKey *)(*backend->display_mod);
203 	vkey->setIntros(1);
204 	vkey->setAutoNormalize(0);
205 	vkey->setChapter(0);
206 	vkey->setVerse(0);
207 	backend->display_mod->display();
208 }
209 
210 /******************************************************************************
211  * Name
212  *   main_chapter_heading
213  *
214  * Synopsis
215  *   #include "main/module_dialogs.h"
216  *
217  *   void main_chapter_heading(char * mod_name)
218  *
219  * Description
220  *
221  *
222  * Return value
223  *   void
224  */
225 
main_chapter_heading(char * mod_name)226 void main_chapter_heading(char *mod_name)
227 {
228 	VerseKey *vkey;
229 	SWMgr *mgr = backend->get_mgr();
230 
231 	backend->display_mod = mgr->Modules[mod_name];
232 	backend->display_mod->setKey(settings.currentverse);
233 	vkey = (VerseKey *)(SWKey *)(*backend->display_mod);
234 	vkey->setIntros(1);
235 	vkey->setAutoNormalize(0);
236 	vkey->setVerse(0);
237 	backend->display_mod->display();
238 }
239 
240 /******************************************************************************
241  * Name
242  *   main_save_note
243  *
244  * Synopsis
245  *   #include "main/sword.h"
246  *
247  *   void main_save_note(const gchar * module_name,
248  *				          const gchar * key_str ,
249  *				          const gchar * note_str )
250  *
251  * Description
252  *
253  *
254  * Return value
255  *   void
256  */
257 
main_save_note(const gchar * module_name,const gchar * key_str,const gchar * note_str)258 void main_save_note(const gchar *module_name,
259 		    const gchar *key_str,
260 		    const gchar *note_str)
261 {
262 	// Massage encoded spaces ("%20") back to real spaces.
263 	// This is a sick. unreliable hack that should be removed
264 	// after the underlying problem is fixed in Sword.
265 	gchar *rework;
266 	for (rework = (char *)strstr(note_str, "%20");
267 	     rework;
268 	     rework = strstr(rework + 1, "%20")) {
269 		*rework = ' ';
270 		(void)strcpy(rework + 1, rework + 3);
271 	}
272 
273 	XI_message(("note module %s\nnote key %s\nnote text%s",
274 		    module_name,
275 		    key_str,
276 		    note_str));
277 	backend->save_note_entry(module_name, key_str, note_str);
278 
279 	main_display_commentary(module_name, settings.currentverse);
280 }
281 
282 /******************************************************************************
283  * Name
284  *   main_delete_note
285  *
286  * Synopsis
287  *   #include "main/sword.h"
288  *
289  *   void main_delete_note(DIALOG_DATA * d)
290  *
291  * Description
292  *
293  *
294  * Return value
295  *   void
296  */
297 
main_delete_note(const gchar * module_name,const gchar * key_str)298 void main_delete_note(const gchar *module_name,
299 		      const gchar *key_str)
300 {
301 	backend->set_module_key(module_name, key_str);
302 	XI_message(("note module %s\nnote key %s\n",
303 		    module_name,
304 		    key_str));
305 	backend->delete_entry();
306 
307 	if ((!strcmp(settings.CommWindowModule, module_name)) &&
308 	    (!strcmp(settings.currentverse, key_str)))
309 		main_display_commentary(module_name, key_str);
310 }
311 
312 /******************************************************************************
313  * Name
314  *  set_module_unlocked
315  *
316  * Synopsis
317  *   #include "bibletext.h"
318  *
319  *   void set_module_unlocked(char *mod_name, char *key)
320  *
321  * Description
322  *   unlocks locked module -
323  *
324  * Return value
325  *   void
326  */
327 
main_set_module_unlocked(const char * mod_name,char * key)328 void main_set_module_unlocked(const char *mod_name, char *key)
329 {
330 	SWMgr *mgr = backend->get_mgr();
331 	mgr->setCipherKey(mod_name, key);
332 }
333 
334 /******************************************************************************
335  * Name
336  *  main_save_module_key
337  *
338  * Synopsis
339  *   #include "main/configs.h"
340  *
341  *   void main_save_module_key(gchar * mod_name, gchar * key)
342  *
343  * Description
344  *    to unlock locked modules
345  *
346  * Return value
347  *   void
348  */
349 
main_save_module_key(const char * mod_name,char * key)350 void main_save_module_key(const char *mod_name, char *key)
351 {
352 	backend->save_module_key((char *)mod_name, key);
353 }
354 
355 /******************************************************************************
356  * Name
357  *  main_getText
358  *
359  * Synopsis
360  *   #include "main/sword.h"
361  *   void main_getText(gchar * key)
362  *
363  * Description
364  *   get unabbreviated key
365  *
366  * Return value
367  *   char *
368  */
369 
main_getText(char * key)370 char *main_getText(char *key)
371 {
372 	VerseKey vkey(key);
373 	return strdup((char *)vkey.getText());
374 }
375 
376 /******************************************************************************
377  * Name
378  *  main_getShortText
379  *
380  * Synopsis
381  *   #include "main/sword.h"
382  *   void main_getShortText(gchar * key)
383  *
384  * Description
385  *   get short-name key
386  *
387  * Return value
388  *   char *
389  */
390 
main_getShortText(char * key)391 char *main_getShortText(char *key)
392 {
393 	VerseKey vkey(key);
394 	return strdup((char *)vkey.getShortText());
395 }
396 
397 /******************************************************************************
398  * Name
399  *   main_update_nav_controls
400  *
401  * Synopsis
402  *   #include "toolbar_nav.h"
403  *
404  *   gchar *main_update_nav_controls(const gchar * key)
405  *
406  * Description
407  *   updates the nav toolbar controls
408  *
409  * Return value
410  *   gchar *
411  */
412 
main_update_nav_controls(const char * module_name,const gchar * key)413 gchar *main_update_nav_controls(const char *module_name, const gchar *key)
414 {
415 	char *val_key = backend->get_valid_key(module_name, key);
416 
417 	// we got a valid key. but was it really a valid key within v11n?
418 	// for future use in determining whether to show normal navbar content.
419 	navbar_versekey.valid_key = main_is_Bible_key(module_name, key);
420 
421 	/*
422 	 *  remember verse
423 	 */
424 	xml_set_value("Xiphos", "keys", "verse", val_key);
425 	settings.currentverse = xml_get_value("keys", "verse");
426 
427 	settings.apply_change = FALSE;
428 
429 	navbar_versekey.module_name = g_string_assign(navbar_versekey.module_name, settings.MainWindowModule);
430 	navbar_versekey.key = g_string_assign(navbar_versekey.key, val_key);
431 	main_navbar_versekey_set(navbar_versekey, val_key);
432 
433 	settings.apply_change = TRUE;
434 
435 #ifdef HAVE_DBUS
436 	IpcObject *ipc = ipc_get_main_ipc();
437 	if (ipc)
438 		ipc_object_navigation_signal(ipc, (const gchar *)val_key, NULL);
439 #endif
440 	return val_key;
441 }
442 
443 /******************************************************************************
444  * Name
445  *  get_module_key
446  *
447  * Synopsis
448  *   #include "main/module.h"
449  *
450  *   char *get_module_key(void)
451  *
452  * Description
453  *    returns module key
454  *
455  * Return value
456  *   char *
457  */
458 
main_get_active_pane_key(void)459 char *main_get_active_pane_key(void)
460 {
461 	if (settings.havebible) {
462 		switch (settings.whichwindow) {
463 		case MAIN_TEXT_WINDOW:
464 		case COMMENTARY_WINDOW:
465 			return (char *)settings.currentverse;
466 			break;
467 		case DICTIONARY_WINDOW:
468 			return (char *)settings.dictkey;
469 			break;
470 		case parallel_WINDOW:
471 			return (char *)settings.cvparallel;
472 			break;
473 		case BOOK_WINDOW:
474 			return (char *)settings.book_key;
475 			break;
476 		}
477 	}
478 	return NULL;
479 }
480 
481 /******************************************************************************
482  * Name
483  *  get_module_name
484  *
485  * Synopsis
486  *   #include "main/module.h"
487  *
488  *   char *get_module_name(void)
489  *
490  * Description
491  *    returns module name
492  *
493  * Return value
494  *   char *
495  */
496 
main_get_active_pane_module(void)497 char *main_get_active_pane_module(void)
498 {
499 	if (settings.havebible) {
500 		switch (settings.whichwindow) {
501 		case MAIN_TEXT_WINDOW:
502 			return (char *)xml_get_value("modules",
503 						     "bible");
504 			break;
505 		case COMMENTARY_WINDOW:
506 			return (char *)xml_get_value("modules",
507 						     "comm");
508 			break;
509 		case DICTIONARY_WINDOW:
510 			return (char *)settings.DictWindowModule;
511 			break;
512 		case BOOK_WINDOW:
513 			return (char *)settings.book_mod;
514 			break;
515 		}
516 	}
517 	return NULL;
518 }
519 
520 /******************************************************************************
521  * Name
522  *  module_name_from_description
523  *
524  * Synopsis
525  *   #include ".h"
526  *
527  *   void module_name_from_description(gchar *mod_name, gchar *description)
528  *
529  * Description
530  *
531  *
532  * Return value
533  *   void
534  */
535 
main_module_name_from_description(char * description)536 char *main_module_name_from_description(char *description)
537 {
538 	return backend->module_name_from_description(description);
539 }
540 
541 /******************************************************************************
542  * Name
543  *  main_get_sword_version
544  *
545  * Synopsis
546  *   #include "sword.h"
547  *
548  *   const char *main_get_sword_version(void)
549  *
550  * Description
551  *
552  *
553  * Return value
554  *   const char *
555  */
556 
main_get_sword_version(void)557 const char *main_get_sword_version(void)
558 {
559 	return backend->get_sword_version();
560 }
561 
562 /******************************************************************************
563  * Name
564  *   get_search_results_text
565  *
566  * Synopsis
567  *   #include "sword.h"
568  *
569  *   char *get_search_results_text(char * mod_name, char * key)
570  *
571  * Description
572  *
573  *
574  * Return value
575  *   char *
576  */
577 
main_get_search_results_text(char * mod_name,char * key)578 char *main_get_search_results_text(char *mod_name, char *key)
579 {
580 	return backend->get_render_text((char *)mod_name, (char *)key);
581 }
582 
583 /******************************************************************************
584  * Name
585  *  main_get_path_to_mods
586  *
587  * Synopsis
588  *   #include "sword.h"
589  *
590  *   	gchar *main_get_path_to_mods(void)
591  *
592  * Description
593  *    returns the path to the sword modules
594  *
595  * Return value
596  *   gchar *
597  */
598 
main_get_path_to_mods(void)599 char *main_get_path_to_mods(void)
600 {
601 	SWMgr *mgr = backend->get_mgr();
602 	char *path = mgr->prefixPath;
603 	return (path ? g_strdup(path) : NULL);
604 }
605 
606 /******************************************************************************
607  * Name
608  *  main_init_language_map
609  *
610  * Synopsis
611  *   #include "sword.h"
612  *
613  *   void main_init_language_map(void)
614  *
615  * Description
616  *   initializes the hard-coded abbrev->name mapping.
617  *
618  * Return value
619  *   void
620  */
621 
622 typedef std::map<SWBuf, SWBuf> ModLanguageMap;
623 ModLanguageMap languageMap;
624 
main_init_language_map()625 void main_init_language_map()
626 {
627 	gchar *language_file;
628 	FILE *language;
629 	gchar *s, *end, *abbrev, *name, *newline;
630 	gchar *mapspace;
631 	size_t length;
632 
633 	if ((language_file = gui_general_user_file("languages", FALSE)) == NULL) {
634 		gui_generic_warning(_("Xiphos's file for language\nabbreviations is missing."));
635 		return;
636 	}
637 	XI_message(("%s", language_file));
638 
639 	if ((language = g_fopen(language_file, "r")) == NULL) {
640 		gui_generic_warning(_("Xiphos's language abbreviation\nfile cannot be opened."));
641 		g_free(language_file);
642 		return;
643 	}
644 	g_free(language_file);
645 	(void)fseek(language, 0L, SEEK_END);
646 	length = ftell(language);
647 	rewind(language);
648 
649 	if ((length == 0) ||
650 	    (mapspace = (gchar *)g_malloc(length + 2)) == NULL) {
651 		fclose(language);
652 		gui_generic_warning(_("Xiphos cannot allocate space\nfor language abbreviations."));
653 		return;
654 	}
655 	if (fread(mapspace, 1, length, language) != length) {
656 		fclose(language);
657 		g_free(mapspace);
658 		gui_generic_warning(_("Xiphos cannot read the\nlanguage abbreviation file."));
659 		return;
660 	}
661 	fclose(language);
662 	end = length + mapspace;
663 	*end = '\0';
664 
665 	for (s = mapspace; s < end; ++s) {
666 		if ((newline = strchr(s, '\n')) == NULL) {
667 			XI_message(("incomplete last line in languages"));
668 			break;
669 		}
670 		*newline = '\0';
671 
672 		if ((*s == '#') || (s == newline)) {
673 			s = newline; // comment or empty line.
674 			continue;
675 		}
676 
677 		abbrev = s;
678 		if ((name = strchr(s, '\t')) == NULL) {
679 			XI_message(("tab-less line in languages"));
680 			break;
681 		}
682 		*(name++) = '\0'; // NUL-terminate abbrev, mark name.
683 		languageMap[SWBuf(abbrev)] = SWBuf(name);
684 		s = newline;
685 	}
686 
687 	g_free(mapspace);
688 }
689 
main_get_language_map(const char * language)690 const char *main_get_language_map(const char *language)
691 {
692 	if (language == NULL)
693 		return "Unknown";
694 	return languageMap[language].c_str();
695 }
696 
main_get_module_language_list(void)697 char **main_get_module_language_list(void)
698 {
699 	return backend->get_module_language_list();
700 }
701 
702 /******************************************************************************
703  * Name
704  *   set_sword_locale
705  *
706  * Synopsis
707  *   #include "main/sword.h"
708  *
709  *   char *set_sword_locale(const char *sys_locale)
710  *
711  * Description
712  *   set sword's idea of the locale in which the user operates
713  *
714  * Return value
715  *   char *
716  */
set_sword_locale(const char * sys_locale)717 char *set_sword_locale(const char *sys_locale)
718 {
719 	if (sys_locale) {
720 		SWBuf locale;
721 		StringList localelist = LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
722 		StringList::iterator it;
723 		int ncmp[3] = {100, 5, 2}; // fixed data
724 
725 		// length-limited match
726 		for (int i = 0; i < 3; ++i) {
727 			for (it = localelist.begin(); it != localelist.end(); ++it) {
728 				locale = *it;
729 				if (!strncmp(sys_locale, locale.c_str(), ncmp[i])) {
730 					LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName(locale.c_str());
731 					return g_strdup(locale.c_str());
732 				}
733 			}
734 		}
735 	}
736 
737 	// either we were given a null sys_locale, or it didn't match anything.
738 	char *err = g_strdup_printf(_("No matching locale found for `%s'.\n%s"),
739 				    sys_locale,
740 				    _("Book names and menus may not be translated."));
741 	gui_generic_warning(err);
742 	g_free(err);
743 	return NULL;
744 }
745 
746 /******************************************************************************
747  * Name
748  *   backend_init
749  *
750  * Synopsis
751  *   #include "main/sword.h"
752  *
753  *   void main_init_backend(void)
754  *
755  * Description
756  *   start sword
757  *
758  * Return value
759  *   void
760  */
761 
main_init_backend(void)762 void main_init_backend(void)
763 {
764 	StringMgr::setSystemStringMgr(new GS_StringMgr());
765 
766 	const char *lang = getenv("LANG");
767 	if (!lang)
768 		lang = "C";
769 	sword_locale = set_sword_locale(lang);
770 	collator = ucol_open(sword_locale, &collator_status);
771 	lang = LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName();
772 
773 	backend = new BackEnd();
774 
775 	backend->init_SWORD(0);
776 	settings.path_to_mods = main_get_path_to_mods();
777 	//#ifndef DEBUG
778 	g_chdir(settings.path_to_mods);
779 	//#else
780 	//	XI_warning(("no chdir(SWORD_PATH) => modmgr 'archive' may not work"));
781 	//#endif
782 	XI_print(("%s sword-%s\n", "Starting", backend->get_sword_version()));
783 	XI_print(("%s\n", "Initiating SWORD"));
784 	XI_print(("%s: %s\n", "path to sword", settings.path_to_mods));
785 	XI_print(("%s %s\n", "SWORD locale is", lang));
786 	XI_print(("%s\n", "Checking for SWORD Modules"));
787 	settings.spell_language = strdup(lang);
788 	main_init_lists();
789 
790 	//
791 	// BibleSync backend startup.  identify the user by name.
792 	//
793 	biblesync = new BibleSync("Xiphos", VERSION,
794 #ifdef WIN32
795 				  // in win32 glib, get_real_name and get_user_name are the same.
796 				  (string)g_get_real_name()
797 #else
798 				  (string)g_get_real_name() + " (" + g_get_user_name() + ")"
799 #endif
800 				  );
801 }
802 
803 /******************************************************************************
804  * Name
805  *   shutdown_sword
806  *
807  * Synopsis
808  *   #include "sword.h"
809  *
810  *   void shutdown_sword(void)
811  *
812  * Description
813  *   close down sword by deleting backend;
814  *
815  * Return value
816  *   void
817  */
818 
main_shutdown_backend(void)819 void main_shutdown_backend(void)
820 {
821 	if (sword_locale)
822 		free((char *)sword_locale);
823 	sword_locale = NULL;
824 	if (backend)
825 		delete backend;
826 	backend = NULL;
827 
828 	XI_print(("%s\n", "SWORD is shutdown"));
829 }
830 
831 /******************************************************************************
832  * Name
833  *   main_dictionary_entry_changed
834  *
835  * Synopsis
836  *   #include "main/sword.h"
837  *
838  *   void main_dictionary_entry_changed(char * mod_name)
839  *
840  * Description
841  *   text in the dictionary entry has changed and the entry activated
842  *
843  * Return value
844  *   void
845  */
846 
main_dictionary_entry_changed(char * mod_name)847 void main_dictionary_entry_changed(char *mod_name)
848 {
849 	gchar *key = NULL;
850 
851 	if (!mod_name)
852 		return;
853 	if (strcmp(settings.DictWindowModule, mod_name)) {
854 		xml_set_value("Xiphos", "modules", "dict", mod_name);
855 		settings.DictWindowModule = xml_get_value("modules", "dict");
856 	}
857 
858 	key = g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(widgets.entry_dict)));
859 
860 	backend->set_module_key(mod_name, key);
861 	g_free(key);
862 	key = backend->get_module_key();
863 
864 	xml_set_value("Xiphos", "keys", "dictionary", key);
865 	settings.dictkey = xml_get_value("keys", "dictionary");
866 
867 	main_check_unlock(mod_name, TRUE);
868 
869 	backend->set_module_key(mod_name, key);
870 	backend->display_mod->display();
871 
872 	gtk_entry_set_text(GTK_ENTRY(widgets.entry_dict), key);
873 	g_free(key);
874 }
875 
dict_key_list_select(GtkMenuItem * menuitem,gpointer user_data)876 static void dict_key_list_select(GtkMenuItem *menuitem, gpointer user_data)
877 {
878 	gtk_entry_set_text(GTK_ENTRY(widgets.entry_dict), (gchar *)user_data);
879 	gtk_widget_activate(widgets.entry_dict);
880 }
881 
882 /******************************************************************************
883  * Name
884  *
885  *
886  * Synopsis
887  *   #include "main/sword.h"
888  *
889  *
890  *
891  * Description
892  *   text in the dictionary entry has changed and the entry activated
893  *
894  * Return value
895  *   void
896  */
897 
main_dictionary_drop_down_new(char * mod_name,char * old_key)898 GtkWidget *main_dictionary_drop_down_new(char *mod_name, char *old_key)
899 {
900 	gint count = 9, i;
901 	gchar *new_key;
902 	gchar *key = NULL;
903 	GtkWidget *menu;
904 
905 	menu = gtk_menu_new();
906 
907 	if (!settings.havedict || !mod_name)
908 		return NULL;
909 	if (strcmp(settings.DictWindowModule, mod_name)) {
910 		xml_set_value("Xiphos", "modules", "dict",
911 			      mod_name);
912 		settings.DictWindowModule = xml_get_value(
913 		    "modules", "dict");
914 	}
915 	key = g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(widgets.entry_dict)));
916 
917 	XI_message(("\nold_key: %s\nkey: %s", old_key, key));
918 	backend->set_module_key(mod_name, key);
919 	g_free(key);
920 	key = backend->get_module_key();
921 
922 	xml_set_value("Xiphos", "keys", "dictionary", key);
923 	settings.dictkey = xml_get_value("keys", "dictionary");
924 
925 	main_check_unlock(mod_name, TRUE);
926 
927 	backend->set_module_key(mod_name, key);
928 	backend->display_mod->display();
929 
930 	new_key = g_strdup((char *)backend->display_mod->getKeyText());
931 
932 	for (i = 0; i < (count / 2) + 1; i++) {
933 		(*backend->display_mod)--;
934 	}
935 
936 	for (i = 0; i < count; i++) {
937 		free(new_key);
938 		(*backend->display_mod)++;
939 		new_key = g_strdup((char *)backend->display_mod->getKeyText());
940 		/* add menu item */
941 		GtkWidget *item =
942 		    gtk_menu_item_new_with_label((gchar *)new_key);
943 		gtk_widget_show(item);
944 		g_signal_connect(G_OBJECT(item), "activate",
945 				 G_CALLBACK(dict_key_list_select),
946 				 g_strdup(new_key));
947 		gtk_container_add(GTK_CONTAINER(menu), item);
948 	}
949 
950 	free(new_key);
951 	g_free(key);
952 	return menu;
953 }
954 
955 /******************************************************************************
956  * Name
957  *   main_dictionary_button_clicked
958  *
959  * Synopsis
960  *   #include "main/sword.h"
961  *
962  *   void main_dictionary_button_clicked(gint direction)
963  *
964  * Description
965  *   The back or foward dictinary key button was clicked.
966  *   the module key is set to the current dictkey.
967  *   then the module is incremented or decremented.
968  *   the new key is returned from the module and the dictionary entry is set
969  *   to the new key. The entry is then activated.
970  *
971  * Return value
972  *   void
973  */
974 
main_dictionary_button_clicked(gint direction)975 void main_dictionary_button_clicked(gint direction)
976 {
977 	gchar *key = NULL;
978 
979 	if (!settings.havedict || !settings.DictWindowModule)
980 		return;
981 
982 	backend->set_module_key(settings.DictWindowModule,
983 				settings.dictkey);
984 	if (direction == 0)
985 		(*backend->display_mod)--;
986 	else
987 		(*backend->display_mod)++;
988 	key = g_strdup((char *)backend->display_mod->getKeyText());
989 	gtk_entry_set_text(GTK_ENTRY(widgets.entry_dict), key);
990 	gtk_widget_activate(widgets.entry_dict);
991 	g_free(key);
992 }
993 
main_display_book(const char * mod_name,const char * key)994 void main_display_book(const char *mod_name,
995 		       const char *key)
996 {
997 	if (!settings.havebook || !mod_name)
998 		return;
999 
1000 	if (key == NULL)
1001 		key = "0";
1002 
1003 	XI_message(("main_display_book\nmod_name: %s\nkey: %s", mod_name, key));
1004 
1005 	if (!backend->is_module(mod_name))
1006 		return;
1007 	if (!settings.book_mod)
1008 		settings.book_mod = g_strdup((char *)mod_name);
1009 
1010 	if (strcmp(settings.book_mod, mod_name)) {
1011 		xml_set_value("Xiphos", "modules", "book", mod_name);
1012 		gui_reassign_strdup(&settings.book_mod, (gchar *)mod_name);
1013 	}
1014 
1015 	if (!isdigit(key[0])) {
1016 		xml_set_value("Xiphos", "keys", "book", key);
1017 		settings.book_key = xml_get_value("keys", "book");
1018 
1019 		backend->set_module(mod_name);
1020 		backend->set_treekey(0);
1021 		settings.book_offset = backend->treekey_set_key((char *)key);
1022 	} else {
1023 		settings.book_offset = atol(key);
1024 		if (settings.book_offset < 4)
1025 			settings.book_offset = 4;
1026 		xml_set_value("Xiphos", "keys", "book", key);
1027 		settings.book_key = xml_get_value("keys", "book");
1028 		xml_set_value("Xiphos", "keys", "offset", key);
1029 
1030 		backend->set_module(mod_name);
1031 		backend->set_treekey(settings.book_offset);
1032 	}
1033 
1034 	main_check_unlock(mod_name, TRUE);
1035 
1036 	backend->display_mod->display();
1037 	main_setup_navbar_book(settings.book_mod, settings.book_offset);
1038 	//if (settings.browsing)
1039 	gui_update_tab_struct(NULL,
1040 			      NULL,
1041 			      NULL,
1042 			      mod_name,
1043 			      NULL,
1044 			      key,
1045 			      FALSE,
1046 			      settings.showtexts,
1047 			      settings.showpreview,
1048 			      settings.showcomms,
1049 			      settings.showdicts);
1050 }
1051 
main_display_commentary(const char * mod_name,const char * key)1052 void main_display_commentary(const char *mod_name,
1053 			     const char *key)
1054 {
1055 	if (!settings.havecomm || !settings.comm_showing)
1056 		return;
1057 
1058 	if (!mod_name)
1059 		mod_name = ((settings.browsing && (cur_passage_tab != NULL))
1060 				? g_strdup(cur_passage_tab->commentary_mod)
1061 				: xml_get_value("modules", "comm"));
1062 
1063 	if (!mod_name || !backend->is_module(mod_name))
1064 		return;
1065 
1066 	int modtype = backend->module_type(mod_name);
1067 	if ((modtype != COMMENTARY_TYPE) && (modtype != PERCOM_TYPE))
1068 		return; // what are we doing here?
1069 
1070 	if (!settings.CommWindowModule)
1071 		settings.CommWindowModule = g_strdup((gchar *)mod_name);
1072 
1073 	settings.comm_showing = TRUE;
1074 	settings.whichwindow = COMMENTARY_WINDOW;
1075 
1076 	if (strcmp(settings.CommWindowModule, mod_name)) {
1077 		xml_set_value("Xiphos", "modules", "comm", mod_name);
1078 		gui_reassign_strdup(&settings.CommWindowModule, (gchar *)mod_name);
1079 
1080 		// handle a conf directive "Companion=This,That,TheOther"
1081 		char *companion = main_get_mod_config_entry(mod_name, "Companion");
1082 		gchar **name_set = (companion ? g_strsplit(companion, ",", -1) : NULL);
1083 
1084 		if (companion &&
1085 		    (!companion_activity) &&
1086 		    name_set[0] &&
1087 		    *name_set[0] &&
1088 		    backend->is_module(name_set[0]) &&
1089 		    ((settings.MainWindowModule == NULL) ||
1090 		     strcmp(name_set[0], settings.MainWindowModule))) {
1091 			companion_activity = TRUE;
1092 
1093 			gint name_length = g_strv_length(name_set);
1094 			char *companion_question =
1095 			    g_strdup_printf(_("Module %s has companion modules:\n%s.\n"
1096 					      "Would you like to open these as well?%s"),
1097 					    mod_name, companion,
1098 					    ((name_length > 1)
1099 						 ? _("\n\nThe first will open in the main window\n"
1100 						     "and others in separate windows.")
1101 						 : ""));
1102 
1103 			if (gui_yes_no_dialog(companion_question, NULL)) {
1104 				main_display_bible(name_set[0], key);
1105 				for (int i = 1; i < name_length; i++) {
1106 					main_dialogs_open(name_set[i], key, FALSE);
1107 				}
1108 			}
1109 			g_free(companion_question);
1110 			companion_activity = FALSE;
1111 		}
1112 		if (name_set)
1113 			g_strfreev(name_set);
1114 		if (companion)
1115 			g_free(companion);
1116 	}
1117 
1118 	main_check_unlock(mod_name, TRUE);
1119 
1120 	valid_scripture_key = main_is_Bible_key(mod_name, key);
1121 
1122 	backend->set_module_key(mod_name, key);
1123 	backend->display_mod->display();
1124 
1125 	valid_scripture_key = TRUE; // leave nice for future use.
1126 
1127 	//if (settings.browsing)
1128 	gui_update_tab_struct(NULL,
1129 			      mod_name,
1130 			      NULL,
1131 			      NULL,
1132 			      NULL,
1133 			      NULL,
1134 			      TRUE,
1135 			      settings.showtexts,
1136 			      settings.showpreview,
1137 			      settings.showcomms,
1138 			      settings.showdicts);
1139 }
1140 
main_display_dictionary(const char * mod_name,const char * key)1141 void main_display_dictionary(const char *mod_name,
1142 			     const char *key)
1143 {
1144 	const gchar *old_key, *feature;
1145 
1146 	// for devotional use.
1147 	gchar buf[10];
1148 
1149 	if (!settings.havedict || !mod_name)
1150 		return;
1151 
1152 	XI_message(("main_display_dictionary\nmod_name: %s\nkey: %s", mod_name, key));
1153 
1154 	if (!backend->is_module(mod_name))
1155 		return;
1156 	if (!settings.DictWindowModule)
1157 		settings.DictWindowModule = g_strdup((gchar *)mod_name);
1158 
1159 	if (key == NULL)
1160 		key = (char *)"Grace";
1161 
1162 	feature = (char *)backend->get_mgr()->getModule(mod_name)->getConfigEntry("Feature");
1163 
1164 	// turn on "all strong's" iff we have that kind of dictionary.
1165 	if (feature && (!strcmp(feature, "HebrewDef") || !strcmp(feature, "GreekDef")))
1166 		gtk_widget_show(widgets.all_strongs);
1167 	else
1168 		gtk_widget_hide(widgets.all_strongs);
1169 
1170 	if (strcmp(settings.DictWindowModule, mod_name)) {
1171 		// new dict -- is it actually a devotional?
1172 		time_t curtime;
1173 
1174 		if (feature && !strcmp(feature, "DailyDevotion")) {
1175 			if ((strlen(key) != 5) || // blunt tests.
1176 			    (key[0] < '0') || (key[0] > '9') ||
1177 			    (key[1] < '0') || (key[1] > '9') ||
1178 			    (key[2] != '.') ||
1179 			    (key[3] < '0') || (key[3] > '9') ||
1180 			    (key[4] < '0') || (key[4] > '9')) { // not MM.DD
1181 				struct tm *loctime;
1182 
1183 				curtime = time(NULL);
1184 				loctime = localtime(&curtime);
1185 				strftime(buf, 10, "%m.%d", loctime);
1186 				key = buf;
1187 			}
1188 		}
1189 		xml_set_value("Xiphos", "modules", "dict", mod_name);
1190 		gui_reassign_strdup(&settings.DictWindowModule, (gchar *)mod_name);
1191 	}
1192 
1193 	// old_key is uppercase
1194 	key = g_utf8_strup(key, -1);
1195 	old_key = gtk_entry_get_text(GTK_ENTRY(widgets.entry_dict));
1196 	if (!strcmp(old_key, key))
1197 		main_dictionary_entry_changed(settings.DictWindowModule);
1198 	else {
1199 		gtk_entry_set_text(GTK_ENTRY(widgets.entry_dict), key);
1200 		gtk_widget_activate(widgets.entry_dict);
1201 	}
1202 
1203 	//if (settings.browsing)
1204 	gui_update_tab_struct(NULL,
1205 			      NULL,
1206 			      mod_name,
1207 			      NULL,
1208 			      key,
1209 			      NULL,
1210 			      settings.comm_showing,
1211 			      settings.showtexts,
1212 			      settings.showpreview,
1213 			      settings.showcomms,
1214 			      settings.showdicts);
1215 }
1216 
main_display_bible(const char * mod_name,const char * key)1217 void main_display_bible(const char *mod_name,
1218 			const char *key)
1219 {
1220 	gchar *bs_key = g_strdup(key);	// avoid tab data corruption problem.
1221 
1222 	/* keeps us out of a crash causing loop */
1223 	extern guint scroll_adj_signal;
1224 	extern GtkAdjustment *adjustment;
1225 	if (adjustment)
1226 		g_signal_handler_block(adjustment, scroll_adj_signal);
1227 
1228 	if (!gtk_widget_get_realized(GTK_WIDGET(widgets.html_text)))
1229 		return;
1230 	if (!mod_name)
1231 		mod_name = ((settings.browsing && (cur_passage_tab != NULL))
1232 				? g_strdup(cur_passage_tab->text_mod)
1233 				: xml_get_value("modules", "bible"));
1234 
1235 	if (!settings.havebible || !mod_name)
1236 		return;
1237 	if (!backend->is_module(mod_name))
1238 		return;
1239 
1240 	int modtype = backend->module_type(mod_name);
1241 	if (modtype != TEXT_TYPE)
1242 		return; // what are we doing here?
1243 
1244 	if (!settings.MainWindowModule)
1245 		settings.MainWindowModule = g_strdup((gchar *)mod_name);
1246 
1247 	if (strcmp(settings.currentverse, key)) {
1248 		xml_set_value("Xiphos", "keys", "verse",
1249 			      key);
1250 		settings.currentverse = xml_get_value(
1251 		    "keys", "verse");
1252 	}
1253 
1254 	if (strcmp(settings.MainWindowModule, mod_name)) {
1255 		xml_set_value("Xiphos", "modules", "bible", mod_name);
1256 		gui_reassign_strdup(&settings.MainWindowModule, (gchar *)mod_name);
1257 
1258 		// handle a conf directive "Companion=This,That,TheOther"
1259 		char *companion = main_get_mod_config_entry(mod_name, "Companion");
1260 		gchar **name_set = (companion ? g_strsplit(companion, ",", -1) : NULL);
1261 
1262 		if (companion &&
1263 		    (!companion_activity) &&
1264 		    name_set[0] &&
1265 		    *name_set[0] &&
1266 		    backend->is_module(name_set[0]) &&
1267 		    ((settings.CommWindowModule == NULL) ||
1268 		     strcmp(name_set[0], settings.CommWindowModule))) {
1269 			companion_activity = TRUE;
1270 
1271 			gint name_length = g_strv_length(name_set);
1272 			char *companion_question =
1273 			    g_strdup_printf(_("Module %s has companion modules:\n%s.\n"
1274 					      "Would you like to open these as well?%s"),
1275 					    mod_name, companion,
1276 					    ((name_length > 1)
1277 						 ? _("\n\nThe first will open in the main window\n"
1278 						     "and others in separate windows.")
1279 						 : ""));
1280 
1281 			if (gui_yes_no_dialog(companion_question, NULL)) {
1282 				main_display_commentary(name_set[0], key);
1283 				for (int i = 1; i < name_length; i++) {
1284 					main_dialogs_open(name_set[i], key, FALSE);
1285 				}
1286 			}
1287 			g_free(companion_question);
1288 			companion_activity = FALSE;
1289 		}
1290 		if (name_set)
1291 			g_strfreev(name_set);
1292 		if (companion)
1293 			g_free(companion);
1294 
1295 		navbar_versekey.module_name = g_string_assign(navbar_versekey.module_name,
1296 							      settings.MainWindowModule);
1297 
1298 		navbar_versekey.key = g_string_assign(navbar_versekey.key,
1299 						      settings.currentverse);
1300 
1301 		main_search_sidebar_fill_bounds_combos();
1302 	}
1303 
1304 	settings.whichwindow = MAIN_TEXT_WINDOW;
1305 
1306 	main_check_unlock(mod_name, TRUE);
1307 
1308 	valid_scripture_key = main_is_Bible_key(mod_name, key);
1309 
1310 	if (backend->module_has_testament(mod_name,
1311 					  backend->get_key_testament(mod_name, key))) {
1312 		backend->set_module_key(mod_name, key);
1313 		backend->display_mod->display();
1314 	} else {
1315 		gchar *val_key = NULL;
1316 
1317 		if (backend->get_key_testament(mod_name, key) == 1)
1318 			val_key = main_update_nav_controls(mod_name, "Matthew 1:1");
1319 		else
1320 			val_key = main_update_nav_controls(mod_name, "Genesis 1:1");
1321 
1322 		backend->set_module_key(mod_name, val_key);
1323 		backend->display_mod->display();
1324 		g_free(val_key);
1325 	}
1326 
1327 	valid_scripture_key = TRUE; // leave nice for future use.
1328 
1329 	XI_message(("mod_name = %s", mod_name));
1330 	//if (settings.browsing) {
1331 	gui_update_tab_struct(mod_name,
1332 			      NULL,
1333 			      NULL,
1334 			      NULL,
1335 			      NULL,
1336 			      NULL,
1337 			      settings.comm_showing,
1338 			      settings.showtexts,
1339 			      settings.showpreview,
1340 			      settings.showcomms,
1341 			      settings.showdicts);
1342 	gui_set_tab_label(settings.currentverse, FALSE);
1343 	//}
1344 
1345 	gui_change_window_title(settings.MainWindowModule);
1346 	// (called _after_ tab data updated so not overwritten with old tab)
1347 
1348 	/*
1349 	 * change parallel verses
1350 	 */
1351 	if (settings.dockedInt)
1352 		main_update_parallel_page();
1353 	else {
1354 		if (settings.showparatab)
1355 			gui_keep_parallel_tab_in_sync();
1356 		else
1357 			gui_keep_parallel_dialog_in_sync();
1358 	}
1359 
1360 	// multicast now, iff user has not asked for keyboard-only xmit.
1361 	if (!settings.bs_keyboard)
1362 		biblesync_prep_and_xmit(mod_name, bs_key);
1363 	g_free(bs_key);
1364 
1365 	if (adjustment)
1366 		g_signal_handler_unblock(adjustment, scroll_adj_signal);
1367 }
1368 
1369 /******************************************************************************
1370  * Name
1371  *   main_display_devotional
1372  *
1373  * Synopsis
1374  *   #include "main/sword.h"
1375  *
1376  *   void main_display_devotional(void)
1377  *
1378  * Description
1379  *
1380  *
1381  * Return value
1382  *   void
1383  */
1384 
main_display_devotional(void)1385 void main_display_devotional(void)
1386 {
1387 	gchar buf[10];
1388 	gchar *prettybuf;
1389 	time_t curtime;
1390 	struct tm *loctime;
1391 	gchar *text;
1392 
1393 	/*
1394 	 * This makes sense only if you've installed & defined one.
1395 	 */
1396 	if (settings.devotionalmod == NULL) {
1397 		GList *glist = get_list(DEVOTION_LIST);
1398 
1399 		if (g_list_length(glist) != 0) {
1400 			xml_set_value("Xiphos", "modules", "devotional",
1401 				      (char *)glist->data);
1402 			gui_reassign_strdup(&settings.devotionalmod, (gchar *)glist->data);
1403 		} else {
1404 			gui_generic_warning(_("Daily devotional was requested, but there are none installed."));
1405 		}
1406 	}
1407 
1408 	/*
1409 	 * Get the current time, converted to local time.
1410 	 */
1411 	curtime = time(NULL);
1412 	loctime = localtime(&curtime);
1413 	strftime(buf, 10, "%m.%d", loctime);
1414 	prettybuf = g_strdup_printf("<b>%s %d</b>",
1415 				    gettext(month_names[loctime->tm_mon]),
1416 				    loctime->tm_mday);
1417 
1418 	text = backend->get_render_text(settings.devotionalmod, buf);
1419 	if (text) {
1420 		main_entry_display(settings.show_previewer_in_sidebar
1421 				       ? sidebar.html_viewer_widget
1422 				       : widgets.html_previewer_text,
1423 				   settings.devotionalmod, text, prettybuf, TRUE);
1424 		g_free(text);
1425 	}
1426 	g_free(prettybuf);
1427 }
1428 
main_setup_displays(void)1429 void main_setup_displays(void)
1430 {
1431 	backend->textDisplay = new GTKChapDisp(widgets.html_text, backend);
1432 	backend->commDisplay = new GTKEntryDisp(widgets.html_comm, backend);
1433 	backend->bookDisplay = new GTKEntryDisp(widgets.html_book, backend);
1434 	backend->dictDisplay = new GTKEntryDisp(widgets.html_dict, backend);
1435 }
1436 
main_get_module_language(const char * module_name)1437 const char *main_get_module_language(const char *module_name)
1438 {
1439 	return backend->module_get_language(module_name);
1440 }
1441 
1442 /******************************************************************************
1443  * Name
1444  *  main_check_for_option
1445  *
1446  * Synopsis
1447  *   #include ".h"
1448  *
1449  *  	gint main_check_for_option(const gchar * mod_name, const gchar * key, const gchar * option)
1450  *
1451  * Description
1452  *    get any option for a module
1453  *
1454  * Return value
1455  *   gint
1456  */
1457 
main_check_for_option(const gchar * mod_name,const gchar * key,const gchar * option)1458 gint main_check_for_option(const gchar *mod_name, const gchar *key, const gchar *option)
1459 {
1460 	return backend->has_option(mod_name, key, option);
1461 }
1462 
1463 /******************************************************************************
1464  * Name
1465  *  main_check_for_global_option
1466  *
1467  * Synopsis
1468  *   #include ".h"
1469  *
1470  *  	gint main_check_for_global_option(const gchar * mod_name, const gchar * option)
1471  *
1472  * Description
1473  *    get global options for a module
1474  *
1475  * Return value
1476  *   gint
1477  */
1478 
main_check_for_global_option(const gchar * mod_name,const gchar * option)1479 gint main_check_for_global_option(const gchar *mod_name, const gchar *option)
1480 {
1481 	return backend->has_global_option(mod_name, option);
1482 }
1483 
1484 /******************************************************************************
1485  * Name
1486  *   main_is_module
1487  *
1488  * Synopsis
1489  *   #include "main/module.h"
1490  *
1491  *   int main_is_module(char * mod_name)
1492  *
1493  * Description
1494  *    check for presents of a module by name
1495  *
1496  * Return value
1497  *   int
1498  */
1499 
main_is_module(char * mod_name)1500 int main_is_module(char *mod_name)
1501 {
1502 	return backend->is_module(mod_name);
1503 }
1504 
1505 /******************************************************************************
1506  * Name
1507  *   main_has_search_framework
1508  *
1509  * Synopsis
1510  *   #include "main/module.h"
1511  *
1512  *   int main_has_search_framework(char * mod_name)
1513  *
1514  * Description
1515  *    tells us whether CLucene is available
1516  *
1517  * Return value
1518  *   int (boolean)
1519  */
1520 
main_has_search_framework(char * mod_name)1521 int main_has_search_framework(char *mod_name)
1522 {
1523 	SWMgr *mgr = backend->get_mgr();
1524 	SWModule *mod = mgr->getModule(mod_name);
1525 	return (mod && mod->hasSearchFramework());
1526 }
1527 
1528 /******************************************************************************
1529  * Name
1530  *   main_optimal_search
1531  *
1532  * Synopsis
1533  *   #include "main/module.h"
1534  *
1535  *   int main_optimal_search(char * mod_name)
1536  *
1537  * Description
1538  *    tells us whether a CLucene index exists
1539  *
1540  * Return value
1541  *   int (boolean)
1542  */
1543 
main_optimal_search(char * mod_name)1544 int main_optimal_search(char *mod_name)
1545 {
1546 	SWMgr *mgr = backend->get_mgr();
1547 	SWModule *mod = mgr->Modules.find(mod_name)->second;
1548 	return mod->isSearchOptimallySupported("God", -4, 0, 0);
1549 }
1550 
main_get_mod_config_entry(const char * module_name,const char * entry)1551 char *main_get_mod_config_entry(const char *module_name,
1552 				const char *entry)
1553 {
1554 	return backend->get_config_entry((char *)module_name, (char *)entry);
1555 }
1556 
main_get_mod_config_file(const char * module_name,const char * moddir)1557 char *main_get_mod_config_file(const char *module_name,
1558 			       const char *moddir)
1559 {
1560 #ifdef SWORD_SHOULD_HAVE_A_WAY_TO_GET_A_CONF_FILENAME_FROM_A_MODNAME
1561 	return backend->get_config_file((char *)module_name, (char *)moddir);
1562 #else
1563 	GDir *dir;
1564 	SWBuf name;
1565 
1566 	name = moddir;
1567 	name += "/mods.d";
1568 	if ((dir = g_dir_open(name, 0, NULL))) {
1569 		const gchar *ent;
1570 
1571 		g_dir_rewind(dir);
1572 		while ((ent = g_dir_read_name(dir))) {
1573 			name = moddir;
1574 			name += "/mods.d/";
1575 			name += ent;
1576 			SWConfig *config = new SWConfig(name.c_str());
1577 			if (config->getSections().find(module_name) !=
1578 			    config->getSections().end()) {
1579 				gchar *ret_name = g_strdup(ent);
1580 				g_dir_close(dir);
1581 				delete config;
1582 				return ret_name;
1583 			} else
1584 				delete config;
1585 		}
1586 		g_dir_close(dir);
1587 	}
1588 	return NULL;
1589 #endif
1590 }
1591 
main_is_mod_rtol(const char * module_name)1592 int main_is_mod_rtol(const char *module_name)
1593 {
1594 	char *direction = backend->get_config_entry((char *)module_name, (char *)"Direction");
1595 	return (direction && !strcmp(direction, "RtoL"));
1596 }
1597 
1598 /******************************************************************************
1599  * Name
1600  *  main_has_cipher_tag
1601  *
1602  * Synopsis
1603  *   #include "main/.h"
1604  *
1605  *   int main_has_cipher_tag(char *mod_name)
1606  *
1607  * Description
1608  *
1609  *
1610  * Return value
1611  *   int
1612  */
1613 
main_has_cipher_tag(char * mod_name)1614 int main_has_cipher_tag(char *mod_name)
1615 {
1616 	gchar *cipherkey = backend->get_config_entry(mod_name, (char *)"CipherKey");
1617 	int retval = (cipherkey != NULL);
1618 	g_free(cipherkey);
1619 	return retval;
1620 }
1621 
1622 #define CIPHER_INTRO \
1623 	_("<b>Locked Module.</b>\n\n<u>You are opening a module which requires a <i>key</i>.</u>\n\nThe module is locked, meaning that the content is encrypted by its publisher, and you must enter its key in order for the content to become useful.  This key should have been received by you on the web page which confirmed your purchase, or perhaps sent via email after purchase.\n\nPlease enter the key in the dialog.")
1624 
1625 /******************************************************************************
1626  * Name
1627  *  main_check_unlock
1628  *
1629  * Synopsis
1630  *   #include "main/.h"
1631  *
1632  *   int main_check_unlock(const char *mod_name)
1633  *
1634  * Description
1635  *
1636  *
1637  * Return value
1638  *   int
1639  */
1640 
main_check_unlock(const char * mod_name,gboolean conditional)1641 void main_check_unlock(const char *mod_name, gboolean conditional)
1642 {
1643 	gchar *cipher_old = main_get_mod_config_entry(mod_name, "CipherKey");
1644 
1645 	/* if forced by the unlock menu item, or it's present but empty... */
1646 	if (!conditional ||
1647 	    ((cipher_old != NULL) && (*cipher_old == '\0'))) {
1648 
1649 		if (conditional) {
1650 			GtkWidget *dialog;
1651 			dialog = gtk_message_dialog_new_with_markup(NULL, /* no need for a parent window */
1652 								    GTK_DIALOG_DESTROY_WITH_PARENT,
1653 								    GTK_MESSAGE_INFO,
1654 								    GTK_BUTTONS_OK,
1655 								    CIPHER_INTRO);
1656 			g_signal_connect_swapped(dialog, "response",
1657 						 G_CALLBACK(gtk_widget_destroy),
1658 						 dialog);
1659 			gtk_widget_show(dialog);
1660 		}
1661 
1662 		gchar *cipher_key = gui_add_cipher_key(mod_name, cipher_old);
1663 		if (cipher_key) {
1664 			ModuleCacheErase(mod_name);
1665 			redisplay_to_realign();
1666 			g_free(cipher_key);
1667 		}
1668 	}
1669 	g_free(cipher_old);
1670 }
1671 
1672 /******************************************************************************
1673  * Name
1674  *   main_get_striptext
1675  *
1676  * Synopsis
1677  *   #include "main/sword.h"
1678  *
1679  *   char *main_get_striptext(char *module_name, char *key)
1680  *
1681  * Description
1682  *
1683  *
1684  * Return value
1685  *   char *
1686  */
1687 
main_get_striptext(char * module_name,char * key)1688 char *main_get_striptext(char *module_name, char *key)
1689 {
1690 	return backend->get_strip_text(module_name, key);
1691 }
1692 
1693 /******************************************************************************
1694  * Name
1695  *   main_get_rendered_text
1696  *
1697  * Synopsis
1698  *   #include "main/sword.h"
1699  *
1700  *   char *main_get_rendered_text(char *module_name, char *key)
1701  *
1702  * Description
1703  *
1704  *
1705  * Return value
1706  *   char *
1707  */
1708 
main_get_rendered_text(const char * module_name,const char * key)1709 char *main_get_rendered_text(const char *module_name, const char *key)
1710 {
1711 	return backend->get_render_text(module_name, key);
1712 }
1713 
1714 /******************************************************************************
1715  * Name
1716  *   main_get_raw_text
1717  *
1718  * Synopsis
1719  *   #include "main/sword.h"
1720  *
1721  *   char *main_get_raw_text(char *module_name, char *key)
1722  *
1723  * Description
1724  *
1725  *
1726  * Return value
1727  *   char *
1728  */
1729 
main_get_raw_text(char * module_name,char * key)1730 char *main_get_raw_text(char *module_name, char *key)
1731 {
1732 	return backend->get_raw_text(module_name, key);
1733 }
1734 
1735 /******************************************************************************
1736  * Name
1737  *  main_get_mod_type
1738  *
1739  * Synopsis
1740  *   #include "main/module.h"
1741  *
1742  *   int main_get_mod_type(char * mod_name)
1743  *
1744  * Description
1745  *
1746  *
1747  * Return value
1748  *   int
1749  */
1750 
main_get_mod_type(char * mod_name)1751 int main_get_mod_type(char *mod_name)
1752 {
1753 
1754 	return backend->module_type(mod_name);
1755 }
1756 
1757 /******************************************************************************
1758  * Name
1759  *  main_get_module_description
1760  *
1761  * Synopsis
1762  *   #include "main/module.h"
1763  *
1764  *   gchar *main_get_module_description(gchar * module_name)
1765  *
1766  * Description
1767  *
1768  *
1769  * Return value
1770  *   gchar *
1771  */
1772 
main_get_module_description(const char * module_name)1773 const char *main_get_module_description(const char *module_name)
1774 {
1775 	return backend->module_description(module_name);
1776 }
1777 
1778 /******************************************************************************
1779  * Name
1780  *  main_format_number
1781  *
1782  * Synopsis
1783  *   #include "main/sword.h"
1784  *   char *main_format_number(int x)
1785  *
1786  * Description
1787  *   returns a digit string in either "latinate arabic" (normal) or
1788  *   farsi characters.
1789  *   re_encode_digits is chosen at startup in settings.c.
1790  *   caller must free allocated string space when finished with it.
1791  *
1792  * Return value
1793  *   char *
1794  */
1795 
1796 int re_encode_digits = FALSE;
1797 
1798 char *
main_format_number(int x)1799 main_format_number(int x)
1800 {
1801 	char *digits = g_strdup_printf("%d", x);
1802 
1803 	if (re_encode_digits) {
1804 		//
1805 		// "\333\260" is farsi "zero".
1806 		//
1807 		char *d, *f, *farsi = g_new(char, 2 * (strlen(digits) + 1));
1808 		// 2 "chars" per farsi-displayed digit + slop.
1809 
1810 		for (d = digits, f = farsi; *d; ++d) {
1811 			*(f++) = '\333';
1812 			*(f++) = '\260' + ((*d) - '0');
1813 		}
1814 		*f = '\0';
1815 		g_free(digits);
1816 		return farsi;
1817 	}
1818 	return digits;
1819 }
1820 
1821 /******************************************************************************
1822  * Name
1823  *  main_flush_widgets_content
1824  *
1825  * Synopsis
1826  *   #include "main/sword.h"
1827  *   void main_flush_widgets_content()
1828  *
1829  * Description
1830  *   cleans content from all subwindow widgets.
1831  *
1832  * Return value
1833  *   int
1834  */
main_flush_widgets_content(void)1835 void main_flush_widgets_content(void)
1836 {
1837 	GString *blank_html_content = g_string_new(NULL);
1838 	g_string_printf(blank_html_content,
1839 			"<html><head></head><body bgcolor=\"%s\" text=\"%s\"> </body></html>",
1840 			settings.bible_bg_color, settings.bible_text_color);
1841 
1842 	if (gtk_widget_get_realized(GTK_WIDGET(widgets.html_text)))
1843 		HtmlOutput(blank_html_content->str, widgets.html_text, NULL, NULL);
1844 	if (gtk_widget_get_realized(GTK_WIDGET(widgets.html_comm)))
1845 		HtmlOutput(blank_html_content->str, widgets.html_comm, NULL, NULL);
1846 	if (gtk_widget_get_realized(GTK_WIDGET(widgets.html_dict)))
1847 		HtmlOutput(blank_html_content->str, widgets.html_dict, NULL, NULL);
1848 	if (gtk_widget_get_realized(GTK_WIDGET(widgets.html_book)))
1849 		HtmlOutput(blank_html_content->str, widgets.html_book, NULL, NULL);
1850 	g_string_free(blank_html_content, TRUE);
1851 }
1852 
1853 /******************************************************************************
1854  * Name
1855  *  main_is_Bible_key
1856  *
1857  * Synopsis
1858  *   #include "main/sword.h"
1859  *   void main_is_Bible_key()
1860  *
1861  * Description
1862  *   returns boolean status of whether input is a legit Bible key.
1863  *
1864  * Return value
1865  *   gboolean
1866  */
main_is_Bible_key(const gchar * name,const gchar * key)1867 gboolean main_is_Bible_key(const gchar *name, const gchar *key)
1868 {
1869 	return (gboolean)(backend->is_Bible_key(name, key, settings.currentverse) != 0);
1870 }
1871 
1872 /******************************************************************************
1873  * Name
1874  *  main_get_osisref_from_key
1875  *
1876  * Synopsis
1877  *   #include "main/sword.h"
1878  *   void main_get_osisref_from_key()
1879  *
1880  * Description
1881  *   returns OSISRef-formatted key value.
1882  *
1883  * Return value
1884  *   const char *
1885  */
1886 const char *
main_get_osisref_from_key(const char * module,const char * key)1887 main_get_osisref_from_key(const char *module, const char *key)
1888 {
1889 	return backend->get_osisref_from_key(module, key);
1890 }
1891