Bugfix for issue #4: crash with non-existent default module.

This commit is contained in:
Paul Mosier 2022-12-27 15:45:30 -05:00
parent 0e430dcd9e
commit 90bb1d499c
4 changed files with 170 additions and 18 deletions

3
.gitignore vendored
View File

@ -32,4 +32,5 @@
*.out
*.app
push-checklist.org
push-checklist.org
scriptura

View File

@ -20,10 +20,15 @@
#include <iostream>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "scabbard.h"
scabbard::scabbard() {
// initialize the thing!
swrd = *(new sword::SWMgr());
/* store what markup information the user has requested be shown
* SWBuf.c_str() returns the ascii code 48 for '0', so we have to do some
* math to get the proper boolean setting */
@ -31,9 +36,11 @@ scabbard::scabbard() {
markstrongs = parseConf(config["markup"]["strongs"]);
markfoot = parseConf(config["markup"]["footnotes"]);
/* everything following is based on constructing the menu used to display
* to the reader about what modules the system has - start with a
* temporary array of module types */
// construct the menu list of modules
constructModlist();
}
void scabbard::constructModlist() {
int tmpnum = 4;
modtype tmpmods[4];
strcpy(tmpmods[0].label, "Generic Books");
@ -187,6 +194,21 @@ const char* scabbard::getModDescription(const char* modname) {
return text->getDescription();
}
int scabbard::modExists(const char* modname) {
sword::SWModule *text = swrd.getModule(modname);
return (text == 0 ? 0 : 1);
}
starray scabbard::getModules() {
starray retval;
retval = stinit(retval);
for (iter = swrd.Modules.begin(); iter != swrd.Modules.end(); iter++) {
sword::SWModule *mod = iter->second;
retval = stappend(retval, mod->getName());
}
return retval;
}
int scabbard::getKeyType(int modt) {
return modules[modt].keytype;
}
@ -228,6 +250,87 @@ const char* scabbard::search(modkey mod) {
return directSearch(text, mod);
}
void scabbard::installKJVA() {
sword::SWBuf swordhome = getenv("HOME");
swordhome += "/.sword";
// ensure some directories exist -- apparently installmgr doesn't create them
if ((mkdir(swordhome + "/mods.d", 00755) != 0) && (errno != EEXIST)) {
printf("Error creating directory to perform the install:\n");
printf("~/.sword/mods.d\n");
printf("Please create manually or check directory permissions.\n");
exit(0);
}
sword::SWBuf finaldir = swordhome.c_str();
finaldir += "/modules";
mkdir(finaldir.c_str(), 00755);
finaldir += "/texts";
mkdir(finaldir.c_str(), 00755);
finaldir += "/ztext";
mkdir(finaldir.c_str(), 00755);
finaldir += "/kjva";
if ((mkdir(finaldir.c_str(), 00755) != 0) && (errno != EEXIST)) {
printf("Error creating directory to perform the install:\n");
printf("~/.sword/modules/texts/ztext/kjva\n");
printf("Please create manually or check directory permissions.\n");
exit(0);
}
printf("Directories created for new module.\n");
// installmgr -init
sword::InstallMgr* im = new sword::InstallMgr(swordhome + "/InstallMgr");
im->setUserDisclaimerConfirmed(true);
// sync config (installmgr -sc)
sword::InstallSource is("FTP");
is.caption = "CrossWire";
is.source = "ftp.crosswire.org";
is.directory = "/pub/sword/raw";
sword::SWConfig installconf(swordhome + "/InstallMgr/InstallMgr.conf");
if (! installconf["General"]["PassiveFTP"])
installconf["General"]["PassiveFTP"] = "true";
if (! installconf["General"]["TimeoutMillis"])
installconf["General"]["TimeoutMillis"] = "10000";
if (! installconf["General"]["UnverifiedPeerAllowed"])
installconf["General"]["UnverifiedPeerAllowed"] = false;
if (! installconf["General"]["FTPSource"])
installconf["Sources"]["FTPSource"] = is.getConfEnt();
installconf.save();
im->refreshRemoteSourceConfiguration();
/* refresh remote source (installmgr -r)
* apparently we can't reuse our prior declared InstallSource here */
sword::InstallSourceMap::iterator source = im->sources.find("CrossWire");
sword::InstallSource *is2 = source->second;
if (source == im->sources.end()) {
fprintf(stderr, "Couldn't find remote source [%s]\n", "CrossWire");
}
if (int refresh = im->refreshRemoteSource(is2)) {
printf("Refresh call failed, error: %d\n", refresh);
printf("Most likely this is an InstalMgr configuration issue.\n");
printf("Please ensure your SWORD environment is properly configured,\n");
printf(" or download & install the module manually before trying again.\n");
exit(0);
}
// install module (installmgr -ri CrossWire KJVA)
sword::SWMgr* rmgr = is2->getMgr();
sword::SWModule* modname = rmgr->getModule("KJVA");
if (im->installModule(new sword::SWMgr(), 0, modname->getName(), is2)) {
printf("Error installing module.\n");
printf("Most likely this is an environment configuration issue.\n");
printf("Please ensure your SWORD environment is properly configured,\n");
printf(" or download & install the module manually before trying again.\n");
exit(0);
}
// update internal module list & refresh SWMgr w/installed module info
swrd = *(new sword::SWMgr());
constructModlist();
}
/* really old code in case we need to pull output from diatheke
FILE *modlist = popen("diatheke -b system -k modulelist", "r");
char buf[1024];

View File

@ -27,6 +27,7 @@
#include <swbuf.h>
#include <versekey.h>
#include <treekey.h>
#include <installmgr.h>
#include <osisredletterwords.h>
#include <osisstrongs.h>
@ -83,6 +84,9 @@ class scabbard {
//!< modkey containing the search term
);
//! Construct the internal list of modules used in the selection menu.
void constructModlist();
public:
//! Takes as input various preferences on text markup from our config file
scabbard();
@ -113,11 +117,20 @@ class scabbard {
int mod //!< from getModDescriptions()
);
/*! Get the full text name for a module identified by key name.
/*! Get the full text name for a module identified by key name. Vulnerable
* to malicious input.
* \returns the module description */
const char* getModDescription(const char* modname //!< module internal name
);
//! Return an array of all module names.
starray getModules();
/*! Given a text name for a module, determine if it exists.
*/
int modExists(const char* modname //!< module internal name
);
/*! Determine how a module is keyed/indexed.
* \returns the proper keytype; see the keytype field for modkey */
int getKeyType(int modt //!< return value from getModClassifications()
@ -129,11 +142,14 @@ class scabbard {
);
/*! Search for a term or passage.
* \returns the text requested, or in the case of a non-versekeyed text,
* the nearest alphabetical entry to the search term supplied */
* \returns the text requested, or in the case of a non-versekeyed text,
* the nearest alphabetical entry to the search term supplied */
const char* search(modkey mod //!< the modkey supplied by the pane
);
//! Install KJVA from ftp.crosswire.org.
void installKJVA();
};
#endif

View File

@ -205,16 +205,50 @@ int main(int argc, char** argv) {
}
config = *(new sword::SWConfig(configfile));
// ensure some needed config settings are in place
/* load up a scabbard & set blank starting data - scabbard args are
* sanitized in the constructor */
scabbard scab = {};
/* before we render anything, ensure some needed config settings are in
* place & sanitized, with needed changes saved back to file */
if (! strcmp(config["layout"]["panels"], ""))
config["layout"]["panels"] = "v";
if (! strcmp(config["defaults"]["scope"], ""))
config["defaults"]["scope"] = "Gen 1:1 - Rev 22:21";
if (! strcmp(config["defaults"]["searchkey"], ""))
config["defaults"]["searchkey"] = "2 Tim 1:7";
if (! strcmp(config["defaults"]["module"], ""))
// XXX -- should load install manager, and if default module is present, verify it
config["defaults"]["module"] = "KJVA";
if ((! strcmp(config["defaults"]["module"], "")) ||
(! scab.modExists(config["defaults"]["module"]))) {
/* prompt for a default module - we're on partial startup here and
* still outside of ncurses, so we do this the old fashioned way. */
printf("You either do not have a default module selected, "
"or what you have chosen is not installed.\n");
printf("Please select one before continuing.\n\n");
printf("0 - Install KJVA from ftp.crosswire.org.\n");
starray mods = scab.getModules();
for (int i = 0; i < mods.length; i++) {
const char* longname = scab.getModDescription(mods.strings[i]);
printf("%d - %s\n", i+1, longname);
}
printf("\nDefault module to choose: ");
char readit[4];
fgets(readit, 4, stdin);
long selection = 0;
selection = strtol(readit, NULL, 10);
const char* defmod;
if ((selection == 0) || (selection > mods.length)) {
printf("Installing from ftp.crosswire.org...\n");
scab.installKJVA();
defmod = "KJVA";
printf("done.\n");
} else defmod = mods.strings[selection - 1];
config["defaults"]["module"] = defmod;
}
if (! strcmp(config["defaults"]["searchtype"], "")) {
char* temp;
asprintf(&temp, "%d", DEFSEARCH);
@ -233,6 +267,7 @@ int main(int argc, char** argv) {
* keys & so on */
initscr();
cbreak();
curs_set(0);
noecho();
start_color();
@ -275,9 +310,10 @@ int main(int argc, char** argv) {
config[pages[i][j]]["searchkey"] = config["defaults"]["searchkey"]);
}
// XXX -- confirm this module actually exists; if not, then use our default because we've already sanitized that
if (linking && (! strcmp(config[pages[i][j]]["module"], "")))
if (linking && ((! strcmp(config[pages[i][j]]["module"], "")) ||
(! scab.modExists(config[pages[i][j]]["module"])))) {
config[pages[i][j]]["module"] = config["defaults"]["module"];
}
if (linking && (! strcmp(config[pages[i][j]]["keytype"], "")))
config[pages[i][j]]["keytype"] = config["defaults"]["keytype"];
@ -296,11 +332,7 @@ int main(int argc, char** argv) {
// set index for page list
currentpage = 0;
/* load up a scabbard & set blank starting data - scabbard args are
* sanitized in the constructor */
scabbard scab = {};
// configure panes
// initialize panes and render
landmarks();
pane* p = (pane*) malloc(sizeof(pane) * NUMPANES);
if (! p) wrapup(1, "Error allocating memory for panes.\n");