summaryrefslogtreecommitdiff
path: root/src/mgr
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr')
-rw-r--r--src/mgr/Makefile4
-rw-r--r--src/mgr/Makefile.am33
-rw-r--r--src/mgr/curlftpt.cpp159
-rw-r--r--src/mgr/encfiltmgr.cpp154
-rw-r--r--src/mgr/filemgr.cpp566
-rw-r--r--src/mgr/ftplibftpt.cpp108
-rw-r--r--src/mgr/ftptrans.cpp170
-rw-r--r--src/mgr/installmgr.cpp579
-rw-r--r--src/mgr/localemgr.cpp257
-rw-r--r--src/mgr/markupfiltmgr.cpp295
-rw-r--r--src/mgr/stringmgr.cpp280
-rw-r--r--src/mgr/swcacher.cpp47
-rw-r--r--src/mgr/swconfig.cpp155
-rw-r--r--src/mgr/swfiltermgr.cpp93
-rw-r--r--src/mgr/swlocale.cpp204
-rw-r--r--src/mgr/swmgr.cpp1275
-rw-r--r--src/mgr/swsearchable.cpp53
17 files changed, 4432 insertions, 0 deletions
diff --git a/src/mgr/Makefile b/src/mgr/Makefile
new file mode 100644
index 0000000..339f87a
--- /dev/null
+++ b/src/mgr/Makefile
@@ -0,0 +1,4 @@
+root := ../..
+
+all:
+ make -C ${root}
diff --git a/src/mgr/Makefile.am b/src/mgr/Makefile.am
new file mode 100644
index 0000000..1b1e33b
--- /dev/null
+++ b/src/mgr/Makefile.am
@@ -0,0 +1,33 @@
+mgrdir = $(top_srcdir)/src/mgr
+
+if CONFDEF
+globdef = -DGLOBCONFPATH=\"${globalconfdir}/sword.conf\"
+else
+globdef =
+endif
+
+AM_CPPFLAGS += $(globdef)
+AM_CPPFLAGS += -D_FTPLIB_NO_COMPAT
+
+if WITHCURL
+FTP_SOURCES = $(mgrdir)/curlftpt.cpp
+else
+FTP_SOURCES = $(mgrdir)/ftplibftpt.cpp
+endif
+
+libsword_la_SOURCES += $(FTP_SOURCES)
+libsword_la_SOURCES += $(mgrdir)/swconfig.cpp
+libsword_la_SOURCES += $(mgrdir)/swmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/swfiltermgr.cpp
+libsword_la_SOURCES += $(mgrdir)/encfiltmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/markupfiltmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/filemgr.cpp
+libsword_la_SOURCES += $(mgrdir)/ftptrans.cpp
+libsword_la_SOURCES += $(mgrdir)/swlocale.cpp
+libsword_la_SOURCES += $(mgrdir)/localemgr.cpp
+libsword_la_SOURCES += $(mgrdir)/swcacher.cpp
+libsword_la_SOURCES += $(mgrdir)/swsearchable.cpp
+libsword_la_SOURCES += $(mgrdir)/installmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/stringmgr.cpp
+
+
diff --git a/src/mgr/curlftpt.cpp b/src/mgr/curlftpt.cpp
new file mode 100644
index 0000000..bb47958
--- /dev/null
+++ b/src/mgr/curlftpt.cpp
@@ -0,0 +1,159 @@
+ /*****************************************************************************
+ * CURLFTPTransport functions
+ *
+ */
+
+
+#include <curlftpt.h>
+
+#include <fcntl.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#include <swlog.h>
+
+SWORD_NAMESPACE_START
+
+
+struct FtpFile {
+ const char *filename;
+ FILE *stream;
+ SWBuf *destBuf;
+};
+
+
+int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream);
+int my_fprogress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
+
+static CURLFTPTransport_init _CURLFTPTransport_init;
+
+CURLFTPTransport_init::CURLFTPTransport_init() {
+ //curl_global_init(CURL_GLOBAL_DEFAULT); // curl_easy_init automatically calls it if needed
+}
+
+CURLFTPTransport_init::~CURLFTPTransport_init() {
+ curl_global_cleanup();
+}
+
+int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) {
+ struct FtpFile *out=(struct FtpFile *)stream;
+ if (out && !out->stream && !out->destBuf) {
+ /* open file for writing */
+ out->stream=fopen(out->filename, "wb");
+ if (!out->stream)
+ return -1; /* failure, can't open file to write */
+ }
+ if (out->destBuf) {
+ int s = out->destBuf->size();
+ out->destBuf->size(s+(size*nmemb));
+ memcpy(out->destBuf->getRawData()+s, buffer, size*nmemb);
+ return nmemb;
+ }
+ return fwrite(buffer, size, nmemb, out->stream);
+}
+
+
+int my_fprogress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
+ if (clientp) {
+ ((StatusReporter *)clientp)->statusUpdate(dltotal, dlnow);
+ }
+ return 0;
+}
+
+
+static int my_trace(CURL *handle, curl_infotype type, unsigned char *data, size_t size, void *userp) {
+ SWBuf header;
+ (void)userp; /* prevent compiler warning */
+ (void)handle; /* prevent compiler warning */
+
+ switch (type) {
+ case CURLINFO_TEXT: header = "TEXT"; break;
+ case CURLINFO_HEADER_OUT: header = "=> Send header"; break;
+ case CURLINFO_HEADER_IN: header = "<= Recv header"; break;
+
+ // these we don't want to log (HUGE)
+ case CURLINFO_DATA_OUT: header = "=> Send data";
+ case CURLINFO_SSL_DATA_OUT: header = "=> Send SSL data";
+ case CURLINFO_DATA_IN: header = "<= Recv data";
+ case CURLINFO_SSL_DATA_IN: header = "<= Recv SSL data";
+ default: /* in case a new one is introduced to shock us */
+ return 0;
+ }
+
+ if (size > 120) size = 120;
+ SWBuf text;
+ text.size(size);
+ memcpy(text.getRawData(), data, size);
+ SWLog::getSystemLog()->logDebug("CURLFTPTransport: %s: %s", header.c_str(), text.c_str());
+ return 0;
+}
+
+CURLFTPTransport::CURLFTPTransport(const char *host, StatusReporter *sr) : FTPTransport(host, sr) {
+ session = (CURL *)curl_easy_init();
+}
+
+
+CURLFTPTransport::~CURLFTPTransport() {
+ curl_easy_cleanup(session);
+}
+
+
+char CURLFTPTransport::getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf) {
+ signed char retVal = 0;
+ struct FtpFile ftpfile = {destPath, 0, destBuf};
+
+ CURLcode res;
+
+ if (session) {
+ curl_easy_setopt(session, CURLOPT_URL, sourceURL);
+
+ curl_easy_setopt(session, CURLOPT_USERPWD, "ftp:installmgr@user.com");
+ curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, my_fwrite);
+ if (!passive)
+ curl_easy_setopt(session, CURLOPT_FTPPORT, "-");
+ curl_easy_setopt(session, CURLOPT_NOPROGRESS, 0);
+ curl_easy_setopt(session, CURLOPT_PROGRESSDATA, statusReporter);
+ curl_easy_setopt(session, CURLOPT_PROGRESSFUNCTION, my_fprogress);
+ curl_easy_setopt(session, CURLOPT_DEBUGFUNCTION, my_trace);
+ /* Set a pointer to our struct to pass to the callback */
+ curl_easy_setopt(session, CURLOPT_FILE, &ftpfile);
+
+ /* Switch on full protocol/debug output */
+ curl_easy_setopt(session, CURLOPT_VERBOSE, true);
+
+ /* FTP connection settings */
+
+#if (LIBCURL_VERSION_MAJOR > 7) || \
+ ((LIBCURL_VERSION_MAJOR == 7) && (LIBCURL_VERSION_MINOR > 10)) || \
+ ((LIBCURL_VERSION_MAJOR == 7) && (LIBCURL_VERSION_MINOR == 10) && (LIBCURL_VERSION_PATCH >= 5))
+# define EPRT_AVAILABLE 1
+#endif
+
+#ifdef EPRT_AVAILABLE
+ curl_easy_setopt(session, CURLOPT_FTP_USE_EPRT, 0);
+ SWLog::getSystemLog()->logDebug("***** using CURLOPT_FTP_USE_EPRT\n");
+#endif
+
+
+ SWLog::getSystemLog()->logDebug("***** About to perform curl easy action. \n");
+ SWLog::getSystemLog()->logDebug("***** destPath: %s \n", destPath);
+ SWLog::getSystemLog()->logDebug("***** sourceURL: %s \n", sourceURL);
+ res = curl_easy_perform(session);
+ SWLog::getSystemLog()->logDebug("***** Finished performing curl easy action. \n");
+
+ if(CURLE_OK != res) {
+ retVal = -1;
+ }
+ }
+
+ if (ftpfile.stream)
+ fclose(ftpfile.stream); /* close the local file */
+
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END
+
diff --git a/src/mgr/encfiltmgr.cpp b/src/mgr/encfiltmgr.cpp
new file mode 100644
index 0000000..970900c
--- /dev/null
+++ b/src/mgr/encfiltmgr.cpp
@@ -0,0 +1,154 @@
+/******************************************************************************
+ * swencodingmgr.cpp - implementaion of class EncodingFilterMgr, subclass of
+ * used to transcode all module text to a requested
+ * encoding.
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <encfiltmgr.h>
+#include <utilstr.h>
+
+#include <scsuutf8.h>
+#include <latin1utf8.h>
+
+#include <unicodertf.h>
+#include <utf8latin1.h>
+#include <utf8utf16.h>
+#include <utf8html.h>
+#include <swmodule.h>
+
+#include <swmgr.h>
+
+SWORD_NAMESPACE_START
+
+/******************************************************************************
+ * EncodingFilterMgr Constructor - initializes instance of EncodingFilterMgr
+ *
+ * ENT:
+ * enc - Encoding format to emit
+ */
+
+EncodingFilterMgr::EncodingFilterMgr (char enc)
+ : SWFilterMgr() {
+
+ scsuutf8 = new SCSUUTF8();
+ latin1utf8 = new Latin1UTF8();
+
+ encoding = enc;
+
+ switch (encoding) {
+ case ENC_LATIN1:
+ targetenc = new UTF8Latin1();
+ break;
+ case ENC_UTF16:
+ targetenc = new UTF8UTF16();
+ break;
+ case ENC_RTF:
+ targetenc = new UnicodeRTF();
+ break;
+ case ENC_HTML:
+ targetenc = new UTF8HTML();
+ break;
+ default: // i.e. case ENC_UTF8
+ targetenc = NULL;
+ }
+}
+
+/******************************************************************************
+ * EncodingFilterMgr Destructor - Cleans up instance of EncodingFilterMgr
+ */
+EncodingFilterMgr::~EncodingFilterMgr() {
+ if (scsuutf8)
+ delete scsuutf8;
+ if (latin1utf8)
+ delete latin1utf8;
+ if (targetenc)
+ delete targetenc;
+}
+
+void EncodingFilterMgr::AddRawFilters(SWModule *module, ConfigEntMap &section) {
+
+ ConfigEntMap::iterator entry;
+
+ SWBuf encoding = ((entry = section.find("Encoding")) != section.end()) ? (*entry).second : (SWBuf)"";
+ if (!encoding.length() || !stricmp(encoding.c_str(), "Latin-1")) {
+ module->AddRawFilter(latin1utf8);
+ }
+ else if (!stricmp(encoding.c_str(), "SCSU")) {
+ module->AddRawFilter(scsuutf8);
+ }
+}
+
+void EncodingFilterMgr::AddEncodingFilters(SWModule *module, ConfigEntMap &section) {
+ if (targetenc)
+ module->AddEncodingFilter(targetenc);
+}
+
+/******************************************************************************
+ * EncodingFilterMgr::Encoding - sets/gets encoding
+ *
+ * ENT: enc - new encoding or 0 to simply get the current encoding
+ *
+ * RET: encoding
+ */
+char EncodingFilterMgr::Encoding(char enc) {
+ if (enc && enc != encoding) {
+ encoding = enc;
+ SWFilter * oldfilter = targetenc;
+
+ switch (encoding) {
+ case ENC_LATIN1:
+ targetenc = new UTF8Latin1();
+ break;
+ case ENC_UTF16:
+ targetenc = new UTF8UTF16();
+ break;
+ case ENC_RTF:
+ targetenc = new UnicodeRTF();
+ break;
+ case ENC_HTML:
+ targetenc = new UTF8HTML();
+ break;
+ default: // i.e. case ENC_UTF8
+ targetenc = NULL;
+ }
+
+ ModMap::const_iterator module;
+
+ if (oldfilter != targetenc) {
+ if (oldfilter) {
+ if (!targetenc) {
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ module->second->RemoveRenderFilter(oldfilter);
+ }
+ else {
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ module->second->ReplaceRenderFilter(oldfilter, targetenc);
+ }
+ delete oldfilter;
+ }
+ else if (targetenc) {
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ module->second->AddRenderFilter(targetenc);
+ }
+ }
+
+ }
+ return encoding;
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/filemgr.cpp b/src/mgr/filemgr.cpp
new file mode 100644
index 0000000..4a91dfa
--- /dev/null
+++ b/src/mgr/filemgr.cpp
@@ -0,0 +1,566 @@
+/******************************************************************************
+ * filemgr.cpp - implementation of class FileMgr used for pooling file
+ * handles
+ *
+ * $Id: filemgr.cpp 2108 2007-10-13 20:35:02Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <filemgr.h>
+#include <utilstr.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <swbuf.h>
+#if !defined(__GNUC__) && !defined(_WIN32_WCE)
+#include <io.h>
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef S_IRGRP
+#define S_IRGRP 0
+#endif
+
+#ifndef S_IROTH
+#define S_IROTH 0
+#endif
+
+// Fix for VC6
+#ifndef S_IREAD
+#ifdef _S_IREAD
+#define S_IREAD _S_IREAD
+#define S_IWRITE _S_IWRITE
+#endif
+#endif
+// -----------
+
+
+SWORD_NAMESPACE_START
+
+
+int FileMgr::CREAT = O_CREAT;
+int FileMgr::APPEND = O_APPEND;
+int FileMgr::TRUNC = O_TRUNC;
+int FileMgr::RDONLY = O_RDONLY;
+int FileMgr::RDWR = O_RDWR;
+int FileMgr::WRONLY = O_WRONLY;
+int FileMgr::IREAD = S_IREAD;
+int FileMgr::IWRITE = S_IWRITE;
+
+
+// ---------------- statics -----------------
+FileMgr *FileMgr::systemFileMgr = 0;
+
+class __staticsystemFileMgr {
+public:
+ __staticsystemFileMgr() { }
+ ~__staticsystemFileMgr() { delete FileMgr::systemFileMgr; }
+} _staticsystemFileMgr;
+
+
+FileMgr *FileMgr::getSystemFileMgr() {
+ if (!systemFileMgr)
+ systemFileMgr = new FileMgr();
+
+ return systemFileMgr;
+}
+
+
+void FileMgr::setSystemFileMgr(FileMgr *newFileMgr) {
+ if (systemFileMgr)
+ delete systemFileMgr;
+ systemFileMgr = newFileMgr;
+}
+
+// --------------- end statics --------------
+
+
+FileDesc::FileDesc(FileMgr *parent, const char *path, int mode, int perms, bool tryDowngrade) {
+ this->parent = parent;
+ this->path = 0;
+ stdstr(&this->path, path);
+ this->mode = mode;
+ this->perms = perms;
+ this->tryDowngrade = tryDowngrade;
+ offset = 0;
+ fd = -77;
+}
+
+
+FileDesc::~FileDesc() {
+ if (fd > 0)
+ close(fd);
+
+ if (path)
+ delete [] path;
+}
+
+
+int FileDesc::getFd() {
+ if (fd == -77)
+ fd = parent->sysOpen(this);
+// if ((fd < -1) && (fd != -77)) // kludge to hand ce
+// return 777;
+ return fd;
+}
+
+
+long FileDesc::seek(long offset, int whence) {
+ return lseek(getFd(), offset, whence);
+}
+
+
+long FileDesc::read(void *buf, long count) {
+ return ::read(getFd(), buf, count);
+}
+
+
+long FileDesc::write(const void *buf, long count) {
+ return ::write(getFd(), buf, count);
+}
+
+
+FileMgr::FileMgr(int maxFiles) {
+ this->maxFiles = maxFiles; // must be at least 2
+ files = 0;
+}
+
+
+FileMgr::~FileMgr() {
+ FileDesc *tmp;
+
+ while(files) {
+ tmp = files->next;
+ delete files;
+ files = tmp;
+ }
+}
+
+
+FileDesc *FileMgr::open(const char *path, int mode, bool tryDowngrade) {
+ return open(path, mode, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH, tryDowngrade);
+}
+
+
+FileDesc *FileMgr::open(const char *path, int mode, int perms, bool tryDowngrade) {
+ FileDesc **tmp, *tmp2;
+
+ for (tmp = &files; *tmp; tmp = &((*tmp)->next)) {
+ if ((*tmp)->fd < 0) // insert as first non-system_open file
+ break;
+ }
+
+ tmp2 = new FileDesc(this, path, mode, perms, tryDowngrade);
+ tmp2->next = *tmp;
+ *tmp = tmp2;
+
+ return tmp2;
+}
+
+
+void FileMgr::close(FileDesc *file) {
+ FileDesc **loop;
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+ if (*loop == file) {
+ *loop = (*loop)->next;
+ delete file;
+ break;
+ }
+ }
+}
+
+
+int FileMgr::sysOpen(FileDesc *file) {
+ FileDesc **loop;
+ int openCount = 1; // because we are presently opening 1 file, and we need to be sure to close files to accomodate, if necessary
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+
+ if ((*loop)->fd > 0) {
+ if (++openCount > maxFiles) {
+ (*loop)->offset = lseek((*loop)->fd, 0, SEEK_CUR);
+ ::close((*loop)->fd);
+ (*loop)->fd = -77;
+ }
+ }
+
+ if (*loop == file) {
+ if (*loop != files) {
+ *loop = (*loop)->next;
+ file->next = files;
+ files = file;
+ }
+ if ((!access(file->path, 04)) || ((file->mode & O_CREAT) == O_CREAT)) { // check for at least file exists / read access before we try to open
+ char tries = (((file->mode & O_RDWR) == O_RDWR) && (file->tryDowngrade)) ? 2 : 1; // try read/write if possible
+ for (int i = 0; i < tries; i++) {
+ if (i > 0) {
+ file->mode = (file->mode & ~O_RDWR); // remove write access
+ file->mode = (file->mode | O_RDONLY);// add read access
+ }
+ file->fd = ::open(file->path, file->mode|O_BINARY, file->perms);
+
+ if (file->fd >= 0)
+ break;
+ }
+
+ if (file->fd >= 0)
+ lseek(file->fd, file->offset, SEEK_SET);
+ }
+ else file->fd = -1;
+ if (!*loop)
+ break;
+ }
+ }
+ return file->fd;
+}
+
+
+// to truncate a file at its current position
+// leaving byte at current possition intact
+// deleting everything afterward.
+signed char FileMgr::trunc(FileDesc *file) {
+
+ static const char *writeTest = "x";
+ long size = file->seek(1, SEEK_CUR);
+ if (size == 1) // was empty
+ size = 0;
+ char nibble [ 32767 ];
+ bool writable = file->write(writeTest, 1);
+ int bytes = 0;
+
+ if (writable) {
+ // get tmpfilename
+ char *buf = new char [ strlen(file->path) + 10 ];
+ int i;
+ for (i = 0; i < 9999; i++) {
+ sprintf(buf, "%stmp%.4d", file->path, i);
+ if (!existsFile(buf))
+ break;
+ }
+ if (i == 9999)
+ return -2;
+
+ int fd = ::open(buf, O_CREAT|O_RDWR, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH);
+ if (fd < 0)
+ return -3;
+
+ file->seek(0, SEEK_SET);
+ while (size > 0) {
+ bytes = file->read(nibble, 32767);
+ write(fd, nibble, (bytes < size)?bytes:size);
+ size -= bytes;
+ }
+ // zero out the file
+ ::close(file->fd);
+ file->fd = ::open(file->path, O_TRUNC, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH);
+ ::close(file->fd);
+ file->fd = -77; // force file open by filemgr
+ // copy tmp file back (dumb, but must preserve file permissions)
+ lseek(fd, 0, SEEK_SET);
+ do {
+ bytes = read(fd, nibble, 32767);
+ file->write(nibble, bytes);
+ } while (bytes == 32767);
+
+ ::close(fd);
+ ::close(file->fd);
+ removeFile(buf); // remove our tmp file
+ file->fd = -77; // causes file to be swapped out forcing open on next call to getFd()
+ }
+ else { // put offset back and return failure
+ file->seek(-1, SEEK_CUR);
+ return -1;
+ }
+ return 0;
+}
+
+
+signed char FileMgr::existsFile(const char *ipath, const char *ifileName)
+{
+ int len = strlen(ipath) + ((ifileName)?strlen(ifileName):0) + 3;
+ char *ch;
+ char *path = new char [ len ];
+ strcpy(path, ipath);
+
+ if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
+ path[strlen(path)-1] = 0;
+
+ if (ifileName) {
+ ch = path + strlen(path);
+ sprintf(ch, "/%s", ifileName);
+ }
+ signed char retVal = !access(path, 04);
+ delete [] path;
+ return retVal;
+}
+
+
+signed char FileMgr::existsDir(const char *ipath, const char *idirName)
+{
+ char *ch;
+ int len = strlen(ipath) + ((idirName)?strlen(idirName):0) + 1;
+ if (idirName)
+ len += strlen(idirName);
+ char *path = new char [ len ];
+ strcpy(path, ipath);
+
+ if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
+ path[strlen(path)-1] = 0;
+
+ if (idirName) {
+ ch = path + strlen(path);
+ sprintf(ch, "/%s", idirName);
+ }
+ signed char retVal = !access(path, 04);
+ delete [] path;
+ return retVal;
+}
+
+
+int FileMgr::createParent(const char *pName) {
+ char *buf = new char [ strlen(pName) + 1 ];
+ int retCode = 0;
+
+ strcpy(buf, pName);
+ int end = strlen(buf) - 1;
+ while (end) {
+ if ((buf[end] == '/') || (buf[end] == '\\'))
+ break;
+ end--;
+ }
+ buf[end] = 0;
+ if (strlen(buf)>0) {
+ if (access(buf, 02)) { // not exists with write access?
+ if ((retCode = mkdir(buf
+#ifndef WIN32
+ , 0755
+#endif
+ ))) {
+ createParent(buf);
+ retCode = mkdir(buf
+#ifndef WIN32
+ , 0755
+#endif
+ );
+ }
+ }
+ }
+ else retCode = -1;
+ delete [] buf;
+ return retCode;
+}
+
+
+int FileMgr::openFileReadOnly(const char *fName) {
+ int fd = ::open(fName, O_RDONLY|O_BINARY, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH);
+ return fd;
+}
+
+
+int FileMgr::createPathAndFile(const char *fName) {
+ int fd;
+
+ fd = ::open(fName, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH);
+ if (fd < 1) {
+ createParent(fName);
+ fd = ::open(fName, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH);
+ }
+ return fd;
+}
+
+
+int FileMgr::copyFile(const char *sourceFile, const char *targetFile) {
+ int sfd, dfd, len;
+ char buf[4096];
+
+ if ((sfd = ::open(sourceFile, O_RDONLY|O_BINARY, S_IREAD|S_IWRITE|S_IRGRP|S_IROTH)) < 1)
+ return -1;
+ if ((dfd = createPathAndFile(targetFile)) < 1)
+ return -1;
+
+ do {
+ len = read(sfd, buf, 4096);
+ write(dfd, buf, len);
+ }
+ while(len == 4096);
+ ::close(dfd);
+ ::close(sfd);
+
+ return 0;
+}
+
+
+int FileMgr::removeFile(const char *fName) {
+ return ::remove(fName);
+}
+
+char FileMgr::getLine(FileDesc *fDesc, SWBuf &line) {
+ int len;
+ bool more = true;
+ char chunk[255];
+
+ line = "";
+
+ // assert we have a valid file handle
+ if (fDesc->getFd() < 1)
+ return 0;
+
+ while (more) {
+ more = false;
+ long index = fDesc->seek(0, SEEK_CUR);
+ len = fDesc->read(chunk, 254);
+
+ // assert we have a readable file (not a directory)
+ if (len < 1)
+ break;
+
+ int start = 0;
+ // clean up any preceding white space if we're at the beginning of line
+ if (!line.length()) {
+ for (;start < len; start++) {
+ if ((chunk[start] != 13) && (chunk[start] != ' ') && (chunk[start] != '\t'))
+ break;
+ }
+ }
+
+ // find the end
+ int end;
+ for (end = start; ((end < (len-1)) && (chunk[end] != 10)); end++);
+
+ if ((chunk[end] != 10) && (len == 254)) {
+ more = true;
+ }
+ index += (end + 1);
+
+ // reposition to next valid place to read
+ fDesc->seek(index, SEEK_SET);
+
+ // clean up any trailing junk on line if we're at the end
+ if (!more) {
+ for (; end > start; end--) {
+ if ((chunk[end] != 10) && (chunk[end] != 13) && (chunk[end] != ' ') && (chunk[end] != '\t')) {
+ if (chunk[end] == '\\') {
+ more = true;
+ end--;
+ }
+ break;
+ }
+ }
+ }
+
+ int size = (end - start) + 1;
+
+ if (size > 0) {
+ // line.appendFormatted("%.*s", size, chunk+start);
+ line.append(chunk+start, size);
+ }
+ }
+ return ((len>0) || line.length());
+}
+
+
+char FileMgr::isDirectory(const char *path) {
+ struct stat stats;
+ if (stat(path, &stats))
+ return 0;
+ return ((stats.st_mode & S_IFDIR) == S_IFDIR);
+}
+
+
+int FileMgr::copyDir(const char *srcDir, const char *destDir) {
+ DIR *dir;
+ struct dirent *ent;
+ if ((dir = opendir(srcDir))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ SWBuf srcPath = (SWBuf)srcDir + (SWBuf)"/" + ent->d_name;
+ SWBuf destPath = (SWBuf)destDir + (SWBuf)"/" + ent->d_name;
+ if (!isDirectory(srcPath.c_str())) {
+ copyFile(srcPath.c_str(), destPath.c_str());
+ }
+ else {
+ copyDir(srcPath.c_str(), destPath.c_str());
+ }
+ }
+ }
+ closedir(dir);
+ }
+ return 0;
+}
+
+
+int FileMgr::removeDir(const char *targetDir) {
+ DIR *dir = opendir(targetDir);
+ struct dirent *ent;
+ if (dir) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ SWBuf targetPath = (SWBuf)targetDir + (SWBuf)"/" + ent->d_name;
+ if (!isDirectory(targetPath.c_str())) {
+ FileMgr::removeFile(targetPath.c_str());
+ }
+ else {
+ removeDir(targetPath.c_str());
+ }
+ }
+ }
+ closedir(dir);
+ removeFile(targetDir);
+ }
+ return 0;
+}
+
+
+void FileMgr::flush() {
+ FileDesc **loop;
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+ if ((*loop)->fd > 0) {
+ (*loop)->offset = lseek((*loop)->fd, 0, SEEK_CUR);
+ ::close((*loop)->fd);
+ (*loop)->fd = -77;
+ }
+ }
+}
+
+long FileMgr::resourceConsumption() {
+ long count = 0;
+ FileDesc **loop;
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+ if ((*loop)->fd > 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/ftplibftpt.cpp b/src/mgr/ftplibftpt.cpp
new file mode 100644
index 0000000..4921dd5
--- /dev/null
+++ b/src/mgr/ftplibftpt.cpp
@@ -0,0 +1,108 @@
+ /*****************************************************************************
+ * FTPLibFTPTransport functions
+ *
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#include <ftplib.h>
+
+#include <ftplibftpt.h>
+#include <swlog.h>
+#include <filemgr.h>
+
+
+SWORD_NAMESPACE_START
+
+
+static FTPLibFTPTransport_init _FTPLibFTPTransport_init;
+
+FTPLibFTPTransport_init::FTPLibFTPTransport_init() {
+ FtpInit();
+}
+
+FTPLibFTPTransport_init::~FTPLibFTPTransport_init() {
+}
+
+
+FTPLibFTPTransport::FTPLibFTPTransport(const char *host, StatusReporter *sr) : FTPTransport(host, sr) {
+
+ ftpConnection = 0;
+}
+
+
+FTPLibFTPTransport::~FTPLibFTPTransport() {
+ if (ftpConnection)
+ FtpQuit(ftpConnection);
+}
+
+
+char FTPLibFTPTransport::assureLoggedIn() {
+ char retVal = 0;
+ if (ftpConnection == 0) {
+ SWLog::getSystemLog()->logDebug("connecting to host %s\n", host.c_str());
+ if (FtpConnect(host, &ftpConnection))
+ if (FtpLogin("anonymous", "installmgr@user.com", ftpConnection)) {
+ retVal = 0;
+ }
+ else {
+ SWLog::getSystemLog()->logError("Failed to login to %s\n", host.c_str());
+ retVal = -2;
+ }
+ else {
+ SWLog::getSystemLog()->logError("Failed to connect to %s\n", host.c_str());
+ retVal = -1;
+ }
+ }
+ return retVal;
+}
+
+
+char FTPLibFTPTransport::getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf) {
+
+ char retVal = 0;
+
+ // assert we can login
+ retVal = assureLoggedIn();
+ if (retVal) return retVal;
+
+ SWBuf sourcePath = sourceURL;
+ SWBuf outFile = (!destBuf) ? destPath : "swftplib.tmp";
+ sourcePath << (6 + host.length()); // shift << "ftp://hostname";
+ SWLog::getSystemLog()->logDebug("getting file %s to %s\n", sourcePath.c_str(), outFile.c_str());
+ if (passive)
+ FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, ftpConnection);
+ else
+ FtpOptions(FTPLIB_CONNMODE, FTPLIB_PORT, ftpConnection);
+ // !!!WDG also want to set callback options
+ if (sourcePath.endsWith("/") || sourcePath.endsWith("\\")) {
+ SWLog::getSystemLog()->logDebug("getting test directory %s\n", sourcePath.c_str());
+ FtpDir(NULL, sourcePath, ftpConnection);
+ SWLog::getSystemLog()->logDebug("getting real directory %s\n", sourcePath.c_str());
+ retVal = FtpDir(outFile.c_str(), sourcePath, ftpConnection) - 1;
+ }
+ else {
+ SWLog::getSystemLog()->logDebug("getting file %s\n", sourcePath.c_str());
+ retVal = FtpGet(outFile.c_str(), sourcePath, FTPLIB_IMAGE, ftpConnection) - 1;
+ }
+
+ // Is there a way to FTPGet directly to a buffer?
+ // If not, we probably want to add x-platform way to open a tmp file with FileMgr
+ // This wreaks and will easily fail if a user's CWD is not writable.
+ if (destBuf) {
+ FileDesc *fd = FileMgr::getSystemFileMgr()->open("swftplib.tmp", FileMgr::RDONLY);
+ long size = fd->seek(0, SEEK_END);
+ fd->seek(0, SEEK_SET);
+ destBuf->size(size);
+ fd->read(destBuf->getRawData(), size);
+ FileMgr::getSystemFileMgr()->close(fd);
+ FileMgr::removeFile("swftplib.tmp");
+ }
+
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END
+
diff --git a/src/mgr/ftptrans.cpp b/src/mgr/ftptrans.cpp
new file mode 100644
index 0000000..ab0a605
--- /dev/null
+++ b/src/mgr/ftptrans.cpp
@@ -0,0 +1,170 @@
+ /*****************************************************************************
+ * FTPTransport functions
+ *
+ */
+
+
+#include <ftptrans.h>
+#include <filemgr.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <swlog.h>
+
+
+using std::vector;
+
+
+SWORD_NAMESPACE_START
+
+
+namespace {
+
+void removeTrailingSlash(SWBuf &buf) {
+ int len = buf.size();
+ if ((buf[len-1] == '/')
+ || (buf[len-1] == '\\'))
+ buf.size(len-1);
+}
+
+};
+
+
+void StatusReporter::preStatus(long totalBytes, long completedBytes, const char *message) {
+}
+
+void StatusReporter::statusUpdate(double dtTotal, double dlNow) {
+}
+
+
+FTPTransport::FTPTransport(const char *host, StatusReporter *statusReporter) {
+ this->statusReporter = statusReporter;
+ this->host = host;
+ term = false;
+}
+
+
+FTPTransport::~FTPTransport() {
+}
+
+
+// override this method in your real transport class
+char FTPTransport::getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf) {
+ char retVal = 0;
+ return retVal;
+}
+
+
+vector<struct DirEntry> FTPTransport::getDirList(const char *dirURL) {
+
+ vector<struct DirEntry> dirList;
+
+ SWBuf dirBuf;
+ if (!getURL("", dirURL, &dirBuf)) {
+ char *start = dirBuf.getRawData();
+ char *end = start;
+ while (start < (dirBuf.getRawData()+dirBuf.size())) {
+ struct ftpparse item;
+ bool looking = true;
+ for (end = start; *end; end++) {
+ if (looking) {
+ if ((*end == 10) || (*end == 13)) {
+ *end = 0;
+ looking = false;
+ }
+ }
+ else if ((*end != 10) && (*end != 13))
+ break;
+ }
+ SWLog::getSystemLog()->logWarning("FTPURLGetDir: parsing item %s(%d)\n", start, end-start);
+ int status = ftpparse(&item, start, end - start);
+ SWLog::getSystemLog()->logWarning("FTPURLGetDir: got item %s\n", item.name);
+ if (status) {
+ struct DirEntry i;
+ i.name = item.name;
+ i.size = item.size;
+ i.isDirectory = (item.flagtrycwd == 1);
+ dirList.push_back(i);
+ }
+ start = end;
+ }
+ }
+ else
+ {
+ SWLog::getSystemLog()->logWarning("FTPURLGetDir: failed to get dir %s\n", dirURL);
+ }
+ return dirList;
+}
+
+
+int FTPTransport::copyDirectory(const char *urlPrefix, const char *dir, const char *dest, const char *suffix) {
+ unsigned int i;
+ int retVal = 0;
+
+ SWBuf url = SWBuf(urlPrefix) + SWBuf(dir);
+ removeTrailingSlash(url);
+ url += '/';
+
+ SWLog::getSystemLog()->logWarning("FTPCopy: getting dir %s\n", url.c_str());
+ vector<struct DirEntry> dirList = getDirList(url.c_str());
+
+ if (!dirList.size()) {
+ SWLog::getSystemLog()->logWarning("FTPCopy: failed to read dir %s\n", url.c_str());
+ return -1;
+ }
+
+ long totalBytes = 0;
+ for (i = 0; i < dirList.size(); i++)
+ totalBytes += dirList[i].size;
+ long completedBytes = 0;
+ for (i = 0; i < dirList.size(); i++) {
+ struct DirEntry &dirEntry = dirList[i];
+ SWBuf buffer = (SWBuf)dest;
+ removeTrailingSlash(buffer);
+ buffer += "/";
+ buffer += dirEntry.name;
+ if (!strcmp(&buffer.c_str()[buffer.length()-strlen(suffix)], suffix)) {
+ SWBuf buffer2 = "Downloading (";
+ buffer2.appendFormatted("%d", i+1);
+ buffer2 += " of ";
+ buffer2.appendFormatted("%d", dirList.size());
+ buffer2 += "): ";
+ buffer2 += dirEntry.name;
+ if (statusReporter)
+ statusReporter->preStatus(totalBytes, completedBytes, buffer2.c_str());
+ FileMgr::createParent(buffer.c_str()); // make sure parent directory exists
+ SWTRY {
+ SWBuf url = (SWBuf)urlPrefix + (SWBuf)dir;
+ removeTrailingSlash(url);
+ url += "/";
+ url += dirEntry.name; //dont forget the final slash
+ if (!dirEntry.isDirectory) {
+ if (getURL(buffer.c_str(), url.c_str())) {
+ SWLog::getSystemLog()->logWarning("FTPCopy: failed to get file %s\n", url.c_str());
+ return -2;
+ }
+ completedBytes += dirEntry.size;
+ }
+ else {
+ SWBuf subdir = (SWBuf)dir;
+ removeTrailingSlash(subdir);
+ subdir += (SWBuf)"/" + dirEntry.name;
+ if (copyDirectory(urlPrefix, subdir, buffer.c_str(), suffix)) {
+ SWLog::getSystemLog()->logWarning("FTPCopy: failed to get file %s\n", subdir.c_str());
+ return -2;
+ }
+ }
+ }
+ SWCATCH (...) {}
+ if (term) {
+ retVal = -3;
+ break;
+ }
+ }
+ }
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END
+
diff --git a/src/mgr/installmgr.cpp b/src/mgr/installmgr.cpp
new file mode 100644
index 0000000..6a1704f
--- /dev/null
+++ b/src/mgr/installmgr.cpp
@@ -0,0 +1,579 @@
+ /*****************************************************************************
+ * InstallMgr functions to be made into something usefully exposed by
+ * master Glassey
+ *
+ */
+
+
+#ifndef EXCLUDEZLIB
+extern "C" {
+#include <untgz.h>
+}
+#endif
+
+#include <installmgr.h>
+#include <filemgr.h>
+#include <utilstr.h>
+
+#include <fcntl.h>
+
+#include <swmgr.h>
+#include <swmodule.h>
+#include <swversion.h>
+#include <swlog.h>
+#include <dirent.h>
+
+#include <stdio.h>
+#include <map>
+
+#ifdef CURLAVAILABLE
+#include <curlftpt.h>
+#else
+#include <ftplibftpt.h>
+#endif
+
+SWORD_NAMESPACE_START
+
+namespace {
+
+void removeTrailingSlash(SWBuf &buf) {
+ int len = buf.size();
+ if ((buf[len-1] == '/')
+ || (buf[len-1] == '\\'))
+ buf.size(len-1);
+}
+
+};
+
+
+using std::map;
+
+const int InstallMgr::MODSTAT_OLDER = 0x001;
+const int InstallMgr::MODSTAT_SAMEVERSION = 0x002;
+const int InstallMgr::MODSTAT_UPDATED = 0x004;
+const int InstallMgr::MODSTAT_NEW = 0x008;
+const int InstallMgr::MODSTAT_CIPHERED = 0x010;
+const int InstallMgr::MODSTAT_CIPHERKEYPRESENT = 0x020;
+
+// override this method and provide your own custom FTPTransport subclass
+// here we try a couple defaults if sword was compiled with support for them.
+// see these classes for examples of how to make your own
+FTPTransport *InstallMgr::createFTPTransport(const char *host, StatusReporter *statusReporter) {
+#ifdef CURLAVAILABLE
+ return new CURLFTPTransport(host, statusReporter);
+#else
+ return new FTPLibFTPTransport(host, statusReporter);
+#endif
+}
+
+
+
+
+InstallMgr::InstallMgr(const char *privatePath, StatusReporter *sr) {
+ statusReporter = sr;
+ this->privatePath = 0;
+ this->transport = 0;
+ stdstr(&(this->privatePath), privatePath);
+ if (this->privatePath) {
+ int len = strlen(this->privatePath);
+ if ((this->privatePath[len-1] == '/')
+ || (this->privatePath[len-1] == '\\'))
+ this->privatePath[len-1] = 0;
+ }
+ SWBuf confPath = (SWBuf)privatePath + "/InstallMgr.conf";
+ FileMgr::createParent(confPath.c_str());
+
+ installConf = new SWConfig(confPath.c_str());
+
+ SectionMap::iterator sourcesSection;
+ ConfigEntMap::iterator sourceBegin;
+ ConfigEntMap::iterator sourceEnd;
+
+ sources.clear();
+
+ setFTPPassive(stricmp((*installConf)["General"]["PassiveFTP"].c_str(), "false")!=0);
+
+ sourcesSection = installConf->Sections.find("Sources");
+ if (sourcesSection != installConf->Sections.end()) {
+ sourceBegin = sourcesSection->second.lower_bound("FTPSource");
+ sourceEnd = sourcesSection->second.upper_bound("FTPSource");
+
+ while (sourceBegin != sourceEnd) {
+ InstallSource *is = new InstallSource("FTP", sourceBegin->second.c_str());
+ sources[is->caption] = is;
+ SWBuf parent = (SWBuf)privatePath + "/" + is->source + "/file";
+ FileMgr::createParent(parent.c_str());
+ is->localShadow = (SWBuf)privatePath + "/" + is->source;
+ sourceBegin++;
+ }
+ }
+
+ defaultMods.clear();
+ sourcesSection = installConf->Sections.find("General");
+ if (sourcesSection != installConf->Sections.end()) {
+ sourceBegin = sourcesSection->second.lower_bound("DefaultMod");
+ sourceEnd = sourcesSection->second.upper_bound("DefaultMod");
+
+ while (sourceBegin != sourceEnd) {
+ defaultMods.insert(sourceBegin->second.c_str());
+ sourceBegin++;
+ }
+ }
+}
+
+
+InstallMgr::~InstallMgr() {
+ delete [] privatePath;
+ delete installConf;
+
+ for (InstallSourceMap::iterator it = sources.begin(); it != sources.end(); ++it) {
+ delete it->second;
+ }
+}
+
+
+void InstallMgr::terminate() { if (transport) transport->terminate(); }
+
+int InstallMgr::removeModule(SWMgr *manager, const char *moduleName) {
+ SectionMap::iterator module;
+ ConfigEntMap::iterator fileBegin;
+ ConfigEntMap::iterator fileEnd, entry;
+
+ // save our own copy, cuz when we remove the module from the SWMgr
+ // it's likely we'll free the memory passed to us in moduleName
+ SWBuf modName = moduleName;
+ module = manager->config->Sections.find(modName);
+
+ if (module != manager->config->Sections.end()) {
+ // to be sure all files are closed
+ // this does not remove the .conf information from SWMgr
+ manager->deleteModule(modName);
+
+ fileBegin = module->second.lower_bound("File");
+ fileEnd = module->second.upper_bound("File");
+
+ SWBuf modFile;
+ SWBuf modDir;
+ entry = module->second.find("AbsoluteDataPath");
+ modDir = entry->second.c_str();
+ removeTrailingSlash(modDir);
+ if (fileBegin != fileEnd) { // remove each file
+ while (fileBegin != fileEnd) {
+ modFile = modDir;
+ modFile += "/";
+ modFile += fileBegin->second.c_str();
+ //remove file
+ FileMgr::removeFile(modFile.c_str());
+ fileBegin++;
+ }
+ }
+ else { //remove all files in DataPath directory
+
+ DIR *dir;
+ struct dirent *ent;
+ ConfigEntMap::iterator entry;
+
+ FileMgr::removeDir(modDir.c_str());
+
+ if ((dir = opendir(manager->configPath))) { // find and remove .conf file
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ modFile = manager->configPath;
+ removeTrailingSlash(modFile);
+ modFile += "/";
+ modFile += ent->d_name;
+ SWConfig *config = new SWConfig(modFile.c_str());
+ if (config->Sections.find(modName) != config->Sections.end()) {
+ delete config;
+ FileMgr::removeFile(modFile.c_str());
+ }
+ else delete config;
+ }
+ }
+ closedir(dir);
+ }
+ }
+ return 0;
+ }
+ return 1;
+}
+
+
+int InstallMgr::ftpCopy(InstallSource *is, const char *src, const char *dest, bool dirTransfer, const char *suffix) {
+ int retVal = 0;
+ FTPTransport *trans = createFTPTransport(is->source, statusReporter);
+ transport = trans; // set classwide current transport for other thread terminate() call
+ trans->setPassive(passive);
+
+ SWBuf urlPrefix = (SWBuf)"ftp://" + is->source;
+
+ // let's be sure we can connect. This seems to be necessary but sucks
+// SWBuf url = urlPrefix + is->directory.c_str() + "/"; //dont forget the final slash
+// if (trans->getURL("swdirlist.tmp", url.c_str())) {
+// SWLog::getSystemLog()->logDebug("FTPCopy: failed to get dir %s\n", url.c_str());
+// return -1;
+// }
+
+
+ if (dirTransfer) {
+ SWBuf dir = (SWBuf)is->directory.c_str();
+ removeTrailingSlash(dir);
+ dir += (SWBuf)"/" + src; //dont forget the final slash
+
+ retVal = trans->copyDirectory(urlPrefix, dir, dest, suffix);
+
+
+ }
+ else {
+ SWTRY {
+ SWBuf url = urlPrefix + is->directory.c_str();
+ removeTrailingSlash(url);
+ url += (SWBuf)"/" + src; //dont forget the final slash
+ if (trans->getURL(dest, url.c_str())) {
+ SWLog::getSystemLog()->logDebug("FTPCopy: failed to get file %s", url.c_str());
+ retVal = -1;
+ }
+ }
+ SWCATCH (...) {
+ retVal = -1;
+ }
+ }
+ SWTRY {
+ FTPTransport *deleteMe = trans;
+ // do this order for threadsafeness
+ // (see terminate())
+ trans = transport = 0;
+ delete deleteMe;
+ }
+ SWCATCH (...) {}
+ return retVal;
+}
+
+
+int InstallMgr::installModule(SWMgr *destMgr, const char *fromLocation, const char *modName, InstallSource *is) {
+ SectionMap::iterator module, section;
+ ConfigEntMap::iterator fileBegin;
+ ConfigEntMap::iterator fileEnd;
+ ConfigEntMap::iterator entry;
+ SWBuf sourceDir;
+ SWBuf buffer;
+ bool aborted = false;
+ bool cipher = false;
+ DIR *dir;
+ struct dirent *ent;
+ SWBuf modFile;
+
+ SWLog::getSystemLog()->logDebug("***** InstallMgr::installModule\n");
+ if (fromLocation)
+ SWLog::getSystemLog()->logDebug("***** fromLocation: %s \n", fromLocation);
+ SWLog::getSystemLog()->logDebug("***** modName: %s \n", modName);
+
+ if (is)
+ sourceDir = (SWBuf)privatePath + "/" + is->source;
+ else sourceDir = fromLocation;
+
+ removeTrailingSlash(sourceDir);
+ sourceDir += '/';
+
+ SWMgr mgr(sourceDir.c_str());
+
+ module = mgr.config->Sections.find(modName);
+
+ if (module != mgr.config->Sections.end()) {
+
+ entry = module->second.find("CipherKey");
+ if (entry != module->second.end())
+ cipher = true;
+
+ //
+ // This first check is a method to allow a module to specify each
+ // file that needs to be copied
+ //
+ fileEnd = module->second.upper_bound("File");
+ fileBegin = module->second.lower_bound("File");
+
+ if (fileBegin != fileEnd) { // copy each file
+ if (is) {
+ while (fileBegin != fileEnd) { // ftp each file first
+ buffer = sourceDir + fileBegin->second.c_str();
+ if (ftpCopy(is, fileBegin->second.c_str(), buffer.c_str())) {
+ aborted = true;
+ break; // user aborted
+ }
+ fileBegin++;
+ }
+ fileBegin = module->second.lower_bound("File");
+ }
+
+ if (!aborted) {
+ // DO THE INSTALL
+ while (fileBegin != fileEnd) {
+ SWBuf sourcePath = sourceDir;
+ sourcePath += fileBegin->second.c_str();
+ SWBuf dest = destMgr->prefixPath;
+ removeTrailingSlash(dest);
+ dest += '/';
+ dest += fileBegin->second.c_str();
+ FileMgr::copyFile(sourcePath.c_str(), dest.c_str());
+
+ fileBegin++;
+ }
+ }
+ //---------------
+
+ if (is) {
+ fileBegin = module->second.lower_bound("File");
+ while (fileBegin != fileEnd) { // delete each tmp ftp file
+ buffer = sourceDir + fileBegin->second.c_str();
+ FileMgr::removeFile(buffer.c_str());
+ fileBegin++;
+ }
+ }
+ }
+
+ // This is the REAL install code, the above code I don't think has
+ // ever been used
+ //
+ // Copy all files in DataPath directory
+ //
+ else {
+ ConfigEntMap::iterator entry;
+
+ entry = module->second.find("AbsoluteDataPath");
+ if (entry != module->second.end()) {
+ SWBuf absolutePath = entry->second.c_str();
+ SWBuf relativePath = absolutePath;
+ entry = module->second.find("PrefixPath");
+ if (entry != module->second.end()) {
+ relativePath << strlen(entry->second.c_str());
+ }
+ else {
+ relativePath << strlen(mgr.prefixPath);
+ }
+ SWLog::getSystemLog()->logDebug("***** mgr.prefixPath: %s \n", mgr.prefixPath);
+ SWLog::getSystemLog()->logDebug("***** destMgr->prefixPath: %s \n", destMgr->prefixPath);
+ SWLog::getSystemLog()->logDebug("***** absolutePath: %s \n", absolutePath.c_str());
+ SWLog::getSystemLog()->logDebug("***** relativePath: %s \n", relativePath.c_str());
+
+ if (is) {
+ if (ftpCopy(is, relativePath.c_str(), absolutePath.c_str(), true)) {
+ aborted = true; // user aborted
+ }
+ }
+ if (!aborted) {
+ SWBuf destPath = (SWBuf)destMgr->prefixPath + relativePath;
+ FileMgr::copyDir(absolutePath.c_str(), destPath.c_str());
+ }
+ if (is) { // delete tmp ftp files
+// mgr->deleteModule(modName);
+ FileMgr::removeDir(absolutePath.c_str());
+ }
+ }
+ }
+ if (!aborted) {
+ SWBuf confDir = sourceDir + "mods.d/";
+ if ((dir = opendir(confDir.c_str()))) { // find and copy .conf file
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ modFile = confDir;
+ modFile += ent->d_name;
+ SWConfig *config = new SWConfig(modFile.c_str());
+ if (config->Sections.find(modName) != config->Sections.end()) {
+ SWBuf targetFile = destMgr->configPath; //"./mods.d/";
+ removeTrailingSlash(targetFile);
+ targetFile += "/";
+ targetFile += ent->d_name;
+ FileMgr::copyFile(modFile.c_str(), targetFile.c_str());
+ if (cipher) {
+ if (getCipherCode(modName, config)) {
+ SWMgr newDest(destMgr->prefixPath);
+ removeModule(&newDest, modName);
+ aborted = true;
+ }
+ else {
+ config->Save();
+ FileMgr::copyFile(modFile.c_str(), targetFile.c_str());
+ }
+ }
+ }
+ delete config;
+ }
+ }
+ closedir(dir);
+ }
+ }
+ return (aborted) ? -1 : 0;
+ }
+ return 1;
+}
+
+
+// override this and provide an input mechanism to allow your users
+// to enter the decipher code for a module.
+// return true you added the cipher code to the config.
+// default to return 'aborted'
+bool InstallMgr::getCipherCode(const char *modName, SWConfig *config) {
+ return false;
+
+/* a sample implementation, roughly taken from the windows installmgr
+
+ SectionMap::iterator section;
+ ConfigEntMap::iterator entry;
+ SWBuf tmpBuf;
+ section = config->Sections.find(modName);
+ if (section != config->Sections.end()) {
+ entry = section->second.find("CipherKey");
+ if (entry != section->second.end()) {
+ entry->second = GET_USER_INPUT();
+ config->Save();
+
+ // LET'S SHOW THE USER SOME SAMPLE TEXT FROM THE MODULE
+ SWMgr *mgr = new SWMgr();
+ SWModule *mod = mgr->Modules[modName];
+ mod->setKey("Ipet 2:12");
+ tmpBuf = mod->StripText();
+ mod->setKey("gen 1:10");
+ tmpBuf += "\n\n";
+ tmpBuf += mod->StripText();
+ SOME_DIALOG_CONTROL->SETTEXT(tmpBuf.c_str());
+ delete mgr;
+
+ // if USER CLICKS OK means we should return true
+ return true;
+ }
+ }
+ return false;
+*/
+
+}
+
+
+int InstallMgr::refreshRemoteSource(InstallSource *is) {
+ SWBuf root = (SWBuf)privatePath + (SWBuf)"/" + is->source.c_str();
+ removeTrailingSlash(root);
+ SWBuf target = root + "/mods.d";
+ int errorCode = -1; //0 means successful
+
+ FileMgr::removeDir(target.c_str());
+
+ if (!FileMgr::existsDir(target))
+ FileMgr::createPathAndFile(target+"/globals.conf");
+
+#ifndef EXCLUDEZLIB
+ SWBuf archive = root + "/mods.d.tar.gz";
+
+ errorCode = ftpCopy(is, "mods.d.tar.gz", archive.c_str(), false);
+ if (!errorCode) { //sucessfully downloaded the tar,gz of module configs
+ FileDesc *fd = FileMgr::getSystemFileMgr()->open(archive.c_str(), FileMgr::RDONLY);
+ untargz(fd->getFd(), root.c_str());
+ FileMgr::getSystemFileMgr()->close(fd);
+ }
+ else if (!term) //if the tar.gz download was canceled don't continue with another download
+#endif
+ errorCode = ftpCopy(is, "mods.d", target.c_str(), true, ".conf"); //copy the whole directory
+
+ is->flush();
+ return errorCode;
+}
+
+
+bool InstallMgr::isDefaultModule(const char *modName) {
+ return defaultMods.count(modName);
+}
+
+/************************************************************************
+ * getModuleStatus - compare the modules of two SWMgrs and return a
+ * vector describing the status of each. See MODSTAT_*
+ */
+map<SWModule *, int> InstallMgr::getModuleStatus(const SWMgr &base, const SWMgr &other) {
+ map<SWModule *, int> retVal;
+ SWBuf targetVersion;
+ SWBuf sourceVersion;
+ SWBuf softwareVersion;
+ bool cipher;
+ bool keyPresent;
+ int modStat;
+
+ for (ModMap::const_iterator mod = other.Modules.begin(); mod != other.Modules.end(); mod++) {
+
+ modStat = 0;
+
+ cipher = false;
+ keyPresent = false;
+
+ const char *v = mod->second->getConfigEntry("CipherKey");
+ if (v) {
+ cipher = true;
+ keyPresent = *v;
+ }
+
+ targetVersion = "0.0";
+ sourceVersion = "1.0";
+ softwareVersion = (const char *)SWVersion::currentVersion;
+
+ v = mod->second->getConfigEntry("Version");
+ if (v) sourceVersion = v;
+
+ v = mod->second->getConfigEntry("MinimumVersion");
+ if (v) softwareVersion = v;
+
+ const SWModule *baseMod = base.getModule(mod->first);
+ if (baseMod) {
+ targetVersion = "1.0";
+ v = baseMod->getConfigEntry("Version");
+ if (v) targetVersion = v;
+ modStat |= (SWVersion(sourceVersion.c_str()) > SWVersion(targetVersion.c_str())) ? MODSTAT_UPDATED : (SWVersion(sourceVersion.c_str()) < SWVersion(targetVersion.c_str())) ? MODSTAT_OLDER : MODSTAT_SAMEVERSION;
+ }
+ else modStat |= MODSTAT_NEW;
+
+ if (cipher) modStat |= MODSTAT_CIPHERED;
+ if (keyPresent) modStat |= MODSTAT_CIPHERKEYPRESENT;
+ retVal[mod->second] = modStat;
+ }
+ return retVal;
+}
+
+
+InstallSource::InstallSource(const char *type, const char *confEnt) {
+ this->type = type;
+ mgr = 0;
+ userData = 0;
+ if (confEnt) {
+ char *buf = 0;
+ stdstr(&buf, confEnt);
+
+ caption = strtok(buf, "|");
+ source = strtok(0, "|");
+ directory = strtok(0, "|");
+ removeTrailingSlash(directory);
+ delete [] buf;
+ }
+}
+
+
+InstallSource::~InstallSource() {
+ if (mgr)
+ delete mgr;
+}
+
+
+void InstallSource::flush() {
+ if (mgr) {
+ delete mgr;
+ mgr = 0;
+ }
+}
+
+
+SWMgr *InstallSource::getMgr() {
+ if (!mgr)
+ // ..., false = don't augment ~home directory.
+ mgr = new SWMgr(localShadow.c_str(), true, 0, false, false);
+ return mgr;
+}
+
+
+SWORD_NAMESPACE_END
+
diff --git a/src/mgr/localemgr.cpp b/src/mgr/localemgr.cpp
new file mode 100644
index 0000000..ead076a
--- /dev/null
+++ b/src/mgr/localemgr.cpp
@@ -0,0 +1,257 @@
+/******************************************************************************
+ * localemgr.cpp - implementation of class LocaleMgr used to interact with
+ * registered locales for a sword installation
+ *
+ * $Id: localemgr.cpp 2080 2007-09-17 06:21:29Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <swmgr.h>
+#include <utilstr.h>
+
+#include <stringmgr.h>
+#include <filemgr.h>
+#include <localemgr.h>
+#include <swlocale.h>
+#include <swlog.h>
+
+
+SWORD_NAMESPACE_START
+
+LocaleMgr *LocaleMgr::systemLocaleMgr = 0;
+
+class __staticsystemLocaleMgr {
+public:
+ __staticsystemLocaleMgr() { }
+ ~__staticsystemLocaleMgr() { delete LocaleMgr::systemLocaleMgr; }
+} _staticsystemLocaleMgr;
+
+
+LocaleMgr *LocaleMgr::getSystemLocaleMgr() {
+ if (!systemLocaleMgr)
+ systemLocaleMgr = new LocaleMgr();
+
+ return systemLocaleMgr;
+}
+
+
+void LocaleMgr::setSystemLocaleMgr(LocaleMgr *newLocaleMgr) {
+ if (systemLocaleMgr)
+ delete systemLocaleMgr;
+ systemLocaleMgr = newLocaleMgr;
+}
+
+
+LocaleMgr::LocaleMgr(const char *iConfigPath) {
+ locales = new LocaleMap();
+ char *prefixPath = 0;
+ char *configPath = 0;
+ char configType = 0;
+ SWBuf path;
+ std::list<SWBuf> augPaths;
+
+ defaultLocaleName = 0;
+
+ if (!iConfigPath) {
+ SWLog::getSystemLog()->logDebug("LOOKING UP LOCALE DIRECTORY...");
+ SWMgr::findConfig(&configType, &prefixPath, &configPath, &augPaths);
+ SWLog::getSystemLog()->logDebug("LOOKING UP LOCALE DIRECTORY COMPLETE.");
+ }
+ else configPath = (char *)iConfigPath;
+
+ if (prefixPath) {
+ switch (configType) {
+ case 2:
+ int i;
+ for (i = strlen(configPath)-1; ((i) && (configPath[i] != '/') && (configPath[i] != '\\')); i--);
+ configPath[i] = 0;
+ path = configPath;
+ path += "/";
+ break;
+ default:
+ path = prefixPath;
+ if ((prefixPath[strlen(prefixPath)-1] != '\\') && (prefixPath[strlen(prefixPath)-1] != '/'))
+ path += "/";
+
+ break;
+ }
+ if (FileMgr::existsDir(path.c_str(), "locales.d")) {
+ path += "locales.d";
+ loadConfigDir(path.c_str());
+ }
+ }
+
+ if (augPaths.size()) { //load locale files from all augmented paths
+ std::list<SWBuf>::iterator it = augPaths.begin();
+ std::list<SWBuf>::iterator end = augPaths.end();
+
+ for (;it != end; ++it) {
+ if (FileMgr::existsDir((*it).c_str(), "locales.d")) {
+ SWBuf path = (*it) + "locales.d";
+ loadConfigDir(path.c_str());
+ }
+ }
+ }
+
+ // Locales will be invalidated if you change the StringMgr
+ // So only use the default hardcoded locale and let the
+ // frontends change the locale if they want
+ stdstr(&defaultLocaleName, "en_US");
+
+ if (prefixPath)
+ delete [] prefixPath;
+
+ if (configPath)
+ delete [] configPath;
+}
+
+
+LocaleMgr::~LocaleMgr() {
+ if (defaultLocaleName)
+ delete [] defaultLocaleName;
+ deleteLocales();
+ delete locales;
+}
+
+
+void LocaleMgr::loadConfigDir(const char *ipath) {
+ DIR *dir;
+ struct dirent *ent;
+ SWBuf newmodfile;
+ LocaleMap::iterator it;
+ SWLog::getSystemLog()->logInformation("LocaleMgr::loadConfigDir loading %s", ipath);
+
+ if ((dir = opendir(ipath))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+ SWLocale *locale = new SWLocale(newmodfile.c_str());
+
+ if (locale->getName()) {
+ bool supported = false;
+ if (StringMgr::hasUTF8Support()) {
+ supported = (locale->getEncoding() && (!strcmp(locale->getEncoding(), "UTF-8") || !strcmp(locale->getEncoding(), "ASCII")) );
+ }
+ else {
+ supported = !locale->getEncoding() || (locale->getEncoding() && (strcmp(locale->getEncoding(), "UTF-8") != 0)); //exclude UTF-8 locales
+ }
+
+ if (!supported) { //not supported
+ delete locale;
+ continue;
+ }
+
+ it = locales->find(locale->getName());
+ if (it != locales->end()) { // already present
+ *((*it).second) += *locale;
+ delete locale;
+ }
+ else locales->insert(LocaleMap::value_type(locale->getName(), locale));
+ }
+ else delete locale;
+ }
+ }
+ closedir(dir);
+ }
+}
+
+
+void LocaleMgr::deleteLocales() {
+
+ LocaleMap::iterator it;
+
+ for (it = locales->begin(); it != locales->end(); it++)
+ delete (*it).second;
+
+ locales->erase(locales->begin(), locales->end());
+}
+
+
+SWLocale *LocaleMgr::getLocale(const char *name) {
+ LocaleMap::iterator it;
+
+ it = locales->find(name);
+ if (it != locales->end())
+ return (*it).second;
+
+ SWLog::getSystemLog()->logWarning("LocaleMgr::getLocale failed to find %s\n", name);
+ return 0;
+}
+
+
+std::list <SWBuf> LocaleMgr::getAvailableLocales() {
+ std::list <SWBuf> retVal;
+ for (LocaleMap::iterator it = locales->begin(); it != locales->end(); it++)
+ retVal.push_back((*it).second->getName());
+
+ return retVal;
+}
+
+
+const char *LocaleMgr::translate(const char *text, const char *localeName) {
+ SWLocale *target;
+ if (!localeName) {
+ localeName = getDefaultLocaleName();
+ }
+ target = getLocale(localeName);
+ if (target)
+ return target->translate(text);
+ return text;
+}
+
+
+const char *LocaleMgr::getDefaultLocaleName() {
+ return defaultLocaleName;
+}
+
+
+void LocaleMgr::setDefaultLocaleName(const char *name) {
+ char *tmplang=0;
+ stdstr(&tmplang, name);
+ // discard everything after '.' usually encoding e.g. .UTF-8
+ strtok(tmplang, ".");
+ // also discard after '@' so e.g. @euro locales are found
+ strtok(tmplang, "@");
+
+ stdstr(&defaultLocaleName, tmplang);
+
+ // First check for what we ask for
+ if (!getLocale(tmplang)) {
+ // check for locale without country
+ char *nocntry=0;
+ stdstr(&nocntry, tmplang);
+ strtok(nocntry, "_");
+ if (getLocale(nocntry)) {
+ stdstr(&defaultLocaleName, nocntry);
+ }
+ delete [] nocntry;
+ }
+ delete [] tmplang;
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/markupfiltmgr.cpp b/src/mgr/markupfiltmgr.cpp
new file mode 100644
index 0000000..5dca845
--- /dev/null
+++ b/src/mgr/markupfiltmgr.cpp
@@ -0,0 +1,295 @@
+/******************************************************************************
+ * swmarkupmgr.cpp - implementaion of class MarkupFilterMgr, subclass of
+ * used to transcode all module text to a requested
+ * markup.
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <thmlplain.h>
+#include <gbfplain.h>
+#include <osisplain.h>
+#include <teiplain.h>
+#include <thmlgbf.h>
+#include <gbfthml.h>
+#include <thmlhtml.h>
+#include <gbfhtml.h>
+#include <plainhtml.h>
+#include <thmlhtmlhref.h>
+#include <gbfhtmlhref.h>
+#include <teihtmlhref.h>
+#include <thmlrtf.h>
+#include <gbfrtf.h>
+#include <gbfosis.h>
+#include <thmlosis.h>
+#include <osisrtf.h>
+#include <teirtf.h>
+#include <osisosis.h>
+#include <osishtmlhref.h>
+#include <gbfwebif.h>
+#include <thmlwebif.h>
+#include <osiswebif.h>
+#include <swmodule.h>
+
+#include <markupfiltmgr.h>
+
+#include <swmgr.h>
+
+SWORD_NAMESPACE_START
+
+/******************************************************************************
+ * MarkupFilterMgr Constructor - initializes instance of MarkupFilterMgr
+ *
+ * ENT:
+ * enc - Encoding format to emit
+ * mark - Markup format to emit
+ */
+
+MarkupFilterMgr::MarkupFilterMgr (char mark, char enc)
+ : EncodingFilterMgr(enc) {
+
+ markup = mark;
+
+ CreateFilters(markup);
+}
+
+
+/******************************************************************************
+ * MarkupFilterMgr Destructor - Cleans up instance of MarkupFilterMgr
+ */
+
+MarkupFilterMgr::~MarkupFilterMgr() {
+ if (fromthml)
+ delete (fromthml);
+ if (fromgbf)
+ delete (fromgbf);
+ if (fromplain)
+ delete (fromplain);
+ if (fromosis)
+ delete (fromosis);
+ if (fromtei)
+ delete (fromtei);
+}
+
+/******************************************************************************
+ * MarkupFilterMgr::Markup - sets/gets markup
+ *
+ * ENT: mark - new encoding or 0 to simply get the current markup
+ *
+ * RET: markup
+ */
+char MarkupFilterMgr::Markup(char mark) {
+ if (mark && mark != markup) {
+ markup = mark;
+ ModMap::const_iterator module;
+
+ SWFilter * oldplain = fromplain;
+ SWFilter * oldthml = fromthml;
+ SWFilter * oldgbf = fromgbf;
+ SWFilter * oldosis = fromosis;
+ SWFilter * oldtei = fromtei;
+
+ CreateFilters(markup);
+
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ switch (module->second->Markup()) {
+ case FMT_THML:
+ if (oldthml != fromthml) {
+ if (oldthml) {
+ if (!fromthml) {
+ module->second->RemoveRenderFilter(oldthml);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldthml, fromthml);
+ }
+ }
+ else if (fromthml) {
+ module->second->AddRenderFilter(fromthml);
+ }
+ }
+ break;
+ case FMT_GBF:
+ if (oldgbf != fromgbf) {
+ if (oldgbf) {
+ if (!fromgbf) {
+ module->second->RemoveRenderFilter(oldgbf);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldgbf, fromgbf);
+ }
+ }
+ else if (fromgbf) {
+ module->second->AddRenderFilter(fromgbf);
+ }
+ break;
+ }
+ case FMT_PLAIN:
+ if (oldplain != fromplain) {
+ if (oldplain) {
+ if (!fromplain) {
+ module->second->RemoveRenderFilter(oldplain);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldplain, fromplain);
+ }
+ }
+ else if (fromplain) {
+ module->second->AddRenderFilter(fromplain);
+ }
+ break;
+ }
+ case FMT_OSIS:
+ if (oldosis != fromosis) {
+ if (oldosis) {
+ if (!fromosis) {
+ module->second->RemoveRenderFilter(oldosis);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldosis, fromosis);
+ }
+ }
+ else if (fromosis) {
+ module->second->AddRenderFilter(fromosis);
+ }
+ break;
+ }
+ case FMT_TEI:
+ if (oldtei != fromtei) {
+ if (oldtei) {
+ if (!fromtei) {
+ module->second->RemoveRenderFilter(oldtei);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldtei, fromtei);
+ }
+ }
+ else if (fromtei) {
+ module->second->AddRenderFilter(fromtei);
+ }
+ break;
+ }
+ }
+
+ if (oldthml)
+ delete oldthml;
+ if (oldgbf)
+ delete oldgbf;
+ if (oldplain)
+ delete oldplain;
+ if (oldosis)
+ delete oldosis;
+ if (oldtei)
+ delete oldtei;
+ }
+ return markup;
+}
+
+void MarkupFilterMgr::AddRenderFilters(SWModule *module, ConfigEntMap &section) {
+ switch (module->Markup()) {
+ case FMT_THML:
+ if (fromthml)
+ module->AddRenderFilter(fromthml);
+ break;
+ case FMT_GBF:
+ if (fromgbf)
+ module->AddRenderFilter(fromgbf);
+ break;
+ case FMT_PLAIN:
+ if (fromplain)
+ module->AddRenderFilter(fromplain);
+ break;
+ case FMT_OSIS:
+ if (fromosis)
+ module->AddRenderFilter(fromosis);
+ break;
+ case FMT_TEI:
+ if (fromtei)
+ module->AddRenderFilter(fromtei);
+ break;
+ }
+}
+
+void MarkupFilterMgr::CreateFilters(char markup) {
+
+ switch (markup) {
+ case FMT_PLAIN:
+ fromplain = NULL;
+ fromthml = new ThMLPlain();
+ fromgbf = new GBFPlain();
+ fromosis = new OSISPlain();
+ fromtei = new TEIPlain();
+ break;
+ case FMT_THML:
+ fromplain = NULL;
+ fromthml = NULL;
+ fromgbf = new GBFThML();
+ fromosis = NULL;
+ fromtei = NULL;
+ break;
+ case FMT_GBF:
+ fromplain = NULL;
+ fromthml = new ThMLGBF();
+ fromgbf = NULL;
+ fromosis = NULL;
+ fromtei = NULL;
+ break;
+ case FMT_HTML:
+ fromplain = new PLAINHTML();
+ fromthml = new ThMLHTML();
+ fromgbf = new GBFHTML();
+ fromosis = NULL;
+ fromtei = NULL;
+ break;
+ case FMT_HTMLHREF:
+ fromplain = new PLAINHTML();
+ fromthml = new ThMLHTMLHREF();
+ fromgbf = new GBFHTMLHREF();
+ fromosis = new OSISHTMLHREF();
+ fromtei = new TEIHTMLHREF();
+ break;
+ case FMT_RTF:
+ fromplain = NULL;
+ fromthml = new ThMLRTF();
+ fromgbf = new GBFRTF();
+ fromosis = new OSISRTF();
+ fromtei = new TEIRTF();
+ break;
+ case FMT_OSIS:
+ fromplain = NULL;
+ fromthml = new ThMLOSIS();
+ fromgbf = new GBFOSIS();
+ fromosis = new OSISOSIS();
+ fromtei = NULL;
+ break;
+ case FMT_WEBIF:
+ fromplain = NULL;
+ fromthml = new ThMLWEBIF();
+ fromgbf = new GBFWEBIF();
+ fromosis = new OSISWEBIF();
+ fromtei = NULL;
+ break;
+ case FMT_TEI:
+ fromplain = NULL;
+ fromthml = NULL;
+ fromgbf = NULL;
+ fromosis = NULL;
+ fromtei = NULL;
+ break;
+ }
+
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/stringmgr.cpp b/src/mgr/stringmgr.cpp
new file mode 100644
index 0000000..c4a994e
--- /dev/null
+++ b/src/mgr/stringmgr.cpp
@@ -0,0 +1,280 @@
+/******************************************************************************
+ * stringmgr.cpp - implementation of class StringMgr
+ *
+ * $Id: stringmgr.cpp 2115 2007-10-16 18:29:00Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <stringmgr.h>
+#include <swlog.h>
+#include <localemgr.h>
+#include <utilstr.h>
+
+#ifdef _ICU_
+
+#include <unicode/utypes.h>
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+#include <unicode/uchar.h>
+
+#include <unicode/unistr.h>
+#include <unicode/translit.h>
+
+#include <unicode/locid.h>
+
+#endif
+
+SWORD_NAMESPACE_START
+
+StringMgr *StringMgr::systemStringMgr = 0;
+
+class __staticsystemStringMgr {
+public:
+ __staticsystemStringMgr() { }
+ ~__staticsystemStringMgr() { if (StringMgr::systemStringMgr) delete StringMgr::systemStringMgr; StringMgr::systemStringMgr = 0; }
+} _staticsystemStringMgr;
+
+/**
+ * Determine whether the string contains a valid unicode sequence. The following table give the pattern of a valid UTF-8 character.
+ * Unicode Range 1st 2nd 3rd 4th 5th 6th
+ * U-00000000 - U-0000007F 0nnnnnnn
+ * U-00000080 - U-000007FF 110nnnnn 10nnnnnn
+ * U-00000800 - U-0000FFFF 1110nnnn 10nnnnnn 10nnnnnn
+ * U-00010000 - U-001FFFFF 11110nnn 10nnnnnn 10nnnnnn 10nnnnnn
+ * U-00200000 - U-03FFFFFF 111110nn 10nnnnnn 10nnnnnn 10nnnnnn 10nnnnnn
+ * U-04000000 - U-7FFFFFFF 1111110n 10nnnnnn 10nnnnnn 10nnnnnn 10nnnnnn 10nnnnnn
+ * Note:
+ * The latest UTF-8 RFC allows for a max of 4 bytes. Earlier allowed 6.
+ * The number of bits of the leading byte before the first 0 is the total number of bytes
+ * The "n" are the bits of the unicode codepoint.
+ *
+ * This routine does not check to see if the code point is in the range. It could.
+ *
+ * @param txt the text to check
+ * @return 1 if all high order characters form a valid unicode sequence
+ * -1 if there are no high order characters
+ * 0 if there are high order characters that do not form a valid unicode sequence
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+int isValidUTF8(unsigned char *txt) {
+ unsigned int countUTF8 = 0;
+#if 0
+ unsigned char parts = 0;
+
+
+ unsigned char *p = txt;
+ while (*p) {
+ // Is the high order bit set?
+ if (*p & 0x80) {
+ // then count the number of high order bits that are set
+ // this determines the number of following bytes need to have high order bits set
+ unsigned char i = *p;
+ for (parts = 0; i & 0x80; parts++) {
+ i <<= 1;
+ }
+
+
+ // The pattern 10nnnnnn is not a unicode character
+ if (parts == 1) {
+ return 0;
+ }
+ else {
+ while (--parts && ++*p) {
+ // The pattern of each following character must be: 10nnnnnn
+ if (0xc0 & *p != 0x80) {
+ return 0;
+ }
+ }
+
+ // Oops, we've run out of bytes too soon: Cannot be UTF-8
+ if (parts) {
+ return 0;
+ }
+ }
+ countUTF8++;
+ }
+ }
+
+ // At this point it is either UTF-8 or ascii
+#endif
+ return countUTF8 ? 1 : -1;
+}
+
+
+#ifdef _ICU_
+
+//here comes our ICUStringMgr reimplementation
+class ICUStringMgr : public StringMgr {
+public:
+ virtual char *upperUTF8(char *, unsigned int maxlen = 0) const;
+
+protected:
+ virtual bool supportsUnicode() const { return true; };
+};
+
+#endif
+
+
+/** Default constructor
+*/
+StringMgr::StringMgr() {
+}
+
+/** Copy constructor
+*/
+StringMgr::StringMgr(const StringMgr &m) {
+}
+
+/** Destructor
+*/
+StringMgr::~StringMgr() {
+}
+
+/** Sets the global StringMgr handle
+* @param newStringMgr The new global StringMgr. This pointer will be deleted by this StringMgr
+*/
+void StringMgr::setSystemStringMgr(StringMgr *newStringMgr) {
+ if (systemStringMgr)
+ delete systemStringMgr;
+
+ systemStringMgr = newStringMgr;
+
+ // TODO: this is magic. apparently we have to reset the system localemgr upon changing stringmgr.
+ // setting system stringmgr should be set before localemgr and not possible to change.
+ // rework this design.
+ LocaleMgr::getSystemLocaleMgr()->setSystemLocaleMgr(new LocaleMgr());
+}
+
+/** Returns the global StringMgr handle
+* @return The global string handle
+*/
+StringMgr* StringMgr::getSystemStringMgr() {
+ if (!systemStringMgr) {
+#ifdef _ICU_
+ systemStringMgr = new ICUStringMgr();
+// SWLog::getSystemLog()->logInformation("created default ICUStringMgr");
+#else
+ systemStringMgr = new StringMgr();
+// SWLog::getSystemLog()->logInformation("created default StringMgr");
+#endif
+ }
+
+ return systemStringMgr;
+}
+
+
+/**
+ * This is a fallback method. It should never be called.
+ * If UTF8 support is desired, then a UTF8 StringMgr needs
+ * to be used.
+ *
+ * Here we just do our best.
+ *
+ * Converts the param to an upper case UTF8 string
+ * @param t - The text encoded in utf8 which should be turned into an upper case string
+ *
+ */
+char *StringMgr::upperUTF8(char *t, unsigned int maxlen) const {
+ // try to decide if it's worth trying to toupper. Do we have more
+ // characters which are probably lower latin than not?
+ // we still don't use isValidUTF8 optimally. what if we have 1 unicode
+ // character in the string? should we not try to upper any of the string?
+ // dunno. Best solution is to upper all other characters. Don't have
+ // time to write that before release.
+ long performOp = 0;
+ if (!isValidUTF8((unsigned char *)t)) {
+ performOp = 1;
+ }
+ else {
+ for (const char *ch = t; *ch; ch++) {
+ performOp += (*ch > 0) ? 1 : -1;
+ }
+ }
+
+ if (performOp > 0) {
+ return upperLatin1(t);
+ }
+
+ return t;
+}
+
+
+/**
+ * Converts the param to an uppercase latin1 string
+ * @param The text encoded in latin1 which should be turned into an upper case string
+ */
+char *StringMgr::upperLatin1(char *buf, unsigned int maxlen) const {
+ if (!buf)
+ return 0;
+
+ char *ret = buf;
+ bool checkMax = maxlen;
+
+ while (*buf && (!checkMax || maxlen--)) {
+ *buf = SW_toupper(*buf);
+ buf++;
+ }
+
+ return ret;
+}
+
+bool StringMgr::supportsUnicode() const {
+ return false; //default impl has no UTF8 support
+}
+
+
+#ifdef _ICU_
+
+char *ICUStringMgr::upperUTF8(char *buf, unsigned int maxlen) const {
+ char *ret = buf;
+ int max = (maxlen) ? maxlen : strlen(buf);
+
+ UErrorCode err = U_ZERO_ERROR;
+
+ if (!buf || !max) {
+ return ret;
+ }
+
+ UChar *lowerStr = new UChar[max+10];
+ UChar *upperStr = new UChar[max+10];
+
+ u_strFromUTF8(lowerStr, max+9, 0, buf, -1, &err);
+ if (err != U_ZERO_ERROR) {
+// SWLog::getSystemLog()->logError("from: %s", u_errorName(err));
+ delete [] lowerStr;
+ delete [] upperStr;
+ return ret;
+ }
+
+ u_strToUpper(upperStr, max+9, lowerStr, -1, 0, &err);
+ if (err != U_ZERO_ERROR) {
+// SWLog::getSystemLog()->logError("upperCase: %s", u_errorName(err));
+ delete [] lowerStr;
+ delete [] upperStr;
+ return ret;
+ }
+
+ ret = u_strToUTF8(ret, max, 0, upperStr, -1, &err);
+
+ delete [] lowerStr;
+ delete [] upperStr;
+ return ret;
+}
+
+#endif
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/swcacher.cpp b/src/mgr/swcacher.cpp
new file mode 100644
index 0000000..57d0817
--- /dev/null
+++ b/src/mgr/swcacher.cpp
@@ -0,0 +1,47 @@
+/******************************************************************************
+ * swcacher.h - definition of class SWCacher used to provide an interface for
+ * objects that cache and want a standard interface for cleaning up.
+ *
+ * $Id: swcacher.cpp 1688 2005-01-01 04:42:26Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <swcacher.h>
+
+SWORD_NAMESPACE_START
+
+
+SWCacher::SWCacher() {
+}
+
+
+SWCacher::~SWCacher() {
+}
+
+
+void SWCacher::flush() {
+}
+
+long SWCacher::resourceConsumption() {
+ return 0;
+}
+
+long SWCacher::lastAccess() {
+ return 0;
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/swconfig.cpp b/src/mgr/swconfig.cpp
new file mode 100644
index 0000000..376c206
--- /dev/null
+++ b/src/mgr/swconfig.cpp
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * swconfig.cpp - implementation of Class SWConfig used for saving and
+ * retrieval of configuration information
+ *
+ * $Id: swconfig.cpp 1828 2005-06-10 16:24:46Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <swconfig.h>
+#include <utilstr.h>
+#include <filemgr.h>
+#include <fcntl.h>
+
+
+SWORD_NAMESPACE_START
+
+SWConfig::SWConfig(const char * ifilename) {
+ filename = ifilename;
+ Load();
+}
+
+
+SWConfig::~SWConfig() {
+}
+
+void SWConfig::Load() {
+ FileDesc *cfile;
+ char *buf, *data;
+ SWBuf line;
+ ConfigEntMap cursect;
+ SWBuf sectname;
+ bool first = true;
+
+ Sections.erase(Sections.begin(), Sections.end());
+
+ cfile = FileMgr::getSystemFileMgr()->open(filename.c_str(), FileMgr::RDONLY);
+ if (cfile->getFd() > 0) {
+ bool goodLine = FileMgr::getLine(cfile, line);
+
+ // clean UTF encoding tags at start of file
+ while (goodLine && line.length() &&
+ ((((unsigned char)line[0]) == 0xEF) ||
+ (((unsigned char)line[0]) == 0xBB) ||
+ (((unsigned char)line[0]) == 0xBF))) {
+ line << 1;
+ }
+
+ while (goodLine) {
+ buf = new char [ line.length() + 1 ];
+ strcpy(buf, line.c_str());
+ if (*strstrip(buf) == '[') {
+ if (!first)
+ Sections.insert(SectionMap::value_type(sectname, cursect));
+ else first = false;
+
+ cursect.erase(cursect.begin(), cursect.end());
+
+ strtok(buf, "]");
+ sectname = buf+1;
+ }
+ else {
+ strtok(buf, "=");
+ if ((*buf) && (*buf != '=')) {
+ if ((data = strtok(NULL, "")))
+ cursect.insert(ConfigEntMap::value_type(buf, strstrip(data)));
+ else cursect.insert(ConfigEntMap::value_type(buf, ""));
+ }
+ }
+ delete [] buf;
+ goodLine = FileMgr::getLine(cfile, line);
+ }
+ if (!first)
+ Sections.insert(SectionMap::value_type(sectname, cursect));
+
+ FileMgr::getSystemFileMgr()->close(cfile);
+ }
+}
+
+
+void SWConfig::Save() {
+ FileDesc *cfile;
+ SWBuf buf;
+ SectionMap::iterator sit;
+ ConfigEntMap::iterator entry;
+ SWBuf sectname;
+
+ cfile = FileMgr::getSystemFileMgr()->open(filename.c_str(), FileMgr::RDWR|FileMgr::CREAT|FileMgr::TRUNC);
+ if (cfile->getFd() > 0) {
+
+ for (sit = Sections.begin(); sit != Sections.end(); sit++) {
+ buf = "\n[";
+ buf += (*sit).first.c_str();
+ buf += "]\n";
+ cfile->write(buf.c_str(), buf.length());
+ for (entry = (*sit).second.begin(); entry != (*sit).second.end(); entry++) {
+ buf = (*entry).first.c_str();
+ buf += "=";
+ buf += (*entry).second.c_str();
+ buf += "\n";
+ cfile->write(buf.c_str(), buf.length());
+ }
+ }
+ buf = "\n";
+ cfile->write(buf.c_str(), buf.length());
+ FileMgr::getSystemFileMgr()->close(cfile);
+ }
+}
+
+
+void SWConfig::augment(SWConfig &addFrom) {
+
+ SectionMap::iterator section;
+ ConfigEntMap::iterator entry, start, end;
+
+ for (section = addFrom.Sections.begin(); section != addFrom.Sections.end(); section++) {
+ for (entry = (*section).second.begin(); entry != (*section).second.end(); entry++) {
+ start = Sections[section->first].lower_bound(entry->first);
+ end = Sections[section->first].upper_bound(entry->first);
+ if (start != end) {
+ if (((++start) != end)
+ || ((++(addFrom.Sections[section->first].lower_bound(entry->first))) != addFrom.Sections[section->first].upper_bound(entry->first))) {
+ for (--start; start != end; start++) {
+ if (!strcmp(start->second.c_str(), entry->second.c_str()))
+ break;
+ }
+ if (start == end)
+ Sections[(*section).first].insert(ConfigEntMap::value_type((*entry).first, (*entry).second));
+ }
+ else Sections[section->first][entry->first.c_str()] = entry->second.c_str();
+ }
+ else Sections[section->first][entry->first.c_str()] = entry->second.c_str();
+ }
+ }
+}
+
+
+ConfigEntMap & SWConfig::operator [] (const char *section) {
+ return Sections[section];
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/swfiltermgr.cpp b/src/mgr/swfiltermgr.cpp
new file mode 100644
index 0000000..434f2e0
--- /dev/null
+++ b/src/mgr/swfiltermgr.cpp
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * swfiltermgr.cpp - definition of class SWFilterMgr used as an interface to
+ * manage filters on a module
+ *
+ * $Id: swfiltermgr.cpp 1688 2005-01-01 04:42:26Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <swfiltermgr.h>
+
+SWORD_NAMESPACE_START
+
+
+SWFilterMgr::SWFilterMgr() {
+}
+
+
+SWFilterMgr::~SWFilterMgr() {
+}
+
+
+void SWFilterMgr::setParentMgr(SWMgr *parentMgr) {
+ this->parentMgr = parentMgr;
+}
+
+
+SWMgr *SWFilterMgr::getParentMgr() {
+ return parentMgr;
+}
+
+
+void SWFilterMgr::AddGlobalOptions(SWModule * module, ConfigEntMap & section, ConfigEntMap::iterator start, ConfigEntMap::iterator end) {
+}
+
+
+void SWFilterMgr::AddLocalOptions(SWModule * module, ConfigEntMap & section, ConfigEntMap::iterator start, ConfigEntMap::iterator end) {
+}
+
+
+/**
+* Adds the encoding filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the encoding filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddEncodingFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+
+/**
+* Adds the render filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the render filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddRenderFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+
+/**
+* Adds the strip filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the strip filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddStripFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+
+/**
+* Adds the raw filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the raw filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddRawFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/swlocale.cpp b/src/mgr/swlocale.cpp
new file mode 100644
index 0000000..facb1ee
--- /dev/null
+++ b/src/mgr/swlocale.cpp
@@ -0,0 +1,204 @@
+/******************************************************************************
+ * swlocale.cpp - implementation of Class SWLocale used for retrieval
+ * of locale lookups
+ *
+ * $Id: swlocale.cpp 1864 2005-11-20 06:06:40Z scribe $
+ *
+ * Copyright 2000 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <swlocale.h>
+#include <utilstr.h>
+#include <map>
+#include <swconfig.h>
+#include <versekey.h>
+
+SWORD_NAMESPACE_START
+
+typedef std::map < SWBuf, SWBuf, std::less < SWBuf > >LookupMap;
+
+// I have bridge patterns, but this hides swconfig and map from lots o stuff
+class SWLocale::Private {
+public:
+ LookupMap lookupTable;
+};
+
+
+SWLocale::SWLocale(const char * ifilename) {
+ p = new Private;
+ ConfigEntMap::iterator confEntry;
+
+ name = 0;
+ description = 0;
+ encoding = 0;
+ bookAbbrevs = 0;
+ BMAX = 0;
+ books = 0;
+ localeSource = new SWConfig(ifilename);
+
+ confEntry = localeSource->Sections["Meta"].find("Name");
+ if (confEntry != localeSource->Sections["Meta"].end())
+ stdstr(&name, (*confEntry).second.c_str());
+
+ confEntry = localeSource->Sections["Meta"].find("Description");
+ if (confEntry != localeSource->Sections["Meta"].end())
+ stdstr(&description, (*confEntry).second.c_str());
+
+ confEntry = localeSource->Sections["Meta"].find("Encoding"); //Either empty (==Latin1) or UTF-8
+ if (confEntry != localeSource->Sections["Meta"].end())
+ stdstr(&encoding, (*confEntry).second.c_str());
+}
+
+
+SWLocale::~SWLocale() {
+
+ delete localeSource;
+
+ if (encoding)
+ delete [] encoding;
+
+ if (description)
+ delete [] description;
+
+ if (name)
+ delete [] name;
+
+ if (bookAbbrevs)
+ delete [] bookAbbrevs;
+
+ if (BMAX) {
+ for (int i = 0; i < 2; i++)
+ delete [] books[i];
+ delete [] BMAX;
+ delete [] books;
+ }
+ delete p;
+}
+
+
+const char *SWLocale::translate(const char *text) {
+ LookupMap::iterator entry;
+
+ entry = p->lookupTable.find(text);
+
+ if (entry == p->lookupTable.end()) {
+ ConfigEntMap::iterator confEntry;
+ confEntry = localeSource->Sections["Text"].find(text);
+ if (confEntry == localeSource->Sections["Text"].end())
+ p->lookupTable.insert(LookupMap::value_type(text, text));
+ else {//valid value found
+ /*
+ - If Encoding==Latin1 and we have a StringHelper, convert to UTF-8
+ - If StringHelper present and Encoding is UTF-8, use UTF8
+ - If StringHelper not present and Latin1, use Latin1
+ - If StringHelper not present and UTF-8, no idea what to do. Should't happen
+ */
+/* if (StringHelper::getSystemStringHelper()) {
+ if (!strcmp(encoding, "UTF-8")) {
+ p->lookupTable.insert(LookupMap::value_type(text, (*confEntry).second.c_str()));
+ }
+ else { //latin1 expected, convert to UTF-8
+ SWBuf t((*confEntry).second.c_str());
+ t = StringHelper::getSystemStringHelper()->latin2unicode( t );
+
+ p->lookupTable.insert(LookupMap::value_type(text, t.c_str()));
+ }
+ }
+ else { //no stringhelper, just insert. Nothing we can do*/
+ p->lookupTable.insert(LookupMap::value_type(text, (*confEntry).second.c_str()));
+// }
+
+ }
+ entry = p->lookupTable.find(text);
+ }
+ return (*entry).second.c_str();
+}
+
+
+const char *SWLocale::getName() {
+ return name;
+}
+
+
+const char *SWLocale::getDescription() {
+ return description;
+}
+
+const char *SWLocale::getEncoding() {
+ return encoding;
+}
+
+void SWLocale::augment(SWLocale &addFrom) {
+ *localeSource += *addFrom.localeSource;
+}
+
+//#define NONNUMERICLOCALETHING 1
+
+const struct abbrev *SWLocale::getBookAbbrevs() {
+ static const char *nullstr = "";
+ if (!bookAbbrevs) {
+ ConfigEntMap::iterator it;
+ int i, j;
+ int size = localeSource->Sections["Book Abbrevs"].size();
+ bookAbbrevs = new struct abbrev[size + 1];
+ for (i = 0, j = 0, it = localeSource->Sections["Book Abbrevs"].begin(); it != localeSource->Sections["Book Abbrevs"].end(); it++, i++) {
+ #ifdef NONNUMERICLOCALETHING
+ int booknum = VerseKey::getOSISBookNum((*it).second.c_str());
+ if (booknum != -1) {
+ bookAbbrevs[j].ab = (*it).first.c_str();
+ bookAbbrevs[j].book = booknum;
+ j++;
+ }
+ #else
+ bookAbbrevs[i].ab = (*it).first.c_str();
+ bookAbbrevs[i].book = atoi((*it).second.c_str());
+ j++;
+ #endif
+ //printf("SWLocale::getBookAbbrevs %s:%s %d\n",bookAbbrevs[i].ab,
+ // (*it).second.c_str(), bookAbbrevs[i].book);
+ }
+ bookAbbrevs[j].ab = nullstr;
+ bookAbbrevs[j].book = -1;
+ }
+
+ return bookAbbrevs;
+}
+
+
+void SWLocale::getBooks(char **iBMAX, struct sbook ***ibooks) {
+ if (!BMAX) {
+ BMAX = new char [2];
+ BMAX[0] = VerseKey::builtin_BMAX[0];
+ BMAX[1] = VerseKey::builtin_BMAX[1];
+
+ books = new struct sbook *[2];
+ books[0] = new struct sbook[BMAX[0]];
+ books[1] = new struct sbook[BMAX[1]];
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < BMAX[i]; j++) {
+ books[i][j] = VerseKey::builtin_books[i][j];
+ books[i][j].name = translate(VerseKey::builtin_books[i][j].name);
+ }
+ }
+ }
+
+ *iBMAX = BMAX;
+ *ibooks = books;
+}
+
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/swmgr.cpp b/src/mgr/swmgr.cpp
new file mode 100644
index 0000000..86c04d7
--- /dev/null
+++ b/src/mgr/swmgr.cpp
@@ -0,0 +1,1275 @@
+/******************************************************************************
+ * swmgr.cpp - implementaion of class SWMgr used to interact with an install
+ * base of sword modules.
+ *
+ * $Id: swmgr.cpp 2169 2008-05-18 02:50:53Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
+#ifndef _MSC_VER
+#include <iostream>
+#endif
+#include <dirent.h>
+
+#include <swmgr.h>
+#include <rawtext.h>
+#include <rawtext4.h>
+#include <filemgr.h>
+#include <rawgenbook.h>
+#include <rawcom.h>
+#include <rawcom4.h>
+#include <hrefcom.h>
+#include <rawld.h>
+#include <rawld4.h>
+#include <utilstr.h>
+#include <gbfplain.h>
+#include <thmlplain.h>
+#include <osisplain.h>
+#include <teiplain.h>
+#include <papyriplain.h>
+#include <gbfstrongs.h>
+#include <gbffootnotes.h>
+#include <gbfheadings.h>
+#include <gbfredletterwords.h>
+#include <gbfmorph.h>
+#include <osisheadings.h>
+#include <osisfootnotes.h>
+#include <osisstrongs.h>
+#include <osismorph.h>
+#include <osislemma.h>
+#include <osisredletterwords.h>
+#include <osismorphsegmentation.h>
+#include <osisscripref.h>
+#include <thmlstrongs.h>
+#include <thmlfootnotes.h>
+#include <thmlheadings.h>
+#include <thmlmorph.h>
+#include <thmlvariants.h>
+#include <thmllemma.h>
+#include <thmlscripref.h>
+#include <cipherfil.h>
+#include <rawfiles.h>
+#include <ztext.h>
+#include <zld.h>
+#include <zcom.h>
+#include <lzsscomprs.h>
+#include <utf8greekaccents.h>
+#include <utf8cantillation.h>
+#include <utf8hebrewpoints.h>
+#include <greeklexattribs.h>
+#include <swfiltermgr.h>
+#include <swcipher.h>
+#include <swoptfilter.h>
+
+#include <swlog.h>
+
+#include <iterator>
+
+#ifndef EXCLUDEZLIB
+#include "zipcomprs.h"
+#endif
+
+
+#ifdef _ICU_
+#include <utf8transliterator.h>
+#endif
+
+SWORD_NAMESPACE_START
+
+#ifdef _ICU_
+bool SWMgr::isICU = true;
+#else
+bool SWMgr::isICU = false;
+#endif
+
+
+#ifdef GLOBCONFPATH
+const char *SWMgr::globalConfPath = GLOBCONFPATH;
+#else
+const char *SWMgr::globalConfPath = "/etc/sword.conf:/usr/local/etc/sword.conf";
+#endif
+
+void SWMgr::init() {
+ SWOptionFilter *tmpFilter = 0;
+ configPath = 0;
+ prefixPath = 0;
+ configType = 0;
+ myconfig = 0;
+ mysysconfig = 0;
+ homeConfig = 0;
+ augmentHome = true;
+
+ cipherFilters.clear();
+ optionFilters.clear();
+ cleanupFilters.clear();
+ tmpFilter = new ThMLVariants();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLVariants", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFStrongs();
+ optionFilters.insert(OptionFilterMap::value_type("GBFStrongs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFFootnotes();
+ optionFilters.insert(OptionFilterMap::value_type("GBFFootnotes", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFRedLetterWords();
+ optionFilters.insert(OptionFilterMap::value_type("GBFRedLetterWords", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFMorph();
+ optionFilters.insert(OptionFilterMap::value_type("GBFMorph", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFHeadings();
+ optionFilters.insert(OptionFilterMap::value_type("GBFHeadings", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISHeadings();
+ optionFilters.insert(OptionFilterMap::value_type("OSISHeadings", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISStrongs();
+ optionFilters.insert(OptionFilterMap::value_type("OSISStrongs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISMorph();
+ optionFilters.insert(OptionFilterMap::value_type("OSISMorph", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISLemma();
+ optionFilters.insert(OptionFilterMap::value_type("OSISLemma", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISFootnotes();
+ optionFilters.insert(OptionFilterMap::value_type("OSISFootnotes", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISScripref();
+ optionFilters.insert(OptionFilterMap::value_type("OSISScripref", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISRedLetterWords();
+ optionFilters.insert(OptionFilterMap::value_type("OSISRedLetterWords", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new OSISMorphSegmentation();
+ optionFilters.insert(OptionFilterMap::value_type("OSISMorphSegmentation", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLStrongs();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLStrongs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLFootnotes();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLFootnotes", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLMorph();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLMorph", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLHeadings();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLHeadings", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLLemma();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLLemma", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLScripref();
+ optionFilters.insert(OptionFilterMap::value_type("ThMLScripref", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new UTF8GreekAccents();
+ optionFilters.insert(OptionFilterMap::value_type("UTF8GreekAccents", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new UTF8HebrewPoints();
+ optionFilters.insert(OptionFilterMap::value_type("UTF8HebrewPoints", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new UTF8Cantillation();
+ optionFilters.insert(OptionFilterMap::value_type("UTF8Cantillation", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GreekLexAttribs();
+ optionFilters.insert(OptionFilterMap::value_type("GreekLexAttribs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new PapyriPlain();
+ optionFilters.insert(OptionFilterMap::value_type("PapyriPlain", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+// UTF8Transliterator needs to be handled differently because it should always available as an option, for all modules
+#ifdef _ICU_
+ transliterator = new UTF8Transliterator();
+ optionFilters.insert(OptionFilterMap::value_type("UTF8Transliterator", transliterator));
+ options.push_back(transliterator->getOptionName());
+ cleanupFilters.push_back(transliterator);
+#endif
+
+ gbfplain = new GBFPlain();
+ cleanupFilters.push_back(gbfplain);
+
+ thmlplain = new ThMLPlain();
+ cleanupFilters.push_back(thmlplain);
+
+ osisplain = new OSISPlain();
+ cleanupFilters.push_back(osisplain);
+
+ teiplain = new TEIPlain();
+ cleanupFilters.push_back(teiplain);
+//#endif
+}
+
+
+void SWMgr::commonInit(SWConfig *iconfig, SWConfig *isysconfig, bool autoload, SWFilterMgr *filterMgr, bool multiMod) {
+
+ init();
+
+ mgrModeMultiMod = multiMod;
+ this->filterMgr = filterMgr;
+ if (filterMgr)
+ filterMgr->setParentMgr(this);
+
+ if (iconfig) {
+ config = iconfig;
+ myconfig = 0;
+ }
+ else config = 0;
+ if (isysconfig) {
+ sysconfig = isysconfig;
+ mysysconfig = 0;
+ }
+ else sysconfig = 0;
+
+ if (autoload)
+ Load();
+}
+
+
+SWMgr::SWMgr(SWFilterMgr *filterMgr, bool multiMod) {
+ commonInit(0, 0, true, filterMgr, multiMod);
+}
+
+
+SWMgr::SWMgr(SWConfig *iconfig, SWConfig *isysconfig, bool autoload, SWFilterMgr *filterMgr, bool multiMod) {
+ commonInit(iconfig, isysconfig, autoload, filterMgr, multiMod);
+}
+
+
+SWMgr::SWMgr(const char *iConfigPath, bool autoload, SWFilterMgr *filterMgr, bool multiMod, bool augmentHome) {
+
+ init();
+
+ mgrModeMultiMod = multiMod;
+ SWBuf path;
+
+ this->filterMgr = filterMgr;
+ if (filterMgr)
+ filterMgr->setParentMgr(this);
+
+ this->augmentHome = augmentHome;
+
+ path = iConfigPath;
+ int len = path.length();
+ if ((len < 1) || ((iConfigPath[len-1] != '\\') && (iConfigPath[len-1] != '/')))
+ path += "/";
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+ stdstr(&prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(&configPath, path.c_str());
+ }
+ else {
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ stdstr(&prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(&configPath, path.c_str());
+ configType = 1;
+ }
+ }
+
+ config = 0;
+ sysconfig = 0;
+
+ if (autoload && configPath)
+ Load();
+}
+
+
+SWMgr::~SWMgr() {
+
+ DeleteMods();
+
+ for (FilterList::iterator it = cleanupFilters.begin(); it != cleanupFilters.end(); it++)
+ delete (*it);
+
+ if (homeConfig)
+ delete homeConfig;
+
+ if (mysysconfig)
+ delete mysysconfig;
+
+ if (myconfig)
+ delete myconfig;
+
+ if (prefixPath)
+ delete [] prefixPath;
+
+ if (configPath)
+ delete [] configPath;
+
+ if (filterMgr)
+ delete filterMgr;
+}
+
+
+void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, std::list<SWBuf> *augPaths, SWConfig *providedSysConf) {
+ SWBuf path;
+ SWBuf sysConfPath;
+ ConfigEntMap::iterator entry;
+ ConfigEntMap::iterator lastEntry;
+
+ char *envsworddir = getenv("SWORD_PATH");
+ char *envhomedir = getenv("HOME");
+ SWConfig *sysConf = 0;
+
+ *configType = 0;
+
+ // check for a sysConf passed in to us
+ SWLog::getSystemLog()->logDebug("Checking for provided SWConfig(\"sword.conf\")...");
+ if (providedSysConf) {
+ sysConf = providedSysConf;
+ SWLog::getSystemLog()->logDebug("found.");
+ }
+ else {
+ // check working directory
+ SWLog::getSystemLog()->logDebug("Checking working directory for sword.conf...");
+ if (FileMgr::existsFile(".", "sword.conf")) {
+ SWLog::getSystemLog()->logDebug("Overriding any systemwide or ~/.sword/ sword.conf with one found in current directory.");
+ sysConfPath = "./sword.conf";
+ }
+ else {
+ SWLog::getSystemLog()->logDebug("Checking working directory for mods.conf...");
+ if (FileMgr::existsFile(".", "mods.conf")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, "./");
+ stdstr(configPath, "./mods.conf");
+ return;
+ }
+
+ SWLog::getSystemLog()->logDebug("Checking working directory for mods.d...");
+ if (FileMgr::existsDir(".", "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, "./");
+ stdstr(configPath, "./mods.d");
+ *configType = 1;
+ return;
+ }
+
+ // check working directory ../library/
+ SWLog::getSystemLog()->logDebug("Checking working directory ../library/ for mods.d...");
+ if (FileMgr::existsDir("../library", "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, "../library/");
+ stdstr(configPath, "../library/mods.d");
+ *configType = 1;
+ return;
+ }
+
+ // check environment variable SWORD_PATH
+ SWLog::getSystemLog()->logDebug("Checking SWORD_PATH...");
+
+ if (envsworddir != NULL) {
+
+ SWLog::getSystemLog()->logDebug("found (%s).", envsworddir);
+ path = envsworddir;
+ if ((envsworddir[strlen(envsworddir)-1] != '\\') && (envsworddir[strlen(envsworddir)-1] != '/'))
+ path += "/";
+
+ SWLog::getSystemLog()->logDebug("Checking $SWORD_PATH for mods.conf...");
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(configPath, path.c_str());
+ return;
+ }
+
+ SWLog::getSystemLog()->logDebug("Checking $SWORD_PATH for mods.d...");
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ return;
+ }
+ }
+
+
+ // check for systemwide globalConfPath
+
+ SWLog::getSystemLog()->logDebug("Parsing %s...", globalConfPath);
+ char *globPaths = 0;
+ char *gfp;
+ stdstr(&globPaths, globalConfPath);
+ for (gfp = strtok(globPaths, ":"); gfp; gfp = strtok(0, ":")) {
+ SWLog::getSystemLog()->logDebug("Checking for %s...", gfp);
+ if (FileMgr::existsFile(gfp)) {
+ SWLog::getSystemLog()->logDebug("found.");
+ break;
+ }
+ }
+ if (gfp)
+ sysConfPath = gfp;
+ delete [] globPaths;
+
+ SWBuf homeDir = envhomedir;
+ if (homeDir.size() > 0) {
+ if ((homeDir[homeDir.size()-1] != '\\') && (homeDir[homeDir.size()-1] != '/'))
+ homeDir += "/";
+ homeDir += ".sword/sword.conf";
+ if (FileMgr::existsFile(homeDir)) {
+ SWLog::getSystemLog()->logDebug("Overriding any systemwide sword.conf with one found in users home directory.");
+ sysConfPath = homeDir;
+ }
+ }
+ }
+ }
+
+ if (sysConfPath.size()) {
+ sysConf = new SWConfig(sysConfPath);
+ }
+
+ if (sysConf) {
+ if ((entry = sysConf->Sections["Install"].find("DataPath")) != sysConf->Sections["Install"].end()) {
+ path = (*entry).second;
+ if (((*entry).second.c_str()[strlen((*entry).second.c_str())-1] != '\\') && ((*entry).second.c_str()[strlen((*entry).second.c_str())-1] != '/'))
+ path += "/";
+
+ SWLog::getSystemLog()->logDebug("DataPath in %s is set to %s.", sysConfPath.c_str(), path.c_str());
+ SWLog::getSystemLog()->logDebug("Checking for mods.conf in DataPath...");
+
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ }
+
+ SWLog::getSystemLog()->logDebug("Checking for mods.d in DataPath...");
+
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ }
+ }
+ if (augPaths) {
+ augPaths->clear();
+ entry = sysConf->Sections["Install"].lower_bound("AugmentPath");
+ lastEntry = sysConf->Sections["Install"].upper_bound("AugmentPath");
+ for (;entry != lastEntry; entry++) {
+ path = entry->second;
+ if ((entry->second.c_str()[strlen(entry->second.c_str())-1] != '\\') && (entry->second.c_str()[strlen(entry->second.c_str())-1] != '/'))
+ path += "/";
+ augPaths->push_back(path);
+ }
+ }
+ }
+
+ if ((sysConf) && (!providedSysConf)) {
+ delete sysConf;
+ }
+
+ if (*configType)
+ return;
+
+ // check ~/.sword/
+
+ SWLog::getSystemLog()->logDebug("Checking home directory for ~/.sword...");
+
+ if (envhomedir != NULL) {
+ path = envhomedir;
+ if ((envhomedir[strlen(envhomedir)-1] != '\\') && (envhomedir[strlen(envhomedir)-1] != '/'))
+ path += "/";
+ path += ".sword/";
+ SWLog::getSystemLog()->logDebug(" Checking for %smods.conf...", path.c_str());
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(configPath, path.c_str());
+ return;
+ }
+
+ SWLog::getSystemLog()->logDebug(" Checking for %smods.d...", path.c_str());
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 2;
+ return;
+ }
+ }
+}
+
+
+void SWMgr::loadConfigDir(const char *ipath)
+{
+ DIR *dir;
+ struct dirent *ent;
+ SWBuf newmodfile;
+
+ if ((dir = opendir(ipath))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ //check whether it ends with .conf, if it doesn't skip it!
+ if (ent->d_name && (strlen(ent->d_name) > 5) && strncmp(".conf", (ent->d_name + strlen(ent->d_name) - 5), 5 )) {
+ continue;
+ }
+
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+ if (config) {
+ SWConfig tmpConfig(newmodfile.c_str());
+ *config += tmpConfig;
+ }
+ else config = myconfig = new SWConfig(newmodfile.c_str());
+ }
+ }
+ closedir(dir);
+
+ if (!config) { // if no .conf file exist yet, create a default
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += "globals.conf";
+ config = myconfig = new SWConfig(newmodfile.c_str());
+ }
+ }
+}
+
+
+void SWMgr::augmentModules(const char *ipath, bool multiMod) {
+ SWBuf path = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ path += "/";
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ char *savePrefixPath = 0;
+ char *saveConfigPath = 0;
+ SWConfig *saveConfig = 0;
+ stdstr(&savePrefixPath, prefixPath);
+ stdstr(&prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(&saveConfigPath, configPath);
+ stdstr(&configPath, path.c_str());
+ saveConfig = config;
+ config = myconfig = 0;
+ loadConfigDir(configPath);
+
+ if (multiMod) {
+ // fix config's Section names to rename modules which are available more than once
+ // find out which sections are in both config objects
+ // inserting all configs first is not good because that overwrites old keys and new modules would share the same config
+ for (SectionMap::iterator it = config->Sections.begin(); it != config->Sections.end(); ++it) {
+ if (saveConfig->Sections.find( (*it).first ) != saveConfig->Sections.end()) { //if the new section is already present rename it
+ ConfigEntMap entMap((*it).second);
+
+ SWBuf name;
+ int i = 1;
+ do { //module name already used?
+ name.setFormatted("%s_%d", (*it).first.c_str(), i);
+ i++;
+ } while (config->Sections.find(name) != config->Sections.end());
+
+ config->Sections.insert(SectionMap::value_type(name, entMap) );
+ config->Sections.erase(it);
+ }
+ }
+ }
+
+ CreateMods(multiMod);
+
+ stdstr(&prefixPath, savePrefixPath);
+ delete []savePrefixPath;
+ stdstr(&configPath, saveConfigPath);
+ delete []saveConfigPath;
+
+ (*saveConfig) += *config;
+
+ homeConfig = myconfig;
+ config = myconfig = saveConfig;
+ }
+}
+
+
+/***********************************************************************
+ * SWMgr::Load - loads actual modules
+ *
+ * RET: status - 0 = ok; -1 no config found; 1 = no modules installed
+ *
+ */
+
+signed char SWMgr::Load() {
+ signed char ret = 0;
+
+ if (!config) { // If we weren't passed a config object at construction, find a config file
+ if (!configPath) { // If we weren't passed a config path at construction...
+ SWLog::getSystemLog()->logDebug("LOOKING UP MODULE CONFIGURATION...");
+ findConfig(&configType, &prefixPath, &configPath, &augPaths, sysconfig);
+ SWLog::getSystemLog()->logDebug("LOOKING UP MODULE CONFIGURATION COMPLETE.");
+ }
+ if (configPath) {
+ if (configType)
+ loadConfigDir(configPath);
+ else config = myconfig = new SWConfig(configPath);
+ }
+ }
+
+ if (config) {
+ SectionMap::iterator Sectloop, Sectend;
+ ConfigEntMap::iterator Entryloop, Entryend;
+
+ DeleteMods();
+
+ for (Sectloop = config->Sections.lower_bound("Globals"), Sectend = config->Sections.upper_bound("Globals"); Sectloop != Sectend; Sectloop++) { // scan thru all 'Globals' sections
+ for (Entryloop = (*Sectloop).second.lower_bound("AutoInstall"), Entryend = (*Sectloop).second.upper_bound("AutoInstall"); Entryloop != Entryend; Entryloop++) // scan thru all AutoInstall entries
+ InstallScan((*Entryloop).second.c_str()); // Scan AutoInstall entry directory for new modules and install
+ }
+ if (configType) { // force reload on config object because we may have installed new modules
+ delete myconfig;
+ config = myconfig = 0;
+ loadConfigDir(configPath);
+ }
+ else config->Load();
+
+ CreateMods(mgrModeMultiMod);
+
+ for (std::list<SWBuf>::iterator pathIt = augPaths.begin(); pathIt != augPaths.end(); pathIt++) {
+ augmentModules(pathIt->c_str(), mgrModeMultiMod);
+ }
+ if (augmentHome) {
+ // augment config with ~/.sword/mods.d if it exists ---------------------
+ char *envhomedir = getenv("HOME");
+ if (envhomedir != NULL && configType != 2) { // 2 = user only
+ SWBuf path = envhomedir;
+ if ((envhomedir[strlen(envhomedir)-1] != '\\') && (envhomedir[strlen(envhomedir)-1] != '/'))
+ path += "/";
+ path += ".sword/";
+ augmentModules(path.c_str(), mgrModeMultiMod);
+ }
+ }
+// -------------------------------------------------------------------------
+ if ( !Modules.size() ) // config exists, but no modules
+ ret = 1;
+
+ }
+ else {
+ SWLog::getSystemLog()->logError("SWMgr: Can't find 'mods.conf' or 'mods.d'. Try setting:\n\tSWORD_PATH=<directory containing mods.conf>\n\tOr see the README file for a full description of setup options (%s)", (configPath) ? configPath : "<configPath is null>");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+SWModule *SWMgr::CreateMod(const char *name, const char *driver, ConfigEntMap &section)
+{
+ SWBuf description, datapath, misc1;
+ ConfigEntMap::iterator entry;
+ SWModule *newmod = 0;
+ SWBuf lang, sourceformat, encoding;
+ signed char direction, enc, markup;
+
+ description = ((entry = section.find("Description")) != section.end()) ? (*entry).second : (SWBuf)"";
+ lang = ((entry = section.find("Lang")) != section.end()) ? (*entry).second : (SWBuf)"en";
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (SWBuf)"";
+ encoding = ((entry = section.find("Encoding")) != section.end()) ? (*entry).second : (SWBuf)"";
+ datapath = prefixPath;
+ if ((prefixPath[strlen(prefixPath)-1] != '\\') && (prefixPath[strlen(prefixPath)-1] != '/'))
+ datapath += "/";
+
+ // DataPath - relative path to data used by module driver. May be a directory, may be a File.
+ // Typically not useful by outside world. See AbsoluteDataPath, PrefixPath, and RelativePrefixPath
+ // below.
+ misc1 += ((entry = section.find("DataPath")) != section.end()) ? (*entry).second : (SWBuf)"";
+ char *buf = new char [ strlen(misc1.c_str()) + 1 ];
+ char *buf2 = buf;
+ strcpy(buf, misc1.c_str());
+// for (; ((*buf2) && ((*buf2 == '.') || (*buf2 == '/') || (*buf2 == '\\'))); buf2++);
+ for (; ((*buf2) && ((*buf2 == '/') || (*buf2 == '\\'))); buf2++);
+ if (!strncmp(buf2, "./", 2)) { //remove the leading ./ in the module data path to make it look better
+ buf2 += 2;
+ }
+ // PrefixPath - absolute directory path to the repository in which this module was found
+ section["PrefixPath"] = datapath;
+ if (*buf2)
+ datapath += buf2;
+ delete [] buf;
+
+ section["AbsoluteDataPath"] = datapath;
+
+ if (!stricmp(sourceformat.c_str(), "GBF"))
+ markup = FMT_GBF;
+ else if (!stricmp(sourceformat.c_str(), "ThML"))
+ markup = FMT_THML;
+ else if (!stricmp(sourceformat.c_str(), "OSIS"))
+ markup = FMT_OSIS;
+ else if (!stricmp(sourceformat.c_str(), "TEI"))
+ markup = FMT_TEI;
+ else
+ markup = FMT_GBF;
+
+ if (!stricmp(encoding.c_str(), "SCSU"))
+ enc = ENC_SCSU;
+ else if (!stricmp(encoding.c_str(), "UTF-8")) {
+ enc = ENC_UTF8;
+ }
+ else enc = ENC_LATIN1;
+
+ if ((entry = section.find("Direction")) == section.end()) {
+ direction = DIRECTION_LTR;
+ }
+ else if (!stricmp((*entry).second.c_str(), "rtol")) {
+ direction = DIRECTION_RTL;
+ }
+ else if (!stricmp((*entry).second.c_str(), "bidi")) {
+ direction = DIRECTION_BIDI;
+ }
+ else {
+ direction = DIRECTION_LTR;
+ }
+
+ if ((!stricmp(driver, "zText")) || (!stricmp(driver, "zCom"))) {
+ SWCompress *compress = 0;
+ int blockType = CHAPTERBLOCKS;
+ int blockNum = 1;
+ misc1 = ((entry = section.find("BlockType")) != section.end()) ? (*entry).second : (SWBuf)"CHAPTER";
+ if (!stricmp(misc1.c_str(), "VERSE"))
+ blockType = VERSEBLOCKS;
+ else if (!stricmp(misc1.c_str(), "CHAPTER"))
+ blockType = CHAPTERBLOCKS;
+ else if (!stricmp(misc1.c_str(), "BOOK"))
+ blockType = BOOKBLOCKS;
+
+ misc1 = ((entry = section.find("BlockNumber")) != section.end()) ? (*entry).second : (SWBuf)"1";
+ blockNum = atoi(misc1.c_str());
+
+ misc1 = ((entry = section.find("CompressType")) != section.end()) ? (*entry).second : (SWBuf)"LZSS";
+#ifndef EXCLUDEZLIB
+ if (!stricmp(misc1.c_str(), "ZIP"))
+ compress = new ZipCompress();
+ else
+#endif
+ if (!stricmp(misc1.c_str(), "LZSS"))
+ compress = new LZSSCompress();
+
+ if (compress) {
+ if (!stricmp(driver, "zText"))
+ newmod = new zText(datapath.c_str(), name, description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str());
+ else newmod = new zCom(datapath.c_str(), name, description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str());
+ }
+ }
+
+ if (!stricmp(driver, "RawText")) {
+ newmod = new RawText(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver, "RawText4")) {
+ newmod = new RawText4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ // backward support old drivers
+ if (!stricmp(driver, "RawGBF")) {
+ newmod = new RawText(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver, "RawCom")) {
+ newmod = new RawCom(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver, "RawCom4")) {
+ newmod = new RawCom4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver, "RawFiles")) {
+ newmod = new RawFiles(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver, "HREFCom")) {
+ misc1 = ((entry = section.find("Prefix")) != section.end()) ? (*entry).second : (SWBuf)"";
+ newmod = new HREFCom(datapath.c_str(), misc1.c_str(), name, description.c_str());
+ }
+
+ int pos = 0; //used for position of final / in AbsoluteDataPath, but also set to 1 for modules types that need to strip module name
+ if (!stricmp(driver, "RawLD")) {
+ newmod = new RawLD(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ pos = 1;
+ }
+
+ if (!stricmp(driver, "RawLD4")) {
+ newmod = new RawLD4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ pos = 1;
+ }
+
+ if (!stricmp(driver, "zLD")) {
+ SWCompress *compress = 0;
+ int blockCount;
+ misc1 = ((entry = section.find("BlockCount")) != section.end()) ? (*entry).second : (SWBuf)"200";
+ blockCount = atoi(misc1.c_str());
+ blockCount = (blockCount) ? blockCount : 200;
+
+ misc1 = ((entry = section.find("CompressType")) != section.end()) ? (*entry).second : (SWBuf)"LZSS";
+#ifndef EXCLUDEZLIB
+ if (!stricmp(misc1.c_str(), "ZIP"))
+ compress = new ZipCompress();
+ else
+#endif
+ if (!stricmp(misc1.c_str(), "LZSS"))
+ compress = new LZSSCompress();
+
+ if (compress) {
+ newmod = new zLD(datapath.c_str(), name, description.c_str(), blockCount, compress, 0, enc, direction, markup, lang.c_str());
+ }
+ pos = 1;
+ }
+
+ if (!stricmp(driver, "RawGenBook")) {
+ misc1 = ((entry = section.find("KeyType")) != section.end()) ? (*entry).second : (SWBuf)"TreeKey";
+ newmod = new RawGenBook(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str(), misc1.c_str());
+ pos = 1;
+ }
+
+ if (pos == 1) {
+ SWBuf &dp = section["AbsoluteDataPath"];
+ for (int i = dp.length() - 1; i; i--) {
+ if (dp[i] == '/') {
+ dp.setSize(i);
+ break;
+ }
+ }
+/*
+ SWBuf &rdp = section["RelativeDataPath"];
+ for (int i = rdp.length() - 1; i; i--) {
+ if (rdp[i] == '/') {
+ rdp.setSize(i);
+ break;
+ }
+ }
+*/
+ }
+
+ // if a specific module type is set in the config, use this
+ if ((entry = section.find("Type")) != section.end())
+ newmod->Type(entry->second.c_str());
+
+ if (newmod){
+ newmod->setConfig(&section);
+ }
+
+ return newmod;
+}
+
+
+void SWMgr::AddGlobalOptions(SWModule *module, ConfigEntMap &section, ConfigEntMap::iterator start, ConfigEntMap::iterator end) {
+ for (;start != end; start++) {
+ OptionFilterMap::iterator it;
+ it = optionFilters.find((*start).second);
+ if (it != optionFilters.end()) {
+ module->AddOptionFilter((*it).second); // add filter to module and option as a valid option
+ StringList::iterator loop;
+ for (loop = options.begin(); loop != options.end(); loop++) {
+ if (!strcmp((*loop).c_str(), (*it).second->getOptionName()))
+ break;
+ }
+ if (loop == options.end()) // if we have not yet included the option
+ options.push_back((*it).second->getOptionName());
+ }
+ }
+ if (filterMgr)
+ filterMgr->AddGlobalOptions(module, section, start, end);
+#ifdef _ICU_
+ module->AddOptionFilter(transliterator);
+#endif
+}
+
+
+char SWMgr::filterText(const char *filterName, SWBuf &text, const SWKey *key, const SWModule *module)
+ {
+ char retVal = -1;
+ for (OptionFilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(filterName, (*it).second->getOptionName()))
+ retVal = it->second->processText(text, key, module); // add filter to module
+ }
+ }
+ return retVal;
+}
+
+
+void SWMgr::AddLocalOptions(SWModule *module, ConfigEntMap &section, ConfigEntMap::iterator start, ConfigEntMap::iterator end)
+{
+ for (;start != end; start++) {
+ OptionFilterMap::iterator it;
+ it = optionFilters.find((*start).second);
+ if (it != optionFilters.end()) {
+ module->AddOptionFilter((*it).second); // add filter to module
+ }
+ }
+
+ if (filterMgr)
+ filterMgr->AddLocalOptions(module, section, start, end);
+}
+
+
+// manually specified StripFilters for special cases, like Papyri marks and such
+void SWMgr::AddStripFilters(SWModule *module, ConfigEntMap &section, ConfigEntMap::iterator start, ConfigEntMap::iterator end)
+{
+ for (;start != end; start++) {
+ OptionFilterMap::iterator it;
+ it = optionFilters.find((*start).second);
+ if (it != optionFilters.end()) {
+ module->AddStripFilter((*it).second); // add filter to module
+ }
+ }
+}
+
+
+void SWMgr::AddRawFilters(SWModule *module, ConfigEntMap &section) {
+ SWBuf sourceformat, cipherKey;
+ ConfigEntMap::iterator entry;
+
+ cipherKey = ((entry = section.find("CipherKey")) != section.end()) ? (*entry).second : (SWBuf)"";
+ if (cipherKey.length()) {
+ SWFilter *cipherFilter = new CipherFilter(cipherKey.c_str());
+ cipherFilters.insert(FilterMap::value_type(module->Name(), cipherFilter));
+ cleanupFilters.push_back(cipherFilter);
+ module->AddRawFilter(cipherFilter);
+ }
+
+ if (filterMgr)
+ filterMgr->AddRawFilters(module, section);
+}
+
+
+void SWMgr::AddEncodingFilters(SWModule *module, ConfigEntMap &section) {
+ if (filterMgr)
+ filterMgr->AddEncodingFilters(module, section);
+}
+
+
+void SWMgr::AddRenderFilters(SWModule *module, ConfigEntMap &section) {
+ SWBuf sourceformat;
+ ConfigEntMap::iterator entry;
+
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (SWBuf)"";
+
+ // Temporary: To support old module types
+ // TODO: Remove at 1.6.0 release?
+ if (!sourceformat.length()) {
+ sourceformat = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (SWBuf)"";
+ if (!stricmp(sourceformat.c_str(), "RawGBF"))
+ sourceformat = "GBF";
+ else sourceformat = "";
+ }
+
+// process module - eg. follows
+// if (!stricmp(sourceformat.c_str(), "GBF")) {
+// module->AddRenderFilter(gbftortf);
+// }
+
+ if (filterMgr)
+ filterMgr->AddRenderFilters(module, section);
+
+}
+
+
+void SWMgr::AddStripFilters(SWModule *module, ConfigEntMap &section)
+{
+ SWBuf sourceformat;
+ ConfigEntMap::iterator entry;
+
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (SWBuf)"";
+ // Temporary: To support old module types
+ if (!sourceformat.length()) {
+ sourceformat = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (SWBuf)"";
+ if (!stricmp(sourceformat.c_str(), "RawGBF"))
+ sourceformat = "GBF";
+ else sourceformat = "";
+ }
+
+ if (!stricmp(sourceformat.c_str(), "GBF")) {
+ module->AddStripFilter(gbfplain);
+ }
+ else if (!stricmp(sourceformat.c_str(), "ThML")) {
+ module->AddStripFilter(thmlplain);
+ }
+ else if (!stricmp(sourceformat.c_str(), "OSIS")) {
+ module->AddStripFilter(osisplain);
+ }
+ else if (!stricmp(sourceformat.c_str(), "TEI")) {
+ module->AddStripFilter(teiplain);
+ }
+
+ if (filterMgr)
+ filterMgr->AddStripFilters(module, section);
+
+}
+
+
+void SWMgr::CreateMods(bool multiMod) {
+ SectionMap::iterator it;
+ ConfigEntMap::iterator start;
+ ConfigEntMap::iterator end;
+ ConfigEntMap::iterator entry;
+ SWModule *newmod;
+ SWBuf driver, misc1;
+ for (it = config->Sections.begin(); it != config->Sections.end(); it++) {
+ ConfigEntMap &section = (*it).second;
+ newmod = 0;
+
+ driver = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (SWBuf)"";
+ if (driver.length()) {
+ newmod = CreateMod((*it).first, driver, section);
+ if (newmod) {
+ // Filters to add for this module and globally announce as an option to the user
+ // e.g. translit, strongs, redletterwords, etc, so users can turn these on and off globally
+ start = (*it).second.lower_bound("GlobalOptionFilter");
+ end = (*it).second.upper_bound("GlobalOptionFilter");
+ AddGlobalOptions(newmod, section, start, end);
+
+ // Only add the option to the module, don't announce it's availability
+ // These are useful for like: filters that parse special entryAttribs in a text
+ // or whatever you might want to happen on entry lookup
+ start = (*it).second.lower_bound("LocalOptionFilter");
+ end = (*it).second.upper_bound("LocalOptionFilter");
+ AddLocalOptions(newmod, section, start, end);
+
+ //STRIP FILTERS
+
+ // add all basic ones for for the modtype
+ AddStripFilters(newmod, section);
+
+ // Any special processing for this module when searching:
+ // e.g. for papyri, removed all [](). notation
+ start = (*it).second.lower_bound("LocalStripFilter");
+ end = (*it).second.upper_bound("LocalStripFilter");
+ AddStripFilters(newmod, section, start, end);
+
+ AddRawFilters(newmod, section);
+ AddRenderFilters(newmod, section);
+ AddEncodingFilters(newmod, section);
+
+ SWModule *oldmod = Modules[newmod->Name()];
+ if (oldmod) {
+ delete oldmod;
+ }
+
+ Modules[newmod->Name()] = newmod;
+ }
+ }
+ }
+}
+
+
+void SWMgr::DeleteMods() {
+
+ ModMap::iterator it;
+
+ for (it = Modules.begin(); it != Modules.end(); it++)
+ delete (*it).second;
+
+ Modules.clear();
+}
+
+
+void SWMgr::deleteModule(const char *modName) {
+ ModMap::iterator it = Modules.find(modName);
+ if (it != Modules.end()) {
+ delete (*it).second;
+ Modules.erase(it);
+ }
+}
+
+
+void SWMgr::InstallScan(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *ent;
+ FileDesc *conffd = 0;
+ SWBuf newmodfile;
+ SWBuf targetName;
+
+ if (FileMgr::existsDir(dirname)) {
+ if ((dir = opendir(dirname))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ newmodfile = dirname;
+ if ((dirname[strlen(dirname)-1] != '\\') && (dirname[strlen(dirname)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+
+ // mods.d
+ if (configType) {
+ if (conffd)
+ FileMgr::getSystemFileMgr()->close(conffd);
+ targetName = configPath;
+ if ((configPath[strlen(configPath)-1] != '\\') && (configPath[strlen(configPath)-1] != '/'))
+ targetName += "/";
+ targetName += ent->d_name;
+ conffd = FileMgr::getSystemFileMgr()->open(targetName.c_str(), FileMgr::WRONLY|FileMgr::CREAT, FileMgr::IREAD|FileMgr::IWRITE);
+ }
+
+ // mods.conf
+ else {
+ if (!conffd) {
+ conffd = FileMgr::getSystemFileMgr()->open(config->filename.c_str(), FileMgr::WRONLY|FileMgr::APPEND);
+ if (conffd > 0)
+ conffd->seek(0L, SEEK_END);
+ else {
+ FileMgr::getSystemFileMgr()->close(conffd);
+ conffd = 0;
+ }
+ }
+ }
+ AddModToConfig(conffd, newmodfile.c_str());
+ FileMgr::removeFile(newmodfile.c_str());
+ }
+ }
+ if (conffd)
+ FileMgr::getSystemFileMgr()->close(conffd);
+ closedir(dir);
+ }
+ }
+}
+
+
+char SWMgr::AddModToConfig(FileDesc *conffd, const char *fname)
+{
+ FileDesc *modfd;
+ char ch;
+
+ SWLog::getSystemLog()->logTimedInformation("Found new module [%s]. Installing...", fname);
+ modfd = FileMgr::getSystemFileMgr()->open(fname, FileMgr::RDONLY);
+ ch = '\n';
+ conffd->write(&ch, 1);
+ while (modfd->read(&ch, 1) == 1)
+ conffd->write(&ch, 1);
+ ch = '\n';
+ conffd->write(&ch, 1);
+ FileMgr::getSystemFileMgr()->close(modfd);
+ return 0;
+}
+
+
+void SWMgr::setGlobalOption(const char *option, const char *value)
+{
+ for (OptionFilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName()))
+ (*it).second->setOptionValue(value);
+ }
+ }
+}
+
+
+const char *SWMgr::getGlobalOption(const char *option)
+{
+ for (OptionFilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName()))
+ return (*it).second->getOptionValue();
+ }
+ }
+ return 0;
+}
+
+
+const char *SWMgr::getGlobalOptionTip(const char *option)
+{
+ for (OptionFilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName()))
+ return (*it).second->getOptionTip();
+ }
+ }
+ return 0;
+}
+
+
+StringList SWMgr::getGlobalOptions()
+{
+ return options;
+}
+
+
+StringList SWMgr::getGlobalOptionValues(const char *option)
+{
+ StringList options;
+ for (OptionFilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName())) {
+ options = (*it).second->getOptionValues();
+ break; // just find the first one. All option filters with the same option name should expect the same values
+ }
+ }
+ }
+ return options;
+}
+
+
+signed char SWMgr::setCipherKey(const char *modName, const char *key) {
+ FilterMap::iterator it;
+ ModMap::iterator it2;
+
+ // check for filter that already exists
+ it = cipherFilters.find(modName);
+ if (it != cipherFilters.end()) {
+ ((CipherFilter *)(*it).second)->getCipher()->setCipherKey(key);
+ return 0;
+ }
+ // check if module exists
+ else {
+ it2 = Modules.find(modName);
+ if (it2 != Modules.end()) {
+ SWFilter *cipherFilter = new CipherFilter(key);
+ cipherFilters.insert(FilterMap::value_type(modName, cipherFilter));
+ cleanupFilters.push_back(cipherFilter);
+ (*it2).second->AddRawFilter(cipherFilter);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+SWORD_NAMESPACE_END
diff --git a/src/mgr/swsearchable.cpp b/src/mgr/swsearchable.cpp
new file mode 100644
index 0000000..48ae556
--- /dev/null
+++ b/src/mgr/swsearchable.cpp
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * swsearchable.h - definition of class SWSearchable used to provide an
+ * interface for objects that be searched.
+ *
+ * $Id: swsearchable.cpp 1959 2006-08-28 00:39:56Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <swsearchable.h>
+#include <listkey.h>
+
+SWORD_NAMESPACE_START
+
+void SWSearchable::nullPercent(char percent, void *percentUserData) {}
+
+SWSearchable::SWSearchable() {
+}
+
+
+SWSearchable::~SWSearchable() {
+}
+
+ // special search framework
+signed char SWSearchable::createSearchFramework(void (*percent)(char, void *), void *percentUserData) {
+ return 0;
+}
+
+
+void SWSearchable::deleteSearchFramework() {
+}
+
+
+bool SWSearchable::isSearchOptimallySupported(const char *istr, int searchType, int flags, SWKey *scope) {
+ bool retVal = false;
+ search(istr, searchType, flags, scope, &retVal);
+ return retVal;
+}
+
+SWORD_NAMESPACE_END