tqsl-2.8.2/0000755000175000017500000000000015061653744012517 5ustar rmurphyrmurphytqsl-2.8.2/README0000644000175000017500000003446515061653744013413 0ustar rmurphyrmurphyThis is the TrustedQSL project, which provides tools for digitally signing Amateur Radio QSO records. src: Source code and documentation for tqsllib, the TrustedQSL library. apps: Source code for "tqsl" and other sample applications. html: Various legacy documents This document describes the changes to TrustedQSL since version 1.13 and explains how applications can use TQSL in their applications. Command Line Changes -------------------- Many applications use the 'tqsl' application in command line mode to sign log files. There were several new capabilities added to command line operation in 1.14. The first is that tqsl can now automatically sign and upload a log to the LoTW site for the user. This allows your application to simply write an adif file which is then processed and uploaded to LoTW without requiring the application to read the output file and either upload it or tell your user to upload it. The command line parser in 1.14 was rewritten and is less forgiving of improperly formatted command lines. Command Line Options -------------------- The following summarizes the command line options and what they do: Usage: tqsl [-a ] [-b ] [-e ] [-d] [-l ] [-s] [-f ] [-o ] [-u] [-x] [-p ] [-q] [-n] [-v] [-h] [-t ] [-c ] [Input ADIF or Cabrillo log file to sign] The following command line options may be specified on the command line: -a Specify dialog action - abort, all, compliant or ask This option instructs TQSL on how to handle QSOs that do not appear to be valid. There are many potential causes for invalid QSOs. Examples include QSOs with dates outside the valid range for the certificate being used, QSOs with invalid amateur callsigns, previously uploaded QSOs, and attempts to sign with an expired callsign certificate. This option specifies how tqsl should handle these exceptions. Using "-a ask" instructs tqsl to use a dialog to ask the user how to proceed. This is the default behavior if "-a" is not provided on the command line. Using "-a abort" instructs tqsl to issue an error message when an exception QSO is processed and immediately abort signing. Using "-a compliant" instructs tqsl to sign the QSOs which are compliant (not previously uploaded, in date range, and with valid callsigns) and ignore any exception QSOs. This is the recommended behavior for command line applications but is not the default action for compatibility reasons. Using "-a all" instructs tqsl to process all QSOs, ignoring previously uploaded QSOs and invalid callsigns. QSOs outside the range of valid dates for the selected station certificate will not be signed, as they would not be accepted by Logbook. -b Set begin date for the QSO date filter. -e Set end date for the QSL date filter. These options filter QSOs being signed to those after the begin date and before the end date. If neither of these are supplied, then no filtering will be performed. These values will override any date range entries provided by the user. This implies that "-d" (suppress date range dialog) should be used with -b or -e. -d Suppress date range dialog This option instructs tqsl to not ask the user to select a range of dates for processing QSOs. If this is used, all QSOs in the input file will be selected for processing. Command line tools will usually include this option to suppress tqsl dialogs. However, this means that the logging program is responsible for filtering QSOs before delivering them to tqsl. -f Select handling option for QTH details This option instructs tqsl on how to handle the MY_ fields in an ADIF log file. These specify the callsign, QTH details such as zones, gridsquare, state/county, etc. for a QSO. If the log includes this detail, TQSL can read these fields and take action to use that information to ensure that the Station Location is correct. By default, TQSL will report any discrepancies between QTH and the Station Location; TQSL can also be directed to ignore the QTH information. -f ignore Directs TQSL to ignore the QTH information -f report Directs TQSL to report any differences between the station location and the MY_ QTH deails -f update Directs TQSL to overwrite the Station Location information with data from the log. When using "-f update", the ideal practice should be to either specify all QTH information (state, county, grid, zones) in the ADIF "MY_" fields, or use an minimal Station Location with no QTH data. If no station location is provided on the command line, (the "-l" option specifies the station location name), an empty station location is used which has no callsign or QTH data. -i Import a TQSL file. This can be a public key (tq6) file, a key container (p12), or a backup (tbk) file. -l Select Station Location. This option selects a station location. This is used for signing logs or in conjunction with the "-s" option to define a location for editing. If an empty Station Location name is chosen (-l "") then TQSL enables the QTH handing specified with "-f update". -s Edit (if used with -l) or create Station Location This option can be used to create a new Station Location (-s without -l) or to edit an existing Station Location (when both -s and -l are provided). -o Output file name (defaults to input name minus extension plus .tq8) This option instructs tqsl where the signed output file will be stored. If it is not provided, the output file will be written to the same location as the input file with the extension changed to ".tq8" -u Upload after signing instead of saving This option instructs tqsl to upload the log file after it is successfully signed. -q Operate in batch mode, not menu-driven mode. -x Operate in batch mode, not menu-driven mode. If -x or -q are included on the command line, tqsl suppresses user dialogs and sends error messages to standard error. A logging application is expected to read this file and possibly display the contents to the user so they can see the results of the command action. If these options are not included, a calling application cannot distinguish between a successful signing and one where a user cancels the signing. -n Look for updated (new) versions of key files. If -n is given on the command line, tqsl checks for new versions of the tqsl program, an updated tqsl configuration file, and verifies that any user certificates are not about to expire. If any of these circumstances exist, the user is prompted to perform the required updates. When the check is completed, tqsl exits. This command line option can not be combined with any other command line options as it only performs an update check and does not sign any logs submitted with the command. -p Password for the signing key This option allows an application to provide the password for the private key that will be used to sign the log file. -v Display the version information and exit -h Display command line help These options allow the user to display the version number of tqsl or to obtain help on the command line usage. -t Open a diagnostic trace file at startup When supplied, this option enables diagnostic tracing at startup, opening the supplied file to record TQSL operations details. This is useful for debugging purposes. -c Use the given callsign when signing a log This option allows a logging program to specify what callsign to use for a log signing operation. This will override the callsign associated with the selected station location, if any. Command Line Usage ------------------ An application that uses the command line invokes the tqsl binary, optionally providing a set of options that dictate how tqsl operates. Normally, such an application should include the "-x" or "-q" options to indicate to tqsl that application popups should be suppressed. Errors discovered during the signing process are sent to the standard error file. Callers would normally indicate where those messages should be sent by adding "2> file.txt" to the command line used to run tqsl. This directs the shell (Windows or Unix) to write the error messages to that file. When operated in "batch" mode (i.e. -x or -q used), tqsl provides information that the calling program can use to determine if the signing operation succeeded. The first way is by capturing tqsl's exit status code. This provides information on success or failure using the following values: 0 - Success: all QSOs submitted were signed and saved or uploaded 1 - Cancelled by user 2 - The log was rejected by the LoTW server 3 - The response from the LoTW server was unexpected 4 - An error occurred in tqsl 5 - An error occurred in tqsllib (invalid filename, bad file format) 6 - Unable to open input file 7 - Unable to open output file 8 - No QSOs were processed because some QSOs were already uploaded or out of date range (no QSOs written) 9 - Some QSOs were processed, and some QSOs were ignored because they were already uploaded or out of date range (some QSOs were uploaded) 10 - Command syntax error 11 - LoTW network connection failed (no network or LoTW is unreachable) 12 - Unknown error 13 - The TQSL upload tracking database is locked. 14 - Already uploaded QSOs were detected 15 - An incorrect passprhase was used while loading a P12 file from the command line This exit status is also written to stderr in a format that can be parsed by the calling application. The last output from tqsl will be of the format hh:mm:ss AM|PM Final Status: Description (code) (For cases where the language is not English, this will be duplicated - first in the local language, then in English.) The first two fields are a timestamp, the words "Final Status:" always appears. Following that is a short descriptive message giving the exit status. The last thing on the line is the numeric exit code (as above) in parenthesis. Examples of output follows: 05:57:39 PM: Warning: Signing cancelled 05:57:39 PM: No records output 05:57:39 PM: Final Status: cancelled by user (1) 06:05:56 PM: /home/rmurphy/k1mu.adi: 414 QSO records were previously uploaded 06:05:56 PM: /home/rmurphy/k1mu.adi: wrote 1 records to /home/rmurphy/k1mu.tq8 06:05:56 PM: /home/rmurphy/k1mu.tq8 is ready to be emailed or uploaded. Note: TQSL assumes that this file will be uploaded to LoTW. Resubmitting these QSOs will cause them to be reported as duplicates. 06:05:56 PM: Final Status: Some QSOs were previously uploaded or out of date range (9) An example usage for signing a log would be tqsl -q -l "K1MU home" -p "Insecure" -a compliant -u -d k1mu.adi 2>temp.txt This indicates quiet mode (-q), selects a station location and a password, indicates that only compliant QSOs will be written (-a), uploads to LoTW (-u), suppresses date popups (-d), provides an input file (k1mu.adi), and finally writes log messages to temp.txt. The logging program would read and process that log once tqsl is done. An application would add "-o" to indicate where tqsl should write the signed log if "-u" (upload) is not provided. Command line applications are strongly encouraged to add "-a=compliant" to their invocations of tqsl, and to consider storing and displaying the log messages to their users. Application Changes ------------------- Some logging applications directly call tqsllib functions to sign log files. The application programming interface (API) to tqsllib has not changed in ways that introduce incompatibilities, but there are additional API calls which are necessary for applications to allow QSO upload tracking to work properly. Normally, an application will call tqsl_beginCabrilloConverter() or tqsl_beginADIFConverter to begin signing a log file. After the converter is created by those calls, the application should then call tqsl_setConverterAllowDuplicates(conv, false) which tells tqsllib that upload tracking should be enabled. If you do not call tqsl_setConverterAllowDuplicates, the library will assume that previously uploaded QSOs should be permitted (for compatibility reasons), which may cause unnecessary QSOs to be uploaded. If upload tracking is enabled, there is a new error return from tqsl_getConverterGABBI that indicates previosuly uploaded QSOs. In this case, tQSL_Error is set to TQSL_DUPLICATE_QSO. Software may need to be modified to handle this new result and act appropriately (ignore it, or abort the signing operation.) After successful processing of a log, an application should call either tqsl_convertCommit(conv) or tqsl_convertRollBack(conv) prior to calling tqsl_endConverter() to signal that a log conversion has completed. tqsl_converterCommit() indicates to tqsllib that the log has been successfully processed and that the QSOs should be added to the upload tracking database. Calling tqsl_converterRollBack() indicates to tqsllib that the log has not been successfully processed and that the QSO records should not be added to the upload tracking database. Simply adding the necessary call before the converter is closed is enough to bring the application up to date. change tqsl_endConverter(&conv) to tqsl_converterCommit(conv); tqsl_endConverter(&conv); Using tqsllib ------------- A minimal set of calls to permit an application to sign a log is the following. Of course, error checking should be performed for each call. tqsl_getStationLocation(&loc, location_name); tqsl_getLocationCallSign(loc, callsign, sizeof callsign); tqsl_getLocationDXCCEntity(loc, &dxcc); tqsl_selectCertificates(&certlist, &ncerts, callsign, dxcc); tqsl_beginADIFConverter(&conv, input_file, certlist, ncerts, loc); tqsl_setConverterAllowDuplicates(conv, false); tqsl_setConverterAppName(conv, "myAppName"); (tell tqsllib the name of your application) while (cp = tqsl_getConverterGABBI(conv) != 0) write the string pointed to by "cp" to your file tqsl_converterCommit(conv); tqsl_endConverter(&conv); tqsl_endStationLocationCapture(&loc); The tq8 files created by tqsl are compressed using zlib functions. You can also submit uncompressed files using a .tq7 extension. tqsl-2.8.2/win32-msi/0000755000175000017500000000000015061653721014242 5ustar rmurphyrmurphytqsl-2.8.2/win32-msi/tqsl-install/0000755000175000017500000000000015061653721016671 5ustar rmurphyrmurphytqsl-2.8.2/win32-msi/tqsl-install/update-helpfrag.cmd0000644000175000017500000000024415061653721022426 0ustar rmurphyrmurphy"C:\Program Files (x86)\WiX Toolset v3.11\bin\heat.exe" dir ..\..\apps\help -cg "HelpDir" -dr "APPLICATIONFOLDER" -indent 2 -out helpfrag.wxs -var "var.helpSrc" -agtqsl-2.8.2/win32-msi/tqsl-install/tqsl-install.wixproj0000644000175000017500000000503115061653721022743 0ustar rmurphyrmurphy Debug x86 3.7 1dfa6e6b-1725-4fa3-81d7-64d8a82cb824 2.0 tqsl-2.8 Package $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets bin\$(Configuration)\ obj\$(Configuration)\ Debug -b "..\..\bin\Release" -b "..\..\apps" -b "..\..\src" -b "..\..\src\Release" -b "..\..\apps\Release" bin\$(Configuration)\ obj\$(Configuration)\ -b "..\..\bin\Release" -b "..\..\apps" -b "..\..\src" -b "..\..\src\Release" -b "..\..\..\apps\Release" $(WixExtDir)\WixUIExtension.dll WixUIExtension tqsl-2.8.2/win32-msi/tqsl-install/tqsl-install.sln0000644000175000017500000000151615061653721022041 0ustar rmurphyrmurphy Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "tqsl-install", "tqsl-install.wixproj", "{1DFA6E6B-1725-4FA3-81D7-64D8A82CB824}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1DFA6E6B-1725-4FA3-81D7-64D8A82CB824}.Debug|x86.ActiveCfg = Debug|x86 {1DFA6E6B-1725-4FA3-81D7-64D8A82CB824}.Debug|x86.Build.0 = Debug|x86 {1DFA6E6B-1725-4FA3-81D7-64D8A82CB824}.Release|x86.ActiveCfg = Release|x86 {1DFA6E6B-1725-4FA3-81D7-64D8A82CB824}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal tqsl-2.8.2/win32-msi/tqsl-install/langfrags.wxs0000644000175000017500000002402615061653721021404 0ustar rmurphyrmurphy tqsl-2.8.2/win32-msi/tqsl-install/helpfrag.wxs0000644000175000017500000007606515061653721021242 0ustar rmurphyrmurphy tqsl-2.8.2/win32-msi/tqsl-install/Product.wxs0000644000175000017500000002244215061653721021060 0ustar rmurphyrmurphy NOT Version9X INSTALLDESKTOPSHORTCUT ISINNOINSTALLED NEWERFOUND notepad.exe CLONEXIT AND NOT Installed QSONEXIT AND NOT Installed tqsl-2.8.2/win32-msi/tqsl-install/MyWixUI_InstallDir.wxs0000644000175000017500000001110715061653721023074 0ustar rmurphyrmurphy 1 "1"]]> 1 NOT Installed Installed AND PATCH 1 LicenseAccepted = "1" 1 1 NOT WIXUI_DONTVALIDATEPATH "1"]]> (ISINNOINSTALLED) AND (WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1") (NOT ISINNOINSTALLED) AND (WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1") 1 1 NOT Installed Installed AND NOT PATCH Installed AND PATCH 1 1 1 1 tqsl-2.8.2/win32-msi/tqsl-install/MyInstallDirDlg.wxs0000644000175000017500000000501415061653721022436 0ustar rmurphyrmurphy 1 tqsl-2.8.2/win32-msi/tqsl-install/MyExitDialog.wxs0000644000175000017500000000730715061653721022002 0ustar rmurphyrmurphy tqsl-2.8.2/win32-msi/tqsl-install/AlertUninstall.wxs0000644000175000017500000000210215061653721022370 0ustar rmurphyrmurphy 1 1 1 tqsl-2.8.2/win32-msi/tqsl-install/.gitignore0000644000175000017500000000001215061653721020652 0ustar rmurphyrmurphybin/ obj/ tqsl-2.8.2/toolset-to-vc08.py0000644000175000017500000000120215061653721015746 0ustar rmurphyrmurphyVCXPROJ=".vcxproj" v2012_PLATFORM_TOOLSET="v110" v2008_PLATFORM_TOOLSET="v90" from os import walk, path if __name__=="__main__": count=0 for root, dirs, files in walk("."): for file in files: if file.endswith(VCXPROJ): print "Replacing in", path.join(root, file), "...", with open(path.join(root, file), 'r') as proj: s=proj.read() s=s.replace(v2012_PLATFORM_TOOLSET, v2008_PLATFORM_TOOLSET) with open(path.join(root, file), 'w') as proj: proj.write(s) print "done" count+=1 print "Replaced toolset in", count, "project files"tqsl-2.8.2/src/0000755000175000017500000000000015061653721013301 5ustar rmurphyrmurphytqsl-2.8.2/src/xml.h0000644000175000017500000001475315061653721014264 0ustar rmurphyrmurphy/*************************************************************************** xml.h - description ------------------- begin : Fri Aug 9 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef __xml_h #define __xml_h #include #include #include #include #include using std::pair; using std::string; using std::ostream; using std::map; using std::multimap; using std::vector; namespace tqsllib { class XMLElement; typedef multimap XMLElementList; typedef map XMLElementAttributeList; /** Encapsulates an XML element * * An XMLElement comprises a name, the enclosed text, an optional set of * attributes, and an optional list of contained elements. * * Having a list of contained elements allows construction of the XML * document tree structure. In most cases, the structure will be populated * by a call to parseFile(). */ class XMLElement { public: XMLElement() : _name(""), _text(""), _pretext("") {} /// Constructor initializes element name explicit XMLElement(const string& name) : _text(""), _pretext("") { _name = name; } /// Clear the element of all data void clear(); /// Set the element name void setElementName(const string& name) { _name = name; } /// Get the element name string getElementName() const { return _name; } /// Set an attribute. /** Attributes are treated as unique key/value pairs. */ void setAttribute(const string& key, const string& value); void setAttribute(const char* key, const char* value); void setAttribute(const char* key, const string& value); /// Get an attribute by its key. /** Returns a pair where: * * \li \c getAttribute().first := the attribute's value * \li \c getAttribute().second := a bool, true if the attribute key exists */ pair getAttribute(const string& key); /// Add an element to the list of contained subelements XMLElementList::iterator addElement(XMLElement* element); XMLElementAttributeList& getAttributeList() { return _attributes; } XMLElementList& getElementList() { return _elements; } /// Parse an XML file and add its element tree to this element int parseFile(const char *filename); #define XML_PARSE_NO_ERROR 0 #define XML_PARSE_SYSTEM_ERROR 1 #define XML_PARSE_SYNTAX_ERROR 2 /// Parse an XML string and add its element tree to this element int parseString(const char *xmlstring); /// Get the first attribute of the element /** Provides the attribute key and value. Returns \c false if the * element contains no attributes */ bool getFirstAttribute(string& key, string& attr); /// Get the next attribute of the element /** Should be called only after calling getFirstAttribute and getting * a return value of \c true. * Provides the attribute key and value. Returns \c false if the * element contains no more attributes */ bool getNextAttribute(string& key, string& attr); /// Get the first contained element named \c name. /** Returns \c false if the element contains no elements named \c name */ bool getFirstElement(const string& name, XMLElement&); /// Get the first contained element. /** Returns \c false if the element contains no elements */ bool getFirstElement(XMLElement&); /// Get the next contained element. /** Should be called only after calling getFirstElement and getting * a return value of \c true. If the getFirstElement that takes an * element name was called, getNextElement will return \c false when there * are no more elements of that name in the element list. * * Returns \c false if the element contains no more elements */ bool getNextElement(XMLElement&); /// Set the contained text string void setText(const string& s) { _text = s; } /// Get the contained text string. /** Note that this string comprises the text contained in this * element only, not any text contained in elements on the * element list; they each have their own contained text. */ string getText() const { return _text; } void setPretext(const string& s) { _pretext = s; } string getPretext() const { return _pretext; } private: static void xml_start(void *data, const XML_Char *name, const XML_Char **atts); static void xml_end(void *data, const XML_Char *name); static void xml_text(void *data, const XML_Char *text, int len); string _name, _text, _pretext; XMLElementAttributeList _attributes; XMLElementList _elements; vector _parsingStack; XMLElementList::iterator _iter; bool _iterByName; string _iterName; XMLElementAttributeList::iterator _aiter; }; inline void XMLElement::clear() { _name = _text = _pretext = _iterName = ""; _attributes.clear(); _elements.clear(); _parsingStack.clear(); } inline void XMLElement::setAttribute(const string& key, const string& value) { _attributes[key] = value; } inline void XMLElement::setAttribute(const char* key, const char* value) { string k = key; string v = value; _attributes[k] = v; } inline void XMLElement::setAttribute(const char* key, const string& value) { string k = key; _attributes[k] = value; } inline XMLElementList::iterator XMLElement::addElement(XMLElement* element) { XMLElementList::iterator it = _elements.insert(make_pair(element->getElementName(), element)); return it; } inline bool XMLElement::getFirstElement(XMLElement& element) { _iterByName = false; _iter = _elements.begin(); return getNextElement(element); } inline bool XMLElement::getFirstElement(const string& name, XMLElement& element) { _iterName = name; _iterByName = true; _iter = _elements.find(_iterName); return getNextElement(element); } inline bool XMLElement::getNextElement(XMLElement& element) { if (_iter == _elements.end()) return false; if (_iterByName && _iter->second->getElementName() != _iterName) return false; element = *_iter->second; ++_iter; return true; } inline bool XMLElement::getFirstAttribute(string& key, string& attr) { _aiter = _attributes.begin(); return getNextAttribute(key, attr); } inline bool XMLElement::getNextAttribute(string& key, string& attr) { if (_aiter == _attributes.end()) return false; key = _aiter->first; attr = _aiter->second; ++_aiter; return true; } ostream& operator<< (ostream& stream, XMLElement& el); } // namespace tqsllib #endif // __xml_h tqsl-2.8.2/src/xml.cpp0000644000175000017500000001225615061653721014613 0ustar rmurphyrmurphy/*************************************************************************** xml.cpp - description ------------------- begin : Fri Aug 9 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #define TQSLLIB_DEF #include "xml.h" #include "tqsllib.h" #ifdef _WIN32 #include #endif #include #include #include #include #include #include using std::pair; using std::string; using std::ostream; using std::map; namespace tqsllib { pair XMLElement::getAttribute(const string& key) { string s; XMLElementAttributeList::iterator pos; pos = _attributes.find(key); pair rval; if (pos == _attributes.end()) { rval.second = false; } else { rval.first = pos->second; rval.second = true; } return rval; } void XMLElement::xml_start(void *data, const XML_Char *name, const XML_Char **atts) { XMLElement *el = reinterpret_cast(data); XMLElement *new_el = new XMLElement(name); if (!new_el) { tqslTrace("XMLElement::xml_start", "Out of memory!"); return; } //cout << "Element: " << name << endl; for (int i = 0; atts[i]; i += 2) { new_el->setAttribute(atts[i], atts[i+1]); } if (el->_parsingStack.empty()) { el->_parsingStack.push_back(el->addElement(new_el)); } else { new_el->setPretext(el->_parsingStack.back()->second->getText()); el->_parsingStack.back()->second->setText(""); el->_parsingStack.push_back(el->_parsingStack.back()->second->addElement(new_el)); } } void XMLElement::xml_end(void *data, const XML_Char *name) { XMLElement *el = reinterpret_cast(data); if (!(el->_parsingStack.empty())) el->_parsingStack.pop_back(); } void XMLElement::xml_text(void *data, const XML_Char *text, int len) { XMLElement *el = reinterpret_cast(data); el->_parsingStack.back()->second->_text.append(text, len); } int XMLElement::parseString(const char *xmlstring) { XML_Parser xp = XML_ParserCreate(0); XML_SetUserData(xp, reinterpret_cast(this)); XML_SetStartElementHandler(xp, &XMLElement::xml_start); XML_SetEndElementHandler(xp, &XMLElement::xml_end); XML_SetCharacterDataHandler(xp, &XMLElement::xml_text); _parsingStack.clear(); // Process the XML if (XML_Parse(xp, xmlstring, strlen(xmlstring), 1) == 0) { XML_ParserFree(xp); strncpy(tQSL_CustomError, xmlstring, 80); tQSL_CustomError[79] = '\0'; return XML_PARSE_SYNTAX_ERROR; } XML_ParserFree(xp); return XML_PARSE_NO_ERROR; } int XMLElement::parseFile(const char *filename) { gzFile in = NULL; #ifdef _WIN32 wchar_t* fn = utf8_to_wchar(filename); int fd = _wopen(fn, _O_RDONLY|_O_BINARY); free_wchar(fn); if (fd != -1) in = gzdopen(fd, "rb"); #else in = gzopen(filename, "rb"); #endif if (!in) return XML_PARSE_SYSTEM_ERROR; // Failed to open file char buf[256]; XML_Parser xp = XML_ParserCreate(0); XML_SetUserData(xp, reinterpret_cast(this)); XML_SetStartElementHandler(xp, &XMLElement::xml_start); XML_SetEndElementHandler(xp, &XMLElement::xml_end); XML_SetCharacterDataHandler(xp, &XMLElement::xml_text); _parsingStack.clear(); int rcount; while ((rcount = gzread(in, buf, sizeof buf)) > 0) { // Process the XML if (XML_Parse(xp, buf, rcount, 0) == 0) { gzclose(in); strncpy(tQSL_CustomError, buf, 80); tQSL_CustomError[79] = '\0'; XML_ParserFree(xp); return XML_PARSE_SYNTAX_ERROR; } } gzclose(in); bool rval = (rcount == 0); if (rval) rval = (XML_Parse(xp, "", 0, 1) != 0); XML_ParserFree(xp); return (rval ? XML_PARSE_NO_ERROR : XML_PARSE_SYNTAX_ERROR); } static struct { char c; const char *ent; } xml_entity_table[] = { { '"', """ }, { '\'', "'" }, { '>', ">" }, { '<', "<" } }; static string xml_entities(const string& s) { string ns = s; string::size_type idx = 0; while ((idx = ns.find('&', idx)) != string::npos) { ns.replace(idx, 1, "&"); idx++; } for (int i = 0; i < static_cast((sizeof xml_entity_table / sizeof xml_entity_table[0])); i++) { while ((idx = ns.find(xml_entity_table[i].c)) != string::npos) ns.replace(idx, 1, xml_entity_table[i].ent); } return ns; } /* Stream out an XMLElement as XML text */ ostream& operator<< (ostream& stream, XMLElement& el) { bool ok; XMLElement subel; if (el.getElementName() != "") { stream << "<" << el.getElementName(); string key, val; bool ok = el.getFirstAttribute(key, val); while (ok) { stream << " " << key << "=\"" << xml_entities(val) << "\""; ok = el.getNextAttribute(key, val); } if (el.getText() == "" && !el.getFirstElement(subel)) { stream << " />"; return stream; } else { stream << ">"; } } ok = el.getFirstElement(subel); while (ok) { string s = subel.getPretext(); if (s != "") stream << xml_entities(s); stream << subel; ok = el.getNextElement(subel); } if (el.getText() != "") stream << xml_entities(el.getText()); if (el.getElementName() != "") stream << ""; return stream; } } // namespace tqsllib tqsl-2.8.2/src/winstrdefs.h0000644000175000017500000000054715061653721015650 0ustar rmurphyrmurphy/* Copyright (C) 2025 The TrustedQSL Developers */ #ifndef WINSTRDEFS_H #define WINSTRDEFS_H #if defined(_WIN32) || defined(_WIN64) #define snprintf _snprintf #define vsnprintf _vsnprintf #define strcasecmp _stricmp #define strncasecmp _strnicmp #define unlink _unlink #define strdup _strdup #define fileno _fileno #endif #endif//WINSTRDEFS_H tqsl-2.8.2/src/windirent.h0000644000175000017500000006075415061653721015471 0ustar rmurphyrmurphy/* * dirent.h - dirent API for Microsoft Visual Studio * * Copyright (C) 2006-2012 Toni Ronkko * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * ``Software''), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * * Version 1.13, Dec 12 2012, Toni Ronkko * Use traditional 8+3 file name if the name cannot be represented in the * default ANSI code page. Now compiles again with MSVC 6.0. Thanks to * Konstantin Khomoutov for testing. * * Version 1.12.1, Oct 1 2012, Toni Ronkko * Bug fix: renamed wide-character DIR structure _wDIR to _WDIR (with * capital W) in order to maintain compatibility with MingW. * * Version 1.12, Sep 30 2012, Toni Ronkko * Define PATH_MAX and NAME_MAX. Added wide-character variants _wDIR, * _wdirent, _wopendir(), _wreaddir(), _wclosedir() and _wrewinddir(). * Thanks to Edgar Buerkle and Jan Nijtmans for ideas and code. * * Do not include windows.h. This allows dirent.h to be integrated more * easily into programs using winsock. Thanks to Fernando Azaldegui. * * Version 1.11, Mar 15, 2011, Toni Ronkko * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0. * * Version 1.10, Aug 11, 2010, Toni Ronkko * Added d_type and d_namlen fields to dirent structure. The former is * especially useful for determining whether directory entry represents a * file or a directory. For more information, see * http://www.delorie.com/gnu/docs/glibc/libc_270.html * * Improved conformance to the standards. For example, errno is now set * properly on failure and assert() is never used. Thanks to Peter Brockam * for suggestions. * * Fixed a bug in rewinddir(): when using relative directory names, change * of working directory no longer causes rewinddir() to fail. * * Version 1.9, Dec 15, 2009, John Cunningham * Added rewinddir member function * * Version 1.8, Jan 18, 2008, Toni Ronkko * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string * between multi-byte and unicode representations. This makes the * code simpler and also allows the code to be compiled under MingW. Thanks * to Azriel Fasten for the suggestion. * * Mar 4, 2007, Toni Ronkko * Bug fix: due to the strncpy_s() function this file only compiled in * Visual Studio 2005. Using the new string functions only when the * compiler version allows. * * Nov 2, 2006, Toni Ronkko * Major update: removed support for Watcom C, MS-DOS and Turbo C to * simplify the file, updated the code to compile cleanly on Visual * Studio 2005 with both unicode and multi-byte character strings, * removed rewinddir() as it had a bug. * * Aug 20, 2006, Toni Ronkko * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified * comments by removing SGML tags. * * May 14 2002, Toni Ronkko * Embedded the function definitions directly to the header so that no * source modules need to be included in the Visual Studio project. Removed * all the dependencies to other projects so that this header file can be * used independently. * * May 28 1998, Toni Ronkko * First version. *****************************************************************************/ #ifndef DIRENT_H #define DIRENT_H #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) # define _X86_ #endif #include #include #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include /* Indicates that d_type field is available in dirent structure */ #define _DIRENT_HAVE_D_TYPE /* Indicates that d_namlen field is available in dirent structure */ #define _DIRENT_HAVE_D_NAMLEN /* Entries missing from MSVC 6.0 */ #if !defined(FILE_ATTRIBUTE_DEVICE) # define FILE_ATTRIBUTE_DEVICE 0x40 #endif /* File type and permission flags for stat() */ #if !defined(S_IFMT) # define S_IFMT _S_IFMT /* File type mask */ #endif #if !defined(S_IFDIR) # define S_IFDIR _S_IFDIR /* Directory */ #endif #if !defined(S_IFCHR) # define S_IFCHR _S_IFCHR /* Character device */ #endif #if !defined(S_IFFIFO) # define S_IFFIFO _S_IFFIFO /* Pipe */ #endif #if !defined(S_IFREG) # define S_IFREG _S_IFREG /* Regular file */ #endif #if !defined(S_IREAD) # define S_IREAD _S_IREAD /* Read permission */ #endif #if !defined(S_IWRITE) # define S_IWRITE _S_IWRITE /* Write permission */ #endif #if !defined(S_IEXEC) # define S_IEXEC _S_IEXEC /* Execute permission */ #endif #if !defined(S_IFIFO) # define S_IFIFO _S_IFIFO /* Pipe */ #endif #if !defined(S_IFBLK) # define S_IFBLK 0 /* Block device */ #endif #if !defined(S_IFLNK) # define S_IFLNK 0 /* Link */ #endif #if !defined(S_IFSOCK) # define S_IFSOCK 0 /* Socket */ #endif #if defined(_MSC_VER) # define S_IRUSR S_IREAD /* Read user */ # define S_IWUSR S_IWRITE /* Write user */ # define S_IXUSR 0 /* Execute user */ # define S_IRGRP 0 /* Read group */ # define S_IWGRP 0 /* Write group */ # define S_IXGRP 0 /* Execute group */ # define S_IROTH 0 /* Read others */ # define S_IWOTH 0 /* Write others */ # define S_IXOTH 0 /* Execute others */ #endif /* Maximum length of file name */ #if !defined(PATH_MAX) # define PATH_MAX MAX_PATH #endif #if !defined(FILENAME_MAX) # define FILENAME_MAX MAX_PATH #endif #if !defined(NAME_MAX) # define NAME_MAX FILENAME_MAX #endif /* File type flags for d_type */ #define DT_UNKNOWN 0 #define DT_REG S_IFREG #define DT_DIR S_IFDIR #define DT_FIFO S_IFIFO #define DT_SOCK S_IFSOCK #define DT_CHR S_IFCHR #define DT_BLK S_IFBLK /* Macros for converting between st_mode and d_type */ #define IFTODT(mode) ((mode) & S_IFMT) #define DTTOIF(type) (type) /* * File type macros. Note that block devices, sockets and links cannot be * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are * only defined for compatibility. These macros should always return false * on Windows. */ #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) /* Return the exact length of d_namlen without zero terminator */ #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) /* Return number of bytes needed to store d_namlen */ #define _D_ALLOC_NAMLEN(p) (PATH_MAX + 1) #ifdef __cplusplus extern "C" { #endif /* Wide-character version */ struct _wdirent { long d_ino; /* Always zero */ unsigned short d_reclen; /* Structure size */ size_t d_namlen; /* Length of name without \0 */ int d_type; /* File type */ wchar_t d_name[PATH_MAX + 1]; /* File name */ }; typedef struct _wdirent _wdirent; struct _WDIR { struct _wdirent ent; /* Current directory entry */ WIN32_FIND_DATAW data; /* Private file data */ int cached; /* True if data is valid */ HANDLE handle; /* Win32 search handle */ wchar_t *patt; /* Initial directory name */ }; typedef struct _WDIR _WDIR; static _WDIR *_wopendir(const wchar_t *dirname); static struct _wdirent *_wreaddir(_WDIR *dirp); static int _wclosedir(_WDIR *dirp); static void _wrewinddir(_WDIR* dirp); /* For compatibility with Symbian */ #define wdirent _wdirent #define WDIR _WDIR #define wopendir _wopendir #define wreaddir _wreaddir #define wclosedir _wclosedir #define wrewinddir _wrewinddir /* Multi-byte character versions */ struct dirent { long d_ino; /* Always zero */ unsigned short d_reclen; /* Structure size */ size_t d_namlen; /* Length of name without \0 */ int d_type; /* File type */ char d_name[PATH_MAX + 1]; /* File name */ }; typedef struct dirent dirent; struct DIR { struct dirent ent; struct _WDIR *wdirp; }; typedef struct DIR DIR; static DIR *opendir(const char *dirname); static struct dirent *readdir(DIR *dirp); static int closedir(DIR *dirp); static void rewinddir(DIR* dirp); /* Internal utility functions */ static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); static int dirent_mbstowcs_s( size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count); static int dirent_wcstombs_s( size_t *pReturnValue, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count); static void dirent_set_errno(int error); /* * Open directory stream DIRNAME for read and return a pointer to the * internal working area that is used to retrieve individual directory * entries. */ static _WDIR* _wopendir(const wchar_t *dirname) { _WDIR *dirp = NULL; int error; /* Must have directory name */ if (dirname == NULL || dirname[0] == '\0') { dirent_set_errno(ENOENT); return NULL; } /* Allocate new _WDIR structure */ dirp = reinterpret_cast<_WDIR*>(malloc(sizeof(struct _WDIR))); if (dirp != NULL) { DWORD n; /* Reset _WDIR structure */ dirp->handle = INVALID_HANDLE_VALUE; dirp->patt = NULL; dirp->cached = 0; /* Compute the length of full path plus zero terminator */ n = GetFullPathNameW(dirname, 0, NULL, NULL); /* Allocate room for absolute directory name and search pattern */ dirp->patt = reinterpret_cast(malloc(sizeof(wchar_t) * n + 16)); if (dirp->patt) { /* * Convert relative directory name to an absolute one. This * allows rewinddir() to function correctly even when current * working directory is changed between opendir() and rewinddir(). */ n = GetFullPathNameW(dirname, n, dirp->patt, NULL); if (n > 0) { wchar_t *p; /* Append search pattern \* to the directory name */ p = dirp->patt + n; if (dirp->patt < p) { switch (p[-1]) { case '\\': case '/': case ':': /* Directory ends in path separator, e.g. c:\temp\ */ /*NOP*/ break; default: /* Directory name doesn't end in path separator */ *p++ = '\\'; } } *p++ = '*'; *p = '\0'; /* Open directory stream and retrieve the first entry */ if (dirent_first(dirp)) { /* Directory stream opened successfully */ error = 0; } else { /* Cannot retrieve first entry */ error = 1; dirent_set_errno(ENOENT); } } else { /* Cannot retrieve full path name */ dirent_set_errno(ENOENT); error = 1; } } else { /* Cannot allocate memory for search pattern */ error = 1; } } else { /* Cannot allocate _WDIR structure */ error = 1; } /* Clean up in case of error */ if (error && dirp) { _wclosedir(dirp); dirp = NULL; } return dirp; } /* * Read next directory entry. The directory entry is returned in dirent * structure in the d_name field. Individual directory entries returned by * this function include regular files, sub-directories, pseudo-directories * "." and ".." as well as volume labels, hidden files and system files. */ static struct _wdirent* _wreaddir(_WDIR *dirp) { WIN32_FIND_DATAW *datap; struct _wdirent *entp; /* Read next directory entry */ datap = dirent_next(dirp); if (datap) { size_t n; DWORD attr; /* Pointer to directory entry to return */ entp = &dirp->ent; /* * Copy file name as wide-character string. If the file name is too * long to fit in to the destination buffer, then truncate file name * to PATH_MAX characters and zero-terminate the buffer. */ n = 0; while (n < PATH_MAX && datap->cFileName[n] != 0) { entp->d_name[n] = datap->cFileName[n]; n++; } dirp->ent.d_name[n] = 0; /* Length of file name excluding zero terminator */ entp->d_namlen = n; /* File type */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { entp->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { entp->d_type = DT_DIR; } else { entp->d_type = DT_REG; } /* Reset dummy fields */ entp->d_ino = 0; entp->d_reclen = sizeof(struct _wdirent); } else { /* Last directory entry read */ entp = NULL; } return entp; } /* * Close directory stream opened by opendir() function. This invalidates the * DIR structure as well as any directory entry read previously by * _wreaddir(). */ static int _wclosedir(_WDIR *dirp) { int ok; if (dirp) { /* Release search handle */ if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose(dirp->handle); dirp->handle = INVALID_HANDLE_VALUE; } /* Release search pattern */ if (dirp->patt) { free(dirp->patt); dirp->patt = NULL; } /* Release directory structure */ free(dirp); ok = /*success*/0; } else { /* Invalid directory stream */ dirent_set_errno(EBADF); ok = /*failure*/-1; } return ok; } /* * Rewind directory stream such that _wreaddir() returns the very first * file name again. */ static void _wrewinddir(_WDIR* dirp) { if (dirp) { /* Release existing search handle */ if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose(dirp->handle); } /* Open new search handle */ dirent_first(dirp); } } /* Get first directory entry (internal) */ static WIN32_FIND_DATAW* dirent_first(_WDIR *dirp) { WIN32_FIND_DATAW *datap; /* Open directory and retrieve the first entry */ dirp->handle = FindFirstFileW(dirp->patt, &dirp->data); if (dirp->handle != INVALID_HANDLE_VALUE) { /* a directory entry is now waiting in memory */ datap = &dirp->data; dirp->cached = 1; } else { /* Failed to re-open directory: no directory entry in memory */ dirp->cached = 0; datap = NULL; } return datap; } /* Get next directory entry (internal) */ static WIN32_FIND_DATAW* dirent_next(_WDIR *dirp) { WIN32_FIND_DATAW *p; /* Get next directory entry */ if (dirp->cached != 0) { /* A valid directory entry already in memory */ p = &dirp->data; dirp->cached = 0; } else if (dirp->handle != INVALID_HANDLE_VALUE) { /* Get the next directory entry from stream */ if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) { /* Got a file */ p = &dirp->data; } else { /* The very last entry has been processed or an error occurred */ FindClose(dirp->handle); dirp->handle = INVALID_HANDLE_VALUE; p = NULL; } } else { /* End of directory stream reached */ p = NULL; } return p; } /* * Open directory stream using plain old C-string. */ static DIR* opendir(const char *dirname) { struct DIR *dirp; int error; /* Must have directory name */ if (dirname == NULL || dirname[0] == '\0') { dirent_set_errno(ENOENT); return NULL; } /* Allocate memory for DIR structure */ dirp = reinterpret_cast(malloc(sizeof(struct DIR))); if (dirp) { wchar_t wname[PATH_MAX + 1]; size_t n; /* Convert directory name to wide-character string */ error = dirent_mbstowcs_s( &n, wname, PATH_MAX + 1, dirname, PATH_MAX); if (!error) { /* Open directory stream using wide-character name */ dirp->wdirp = _wopendir(wname); if (dirp->wdirp) { /* Directory stream opened */ error = 0; } else { /* Failed to open directory stream */ error = 1; } } else { /* * Cannot convert file name to wide-character string. This * occurs if the string contains invalid multi-byte sequences or * the output buffer is too small to contain the resulting * string. */ error = 1; } } else { /* Cannot allocate DIR structure */ error = 1; } /* Clean up in case of error */ if (error && dirp) { free(dirp); dirp = NULL; } return dirp; } /* * Read next directory entry. * * When working with text consoles, please note that file names returned by * readdir() are represented in the default ANSI code page while any output to * console is typically formatted on another code page. Thus, non-ASCII * characters in file names will not usually display correctly on console. The * problem can be fixed in two ways: (1) change the character set of console * to 1252 using chcp utility and use Lucida Console font, or (2) use * _cprintf function when writing to console. The _cprinf() will re-encode * ANSI strings to the console code page so many non-ASCII characters will * display correctly. */ static struct dirent* readdir(DIR *dirp) { WIN32_FIND_DATAW *datap; struct dirent *entp; /* Read next directory entry */ datap = dirent_next(dirp->wdirp); if (datap) { size_t n; int error; /* Attempt to convert file name to multi-byte string */ error = dirent_wcstombs_s( &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH); /* * If the file name cannot be represented by a multi-byte string, * then attempt to use old 8+3 file name. This allows traditional * Unix-code to access some file names despite of unicode * characters, although file names may seem unfamiliar to the user. * * Be ware that the code below cannot come up with a short file * name unless the file system provides one. At least * VirtualBox shared folders fail to do this. */ if (error && datap->cAlternateFileName[0] != '\0') { error = dirent_wcstombs_s( &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName, sizeof(datap->cAlternateFileName) / sizeof(datap->cAlternateFileName[0])); } if (!error) { DWORD attr; /* Initialize directory entry for return */ entp = &dirp->ent; /* Length of file name excluding zero terminator */ entp->d_namlen = n - 1; /* File attributes */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { entp->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { entp->d_type = DT_DIR; } else { entp->d_type = DT_REG; } /* Reset dummy fields */ entp->d_ino = 0; entp->d_reclen = sizeof(struct dirent); } else { /* * Cannot convert file name to multi-byte string so construct * an erroneous directory entry and return that. Note that * we cannot return NULL as that would stop the processing * of directory entries completely. */ entp = &dirp->ent; entp->d_name[0] = '?'; entp->d_name[1] = '\0'; entp->d_namlen = 1; entp->d_type = DT_UNKNOWN; entp->d_ino = 0; entp->d_reclen = 0; } } else { /* No more directory entries */ entp = NULL; } return entp; } /* * Close directory stream. */ static int closedir(DIR *dirp) { int ok; if (dirp) { /* Close wide-character directory stream */ ok = _wclosedir(dirp->wdirp); dirp->wdirp = NULL; /* Release multi-byte character version */ free(dirp); } else { /* Invalid directory stream */ dirent_set_errno(EBADF); ok = /*failure*/-1; } return ok; } /* * Rewind directory stream to beginning. */ static void rewinddir( DIR* dirp) { /* Rewind wide-character string directory stream */ _wrewinddir(dirp->wdirp); } /* Convert multi-byte string to wide character string */ static int dirent_mbstowcs_s( size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count) { int error; #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Microsoft Visual Studio 2005 or later */ error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count); #else /* Older Visual Studio or non-Microsoft compiler */ size_t n; /* Convert to wide-character string */ n = mbstowcs(wcstr, mbstr, count); if (n < sizeInWords) { /* Zero-terminate output buffer */ if (wcstr) { wcstr[n] = 0; } /* Length of resuting multi-byte string WITH zero terminator */ if (pReturnValue) { *pReturnValue = n + 1; } /* Success */ error = 0; } else { /* Could not convert string */ error = 1; } #endif return error; } /* Convert wide-character string to multi-byte string */ static int dirent_wcstombs_s( size_t *pReturnValue, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count) { int error; #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Microsoft Visual Studio 2005 or later */ error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count); #else /* Older Visual Studio or non-Microsoft compiler */ size_t n; /* Convert to multi-byte string */ n = wcstombs(mbstr, wcstr, count); if (n < sizeInBytes) { /* Zero-terminate output buffer */ if (mbstr) { mbstr[n] = '\0'; } /* Length of resulting multi-bytes string WITH zero-terminator */ if (pReturnValue) { *pReturnValue = n + 1; } /* Success */ error = 0; } else { /* Cannot convert string */ error = 1; } #endif return error; } /* Set errno variable */ static void dirent_set_errno(int error) { #if defined(_MSC_VER) /* Microsoft Visual Studio */ _set_errno(error); #else /* Non-Microsoft compiler */ errno = error; #endif } #ifdef __cplusplus } #endif #endif /*DIRENT_H*/ tqsl-2.8.2/src/tqsllib2.def0000644000175000017500000006540015061653721015522 0ustar rmurphyrmurphyLIBRARY tqsllib2.dll EXPORTS _tqsl_getSelectedCertificate@12 tqsl_getSelectedCertificate@12=_tqsl_getSelectedCertificate@12 tqsl_getSelectedCertificate=_tqsl_getSelectedCertificate@12 _tqsl_getNumStationLocationCapturePages@8 tqsl_getNumStationLocationCapturePages@8=_tqsl_getNumStationLocationCapturePages@8 tqsl_getNumStationLocationCapturePages=_tqsl_getNumStationLocationCapturePages@8 _tqsl_adifGetError@4 tqsl_adifGetError@4=_tqsl_adifGetError@4 tqsl_adifGetError=_tqsl_adifGetError@4 _tqsl_adifMakeField@24 tqsl_adifMakeField@24=_tqsl_adifMakeField@24 tqsl_adifMakeField=_tqsl_adifMakeField@24 _tqsl_beginADIF@8 tqsl_beginADIF@8=_tqsl_beginADIF@8 tqsl_beginADIF=_tqsl_beginADIF@8 _tqsl_beginADIFConverter@20 tqsl_beginADIFConverter@20=_tqsl_beginADIFConverter@20 tqsl_beginADIFConverter=_tqsl_beginADIFConverter@20 _tqsl_beginCabrillo@8 tqsl_beginCabrillo@8=_tqsl_beginCabrillo@8 tqsl_beginCabrillo=_tqsl_beginCabrillo@8 _tqsl_beginCabrilloConverter@20 tqsl_beginCabrilloConverter@20=_tqsl_beginCabrilloConverter@20 tqsl_beginCabrilloConverter=_tqsl_beginCabrilloConverter@20 _tqsl_beginSigning@16 tqsl_beginSigning@16=_tqsl_beginSigning@16 tqsl_beginSigning=_tqsl_beginSigning@16 _tqsl_cabrilloGetError@4 tqsl_cabrilloGetError@4=_tqsl_cabrilloGetError@4 tqsl_cabrilloGetError=_tqsl_cabrilloGetError@4 _tqsl_checkSigningStatus@4 tqsl_checkSigningStatus@4=_tqsl_checkSigningStatus@4 tqsl_checkSigningStatus=_tqsl_checkSigningStatus@4 _tqsl_clearADIFModes@0 tqsl_clearADIFModes@0=_tqsl_clearADIFModes@0 tqsl_clearADIFModes=_tqsl_clearADIFModes@0 _tqsl_clearCabrilloMap@0 tqsl_clearCabrilloMap@0=_tqsl_clearCabrilloMap@0 tqsl_clearCabrilloMap=_tqsl_clearCabrilloMap@0 _tqsl_compareDates@8 tqsl_compareDates@8=_tqsl_compareDates@8 tqsl_compareDates=_tqsl_compareDates@8 _tqsl_convertDateToText@12 tqsl_convertDateToText@12=_tqsl_convertDateToText@12 tqsl_convertDateToText=_tqsl_convertDateToText@12 _tqsl_convertTimeToText@12 tqsl_convertTimeToText@12=_tqsl_convertTimeToText@12 tqsl_convertTimeToText=_tqsl_convertTimeToText@12 _tqsl_converterCommit@4 tqsl_converterCommit@4=_tqsl_converterCommit@4 tqsl_converterCommit=_tqsl_converterCommit@4 _tqsl_converterRollBack@4 tqsl_converterRollBack@4=_tqsl_converterRollBack@4 tqsl_converterRollBack=_tqsl_converterRollBack@4 _tqsl_createCertRequest@16 tqsl_createCertRequest@16=_tqsl_createCertRequest@16 tqsl_createCertRequest=_tqsl_createCertRequest@16 _tqsl_decodeBase64@12 tqsl_decodeBase64@12=_tqsl_decodeBase64@12 tqsl_decodeBase64=_tqsl_decodeBase64@12 _tqsl_deleteCertificate@4 tqsl_deleteCertificate@4=_tqsl_deleteCertificate@4 tqsl_deleteCertificate=_tqsl_deleteCertificate@4 _tqsl_deleteStationLocation@4 tqsl_deleteStationLocation@4=_tqsl_deleteStationLocation@4 tqsl_deleteStationLocation=_tqsl_deleteStationLocation@4 _tqsl_encodeBase64@16 tqsl_encodeBase64@16=_tqsl_encodeBase64@16 tqsl_encodeBase64=_tqsl_encodeBase64@16 _tqsl_endADIF@4 tqsl_endADIF@4=_tqsl_endADIF@4 tqsl_endADIF=_tqsl_endADIF@4 _tqsl_endCabrillo@4 tqsl_endCabrillo@4=_tqsl_endCabrillo@4 tqsl_endCabrillo=_tqsl_endCabrillo@4 _tqsl_endConverter@4 tqsl_endConverter@4=_tqsl_endConverter@4 tqsl_endConverter=_tqsl_endConverter@4 _tqsl_endSigning@4 tqsl_endSigning@4=_tqsl_endSigning@4 tqsl_endSigning=_tqsl_endSigning@4 _tqsl_endStationLocationCapture@4 tqsl_endStationLocationCapture@4=_tqsl_endStationLocationCapture@4 tqsl_endStationLocationCapture=_tqsl_endStationLocationCapture@4 _tqsl_exportPKCS12File@12 tqsl_exportPKCS12File@12=_tqsl_exportPKCS12File@12 tqsl_exportPKCS12File=_tqsl_exportPKCS12File@12 _tqsl_freeCertificate@4 tqsl_freeCertificate@4=_tqsl_freeCertificate@4 tqsl_freeCertificate=_tqsl_freeCertificate@4 _tqsl_getADIFField@24 tqsl_getADIFField@24=_tqsl_getADIFField@24 tqsl_getADIFField=_tqsl_getADIFField@24 _tqsl_getADIFLine@8 tqsl_getADIFLine@8=_tqsl_getADIFLine@8 tqsl_getADIFLine=_tqsl_getADIFLine@8 _tqsl_getADIFMode@12 tqsl_getADIFMode@12=_tqsl_getADIFMode@12 tqsl_getADIFMode=_tqsl_getADIFMode@12 _tqsl_getBand@20 tqsl_getBand@20=_tqsl_getBand@20 tqsl_getBand=_tqsl_getBand@20 _tqsl_getCabrilloContest@12 tqsl_getCabrilloContest@12=_tqsl_getCabrilloContest@12 tqsl_getCabrilloContest=_tqsl_getCabrilloContest@12 _tqsl_getCabrilloField@12 tqsl_getCabrilloField@12=_tqsl_getCabrilloField@12 tqsl_getCabrilloField=_tqsl_getCabrilloField@12 _tqsl_getCabrilloFreqType@8 tqsl_getCabrilloFreqType@8=_tqsl_getCabrilloFreqType@8 tqsl_getCabrilloFreqType=_tqsl_getCabrilloFreqType@8 _tqsl_getCabrilloLine@8 tqsl_getCabrilloLine@8=_tqsl_getCabrilloLine@8 tqsl_getCabrilloLine=_tqsl_getCabrilloLine@8 _tqsl_getCabrilloMapEntry@12 tqsl_getCabrilloMapEntry@12=_tqsl_getCabrilloMapEntry@12 tqsl_getCabrilloMapEntry=_tqsl_getCabrilloMapEntry@12 _tqsl_getCabrilloRecordText@4 tqsl_getCabrilloRecordText@4=_tqsl_getCabrilloRecordText@4 tqsl_getCabrilloRecordText=_tqsl_getCabrilloRecordText@4 _tqsl_getCertificateAROName@12 tqsl_getCertificateAROName@12=_tqsl_getCertificateAROName@12 tqsl_getCertificateAROName=_tqsl_getCertificateAROName@12 _tqsl_getCertificateCallSign@12 tqsl_getCertificateCallSign@12=_tqsl_getCertificateCallSign@12 tqsl_getCertificateCallSign=_tqsl_getCertificateCallSign@12 _tqsl_getCertificateDXCCEntity@8 tqsl_getCertificateDXCCEntity@8=_tqsl_getCertificateDXCCEntity@8 tqsl_getCertificateDXCCEntity=_tqsl_getCertificateDXCCEntity@8 _tqsl_getCertificateEmailAddress@12 tqsl_getCertificateEmailAddress@12=_tqsl_getCertificateEmailAddress@12 tqsl_getCertificateEmailAddress=_tqsl_getCertificateEmailAddress@12 _tqsl_getCertificateEncoded@12 tqsl_getCertificateEncoded@12=_tqsl_getCertificateEncoded@12 tqsl_getCertificateEncoded=_tqsl_getCertificateEncoded@12 _tqsl_getCertificateIssuer@12 tqsl_getCertificateIssuer@12=_tqsl_getCertificateIssuer@12 tqsl_getCertificateIssuer=_tqsl_getCertificateIssuer@12 _tqsl_getCertificateIssuerOrganization@12 tqsl_getCertificateIssuerOrganization@12=_tqsl_getCertificateIssuerOrganization@12 tqsl_getCertificateIssuerOrganization=_tqsl_getCertificateIssuerOrganization@12 _tqsl_getCertificateIssuerOrganizationalUnit@12 tqsl_getCertificateIssuerOrganizationalUnit@12=_tqsl_getCertificateIssuerOrganizationalUnit@12 tqsl_getCertificateIssuerOrganizationalUnit=_tqsl_getCertificateIssuerOrganizationalUnit@12 _tqsl_getCertificateKeyOnly@8 tqsl_getCertificateKeyOnly@8=_tqsl_getCertificateKeyOnly@8 tqsl_getCertificateKeyOnly=_tqsl_getCertificateKeyOnly@8 _tqsl_getCertificateNotAfterDate@8 tqsl_getCertificateNotAfterDate@8=_tqsl_getCertificateNotAfterDate@8 tqsl_getCertificateNotAfterDate=_tqsl_getCertificateNotAfterDate@8 _tqsl_getCertificateNotBeforeDate@8 tqsl_getCertificateNotBeforeDate@8=_tqsl_getCertificateNotBeforeDate@8 tqsl_getCertificateNotBeforeDate=_tqsl_getCertificateNotBeforeDate@8 _tqsl_getCertificatePrivateKeyType@4 tqsl_getCertificatePrivateKeyType@4=_tqsl_getCertificatePrivateKeyType@4 tqsl_getCertificatePrivateKeyType=_tqsl_getCertificatePrivateKeyType@4 _tqsl_getCertificateQSONotAfterDate@8 tqsl_getCertificateQSONotAfterDate@8=_tqsl_getCertificateQSONotAfterDate@8 tqsl_getCertificateQSONotAfterDate=_tqsl_getCertificateQSONotAfterDate@8 _tqsl_getCertificateQSONotBeforeDate@8 tqsl_getCertificateQSONotBeforeDate@8=_tqsl_getCertificateQSONotBeforeDate@8 tqsl_getCertificateQSONotBeforeDate=_tqsl_getCertificateQSONotBeforeDate@8 _tqsl_getCertificateRequestAddress1@12 tqsl_getCertificateRequestAddress1@12=_tqsl_getCertificateRequestAddress1@12 tqsl_getCertificateRequestAddress1=_tqsl_getCertificateRequestAddress1@12 _tqsl_getCertificateRequestAddress2@12 tqsl_getCertificateRequestAddress2@12=_tqsl_getCertificateRequestAddress2@12 tqsl_getCertificateRequestAddress2=_tqsl_getCertificateRequestAddress2@12 _tqsl_getCertificateRequestCity@12 tqsl_getCertificateRequestCity@12=_tqsl_getCertificateRequestCity@12 tqsl_getCertificateRequestCity=_tqsl_getCertificateRequestCity@12 _tqsl_getCertificateRequestCountry@12 tqsl_getCertificateRequestCountry@12=_tqsl_getCertificateRequestCountry@12 tqsl_getCertificateRequestCountry=_tqsl_getCertificateRequestCountry@12 _tqsl_getCertificateRequestPostalCode@12 tqsl_getCertificateRequestPostalCode@12=_tqsl_getCertificateRequestPostalCode@12 tqsl_getCertificateRequestPostalCode=_tqsl_getCertificateRequestPostalCode@12 _tqsl_getCertificateRequestState@12 tqsl_getCertificateRequestState@12=_tqsl_getCertificateRequestState@12 tqsl_getCertificateRequestState=_tqsl_getCertificateRequestState@12 _tqsl_getCertificateSerial@8 tqsl_getCertificateSerial@8=_tqsl_getCertificateSerial@8 tqsl_getCertificateSerial=_tqsl_getCertificateSerial@8 _tqsl_getCertificateSerialExt@12 tqsl_getCertificateSerialExt@12=_tqsl_getCertificateSerialExt@12 tqsl_getCertificateSerialExt=_tqsl_getCertificateSerialExt@12 _tqsl_getCertificateSerialLength@4 tqsl_getCertificateSerialLength@4=_tqsl_getCertificateSerialLength@4 tqsl_getCertificateSerialLength=_tqsl_getCertificateSerialLength@4 _tqsl_getConfigVersion@8 tqsl_getConfigVersion@8=_tqsl_getConfigVersion@8 tqsl_getConfigVersion=_tqsl_getConfigVersion@8 _tqsl_getConverterCert@8 tqsl_getConverterCert@8=_tqsl_getConverterCert@8 tqsl_getConverterCert=_tqsl_getConverterCert@8 _tqsl_getConverterGABBI@4 tqsl_getConverterGABBI@4=_tqsl_getConverterGABBI@4 tqsl_getConverterGABBI=_tqsl_getConverterGABBI@4 _tqsl_getConverterLine@8 tqsl_getConverterLine@8=_tqsl_getConverterLine@8 tqsl_getConverterLine=_tqsl_getConverterLine@8 _tqsl_getConverterRecordText@4 tqsl_getConverterRecordText@4=_tqsl_getConverterRecordText@4 tqsl_getConverterRecordText=_tqsl_getConverterRecordText@4 _tqsl_getDXCCEntity@12 tqsl_getDXCCEntity@12=_tqsl_getDXCCEntity@12 tqsl_getDXCCEntity=_tqsl_getDXCCEntity@12 _tqsl_getDXCCEntityName@8 tqsl_getDXCCEntityName@8=_tqsl_getDXCCEntityName@8 tqsl_getDXCCEntityName=_tqsl_getDXCCEntityName@8 _tqsl_getDXCCZoneMap@8 tqsl_getDXCCZoneMap@8=_tqsl_getDXCCZoneMap@8 tqsl_getDXCCZoneMap=_tqsl_getDXCCZoneMap@8 _tqsl_getErrorString@0 tqsl_getErrorString@0=_tqsl_getErrorString@0 tqsl_getErrorString=_tqsl_getErrorString@0 _tqsl_getErrorString_v@4 tqsl_getErrorString_v@4=_tqsl_getErrorString_v@4 tqsl_getErrorString_v=_tqsl_getErrorString_v@4 _tqsl_getGABBItCERT@8 tqsl_getGABBItCERT@8=_tqsl_getGABBItCERT@8 tqsl_getGABBItCERT=_tqsl_getGABBItCERT@8 _tqsl_getGABBItCONTACT@16 tqsl_getGABBItCONTACT@16=_tqsl_getGABBItCONTACT@16 tqsl_getGABBItCONTACT=_tqsl_getGABBItCONTACT@16 _tqsl_getGABBItCONTACTData@24 tqsl_getGABBItCONTACTData@24=_tqsl_getGABBItCONTACTData@24 tqsl_getGABBItCONTACTData=_tqsl_getGABBItCONTACTData@24 _tqsl_getGABBItSTATION@12 tqsl_getGABBItSTATION@12=_tqsl_getGABBItSTATION@12 tqsl_getGABBItSTATION=_tqsl_getGABBItSTATION@12 _tqsl_getLocationCallSign@12 tqsl_getLocationCallSign@12=_tqsl_getLocationCallSign@12 tqsl_getLocationCallSign=_tqsl_getLocationCallSign@12 _tqsl_getLocationDXCCEntity@8 tqsl_getLocationDXCCEntity@8=_tqsl_getLocationDXCCEntity@8 tqsl_getLocationDXCCEntity=_tqsl_getLocationDXCCEntity@8 _tqsl_getLocationFieldChanged@12 tqsl_getLocationFieldChanged@12=_tqsl_getLocationFieldChanged@12 tqsl_getLocationFieldChanged=_tqsl_getLocationFieldChanged@12 _tqsl_getLocationFieldCharData@16 tqsl_getLocationFieldCharData@16=_tqsl_getLocationFieldCharData@16 tqsl_getLocationFieldCharData=_tqsl_getLocationFieldCharData@16 _tqsl_getLocationFieldDataGABBI@16 tqsl_getLocationFieldDataGABBI@16=_tqsl_getLocationFieldDataGABBI@16 tqsl_getLocationFieldDataGABBI=_tqsl_getLocationFieldDataGABBI@16 _tqsl_getLocationFieldDataGABBISize@12 tqsl_getLocationFieldDataGABBISize@12=_tqsl_getLocationFieldDataGABBISize@12 tqsl_getLocationFieldDataGABBISize=_tqsl_getLocationFieldDataGABBISize@12 _tqsl_getLocationFieldDataLabel@16 tqsl_getLocationFieldDataLabel@16=_tqsl_getLocationFieldDataLabel@16 tqsl_getLocationFieldDataLabel=_tqsl_getLocationFieldDataLabel@16 _tqsl_getLocationFieldDataLabelSize@12 tqsl_getLocationFieldDataLabelSize@12=_tqsl_getLocationFieldDataLabelSize@12 tqsl_getLocationFieldDataLabelSize=_tqsl_getLocationFieldDataLabelSize@12 _tqsl_getLocationFieldDataLength@12 tqsl_getLocationFieldDataLength@12=_tqsl_getLocationFieldDataLength@12 tqsl_getLocationFieldDataLength=_tqsl_getLocationFieldDataLength@12 _tqsl_getLocationFieldDataType@12 tqsl_getLocationFieldDataType@12=_tqsl_getLocationFieldDataType@12 tqsl_getLocationFieldDataType=_tqsl_getLocationFieldDataType@12 _tqsl_getLocationFieldFlags@12 tqsl_getLocationFieldFlags@12=_tqsl_getLocationFieldFlags@12 tqsl_getLocationFieldFlags=_tqsl_getLocationFieldFlags@12 _tqsl_getLocationFieldIndex@12 tqsl_getLocationFieldIndex@12=_tqsl_getLocationFieldIndex@12 tqsl_getLocationFieldIndex=_tqsl_getLocationFieldIndex@12 _tqsl_getLocationFieldInputType@12 tqsl_getLocationFieldInputType@12=_tqsl_getLocationFieldInputType@12 tqsl_getLocationFieldInputType=_tqsl_getLocationFieldInputType@12 _tqsl_getLocationFieldIntData@12 tqsl_getLocationFieldIntData@12=_tqsl_getLocationFieldIntData@12 tqsl_getLocationFieldIntData=_tqsl_getLocationFieldIntData@12 _tqsl_getLocationFieldListItem@20 tqsl_getLocationFieldListItem@20=_tqsl_getLocationFieldListItem@20 tqsl_getLocationFieldListItem=_tqsl_getLocationFieldListItem@20 _tqsl_getMaxSignatureSize@8 tqsl_getMaxSignatureSize@8=_tqsl_getMaxSignatureSize@8 tqsl_getMaxSignatureSize=_tqsl_getMaxSignatureSize@8 _tqsl_getMode@12 tqsl_getMode@12=_tqsl_getMode@12 tqsl_getMode=_tqsl_getMode@12 _tqsl_getNumBand@4 tqsl_getNumBand@4=_tqsl_getNumBand@4 tqsl_getNumBand=_tqsl_getNumBand@4 _tqsl_getNumDXCCEntity@4 tqsl_getNumDXCCEntity@4=_tqsl_getNumDXCCEntity@4 tqsl_getNumDXCCEntity=_tqsl_getNumDXCCEntity@4 _tqsl_getNumLocationField@8 tqsl_getNumLocationField@8=_tqsl_getNumLocationField@8 tqsl_getNumLocationField=_tqsl_getNumLocationField@8 _tqsl_getNumLocationFieldListItems@12 tqsl_getNumLocationFieldListItems@12=_tqsl_getNumLocationFieldListItems@12 tqsl_getNumLocationFieldListItems=_tqsl_getNumLocationFieldListItems@12 _tqsl_getNumMode@4 tqsl_getNumMode@4=_tqsl_getNumMode@4 tqsl_getNumMode=_tqsl_getNumMode@4 _tqsl_getNumPropagationMode@4 tqsl_getNumPropagationMode@4=_tqsl_getNumPropagationMode@4 tqsl_getNumPropagationMode=_tqsl_getNumPropagationMode@4 _tqsl_getNumProviders@4 tqsl_getNumProviders@4=_tqsl_getNumProviders@4 tqsl_getNumProviders=_tqsl_getNumProviders@4 _tqsl_getNumSatellite@4 tqsl_getNumSatellite@4=_tqsl_getNumSatellite@4 tqsl_getNumSatellite=_tqsl_getNumSatellite@4 _tqsl_getNumStationLocations@8 tqsl_getNumStationLocations@8=_tqsl_getNumStationLocations@8 tqsl_getNumStationLocations=_tqsl_getNumStationLocations@8 _tqsl_getPropagationMode@12 tqsl_getPropagationMode@12=_tqsl_getPropagationMode@12 tqsl_getPropagationMode=_tqsl_getPropagationMode@12 _tqsl_getProvider@8 tqsl_getProvider@8=_tqsl_getProvider@8 tqsl_getProvider=_tqsl_getProvider@8 _tqsl_getSatellite@20 tqsl_getSatellite@20=_tqsl_getSatellite@20 tqsl_getSatellite=_tqsl_getSatellite@20 _tqsl_getSerialFromTQSLFile@8 tqsl_getSerialFromTQSLFile@8=_tqsl_getSerialFromTQSLFile@8 tqsl_getSerialFromTQSLFile=_tqsl_getSerialFromTQSLFile@8 _tqsl_getStationLocation@8 tqsl_getStationLocation@8=_tqsl_getStationLocation@8 tqsl_getStationLocation=_tqsl_getStationLocation@8 _tqsl_getStationLocationCallSign@16 tqsl_getStationLocationCallSign@16=_tqsl_getStationLocationCallSign@16 tqsl_getStationLocationCallSign=_tqsl_getStationLocationCallSign@16 _tqsl_getStationLocationCaptureName@12 tqsl_getStationLocationCaptureName@12=_tqsl_getStationLocationCaptureName@12 tqsl_getStationLocationCaptureName=_tqsl_getStationLocationCaptureName@12 _tqsl_getStationLocationCapturePage@8 tqsl_getStationLocationCapturePage@8=_tqsl_getStationLocationCapturePage@8 tqsl_getStationLocationCapturePage=_tqsl_getStationLocationCapturePage@8 _tqsl_getStationLocationName@16 tqsl_getStationLocationName@16=_tqsl_getStationLocationName@16 tqsl_getStationLocationName=_tqsl_getStationLocationName@16 _tqsl_getVersion@8 tqsl_getVersion@8=_tqsl_getVersion@8 tqsl_getVersion=_tqsl_getVersion@8 _tqsl_hasNextStationLocationCapture@8 tqsl_hasNextStationLocationCapture@8=_tqsl_hasNextStationLocationCapture@8 tqsl_hasNextStationLocationCapture=_tqsl_hasNextStationLocationCapture@8 _tqsl_hasPrevStationLocationCapture@8 tqsl_hasPrevStationLocationCapture@8=_tqsl_hasPrevStationLocationCapture@8 tqsl_hasPrevStationLocationCapture=_tqsl_hasPrevStationLocationCapture@8 _tqsl_importPKCS12File@24 tqsl_importPKCS12File@24=_tqsl_importPKCS12File@24 tqsl_importPKCS12File=_tqsl_importPKCS12File@24 _tqsl_importTQSLFile@12 tqsl_importTQSLFile@12=_tqsl_importTQSLFile@12 tqsl_importTQSLFile=_tqsl_importTQSLFile@12 _tqsl_init@0 tqsl_init@0=_tqsl_init@0 tqsl_init=_tqsl_init@0 _tqsl_initDate@8 tqsl_initDate@8=_tqsl_initDate@8 tqsl_initDate=_tqsl_initDate@8 _tqsl_initStationLocationCapture@4 tqsl_initStationLocationCapture@4=_tqsl_initStationLocationCapture@4 tqsl_initStationLocationCapture=_tqsl_initStationLocationCapture@4 _tqsl_initTime@8 tqsl_initTime@8=_tqsl_initTime@8 tqsl_initTime=_tqsl_initTime@8 _tqsl_isDateNull@4 tqsl_isDateNull@4=_tqsl_isDateNull@4 tqsl_isDateNull=_tqsl_isDateNull@4 _tqsl_isDateValid@4 tqsl_isDateValid@4=_tqsl_isDateValid@4 tqsl_isDateValid=_tqsl_isDateValid@4 _tqsl_isTimeValid@4 tqsl_isTimeValid@4=_tqsl_isTimeValid@4 tqsl_isTimeValid=_tqsl_isTimeValid@4 _tqsl_nextStationLocationCapture@4 tqsl_nextStationLocationCapture@4=_tqsl_nextStationLocationCapture@4 tqsl_nextStationLocationCapture=_tqsl_nextStationLocationCapture@4 _tqsl_prevStationLocationCapture@4 tqsl_prevStationLocationCapture@4=_tqsl_prevStationLocationCapture@4 tqsl_prevStationLocationCapture=_tqsl_prevStationLocationCapture@4 _tqsl_saveStationLocationCapture@8 tqsl_saveStationLocationCapture@8=_tqsl_saveStationLocationCapture@8 tqsl_saveStationLocationCapture=_tqsl_saveStationLocationCapture@8 _tqsl_selectCertificates@28 tqsl_selectCertificates@28=_tqsl_selectCertificates@28 tqsl_selectCertificates=_tqsl_selectCertificates@28 _tqsl_setADIFConverterDateFilter@12 tqsl_setADIFConverterDateFilter@12=_tqsl_setADIFConverterDateFilter@12 tqsl_setADIFConverterDateFilter=_tqsl_setADIFConverterDateFilter@12 _tqsl_setADIFMode@8 tqsl_setADIFMode@8=_tqsl_setADIFMode@8 tqsl_setADIFMode=_tqsl_setADIFMode@8 _tqsl_setCabrilloMapEntry@12 tqsl_setCabrilloMapEntry@12=_tqsl_setCabrilloMapEntry@12 tqsl_setCabrilloMapEntry=_tqsl_setCabrilloMapEntry@12 _tqsl_setConverterAllowBadCall@8 tqsl_setConverterAllowBadCall@8=_tqsl_setConverterAllowBadCall@8 tqsl_setConverterAllowBadCall=_tqsl_setConverterAllowBadCall@8 _tqsl_setConverterAllowDuplicates@8 tqsl_setConverterAllowDuplicates@8=_tqsl_setConverterAllowDuplicates@8 tqsl_setConverterAllowDuplicates=_tqsl_setConverterAllowDuplicates@8 _tqsl_setDirectory@4 tqsl_setDirectory@4=_tqsl_setDirectory@4 tqsl_setDirectory=_tqsl_setDirectory@4 _tqsl_setLocationFieldCharData@12 tqsl_setLocationFieldCharData@12=_tqsl_setLocationFieldCharData@12 tqsl_setLocationFieldCharData=_tqsl_setLocationFieldCharData@12 _tqsl_setLocationFieldIndex@12 tqsl_setLocationFieldIndex@12=_tqsl_setLocationFieldIndex@12 tqsl_setLocationFieldIndex=_tqsl_setLocationFieldIndex@12 _tqsl_setLocationFieldIntData@12 tqsl_setLocationFieldIntData@12=_tqsl_setLocationFieldIntData@12 tqsl_setLocationFieldIntData=_tqsl_setLocationFieldIntData@12 _tqsl_setStationLocationCaptureName@8 tqsl_setStationLocationCaptureName@8=_tqsl_setStationLocationCaptureName@8 tqsl_setStationLocationCaptureName=_tqsl_setStationLocationCaptureName@8 _tqsl_setStationLocationCapturePage@8 tqsl_setStationLocationCapturePage@8=_tqsl_setStationLocationCapturePage@8 tqsl_setStationLocationCapturePage=_tqsl_setStationLocationCapturePage@8 _tqsl_signDataBlock@20 tqsl_signDataBlock@20=_tqsl_signDataBlock@20 tqsl_signDataBlock=_tqsl_signDataBlock@20 _tqsl_signQSORecord@20 tqsl_signQSORecord@20=_tqsl_signQSORecord@20 tqsl_signQSORecord=_tqsl_signQSORecord@20 _tqsl_updateStationLocationCapture@4 tqsl_updateStationLocationCapture@4=_tqsl_updateStationLocationCapture@4 tqsl_updateStationLocationCapture=_tqsl_updateStationLocationCapture@4 _tqsl_verifyDataBlock@20 tqsl_verifyDataBlock@20=_tqsl_verifyDataBlock@20 tqsl_verifyDataBlock=_tqsl_verifyDataBlock@20 _tqsl_beginConverter@4 tqsl_beginConverter@4=_tqsl_beginConverter@4 tqsl_beginConverter=_tqsl_beginConverter@4 _tqsl_closeDiagFile@0 tqsl_closeDiagFile@0=_tqsl_closeDiagFile@0 tqsl_closeDiagFile=_tqsl_closeDiagFile@0 _tqsl_diagFileOpen@0 tqsl_diagFileOpen@0=_tqsl_diagFileOpen@0 tqsl_diagFileOpen=_tqsl_diagFileOpen@0 _tqsl_exportPKCS12Base64@16 tqsl_exportPKCS12Base64@16=_tqsl_exportPKCS12Base64@16 tqsl_exportPKCS12Base64=_tqsl_exportPKCS12Base64@16 _tqsl_freeDeletedCertificateList@8 tqsl_freeDeletedCertificateList@8=_tqsl_freeDeletedCertificateList@8 tqsl_freeDeletedCertificateList=_tqsl_freeDeletedCertificateList@8 _tqsl_freeDeletedLocationList@8 tqsl_freeDeletedLocationList@8=_tqsl_freeDeletedLocationList@8 tqsl_freeDeletedLocationList=_tqsl_freeDeletedLocationList@8 _tqsl_freeStationDataEnc@4 tqsl_freeStationDataEnc@4=_tqsl_freeStationDataEnc@4 tqsl_freeStationDataEnc=_tqsl_freeStationDataEnc@4 _tqsl_getADIFSubMode@16 tqsl_getADIFSubMode@16=_tqsl_getADIFSubMode@16 tqsl_getADIFSubMode=_tqsl_getADIFSubMode@16 _tqsl_getCallsignLocationInfo@8 tqsl_getCallsignLocationInfo@8=_tqsl_getCallsignLocationInfo@8 tqsl_getCallsignLocationInfo=_tqsl_getCallsignLocationInfo@8 _tqsl_getCertificateStatus@4 tqsl_getCertificateStatus@4=_tqsl_getCertificateStatus@4 tqsl_getCertificateStatus=_tqsl_getCertificateStatus@4 _tqsl_getCurrentStationLocationCapturePage@8 tqsl_getCurrentStationLocationCapturePage@8=_tqsl_getCurrentStationLocationCapturePage@8 tqsl_getCurrentStationLocationCapturePage=_tqsl_getCurrentStationLocationCapturePage@8 _tqsl_getDXCCDeleted@8 tqsl_getDXCCDeleted@8=_tqsl_getDXCCDeleted@8 tqsl_getDXCCDeleted=_tqsl_getDXCCDeleted@8 _tqsl_getDXCCEndDate@8 tqsl_getDXCCEndDate@8=_tqsl_getDXCCEndDate@8 tqsl_getDXCCEndDate=_tqsl_getDXCCEndDate@8 _tqsl_getDXCCStartDate@8 tqsl_getDXCCStartDate@8=_tqsl_getDXCCStartDate@8 tqsl_getDXCCStartDate=_tqsl_getDXCCStartDate@8 _tqsl_getDeletedCallsignCertificates@12 tqsl_getDeletedCallsignCertificates@12=_tqsl_getDeletedCallsignCertificates@12 tqsl_getDeletedCallsignCertificates=_tqsl_getDeletedCallsignCertificates@12 _tqsl_getDeletedStationLocations@8 tqsl_getDeletedStationLocations@8=_tqsl_getDeletedStationLocations@8 tqsl_getDeletedStationLocations=_tqsl_getDeletedStationLocations@8 _tqsl_getDuplicateRecords@16 tqsl_getDuplicateRecords@16=_tqsl_getDuplicateRecords@16 tqsl_getDuplicateRecords=_tqsl_getDuplicateRecords@16 _tqsl_getDuplicateRecordsV2@16 tqsl_getDuplicateRecordsV2@16=_tqsl_getDuplicateRecordsV2@16 tqsl_getDuplicateRecordsV2=_tqsl_getDuplicateRecordsV2@16 _tqsl_getKeyEncoded@12 tqsl_getKeyEncoded@12=_tqsl_getKeyEncoded@12 tqsl_getKeyEncoded=_tqsl_getKeyEncoded@12 _tqsl_getLocationField@16 tqsl_getLocationField@16=_tqsl_getLocationField@16 tqsl_getLocationField=_tqsl_getLocationField@16 _tqsl_getLocationFieldLabel@16 tqsl_getLocationFieldLabel@16=_tqsl_getLocationFieldLabel@16 tqsl_getLocationFieldLabel=_tqsl_getLocationFieldLabel@16 _tqsl_getLocationQSODetails@12 tqsl_getLocationQSODetails@12=_tqsl_getLocationQSODetails@12 tqsl_getLocationQSODetails=_tqsl_getLocationQSODetails@12 _tqsl_getLocationStationDetails@12 tqsl_getLocationStationDetails@12=_tqsl_getLocationStationDetails@12 tqsl_getLocationStationDetails=_tqsl_getLocationStationDetails@12 _tqsl_getNextStationLocationCapturePage@8 tqsl_getNextStationLocationCapturePage@8=_tqsl_getNextStationLocationCapturePage@8 tqsl_getNextStationLocationCapturePage=_tqsl_getNextStationLocationCapturePage@8 _tqsl_getNumADIFMode@4 tqsl_getNumADIFMode@4=_tqsl_getNumADIFMode@4 tqsl_getNumADIFMode=_tqsl_getNumADIFMode@4 _tqsl_getPrevStationLocationCapturePage@8 tqsl_getPrevStationLocationCapturePage@8=_tqsl_getPrevStationLocationCapturePage@8 tqsl_getPrevStationLocationCapturePage=_tqsl_getPrevStationLocationCapturePage@8 _tqsl_getStationDataEnc@4 tqsl_getStationDataEnc@4=_tqsl_getStationDataEnc@4 tqsl_getStationDataEnc=_tqsl_getStationDataEnc@4 _tqsl_importKeyPairEncoded@16 tqsl_importKeyPairEncoded@16=_tqsl_importKeyPairEncoded@16 tqsl_importKeyPairEncoded=_tqsl_importKeyPairEncoded@16 _tqsl_importPKCS12Base64@24 tqsl_importPKCS12Base64@24=_tqsl_importPKCS12Base64@24 tqsl_importPKCS12Base64=_tqsl_importPKCS12Base64@24 _tqsl_isCertificateExpired@8 tqsl_isCertificateExpired@8=_tqsl_isCertificateExpired@8 tqsl_isCertificateExpired=_tqsl_isCertificateExpired@8 _tqsl_isCertificateRenewable@8 tqsl_isCertificateRenewable@8=_tqsl_isCertificateRenewable@8 tqsl_isCertificateRenewable=_tqsl_isCertificateRenewable@8 _tqsl_isCertificateSuperceded@8 tqsl_isCertificateSuperceded@8=_tqsl_isCertificateSuperceded@8 tqsl_isCertificateSuperceded=_tqsl_isCertificateSuperceded@8 _tqsl_mergeStationLocations@4 tqsl_mergeStationLocations@4=_tqsl_mergeStationLocations@4 tqsl_mergeStationLocations=_tqsl_mergeStationLocations@4 _tqsl_openDiagFile@4 tqsl_openDiagFile@4=_tqsl_openDiagFile@4 tqsl_openDiagFile=_tqsl_openDiagFile@4 _tqsl_putDuplicateRecord@16 tqsl_putDuplicateRecord@16=_tqsl_putDuplicateRecord@16 tqsl_putDuplicateRecord=_tqsl_putDuplicateRecord@16 _tqsl_removeUploadDatabase@0 tqsl_removeUploadDatabase@0=_tqsl_removeUploadDatabase@0 tqsl_removeUploadDatabase=_tqsl_removeUploadDatabase@0 _tqsl_restoreCallsignCertificate@4 tqsl_restoreCallsignCertificate@4=_tqsl_restoreCallsignCertificate@4 tqsl_restoreCallsignCertificate=_tqsl_restoreCallsignCertificate@4 _tqsl_restoreStationLocation@4 tqsl_restoreStationLocation@4=_tqsl_restoreStationLocation@4 tqsl_restoreStationLocation=_tqsl_restoreStationLocation@4 _tqsl_saveCallsignLocationInfo@8 tqsl_saveCallsignLocationInfo@8=_tqsl_saveCallsignLocationInfo@8 tqsl_saveCallsignLocationInfo=_tqsl_saveCallsignLocationInfo@8 _tqsl_selectCACertificates@12 tqsl_selectCACertificates@12=_tqsl_selectCACertificates@12 tqsl_selectCACertificates=_tqsl_selectCACertificates@12 _tqsl_setCertificateStatus@8 tqsl_setCertificateStatus@8=_tqsl_setCertificateStatus@8 tqsl_setCertificateStatus=_tqsl_setCertificateStatus@8 _tqsl_setConverterAppName@8 tqsl_setConverterAppName@8=_tqsl_setConverterAppName@8 tqsl_setConverterAppName=_tqsl_setConverterAppName@8 _tqsl_setConverterDupesOnly@8 tqsl_setConverterDupesOnly@8=_tqsl_setConverterDupesOnly@8 tqsl_setConverterDupesOnly=_tqsl_setConverterDupesOnly@8 _tqsl_setConverterIgnoreCallsigns@8 tqsl_setConverterIgnoreCallsigns@8=_tqsl_setConverterIgnoreCallsigns@8 tqsl_setConverterIgnoreCallsigns=_tqsl_setConverterIgnoreCallsigns@8 _tqsl_setConverterIgnoreSeconds@8 tqsl_setConverterIgnoreSeconds@8=_tqsl_setConverterIgnoreSeconds@8 tqsl_setConverterIgnoreSeconds=_tqsl_setConverterIgnoreSeconds@8 _tqsl_setConverterQTHDetails@8 tqsl_setConverterQTHDetails@8=_tqsl_setConverterQTHDetails@8 tqsl_setConverterQTHDetails=_tqsl_setConverterQTHDetails@8 _tqsl_setLocationCallSign@12 tqsl_setLocationCallSign@12=_tqsl_setLocationCallSign@12 tqsl_setLocationCallSign=_tqsl_setLocationCallSign@12 _tqsl_setLocationField@12 tqsl_setLocationField@12=_tqsl_setLocationField@12 tqsl_setLocationField=_tqsl_setLocationField@12 _tqsl_setStationLocationCertFlags@8 tqsl_setStationLocationCertFlags@8=_tqsl_setStationLocationCertFlags@8 tqsl_setStationLocationCertFlags=_tqsl_setStationLocationCertFlags@8 _tqsl_subtractDates@12 tqsl_subtractDates@12=_tqsl_subtractDates@12 tqsl_subtractDates=_tqsl_subtractDates@12 tQSL_ADIF_Error DATA tQSL_Cabrillo_Error DATA tQSL_CustomError DATA tQSL_Errno DATA tQSL_Error DATA tQSL_ErrorFile DATA tQSL_DiagFile DATA tQSL_ImportCall DATA tQSL_ImportSerial DATA tqsl-2.8.2/src/tqsllib2-x64.def0000644000175000017500000000744415061653721016145 0ustar rmurphyrmurphyLIBRARY tqsllib2.dll EXPORTS tqsl_getSelectedCertificate tqsl_getNumStationLocationCapturePages tqsl_adifGetError tqsl_adifMakeField tqsl_beginADIF tqsl_beginADIFConverter tqsl_beginCabrillo tqsl_beginCabrilloConverter tqsl_beginSigning tqsl_cabrilloGetError tqsl_checkSigningStatus tqsl_clearADIFModes tqsl_clearCabrilloMap tqsl_compareDates tqsl_convertDateToText tqsl_convertTimeToText tqsl_converterCommit tqsl_converterRollBack tqsl_createCertRequest tqsl_decodeBase64 tqsl_deleteCertificate tqsl_deleteStationLocation tqsl_encodeBase64 tqsl_endADIF tqsl_endCabrillo tqsl_endConverter tqsl_endSigning tqsl_endStationLocationCapture tqsl_exportPKCS12File tqsl_freeCertificate tqsl_getADIFField tqsl_getADIFLine tqsl_getADIFMode tqsl_getBand tqsl_getCabrilloContest tqsl_getCabrilloField tqsl_getCabrilloFreqType tqsl_getCabrilloLine tqsl_getCabrilloMapEntry tqsl_getCabrilloRecordText tqsl_getCertificateAROName tqsl_getCertificateCallSign tqsl_getCertificateDXCCEntity tqsl_getCertificateEmailAddress tqsl_getCertificateEncoded tqsl_getCertificateIssuer tqsl_getCertificateIssuerOrganization tqsl_getCertificateIssuerOrganizationalUnit tqsl_getCertificateKeyOnly tqsl_getCertificateNotAfterDate tqsl_getCertificateNotBeforeDate tqsl_getCertificatePrivateKeyType tqsl_getCertificateQSONotAfterDate tqsl_getCertificateQSONotBeforeDate tqsl_getCertificateRequestAddress1 tqsl_getCertificateRequestAddress2 tqsl_getCertificateRequestCity tqsl_getCertificateRequestCountry tqsl_getCertificateRequestPostalCode tqsl_getCertificateRequestState tqsl_getCertificateSerial tqsl_getCertificateSerialExt tqsl_getCertificateSerialLength tqsl_getConfigVersion tqsl_getConverterCert tqsl_getConverterGABBI tqsl_getConverterLine tqsl_getConverterRecordText tqsl_getDXCCEntity tqsl_getDXCCEntityName tqsl_getDXCCZoneMap tqsl_getErrorString tqsl_getErrorString_v tqsl_getGABBItCERT tqsl_getGABBItCONTACT tqsl_getGABBItCONTACTData tqsl_getGABBItSTATION tqsl_getLocationCallSign tqsl_getLocationDXCCEntity tqsl_getLocationFieldChanged tqsl_getLocationFieldCharData tqsl_getLocationFieldDataGABBI tqsl_getLocationFieldDataGABBISize tqsl_getLocationFieldDataLabel tqsl_getLocationFieldDataLabelSize tqsl_getLocationFieldDataLength tqsl_getLocationFieldDataType tqsl_getLocationFieldFlags tqsl_getLocationFieldIndex tqsl_getLocationFieldInputType tqsl_getLocationFieldIntData tqsl_getLocationFieldListItem tqsl_getMaxSignatureSize tqsl_getMode tqsl_getNumBand tqsl_getNumDXCCEntity tqsl_getNumLocationField tqsl_getNumLocationFieldListItems tqsl_getNumMode tqsl_getNumPropagationMode tqsl_getNumProviders tqsl_getNumSatellite tqsl_getNumStationLocations tqsl_getPropagationMode tqsl_getProvider tqsl_getSatellite tqsl_getSerialFromTQSLFile tqsl_getStationLocation tqsl_getStationLocationCallSign tqsl_getStationLocationCaptureName tqsl_getStationLocationCapturePage tqsl_getStationLocationName tqsl_getVersion tqsl_hasNextStationLocationCapture tqsl_hasPrevStationLocationCapture tqsl_importPKCS12File tqsl_importTQSLFile tqsl_init tqsl_initDate tqsl_initStationLocationCapture tqsl_initTime tqsl_isDateNull tqsl_isDateValid tqsl_isTimeValid tqsl_nextStationLocationCapture tqsl_prevStationLocationCapture tqsl_saveStationLocationCapture tqsl_selectCertificates tqsl_setADIFConverterDateFilter tqsl_setADIFMode tqsl_setCabrilloMapEntry tqsl_setConverterAllowBadCall tqsl_setConverterAllowDuplicates tqsl_setDirectory tqsl_setLocationFieldCharData tqsl_setLocationFieldIndex tqsl_setLocationFieldIntData tqsl_setStationLocationCaptureName tqsl_setStationLocationCapturePage tqsl_signDataBlock tqsl_signQSORecord tqsl_updateStationLocationCapture tqsl_verifyDataBlock tqsl_getLocationField tqsl_setLocationField tQSL_ADIF_Error DATA tQSL_Cabrillo_Error DATA tQSL_CustomError DATA tQSL_Errno DATA tQSL_Error DATA tQSL_ErrorFile DATA tQSL_DiagFile DATA tQSL_ImportCall DATA tQSL_ImportSerial DATA tqsl-2.8.2/src/tqsllib.spec.in0000644000175000017500000000276415061653721016245 0ustar rmurphyrmurphySummary: The TrustedQSL library Name: tqsllib Version: @VERSION@ Release: 2 Copyright: Custom BSD-like Group: Development/Libraries Source: tqsllib-%{version}.tar.gz BuildRoot: /var/tmp/%{name}-buildroot Requires: openssl expat zlib BuildPrereq: openssl-devel expat-devel zlib-devel %package devel Summary: The TrustedQSL Library development tools Group: System/Libraries %description The TrustedQSL library is used for generating digitally signed QSO records (records of Amateur Radio contacts). This package contains the library and configuration files needed to run TrustedQSL applications. %description devel The TrustedQSL library is used for generating digitally signed QSO records (records of Amateur Radio contacts). This package contains the header files needed to build TrustedQSL applications as well as a static tqsllib library and API documentation. %prep %setup -q -n tqsllib-%{version} %build # use --disable-docs because RPM handles docs itself cmake -DCMAKE_INSTALL_PREFIX=/usr . make %install make install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc LICENSE ChangeLog /usr/lib/libtqsllib.so /usr/lib/libtqsllib.so.1 /usr/lib/libtqsllib.so.1.0.0 /usr/share/tqsl/config.xml /usr/bin/dumptqsldata %files devel %defattr(-,root,root) %doc LICENSE ChangeLog doxygen/html /usr/lib/libtqsllib.a /usr/lib/libtqsllib.la /usr/include/tqsllib.h /usr/include/tqslerrno.h /usr/include/cabrillo.h /usr/include/adif.h /usr/include/tqslconvert.h %post /sbin/ldconfig %postun /sbin/ldconfig tqsl-2.8.2/src/tqsllib.rc.in0000644000175000017500000000210315061653721015702 0ustar rmurphyrmurphy#include 1 VERSIONINFO FILEVERSION @TQSLLIB_VERSION_MAJOR@, @TQSLLIB_VERSION_MINOR@, 0, 0 PRODUCTVERSION @TQSLLIB_VERSION_MAJOR@, @TQSLLIB_VERSION_MINOR@, 0, 0 FILEFLAGSMASK 0 FILEFLAGS VS_FFI_FILEFLAGSMASK FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL BEGIN BLOCK "StringFileInfo" BEGIN // Language type = U.S. English(0x0409) and Character Set = Windows, Multilingual(0x04e4) BLOCK "040904E4" // Matches VarFileInfo Translation hex value. BEGIN VALUE "CompanyName", "American Radio Relay League, Inc.\000" VALUE "FileDescription", "TrustedQSL Library\000" VALUE "FileVersion", "@TQSLLIB_VERSION@\000" VALUE "InternalName", "TQSLLIB\000" VALUE "LegalCopyright", "Copyright 2020 American Radio Relay League.\000" VALUE "OriginalFilename", "tqsllib@DLLVER@.dll\000" VALUE "ProductName", "TQSLLIB\000" VALUE "ProductVersion", "@TQSLLIB_VERSION@\000" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04e4 // U.S. English(0x0409) & Windows Multilingual(0x04e4) 1252 END END tqsl-2.8.2/src/tqsllib.h0000644000175000017500000017150315061653721015133 0ustar rmurphyrmurphy/*************************************************************************** tqsllib.h - description ------------------- begin : Mon May 20 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id: tqsllib.h,v 1.14 2013/03/01 13:26:44 k1mu Exp $ ***************************************************************************/ #ifndef TQSLLIB_H #define TQSLLIB_H #if defined(_WIN32) && !defined(TQSL_NODLL) #ifdef TQSLLIB_DEF #define DLLEXPORT __declspec(dllexport) #define DLLEXPORTDATA __declspec(dllexport) #define CALLCONVENTION __stdcall #else #define DLLEXPORT __declspec(dllimport) #define DLLEXPORTDATA __declspec(dllimport) #define CALLCONVENTION __stdcall #endif #else #define DLLEXPORT ///< Symbol exports - Windows only #define DLLEXPORTDATA ///< Symbol exports - Windows only #define CALLCONVENTION ///< Symbol exports - Windows only #include #endif #include #include "adif.h" #include "cabrillo.h" /** \file * tQSL library functions. */ #ifndef PATH_MAX // Should be set by #define PATH_MAX 4096 ///< Override in case not defined in limits.h #endif /* Sizes */ #define TQSL_MAX_PATH_LEN PATH_MAX ///< Max length of a FS path #define TQSL_PASSWORD_MAX 80 ///< Max password length #define TQSL_NAME_ELEMENT_MAX 256 ///< Max Org name length #define TQSL_CALLSIGN_MAX 20 ///< Max callsign length #define TQSL_CRQ_NAME_MAX 60 ///< Max length of request name #define TQSL_CRQ_ADDR_MAX 80 ///< Max length of request addr #define TQSL_CRQ_CITY_MAX 80 ///< Max length of request city #define TQSL_CRQ_STATE_MAX 80 ///< Max length of request state #define TQSL_CRQ_POSTAL_MAX 20 ///< Max length of request zip #define TQSL_CRQ_COUNTRY_MAX 80 ///< Max length of req entity #define TQSL_CRQ_EMAIL_MAX 180 ///< Max length of req email #define TQSL_BAND_MAX 6 ///< Max length of a band name #define TQSL_MODE_MAX 16 ///< Max length of a mode name #define TQSL_FREQ_MAX 20 ///< Max length of a frequency #define TQSL_SATNAME_MAX 20 ///< Max length of a sat name #define TQSL_PROPMODE_MAX 20 ///< Max length of a prop mode #define TQSL_STATE_MAX 30 ///< Max length of a state name #define TQSL_GRID_MAX 30 ///< Max length of a grid set #define TQSL_CNTY_MAX 30 ///< Max length of a county name #define TQSL_COUNTRY_MAX 60 ///< Max length of a country name #define TQSL_ZONE_MAX 5 ///< Max length of a zone number #define TQSL_IOTA_MAX 10 ///< Max length of a IOTA identifier #define TQSL_CERT_CB_USER 0 ///< Callback is for user cert #define TQSL_CERT_CB_CA 1 ///< Callback is for CA cert #define TQSL_CERT_CB_ROOT 2 ///< Callback is for root cert #define TQSL_CERT_CB_PKEY 3 ///< Callback is for private key #define TQSL_CERT_CB_CONFIG 4 ///< Callback for config file #define TQSL_CERT_CB_CERT_TYPE(x) ((x) & 0xf) ///< Type of the cert #define TQSL_CERT_CB_MILESTONE 0 ///< New certificate #define TQSL_CERT_CB_RESULT 0x10 ///< Cert import result #define TQSL_CERT_CB_CALL_TYPE(x) ((x) & TQSL_CERT_CB_RESULT) ///< Callback type #define TQSL_CERT_CB_PROMPT 0 ///< Callback prompt #define TQSL_CERT_CB_DUPLICATE 0x100 ///< Dupe cert callback #define TQSL_CERT_CB_ERROR 0x200 ///< Error import callback #define TQSL_CERT_CB_LOADED 0x400 ///< Cert loaded callback #define TQSL_CERT_CB_SERIAL 0x800 ///< User cert serial callback #define TQSL_CERT_CB_RESULT_TYPE(x) ((x) & 0x0f00) ///< Result type mask #define TQSL_MSG_FLAGGED 0x1000 ///< Alt message handling flag typedef void * tQSL_Cert; ///< Opaque certificate type typedef void * tQSL_Location; ///< Opaque location type typedef char * tQSL_StationDataEnc; ///< Opaque station data type /** Struct that holds y-m-d */ typedef struct { int year; ///< Numeric year int month; ///< Numeric month int day; ///< Numeric day } tQSL_Date; /** Struct that holds h-m-s */ typedef struct { int hour; ///< Time hour field int minute; ///< Time minute field int second; ///< Time seconds field } tQSL_Time; /** Certificate provider data */ typedef struct tqsl_provider_st { char organizationName[TQSL_NAME_ELEMENT_MAX+1]; ///< Provider name char organizationalUnitName[TQSL_NAME_ELEMENT_MAX+1]; ///< Provider unit char emailAddress[TQSL_NAME_ELEMENT_MAX+1]; ///< Provider e-mail char url[TQSL_NAME_ELEMENT_MAX+1]; ///< Provider URL } TQSL_PROVIDER; /** Certificate request data */ typedef struct tqsl_cert_req_st { ///< Cert request data char providerName[TQSL_NAME_ELEMENT_MAX+1]; ///< Provider name char providerUnit[TQSL_NAME_ELEMENT_MAX+1]; ///< Provider unit char callSign[TQSL_CALLSIGN_MAX+1]; ///< Callsign char name[TQSL_CRQ_NAME_MAX+1]; ///< Name char address1[TQSL_CRQ_ADDR_MAX+1]; ///< Address 1 char address2[TQSL_CRQ_ADDR_MAX+1]; ///< Address 2 char city[TQSL_CRQ_CITY_MAX+1]; ///< City char state[TQSL_CRQ_STATE_MAX+1]; ///< State char postalCode[TQSL_CRQ_POSTAL_MAX+1]; ///< Postal Code char country[TQSL_CRQ_COUNTRY_MAX+1]; ///< Country char emailAddress[TQSL_CRQ_EMAIL_MAX+1]; ///< e-mail int dxccEntity; ///< DXCC Entity code tQSL_Date qsoNotBefore; ///< QSOs not before date tQSL_Date qsoNotAfter; ///< QSOs not after date char password[TQSL_PASSWORD_MAX+1]; ///< Password tQSL_Cert signer; ///< Signing cert char renew; ///< Rewewal reference } TQSL_CERT_REQ; /** QSO data */ typedef struct { char callsign[TQSL_CALLSIGN_MAX+1]; ///< QSO callsign char band[TQSL_BAND_MAX+1]; ///< QSO band char mode[TQSL_MODE_MAX+1]; ///< QSO mode char submode[TQSL_MODE_MAX+1]; ///< QSO submode tQSL_Date date; ///< QSO date tQSL_Time time; ///< QSO time char freq[TQSL_FREQ_MAX+1]; ///< QSO frequency char rxfreq[TQSL_FREQ_MAX+1]; ///< QSO receive frequency char rxband[TQSL_BAND_MAX+1]; ///< QSO RX band char propmode[TQSL_PROPMODE_MAX+1]; ///< QSO prop mode char satname[TQSL_SATNAME_MAX+1]; ///< QSO satellite name bool callsign_set; ///< QSO specifies a call worked bool mode_set; ///< QSO specifies a mode bool band_set; ///< QSO specifies a band or frequency bool date_set; ///< QSO specifies a date bool time_set; ///< QSO specifies a time char my_state[TQSL_STATE_MAX+1]; ///< QSO specifies MY_STATE char my_gridsquare[TQSL_GRID_MAX+1]; ///< QSO specifies MY_GRIDSQUARE char my_vucc_grids[TQSL_GRID_MAX+1]; ///< QSO specifies MY_VUCC_GRIDS char my_county[TQSL_CNTY_MAX+1]; ///< QSO specifies MY_CNTY char my_cnty_state[TQSL_STATE_MAX+1]; ///< QSO specifies a state with MY_CNTY char my_country[TQSL_COUNTRY_MAX+1]; ///< QSO specifies MY_COUNTRY char my_cq_zone[TQSL_ZONE_MAX+1]; ///< QSO specifies MY_CQ_ZONE char my_itu_zone[TQSL_ZONE_MAX+1]; ///< QSO specifies MY_ITU_ZONE int my_dxcc; ///< QSO specifies MY_DXCC char my_call[TQSL_CALLSIGN_MAX+1]; ///< Station Callsign #ifdef USE_OWNER_CALLSIGN char my_owner[TQSL_CALLSIGN_MAX+1]; ///< Station Owner Callsign #endif char my_operator[TQSL_CALLSIGN_MAX+1]; ///< Operator's callsign char my_iota[TQSL_IOTA_MAX+1]; ///< QSO specifies MY_IOTA_ bool do_not_sign; ///< Don't sign this QSO } TQSL_QSO_RECORD; /// Base directory for tQSL library working files. DLLEXPORTDATA extern const char *tQSL_BaseDir; /// Directory for resources bundled with tqsl executable DLLEXPORTDATA extern const char *tQSL_RsrcDir; #ifdef __cplusplus extern "C" { #endif /** \defgroup Util Utility API */ /** @{ */ /// Error code from most recent tQSL library call. /** * The values for the error code are defined in tqslerrno.h */ DLLEXPORTDATA extern int tQSL_Error; /// The ADIF error code DLLEXPORTDATA extern TQSL_ADIF_GET_FIELD_ERROR tQSL_ADIF_Error; /// The ADIF error code DLLEXPORTDATA extern TQSL_CABRILLO_ERROR_TYPE tQSL_Cabrillo_Error; /// File name of file giving error. (May be empty.) DLLEXPORTDATA extern char tQSL_ErrorFile[TQSL_MAX_PATH_LEN]; /// Custom error message string DLLEXPORTDATA extern char tQSL_CustomError[256]; /// System errno - stored when tQSL_Error == TQSL_SYSTEM_ERROR DLLEXPORTDATA extern int tQSL_Errno; /// Callsign used in import - used for missing public key error DLLEXPORTDATA extern char tQSL_ImportCall[256]; /// Serial number of recent certificate import DLLEXPORTDATA extern long tQSL_ImportSerial; /// Diagnostic log file DLLEXPORTDATA extern FILE* tQSL_DiagFile; /** Initialize the tQSL library * * This function should be called prior to calling any other library functions. */ DLLEXPORT int CALLCONVENTION tqsl_init(); /** Set the directory where the TQSL files are kept. * May be called either before of after tqsl_init(), but should be called * before calling any other functions in the library. * * Note that this is purely optional. The library will figure out an * appropriate directory if tqsl_setDirectory isn't called. Unless there is * some particular need to set the directory explicitly, programs should * refrain from doing so. */ DLLEXPORT int CALLCONVENTION tqsl_setDirectory(const char *dir); /** Gets the error string for the current tQSL library error and resets the error status. * See tqsl_getErrorString_v(). */ DLLEXPORT const char* CALLCONVENTION tqsl_getErrorString(); /** Gets the error string corresponding to the given error number. * The error string is available only until the next call to * tqsl_getErrorString_v or tqsl_getErrorString. */ DLLEXPORT const char* CALLCONVENTION tqsl_getErrorString_v(int err); /** Encode a block of data into Base64 text. * * \li \c data = block of data to encode * \li \c datalen = length of \c data in bytes * \li \c output = pointer to output buffer * \li \c outputlen = size of output buffer in bytes */ DLLEXPORT int CALLCONVENTION tqsl_encodeBase64(const unsigned char *data, int datalen, char *output, int outputlen); /** Decode Base64 text into binary data. * * \li \c input = NUL-terminated text string of Base64-encoded data * \li \c data = pointer to output buffer * \li \c datalen = pointer to int containing the size of the output buffer in bytes * * Places the number of resulting data bytes into \c *datalen. */ DLLEXPORT int CALLCONVENTION tqsl_decodeBase64(const char *input, unsigned char *data, int *datalen); /** Initialize a tQSL_Date object from a date string. * * The date string must be YYYY-MM-DD or YYYYMMDD format. * * Returns 0 on success, nonzero on failure */ DLLEXPORT int CALLCONVENTION tqsl_initDate(tQSL_Date *date, const char *str); /** Initialize a tQSL_Time object from a time string. * * The time string must be HH[:]MM[[:]SS] format. * * Returns 0 on success, nonzero on failure */ DLLEXPORT int CALLCONVENTION tqsl_initTime(tQSL_Time *time, const char *str); /** Compare two tQSL_Date objects. * * Returns: * - -1 if \c a < \c b * * - 0 if \c a == \c b * * - 1 if \c a > \c b */ DLLEXPORT int CALLCONVENTION tqsl_compareDates(const tQSL_Date *a, const tQSL_Date *b); /** Calculate the number of days between two tQSL_Date objects. * * Returns a positive result if the first date is earlier, otherwise * negative. */ DLLEXPORT int CALLCONVENTION tqsl_subtractDates(const tQSL_Date *a, const tQSL_Date *b, int *diff); /** Converts a tQSL_Date object to a YYYY-MM-DD string. * * Returns a pointer to \c buf or NULL on error */ DLLEXPORT char* CALLCONVENTION tqsl_convertDateToText(const tQSL_Date *date, char *buf, int bufsiz); /** Test whether a tQSL_Date contains a valid date value * * Returns 1 if the date is valid */ DLLEXPORT int CALLCONVENTION tqsl_isDateValid(const tQSL_Date *d); /** Test whether a tQSL_Date is empty (contains all zeroes) * * Returns 1 if the date is null */ DLLEXPORT int CALLCONVENTION tqsl_isDateNull(const tQSL_Date *d); /** Test whether a tQSL_Time contains a valid time value * * Returns 1 if the time is valid */ DLLEXPORT int CALLCONVENTION tqsl_isTimeValid(const tQSL_Time *t); /** Converts a tQSL_Time object to a HH:MM:SSZ string. * * Returns a pointer to \c buf or NULL on error */ DLLEXPORT char* CALLCONVENTION tqsl_convertTimeToText(const tQSL_Time *time, char *buf, int bufsiz); /** Returns the library version. \c major and/or \c minor may be NULL. */ DLLEXPORT int CALLCONVENTION tqsl_getVersion(int *major, int *minor); /** Returns the configuration-file version. \c major and/or \c minor may be NULL. */ DLLEXPORT int CALLCONVENTION tqsl_getConfigVersion(int *major, int *minor); /** @} */ /** \defgroup CertStuff Certificate Handling API * * Certificates are managed by manipulating \c tQSL_Cert objects. A \c tQSL_Cert * contains: * * \li The identity of the organization that issued the certificate (the "issuer"). * \li The name and call sign of the amateur radio operator (ARO). * \li The DXCC entity number for which this certificate is valid. * \li The range of QSO dates for which this certificate can be used. * \li The resources needed to digitally sign and verify QSO records. * * The certificate management process consists of: * * \li Applying for a certificate. Certificate requests are produced via the * tqsl_createCertRequest() function, which produces a certificate-request * file to send to the issuer. * \li Importing the certificate file received from the issuer into the local * "certificate store," a directory managed by the tQSL library, via * tqsl_importTQSLFile(). * \li Selecting an appropriate certificate to use to sign a QSO record via * tqsl_selectCertificates(). */ /** @{ */ #define TQSL_SELECT_CERT_WITHKEYS 1 ///< Private keys only (no cert) #define TQSL_SELECT_CERT_EXPIRED 2 ///< Include expired certs #define TQSL_SELECT_CERT_SUPERCEDED 4 ///< Include superseded certs /** Get a list of certificates * * Selects a set of certificates from the user's certificate store * based on optional selection criteria. The function produces a * list of tQSL_Cert objects. * * \li \c certlist - Pointer to a variable that is set by the * function to point to the list of tQSL_Cert objects. * \li \c ncerts - Pointer to an int that is set to the number * of objects in the \c certlist list. * \li \c callsign - Optional call sign to match. * \li \c date - Optional QSO date string in ISO format. Only certs * that have a QSO date range that encompasses this date will be * returned. * \li \c issuer - Optional issuer (DN) string to match. * \li \c flag - OR of \c TQSL_SELECT_CERT_EXPIRED (include expired * certs), \c TQSL_SELECT_CERT_SUPERCEDED and \c TQSL_SELECT_CERT_WITHKEYS * (keys that don't have associated certs will be returned). * * Returns 0 on success, nonzero on failure. * * Each of the tQSL_Cert objects in the list should be freed * by calling tqsl_freeCertificate(). tqsl_freeCertificateList() is a better * function to use for that as it also frees the allocated array that * holds the certificate pointers. * */ DLLEXPORT int CALLCONVENTION tqsl_selectCertificates(tQSL_Cert **certlist, int *ncerts, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flag); /** Get a list of authority certificates * * Selects a set of certificates from the root or authorities certificate stores * The function produces a list of tQSL_Cert objects. * * Each of the tQSL_Cert objects in the list should be freed * by calling tqsl_freeCertificate(). tqsl_freeCertificateList() is a better * function to use for that as it also frees the allocated array that * holds the certificate pointers. * */ DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates(tQSL_Cert **certlist, int *ncerts, const char *type); /** Get a particulat certificate from the list returnded by * tqsl_selectCertificates. This function exists principally * to make it easier for VB programs to access the list of * certificates. * * It is the caller's responsibility to ensure that 0 <= idx < ncerts * (where ncerts is the value returned by tqsl_selectCertificates) */ DLLEXPORT int CALLCONVENTION tqsl_getSelectedCertificate(tQSL_Cert *cert, const tQSL_Cert **certlist, int idx); /** Find out if the "certificate" is expired */ DLLEXPORT int CALLCONVENTION tqsl_isCertificateExpired(tQSL_Cert cert, int *status); /** Find out if the "certificate" is superceded */ DLLEXPORT int CALLCONVENTION tqsl_isCertificateSuperceded(tQSL_Cert cert, int *status); /** Find out if the "certificate" is just a key pair. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateKeyOnly(tQSL_Cert cert, int *keyonly); /** Find out if the "certificate" is renewable */ DLLEXPORT int CALLCONVENTION tqsl_isCertificateRenewable(tQSL_Cert cert, int *status); /** Get the encoded certificate for inclusion in a GABBI file. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateEncoded(tQSL_Cert cert, char *buf, int bufsiz); /** Get the encoded private key for inclusion in a backup file. */ DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded(tQSL_Cert cert, char *buf, int bufsiz); /** Import a base64 encoded certificate and private key from a backup file. */ DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded(const char *callsign, const char *type, const char *keybuf, const char *certbuf); /** Get the issuer's serial number of the certificate. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerial(tQSL_Cert cert, long *serial); /** Get the issuer's serial number of the certificate as a hexadecimal string. * Needed for certs with long serial numbers (typically root certs). */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt(tQSL_Cert cert, char *serial, int serialsiz); /** Get the length of the issuer's serial number of the certificate as it will be * returned by tqsl_getCertificateSerialExt. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialLength(tQSL_Cert cert); /** Get the issuer (DN) string from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuer(tQSL_Cert cert, char *buf, int bufsiz); /** Get the issuer's organization name from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganization(tQSL_Cert cert, char *buf, int bufsiz); /** Get the issuer's organizational unit name from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganizationalUnit(tQSL_Cert cert, char *buf, int bufsiz); /** Get the ARO call sign string from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateCallSign(tQSL_Cert cert, char *buf, int bufsiz); /** Get the ARO name string from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateAROName(tQSL_Cert cert, char *buf, int bufsiz); /** Get the email address from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateEmailAddress(tQSL_Cert cert, char *buf, int bufsiz); /** Get the QSO not-before date from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c date - Pointer to a tQSL_Date struct to hold the returned date. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotBeforeDate(tQSL_Cert cert, tQSL_Date *date); /** Get the QSO not-after date from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c date - Pointer to a tQSL_Date struct to hold the returned date. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotAfterDate(tQSL_Cert cert, tQSL_Date *date); /** Get the certificate's not-before date from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c date - Pointer to a tQSL_Date struct to hold the returned date. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotBeforeDate(tQSL_Cert cert, tQSL_Date *date); /** Get the certificate's not-after date from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c date - Pointer to a tQSL_Date struct to hold the returned date. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotAfterDate(tQSL_Cert cert, tQSL_Date *date); /** Get the DXCC entity number from a tQSL_Cert. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c dxcc - Pointer to an int to hold the returned date. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateDXCCEntity(tQSL_Cert cert, int *dxcc); /** Get the first address line from the certificate request used in applying * for a tQSL_Cert certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress1(tQSL_Cert cert, char *str, int bufsiz); /** Get the second address line from the certificate request used in applying * for a tQSL_Cert certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress2(tQSL_Cert cert, char *str, int bufsiz); /** Get the city from the certificate request used in applying * for a tQSL_Cert certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCity(tQSL_Cert cert, char *str, int bufsiz); /** Get the state from the certificate request used in applying * for a tQSL_Cert certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestState(tQSL_Cert cert, char *str, int bufsiz); /** Get the postal (ZIP) code from the certificate request used in applying * for a tQSL_Cert certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestPostalCode(tQSL_Cert cert, char *str, int bufsiz); /** Get the country from the certificate request used in applying * for a tQSL_Cert certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * \li \c buf - Buffer to hold the returned string. * \li \c bufsiz - Size of \c buf. * * Returns 0 on success, nonzero on failure. */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCountry(tQSL_Cert cert, char *str, int bufsiz); #define TQSL_PK_TYPE_ERR 0 ///< Error retrieving private key #define TQSL_PK_TYPE_NONE 1 ///< No private key #define TQSL_PK_TYPE_UNENC 2 ///< Private key is not encrypted #define TQSL_PK_TYPE_ENC 3 ///< Private key is encrypted /** Determine the nature of the private key associated with a * certificate. * * \li \c cert - a tQSL_Cert object, normally one returned from * tqsl_selectCertificates() * * Returns one of the following values: * * \li \c TQSL_PK_TYPE_ERR - An error occurred. Use tqsl_getErrorString() to examine. * \li \c TQSL_PK_TYPE_NONE - No matching private key was found. * \li \c TQSL_PK_TYPE_UNENC - The matching private key is unencrypted. * \li \c TQSL_PK_TYPE_ENC - The matching private key is encrypted * (password protected). */ DLLEXPORT int CALLCONVENTION tqsl_getCertificatePrivateKeyType(tQSL_Cert cert); /** Free the memory used by the tQSL_Cert. Once this function is called, * \c cert should not be used again in any way. */ DLLEXPORT void CALLCONVENTION tqsl_freeCertificate(tQSL_Cert cert); /** Free the memory used by a certificate list. The allocated list * of tQSL_Certs are freed and the pointer array is freed. * Once this function is called, the \c list or the \c cert * should not be used again in any way. */ DLLEXPORT void CALLCONVENTION tqsl_freeCertificateList(tQSL_Cert* list, int ncerts); #define TQSL_CERT_STATUS_UNK 0 ///< Status is unknown #define TQSL_CERT_STATUS_SUP 1 ///< Certificate is superceded #define TQSL_CERT_STATUS_EXP 2 ///< Certificate is expired #define TQSL_CERT_STATUS_OK 3 ///< Certificate is valid #define TQSL_CERT_STATUS_INV 4 ///< Invalid serial number /** Determine the status of a callsign certificate * \li \c serial - the serial number of the certificate * tqsl_selectCertificates() * \li \c status - an integer to receive the certificate status * * Returns one of the following values: * * \li \c TQSL_CERT_STATUS_UNK - An error occurred and the status is unknown * \li \c TQSL_CERT_STATUS_SUP - The certificate has been superceded * \li \c TQSL_CERT_STATUS_EXP - The certificate has expired * \li \c TQSL_CERT_STATUS_OK - The certificate is valid * \li \c TQSL_CERT_STATUS_INV - The serial number supplied is invalid * */ DLLEXPORT int CALLCONVENTION tqsl_getCertificateStatus(long serial); /** Store the status of a callsign certificate * \li \c serial - serial number of the certificate * \li \c status - the status value to store. */ DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus(long serial, const char *status); /* int tqsl_checkCertificate(tQSL_Cert); */ /** Import a Gabbi cert file received from a CA * * The callback, \c cb, will be called whenever a certificate is ready * to be imported: * * cb(type, message); * * \c type has several fields that can be accessed via macros: * * \c TQSL_CERT_CB_CALL_TYPE(type) := \c TQSL_CERT_CB_MILESTONE | \c TQSL_CERT_CB_RESULT * * \c TQSL_CERT_CB_CERT_TYPE(type) := \c TQSL_CERT_CB_ROOT | \c TQSL_CERT_CB_CA | \c TQSL_CERT_CB_USER * * \c TQSL_CERT_CB_RESULT_TYPE(type) := \c TQSL_CERT_CB_PROMPT | \c TQSL_CERT_CB_WARNING | \c TQSL_CERT_CB_ERROR * * \c TQSL_CERT_CB_RESULT_TYPE() is meaningful only if \c TQSL_CERT_CB_CALL_TYPE() == \c TQSL_CERT_CB_RESULT */ DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile(const char *file, int(*cb)(int type, const char *message, void *userdata), void *user); /** Get the serial for the first user cert from a .tq6 file * used to support asking the user to save their cert after import * \li \c file is the path to the file * \li \c serial is where the serial number is returned * * Returns 0 on success, nonzero on failure. * */ DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile(const char *file, long *serial); /** Get the number of certificate providers known to tqsllib. */ DLLEXPORT int CALLCONVENTION tqsl_getNumProviders(int *n); /** Get the information for a certificate provider. * * \li \c idx is the index, 0 <= idx < tqsl_getNumProviders() */ DLLEXPORT int CALLCONVENTION tqsl_getProvider(int idx, TQSL_PROVIDER *provider); /** Create a certificate-request Gabbi file. * * The \c req parameter must be properly populated with the required fields. * * If \c req->password is NULL and \c cb is not NULL, the callback will be * called to acquire the password. Otherwise \c req->password will be used as * the password. If the password is NULL or an empty string the generated * private key will be stored unencrypted. * * If req->signer is not zero and the signing certificate requires a password, * the password may be in req->signer_password, else signer_pwcb is called. */ DLLEXPORT int CALLCONVENTION tqsl_createCertRequest(const char *filename, TQSL_CERT_REQ *req, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user); /** Save a key pair and certificates to a file in PKCS12 format. * * The tQSL_Cert must be initialized for signing (see tqsl_beginSigning()) * if the user certificate is being exported. * * The supplied \c p12password is used to encrypt the PKCS12 data. */ DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File(tQSL_Cert cert, const char *filename, const char *p12password); /** Save a key pair and certificates to a file in PKCS12 format. * Use downgraded crypto for Apple Keyring compatibility. * * The tQSL_Cert must be initialized for signing (see tqsl_beginSigning()) * if the user certificate is being exported. * * The supplied \c p12password is used to encrypt the PKCS12 data. */ DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto(tQSL_Cert cert, const char *filename, const char *p12password); /** Save a key pair and certificates to a Base64 string in PKCS12 format. * * The tQSL_Cert must be initialized for signing (see tqsl_beginSigning()) * if the user certificate is being exported. * * The supplied \c p12password is used to encrypt the PKCS12 data. */ DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64(tQSL_Cert cert, char *base64, int b64len, const char *p12password); /** Load certificates and a private key from a PKCS12 file. */ DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File(const char *filename, const char *p12password, const char *password, int (*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type , const char *message, void *userdata), void *user); /** Load certificates and a private key from a Base64 encoded PKCS12 string. */ DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64(const char *base64, const char *p12password, const char *password, int (*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type , const char *message, void *userdata), void *user); /** Get the list of restorable station locations. */ DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates(char ***calls, int *ncall, const char *filter); /** Free the list of restorable Callsign Certificates. */ DLLEXPORT void CALLCONVENTION tqsl_freeDeletedCertificateList(char **list, int nloc); /** Restore a deleted callsign certificate by callsign. */ DLLEXPORT int CALLCONVENTION tqsl_restoreCallsignCertificate(const char *callsign); /** Delete a certificate and private key */ DLLEXPORT int CALLCONVENTION tqsl_deleteCertificate(tQSL_Cert cert); /** @} */ /** \defgroup Sign Signing API * * The Signing API uses a tQSL_Cert (see \ref CertStuff) to digitally * sign a block of data. */ /** @{ */ /** Initialize the tQSL_Cert object for use in signing. * * This produces an unencrypted copy of the private key in memory. * * if \c password is not NULL, it must point to the password to use to decrypt * the private key. If \c password is NULL and \c pwcb is not NULL, \c pwcb * is called to get the password. If the private key is encrypted and both * \c password and \c pwcb are NULL, or if the supplied password fails to * decrypt the key, a TQSL_PASSWORD_ERROR error is returned. * * \c pwcb parameters: \c pwbuf is a pointer to a buffer of \c pwsize chars. * The buffer should be NUL-terminated. */ DLLEXPORT int CALLCONVENTION tqsl_beginSigning(tQSL_Cert cert, char *password, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user); /** Test whether the tQSL_Cert object is initialized for signing. * * Returns 0 if initialized. Sets tQSL_Error to TQSL_SIGNINIT_ERROR if not. */ DLLEXPORT int CALLCONVENTION tqsl_checkSigningStatus(tQSL_Cert cert); /** Get the maximum size of a signature block that will be produced * when the tQSL_Cert is used to sign data. (Note that the size of the * signature block is unaffected by the size of the data block being signed.) */ DLLEXPORT int CALLCONVENTION tqsl_getMaxSignatureSize(tQSL_Cert cert, int *sigsize); /** Sign a data block. * * tqsl_beginSigning() must have been called for * the tQSL_Cert object before calling this function. */ DLLEXPORT int CALLCONVENTION tqsl_signDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen); /** Verify a signed data block. * * tqsl_beginSigning() need \em not have been called. */ DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen); /** Sign a single QSO record * * tqsl_beginSigning() must have been called for * the tQSL_Cert object before calling this function. * * \c loc must be a valid tQSL_Location object. See \ref Data. */ DLLEXPORT int CALLCONVENTION tqsl_signQSORecord(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *rec, unsigned char *sig, int *siglen); /** Terminate signing operations for this tQSL_Cert object. * * This zero-fills the unencrypted private key in memory. */ DLLEXPORT int CALLCONVENTION tqsl_endSigning(tQSL_Cert cert); /** @} */ /** \defgroup Data Data API * * The Data API is used to form data into TrustedQSL records. A TrustedQSL record * consists of a station record and a QSO record. Together, the two records * fully describe one station's end of the QSO -- just as a paper QSL card does. * * The station record contains the callsign and geographic location of the * station submitting the QSO record. The library manages the station records. * The tqsl_xxxStationLocationCapture functions are used to generate and save * a station record. The intent is to provide an interface that makes a step-by-step * system (such as a GUI "wizard") easily implemented. * * The tqsl_getStationLocation() function is used to retrieve station records. * * With the necessary station location available, a signed GABBI output file can * be generated using the tqsl_getGABBIxxxxx functions: * * \li tqsl_getGABBItCERT() - Returns a GABBI tCERT record for the given tQSL_Cert * \li tqsl_getGABBItSTATION() - Returns a GABBI tSTATION record for the given * tQSL_Location * \li tqsl_getGABBItCONTACT() - Returns a GABBI tCONTACT record for the given * TQSL_QSO_RECORD, using the given tQSL_Cert and tQSL_Location. * \li tqsl_getGABBItCONTACTData() - Returns a GABBI tCONTACT record and the * SIGNDATA for the given TQSL_QSO_RECORD, using the given tQSL_Cert and * tQSL_Location. * * The GABBI format requires that the tCERT record contain an integer identifier * that is unique within the GABBI file. Similarly, each tSTATION record must * contain a unique identifier. Additionally, the tSTATION record must reference * the identifier of a preceding tCERT record. Finally, each tCONTACT record must * reference a preceding tSTATION record. (A GABBI processor uses these identifiers * and references to tie the station and contact records together and to verify * their signature via the certificate.) It is the responsibility of the caller * to supply these identifiers and to ensure that the supplied references match * the tQSL_Cert and tQSL_Location used to create the referenced GABBI records. * * Station Location Generation * * The station-location generation process involves determining the values * for a number of station-location parameters. Normally this * will be done by prompting the user for the values. The responses given * by the user may determine which later fields are required. For example, * if the user indicates that the DXCC entity is UNITED STATES, a later * field would ask for the US state. This field would not be required if the * DXCC entity were not in the US. * * To accommodate the dynamic nature of the field requirements, the fields * are ordered such that dependent fields are queried after the field(s) * on which they depend. To make this process acceptable in a GUI * system, the fields are grouped into pages, where multiple fields may * be displayed on the same page. The grouping is such that which fields * are within the page is not dependent on any of the values of the * fields within the page. That is, a page of fields contains the same * fields no matter what value any of the fields contains. (However, * the \em values of fields within the page can depend on the values * of fields that precede them in the page.) * * Here is a brief overview of the sequence of events involved in * generating a station location interactively, one field at a time: * * 1) Call tqsl_initStationLocationCapture() (new location) or tqsl_getStationLocation() * (existing location). * * 2) For \c field from 0 to tqsl_getNumLocationField(): * \li Display the field label [tqsl_getLocationFieldDataLabel()] * \li Get the field content from the user. This can be a selection * from a list, an entered integer or an entered character string, * depending on the value returned by tqsl_getLocationFieldInputType(). * * 3) If tqsl_hasNextStationLocationCapture() returns 1, call * tqsl_nextStationLocationCapture() and go back to step 2. * * In the case of a GUI system, you'll probably want to display the * fields in pages. The sequence of events is a bit different: * * 1) Call tqsl_initStationLocationCapture() (new location) or tqsl_getStationLocation() * (existing location). * * 2) For \c field from 0 to tqsl_getNumLocationField(), * \li Display the field label [tqsl_getLocationFieldDataLabel()] * \li Display the field-input control This can be a list-selection * or an entered character string or integer, depending on the value * returned by tqsl_getLocationFieldInputType(). * * 3) Each time the user changes a field, call tqsl_updateStationLocationCapture(). * This may change the allowable selection for fields that follow the field * the user changed, so the control for each of those fields should be updated * as in step 2. * * 4) Once the user has completed entries for the page, if * tqsl_hasNextStationLocationCapture() returns 1, call * tqsl_nextStationLocationCapture() and go back to step 2. * * N.B. The first two fields in the station-location capture process are * always call sign and DXCC entity, in that order. As a practical matter, these * two fields must match the corresponding fields in the available certificates. * The library will therefore constrain the values of these fields to match * what's available in the certificate store. See \ref CertStuff. */ /** @{ */ /* Location field input types */ #define TQSL_LOCATION_FIELD_TEXT 1 ///< Text type input field #define TQSL_LOCATION_FIELD_DDLIST 2 ///< Dropdown list input field #define TQSL_LOCATION_FIELD_LIST 3 ///< List type input field #define TQSL_LOCATION_FIELD_BADZONE 4 ///< Used to return zone selection errors /* Location field data types */ #define TQSL_LOCATION_FIELD_CHAR 1 ///< Character field #define TQSL_LOCATION_FIELD_INT 2 ///< Integer field /** Begin the process of generating a station record */ DLLEXPORT int CALLCONVENTION tqsl_initStationLocationCapture(tQSL_Location *locp); /** Release the station-location resources. This should be called for * any tQSL_Location that was initialized via tqsl_initStationLocationCapture() * or tqsl_getStationLocation() */ DLLEXPORT int CALLCONVENTION tqsl_endStationLocationCapture(tQSL_Location *locp); /** Update the pages based on the currently selected settings. */ DLLEXPORT int CALLCONVENTION tqsl_updateStationLocationCapture(tQSL_Location loc); /** Return the number of station location capture pages. */ DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocationCapturePages(tQSL_Location loc, int *npages); /** Get the current page number */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCapturePage(tQSL_Location loc, int *page); /** Set the current page number. * Typically, the page number will be 1 (the starting page) or a value * obtained from tqsl_getStationLocationCapturePage(). */ DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCapturePage(tQSL_Location loc, int page); /** Set the certificate flags used in a location page. * This is used to enable expired certs (or disable). */ DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCertFlags(tQSL_Location loc, int flags); /** Advance the page to the next one in the page sequence */ DLLEXPORT int CALLCONVENTION tqsl_nextStationLocationCapture(tQSL_Location loc); /** Return the next page to in the page sequence */ DLLEXPORT int CALLCONVENTION tqsl_getNextStationLocationCapturePage(tQSL_Location loc, int *page); /** Return the page to the previous one in the page sequence. */ DLLEXPORT int CALLCONVENTION tqsl_prevStationLocationCapture(tQSL_Location loc); /** Return the previous page in the page sequence. */ DLLEXPORT int CALLCONVENTION tqsl_getPrevStationLocationCapturePage(tQSL_Location loc, int *page); /** Return the current page in the page sequence. */ DLLEXPORT int CALLCONVENTION tqsl_getCurrentStationLocationCapturePage(tQSL_Location loc, int *page); /** Returns 1 (in rval) if there is a next page */ DLLEXPORT int CALLCONVENTION tqsl_hasNextStationLocationCapture(tQSL_Location loc, int *rval); /** Returns 1 (in rval) if there is a previous page */ DLLEXPORT int CALLCONVENTION tqsl_hasPrevStationLocationCapture(tQSL_Location loc, int *rval); /** Save the station location data. Note that the name must have been * set via tqsl_setStationLocationCaptureName if this is a new * station location. If the \c overwrite parameter is zero and a * station location of that name is already in existence, an error * occurs with tQSL_Error set to TQSL_NAME_EXISTS. */ DLLEXPORT int CALLCONVENTION tqsl_saveStationLocationCapture(tQSL_Location loc, int overwrite); /** Get the name of the station location */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCaptureName(tQSL_Location loc, char *namebuf, int bufsiz); /** Set the name of the station location */ DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCaptureName(tQSL_Location loc, const char *name); /** Get the number of saved station locations */ DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocations(tQSL_Location loc, int *nloc); /** Get the name of the specified (by \c idx) saved station location */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocationName(tQSL_Location loc, int idx, char *buf, int bufsiz); /** Get the call sign from the station location */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCallSign(tQSL_Location loc, int idx, char *buf, int bufsiz); /** Get a named field from the station location */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField(tQSL_Location locp, const char *name, char *namebuf, int bufsize); /** Retrieve a saved station location. * Once finished with the station location, tqsl_endStationLocationCapture() * should be called to release resources. */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocation(tQSL_Location *loc, const char *name); /** Get any errors returned from parsing the selected station location. * This should be called after tqsl_getStationLocation to determine if * any of the existing fields failed validation. Currently only zone * data is validated here, but future validations for things like * properly formatted grid squares is likely. */ DLLEXPORT int CALLCONVENTION tqsl_getStationLocationErrors(tQSL_Location loc, char *buf, int bufsiz); /** Return the contents of the station data file as a byte stream. * The caller is required to tqsl_freeStationDataEnc() this pointer when done with it. */ DLLEXPORT int CALLCONVENTION tqsl_getStationDataEnc(tQSL_StationDataEnc *sdata); /** Free the pointer returned by tqsl_getStationDataEnc(tQSL_StationDataEnc*) */ DLLEXPORT int CALLCONVENTION tqsl_freeStationDataEnc(tQSL_StationDataEnc sdata); /** Merge saved location data with existing */ DLLEXPORT int CALLCONVENTION tqsl_mergeStationLocations(const char *locdata); /** Remove the stored station location by name. */ DLLEXPORT int CALLCONVENTION tqsl_deleteStationLocation(const char *name); /** Restore the deleted station location by name. */ DLLEXPORT int CALLCONVENTION tqsl_restoreStationLocation(const char *name); /** Get the list of restorable station locations. */ DLLEXPORT int CALLCONVENTION tqsl_getDeletedStationLocations(char ***locp, int *nloc); /** Free the list of restorable station locations. */ DLLEXPORT void CALLCONVENTION tqsl_freeDeletedLocationList(char **list, int nloc); /** Get the number of fields on the current station location page */ DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField(tQSL_Location loc, int *numf); /** Get the number of characters in the label for the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize(tQSL_Location loc, int field_num, int *rval); /** Get the label for the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel(tQSL_Location loc, int field_num, char *buf, int bufsiz); /** Get the size of the GABBI name of the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize(tQSL_Location loc, int field_num, int *rval); /** Get the GABBI name of the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI(tQSL_Location loc, int field_num, char *buf, int bufsiz); /** Get the input type of the input field. * * \c type will be one of TQSL_LOCATION_FIELD_TEXT, TQSL_LOCATION_FIELD_DDLIST * or TQSL_LOCATION_FIELD_LIST */ /** Get the number of fields on the current station location page */ DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField(tQSL_Location loc, int *numf); /** Get the number of characters in the label for the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize(tQSL_Location loc, int field_num, int *rval); /** Get the label for the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel(tQSL_Location loc, int field_num, char *buf, int bufsiz); /** Get the size of the GABBI name of the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize(tQSL_Location loc, int field_num, int *rval); /** Get the GABBI name of the specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI(tQSL_Location loc, int field_num, char *buf, int bufsiz); /** Get the input type of the input field. * * \c type will be one of TQSL_LOCATION_FIELD_TEXT, TQSL_LOCATION_FIELD_DDLIST * or TQSL_LOCATION_FIELD_LIST */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldInputType(tQSL_Location loc, int field_num, int *type); /** Get the data type of the input field. * * \c type will be either TQSL_LOCATION_FIELD_CHAR or TQSL_LOCATION_FIELD_INT */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataType(tQSL_Location loc, int field_num, int *type); /** Get the flags for the input field. * * \c flags will be either * TQSL_LOCATION_FIELD_UPPER Field is to be uppercased on input * TQSL_LOCATION_FIELD_MUSTSEL Value must be selected * TQSL_LOCATION_FIELD_SELNXT Value must be selected to allow Next/Finish * */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldFlags(tQSL_Location loc, int field_num, int *flags); /** Get the length of the input field data. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLength(tQSL_Location loc, int field_num, int *rval); /** Get the character data from the specified field. * * If the field input type (see tqsl_getLocationFieldInputType()) is * TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST, this will * return the text of the selected item. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData(tQSL_Location loc, int field_num, char *buf, int bufsiz); /** Get the integer data from the specified field. * * This is only meaningful if the field data type (see tqsl_getLocationFieldDataType()) * is TQSL_LOCATION_FIELD_INT. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIntData(tQSL_Location loc, int field_num, int *dat); /** If the field input type (see tqsl_getLocationFieldInputType()) is * TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST, gets the * index of the selected list item. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIndex(tQSL_Location loc, int field_num, int *dat); /** Get the number of items in the specified field's pick list. */ DLLEXPORT int CALLCONVENTION tqsl_getNumLocationFieldListItems(tQSL_Location loc, int field_num, int *rval); /** Get the text of a specified item of a specified field */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem(tQSL_Location loc, int field_num, int item_idx, char *buf, int bufsiz); /** Set the text data of a specified field. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldCharData(tQSL_Location loc, int field_num, const char *buf); /** Set the integer data of a specified field. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIntData(tQSL_Location loc, int field_num, int dat); /** If the field input type (see tqsl_getLocationFieldInputType()) is * TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST, sets the * index of the selected list item. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIndex(tQSL_Location loc, int field_num, int dat); /** Get the \e changed status of a field. The changed flag is set to 1 if the * field's pick list was changed during the last call to tqsl_updateStationLocationCapture * or zero if the list was not changed. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldChanged(tQSL_Location loc, int field_num, int *changed); /** Get the call sign from the station location. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationCallSign(tQSL_Location loc, char *buf, int bufsiz); /** Set the call sign for the station location. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationCallSign(tQSL_Location loc, const char *buf, int dxcc); /** Get a field from the station location. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationField(tQSL_Location locp, const char *field, char *buf, int bufsiz); /** Get a field label from the station location. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel(tQSL_Location locp, const char *field, char *buf, int bufsiz); /** Set a field in a station location. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationField(tQSL_Location locp, const char *field, const char *buf); /** Get the DXCC entity from the station location. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationDXCCEntity(tQSL_Location loc, int *dxcc); /** Get the QSO details in canonical form. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationQSODetails(tQSL_Location locp, char *buf, int buflen); /** Get the station location details in canonical form. */ DLLEXPORT int CALLCONVENTION tqsl_getLocationStationDetails(tQSL_Location locp, char *buf, int buflen); /** Save the json results for a given callsign location Detail. */ DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo(const char *callsign, const char *json); /** Retrieve the json results for a given callsign location Detail. */ DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo(const char *callsign, char **buf); #define TQSL_VALID_VUCC_ENT 0x2000 ///< Grid is valid for DXCC Entity #define TQSL_VALID_VUCC_PAS 0x4000 ///< Grid is valid for Primary Administrative Subdivision (State, etc.) /** Validate that a given four-character gridsquare is acceptable for entity and primary administrative subdivision */ DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid(int entity, const char *pas, const char *grid, int *result); /** Get the number of DXCC entities in the primary DXCC list. */ DLLEXPORT int CALLCONVENTION tqsl_getNumDXCCEntity(int *number); /** Get a DXCC entity from the list of DXCC entities by its index. */ DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity(int index, int *number, const char **name); /** Get the name of a DXCC Entity by its DXCC number. */ DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName(int number, const char **name); /** Get the zonemap of a DXCC Entity by its DXCC number. */ DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap(int number, const char **zonemap); /** Get the start date of a DXCC Entity by its DXCC number. */ DLLEXPORT int CALLCONVENTION tqsl_getDXCCStartDate(int number, tQSL_Date *d); /** Get the end date of a DXCC Entity by its DXCC number. */ DLLEXPORT int CALLCONVENTION tqsl_getDXCCEndDate(int number, tQSL_Date *d); /** Get the deleted status of a DXCC Entity by its DXCC number. */ DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted(int number, int *deleted); /** Get the number of Band entries in the Band list */ DLLEXPORT int CALLCONVENTION tqsl_getNumBand(int *number); /** Get a band by its index. * * \c name - The GAABI name of the band. * \c spectrum - HF | VHF | UHF * \c low - The low end of the band in kHz (HF) or MHz (VHF/UHF) * \c high - The low high of the band in kHz (HF) or MHz (VHF/UHF) * * Note: \c spectrum, \c low and/or \c high may be NULL. */ DLLEXPORT int CALLCONVENTION tqsl_getBand(int index, const char **name, const char **spectrum, int *low, int *high); /** Get the number of Mode entries in the Mode list */ DLLEXPORT int CALLCONVENTION tqsl_getNumMode(int *number); /** Get a mode by its index. * * \c mode - The GAABI mode name * \c group - CW | PHONE | IMAGE | DATA * * Note: \c group may be NULL. */ DLLEXPORT int CALLCONVENTION tqsl_getMode(int index, const char **mode, const char **group); /** Get the number of ADIF Mode entries in the Mode list */ DLLEXPORT int CALLCONVENTION tqsl_getNumADIFMode(int *number); /** Get an ADIF mode by its index. * * \c mode - The ADIF mode name * */ DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry(int index, const char **mode); /** Get the number of Propagation Mode entries in the Propagation Mode list */ DLLEXPORT int CALLCONVENTION tqsl_getNumPropagationMode(int *number); /** Get a propagation mode by its index. * * \c name - The GAABI propagation mode name * \c descrip - Text description of the propagation mode * * Note: \c descrip may be NULL. */ DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode(int index, const char **name, const char **descrip); /** Get the number of Satellite entries in the Satellite list */ DLLEXPORT int CALLCONVENTION tqsl_getNumSatellite(int *number); /** Get a satellite by its index. * * \c name - The GAABI satellite name * \c descrip - Text description of the satellite * \c start - The date the satellite entered service * \c end - The last date the satellite was in service * * Note: \c descrip, start and/or end may be NULL. */ DLLEXPORT int CALLCONVENTION tqsl_getSatellite(int index, const char **name, const char **descrip, tQSL_Date *start, tQSL_Date *end); /** Clear the map of Cabrillo contests. */ DLLEXPORT int CALLCONVENTION tqsl_clearCabrilloMap(); /** Set the mapping of a Cabrillo contest name (as found in the * CONTEST line of a Cabrillo file) to the QSO line call-worked field number * and the contest type. * * \c field can have a value of TQSL_MIN_CABRILLO_MAP_FIELD (cabrillo.h) * or greater. Field number starts at 1. * * \c contest_type must be TQSL_CABRILLO_HF or TQSL_CABRILLO_VHF, * defined in cabrillo.h */ DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry(const char *contest, int field, int contest_type); /** Get the mapping of a Cabrillo contest name (as found in the * CONTEST line of a Cabrillo file) to a call-worked field number * and the contest type. * * \c fieldnum will be set to 0 if the contest name isn't in the Cabrillo * map. Otherwise it is set to the QSO line field number of the call-worked * field, with field counting starting at 1. * * \c contest_type may be NULL. If not, it is set to the Cabrillo contest * type (TQSL_CABRILLO_HF or TQSL_CABRILLO_VHF), defined in cabrillo.h. */ DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry(const char *contest, int *fieldnum, int *contest_type); /** Clear the map of ADIF modes */ DLLEXPORT int CALLCONVENTION tqsl_clearADIFModes(); /** Set the mapping of an ADIF mode to a TQSL mode. */ DLLEXPORT int CALLCONVENTION tqsl_setADIFMode(const char *adif_item, const char *mode); /** Map an ADIF mode to its TQSL equivalent. */ DLLEXPORT int CALLCONVENTION tqsl_getADIFMode(const char *adif_item, char *mode, int nmode); /** Map a GABBI mode to its mode/submode pair. */ DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode(const char *adif_item, char *mode, char *submode, int nmode); /** Get a GABBI record that contains the certificate. * * \c uid is the value for the CERT_UID field * * Returns the NULL pointer on error. * * N.B. On systems that distinguish text-mode files from binary-mode files, * notably Windows, the GABBI records should be written in binary mode. */ DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItCERT(tQSL_Cert cert, int uid); /** Get a GABBI record that contains the Station Location data. * * \li \c uid is the value for the STATION_UID field. * \li \c certuid is the value of the associated CERT_UID field. * * Returns the NULL pointer on error. * * N.B. On systems that distinguish text-mode files from binary-mode files, * notably Windows, the GABBI records should be written in binary mode. */ DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItSTATION(tQSL_Location loc, int uid, int certuid); /** Get a GABBI record that contains the QSO data. * * \li \c stationuid is the value of the associated STATION_UID field. * * N.B.: If \c cert is not initialized for signing (see tqsl_beginSigning()) * the function will return with a TQSL_SIGNINIT_ERROR error. * * Returns the NULL pointer on error. * * N.B. On systems that distinguish text-mode files from binary-mode files, * notably Windows, the GABBI records should be written in binary mode. */ DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItCONTACT(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid); /** Get a GABBI record that contains the QSO data along with the associated * signdata (QSO data signed to validate the QSO). * * \li \c stationuid is the value of the associated STATION_UID field. * * N.B.: If \c cert is not initialized for signing (see tqsl_beginSigning()) * the function will return with a TQSL_SIGNINIT_ERROR error. * * Returns the NULL pointer on error. * * N.B. On systems that distinguish text-mode files from binary-mode files, * notably Windows, the GABBI records should be written in binary mode. */ DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItCONTACTData(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid, char *signdata, int sdlen); #define GRID_ERROR_INVALID_FIELD 2 ///< Field - first two chars - is invalid #define GRID_ERROR_INVALID_SQUARE 3 ///< Square - second two chars - is invalid #define GRID_ERROR_INVALID_SUBSQUARE 4 ///< Subsquare - third pair - is invalid #define GRID_ERROR_INVALID_SUBSUBSQUARE 5 ///< Sub-subsquare - fourth pair etc. - is invalid #define GRID_ERROR_INVALID_FORMAT 6 ///< Format error /** Check and normalize a Maidenhead Gridsquare * \li \c grid is the input string * \li \c twelve is true if 12 character grids are allowed * \li \c newGrid gets the resulting edited grid */ DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat(const char *grid, int twelve, char* newGrid, int newlen); /** @} */ /** Output to a diagnostic trace file (if one is opened. * * \li \c name is the name of the function being executed */ DLLEXPORT void CALLCONVENTION tqslTrace(const char *name, const char *format, ...); /** Close the diagnostic trace file (if it is open) */ DLLEXPORT void CALLCONVENTION tqsl_closeDiagFile(void); /** Close the diagnostic trace file (if it is open) */ DLLEXPORT int CALLCONVENTION tqsl_diagFileOpen(void); /** Returns true if the log file is open * */ DLLEXPORT int CALLCONVENTION tqsl_openDiagFile(const char* file); /** Removes the upload database if it exists * */ DLLEXPORT void CALLCONVENTION tqsl_removeUploadDatabase(void); #ifdef _WIN32 DLLEXPORT wchar_t* CALLCONVENTION utf8_to_wchar(const char* str); DLLEXPORT char* CALLCONVENTION wchar_to_utf8(const wchar_t* str, bool forceUTF8); DLLEXPORT void CALLCONVENTION free_wchar(wchar_t* ptr); #endif #ifdef __cplusplus } #endif /* Useful defines */ #define TQSL_MAX_PW_LENGTH 32 ///< Password buffer length #endif /* TQSLLIB_H */ tqsl-2.8.2/src/tqsllib.css0000644000175000017500000000211615061653721015465 0ustar rmurphyrmurphyBODY { font-family: Helvetica,Arial,sans-serif; font-size: small } H1 { text-align: center; font-size: x-large } H2 { font-size: large } CODE { font-size: medium } A.qindex {} A.qindexRef {} A.el { text-decoration: none; font-weight: bold; } A.elRef { font-weight: bold } A.code { text-decoration: none; font-weight: normal; color: #4444ee } A.codeRef { font-weight: normal; color: #4444ee } A:link { color: #0000ff } A:visited { color: #0066cc } DL.el { margin-left: -1cm } DIV.fragment { width: 100%; border: none; background-color: #eeeeee } DIV.ah { background-color: black; margin-bottom: 3; margin-top: 3 } TD.md { background-color: #f2f2ff } DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold } DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller } FONT.keyword { color: #008000 } FONT.keywordtype { color: #604020 } FONT.keywordflow { color: #e08000 } FONT.comment { color: #800000 } FONT.preprocessor { color: #806020 } FONT.stringliteral { color: #002080 } FONT.charliteral { color: #008080 } TD { font-size: small } tqsl-2.8.2/src/tqsllib.cpp0000644000175000017500000010130715061653721015461 0ustar rmurphyrmurphy/*************************************************************************** tqsllib.c - description ------------------- begin : Mon May 20 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #define TQSLLIB_DEF #include "tqsllib.h" #include #include #include #include #include #ifdef _WIN32 #include #include #include #include #include #define strtok_r strtok_s #else #include #endif #include #include #include #if OPENSSL_VERSION_MAJOR >= 3 #include #endif #ifdef __APPLE__ #include #endif #include #include using std::string; #include "tqslerrno.h" #include "adif.h" #include "winstrdefs.h" #ifdef _WIN32 #define MKDIR(x, y) _wmkdir((x)) #else #define MKDIR(x, y) mkdir((x), (y)) #endif DLLEXPORTDATA int tQSL_Error = 0; DLLEXPORTDATA int tQSL_Errno = 0; DLLEXPORTDATA TQSL_ADIF_GET_FIELD_ERROR tQSL_ADIF_Error; DLLEXPORTDATA const char *tQSL_BaseDir = NULL; DLLEXPORTDATA const char *tQSL_RsrcDir = NULL; DLLEXPORTDATA char tQSL_ErrorFile[TQSL_MAX_PATH_LEN]; DLLEXPORTDATA char tQSL_CustomError[256]; DLLEXPORTDATA char tQSL_ImportCall[256]; DLLEXPORTDATA long tQSL_ImportSerial = 0; DLLEXPORTDATA FILE* tQSL_DiagFile = NULL; #define TQSL_OID_BASE "1.3.6.1.4.1.12348.1." #define TQSL_OID_CALLSIGN TQSL_OID_BASE "1" #define TQSL_OID_QSO_NOT_BEFORE TQSL_OID_BASE "2" #define TQSL_OID_QSO_NOT_AFTER TQSL_OID_BASE "3" #define TQSL_OID_DXCC_ENTITY TQSL_OID_BASE "4" #define TQSL_OID_SUPERCEDED_CERT TQSL_OID_BASE "5" #define TQSL_OID_CRQ_ISSUER_ORGANIZATION TQSL_OID_BASE "6" #define TQSL_OID_CRQ_ISSUER_ORGANIZATIONAL_UNIT TQSL_OID_BASE "7" #define TQSL_OID_CRQ_EMAIL TQSL_OID_BASE "8" #define TQSL_OID_CRQ_ADDRESS1 TQSL_OID_BASE "9" #define TQSL_OID_CRQ_ADDRESS2 TQSL_OID_BASE "10" #define TQSL_OID_CRQ_CITY TQSL_OID_BASE "11" #define TQSL_OID_CRQ_STATE TQSL_OID_BASE "12" #define TQSL_OID_CRQ_POSTAL TQSL_OID_BASE "13" #define TQSL_OID_CRQ_COUNTRY TQSL_OID_BASE "14" static const char *custom_objects[][3] = { { TQSL_OID_CALLSIGN, "AROcallsign", "AROcallsign" }, { TQSL_OID_QSO_NOT_BEFORE, "QSONotBeforeDate", "QSONotBeforeDate" }, { TQSL_OID_QSO_NOT_AFTER, "QSONotAfterDate", "QSONotAfterDate" }, { TQSL_OID_DXCC_ENTITY, "dxccEntity", "dxccEntity" }, { TQSL_OID_SUPERCEDED_CERT, "supercededCertificate", "supercededCertificate" }, { TQSL_OID_CRQ_ISSUER_ORGANIZATION, "tqslCRQIssuerOrganization", "tqslCRQIssuerOrganization" }, { TQSL_OID_CRQ_ISSUER_ORGANIZATIONAL_UNIT, "tqslCRQIssuerOrganizationalUnit", "tqslCRQIssuerOrganizationalUnit" }, { TQSL_OID_CRQ_EMAIL, "tqslCRQEmail", "tqslCRQEmail" }, { TQSL_OID_CRQ_ADDRESS1, "tqslCRQAddress1", "tqslCRQAddress1" }, { TQSL_OID_CRQ_ADDRESS2, "tqslCRQAddress2", "tqslCRQAddress2" }, { TQSL_OID_CRQ_CITY, "tqslCRQCity", "tqslCRQCity" }, { TQSL_OID_CRQ_STATE, "tqslCRQState", "tqslCRQState" }, { TQSL_OID_CRQ_POSTAL, "tqslCRQPostal", "tqslCRQPostal" }, { TQSL_OID_CRQ_COUNTRY, "tqslCRQCountry", "tqslCRQCountry" }, }; static const char *error_strings[] = { "Memory allocation failure", /* TQSL_ALLOC_ERROR */ "Unable to initialize random number generator", /* TQSL_RANDOM_ERROR */ "Invalid argument", /* TQSL_ARGUMENT_ERROR */ "Operator aborted operation", /* TQSL_OPERATOR_ABORT */ "No Certificate Request matches the selected Callsign Certificate",/* TQSL_NOKEY_ERROR */ "Buffer too small", /* TQSL_BUFFER_ERROR */ "Invalid date format", /* TQSL_INVALID_DATE */ "Certificate not initialized for signing", /* TQSL_SIGNINIT_ERROR */ "Passphrase not correct", /* TQSL_PASSWORD_ERROR */ "Expected name", /* TQSL_EXPECTED_NAME */ "Name exists", /* TQSL_NAME_EXISTS */ "Data for this DXCC entity could not be found", /* TQSL_NAME_NOT_FOUND */ "Invalid time format", /* TQSL_INVALID_TIME */ "QSO date is not within the date range specified on your Callsign Certificate", /* TQSL_CERT_DATE_MISMATCH */ "Certificate provider not found", /* TQSL_PROVIDER_NOT_FOUND */ "No callsign certificate for key", /* TQSL_CERT_KEY_ONLY */ "Configuration file cannot be opened", /* TQSL_CONFIG_ERROR */ "The private key for this Callsign Certificate is not present on this computer; you can obtain it by loading a .tbk or .p12 file", /* TQSL_CERT_NOT_FOUND */ "PKCS#12 file not TQSL compatible", /* TQSL_PKCS12_ERROR */ "Callsign Certificate not TQSL compatible", /* TQSL_CERT_TYPE_ERROR */ "Date out of range", /* TQSL_DATE_OUT_OF_RANGE */ "Previously Signed QSO detected", /* TQSL_DUPLICATE_QSO */ "Database error", /* TQSL_DB_ERROR */ "The selected station location could not be found", /* TQSL_LOCATION_NOT_FOUND */ "The selected callsign could not be found", /* TQSL_CALL_NOT_FOUND */ "The TQSL configuration file cannot be parsed", /* TQSL_CONFIG_SYNTAX_ERROR */ "This file can not be processed due to a system error", /* TQSL_FILE_SYSTEM_ERROR */ "The format of this file is incorrect.", /* TQSL_FILE_SYNTAX_ERROR */ "This Callsign Certificate could not be installed", /* TQSL_CERT_ERROR */ "Callsign Certificate does not match QSO details", /* TQSL_CERT_MISMATCH */ "Station Location does not match QSO details", /* TQSL_LOCATION_MISMATCH */ "Gridsquare is inconsistent with Station Location", /* TQSL_INCONSISTENT_GRID */ "ADIF field has invalid contents", /* TQSL_INVALID_ADIF */ /* note - dupe table in wxutil.cpp */ }; #if !defined(__APPLE__) && !defined(_WIN32) && !defined(__clang__) #pragma GCC diagnostic ignored "-Wformat-truncation" #endif const char* tqsl_openssl_error(void); #if defined(_WIN32) static int pmkdir(const wchar_t *path, int perm) { wchar_t dpath[TQSL_MAX_PATH_LEN]; wchar_t npath[TQSL_MAX_PATH_LEN]; wchar_t *cp; char *p = wchar_to_utf8(path, true); tqslTrace("pmkdir", "path=%s", p); free(p); int nleft = sizeof(npath) / sizeof(npath[0]) - 1; wcsncpy(dpath, path, sizeof(dpath) / sizeof(dpath[0])); cp = wcstok(dpath, L"/\\"); npath[0] = 0; while (cp) { if (wcslen(cp) > 0 && cp[wcslen(cp)-1] != ':') { wcsncat(npath, L"\\", nleft); nleft--; wcsncat(npath, cp, nleft); nleft -= wcslen(cp); if (MKDIR(npath, perm) != 0 && errno != EEXIST) { tqslTrace("pmkdir", "Error creating %s: %s", npath, strerror(errno)); return 1; } } else { wcsncat(npath, cp, nleft); nleft -= wcslen(cp); } cp = wcstok(NULL, L"/\\"); } return 0; } #else // defined(_WIN32) static int pmkdir(const char *path, int perm) { char dpath[TQSL_MAX_PATH_LEN]; char npath[TQSL_MAX_PATH_LEN]; char *cp; tqslTrace("pmkdir", "path=%s", path); int nleft = sizeof npath - 1; strncpy(dpath, path, sizeof dpath); char *state = NULL; cp = strtok_r(dpath, "/\\", &state); npath[0] = 0; while (cp) { if (strlen(cp) > 0 && cp[strlen(cp)-1] != ':') { strncat(npath, "/", nleft); nleft--; strncat(npath, cp, nleft); nleft -= strlen(cp); if (MKDIR(npath, perm) != 0 && errno != EEXIST) { tqslTrace("pmkdir", "Error creating %s: %s", npath, strerror(errno)); return 1; } } else { strncat(npath, cp, nleft); nleft -= strlen(cp); } cp = strtok_r(NULL, "/\\", &state); } return 0; } #endif // defined(_WIN32) static void tqsl_get_rsrc_dir() { tqslTrace("tqsl_get_rsrc_dir", NULL); #ifdef _WIN32 HKEY hkey; DWORD dtype; char wpath[TQSL_MAX_PATH_LEN]; DWORD bsize = sizeof wpath; int wval; if ((wval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\TrustedQSL"), 0, KEY_READ, &hkey)) == ERROR_SUCCESS) { wval = RegQueryValueEx(hkey, _T("InstallPath"), 0, &dtype, (LPBYTE)wpath, &bsize); RegCloseKey(hkey); if (wval == ERROR_SUCCESS) { string p = string(wpath); if (p[p.length() -1] == '\\') p = p.substr(0, p.length() - 1); if (tQSL_RsrcDir) free(const_cast(tQSL_RsrcDir)); tQSL_RsrcDir = strdup(p.c_str()); } } #elif defined(__APPLE__) // Get path to config.xml resource from bundle CFBundleRef tqslBundle = CFBundleGetMainBundle(); CFURLRef configXMLURL = CFBundleCopyResourceURL(tqslBundle, CFSTR("config"), CFSTR("xml"), NULL); if (configXMLURL) { CFStringRef pathString = CFURLCopyFileSystemPath(configXMLURL, kCFURLPOSIXPathStyle); CFRelease(configXMLURL); // Convert CFString path to config.xml to string object CFIndex maxStringLengthInBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(pathString), kCFStringEncodingUTF8); char *pathCString = static_cast(malloc(maxStringLengthInBytes)); if (pathCString) { CFStringGetCString(pathString, pathCString, maxStringLengthInBytes, kCFStringEncodingASCII); CFRelease(pathString); size_t p; string path = string(pathCString); if ((p = path.find("/config.xml")) != string::npos) { path = path.substr(0, p); } if (tQSL_RsrcDir) free(const_cast(tQSL_RsrcDir)); tQSL_RsrcDir = strdup(path.c_str()); free(pathCString); } } #else // Get the base directory string p = CONFDIR; // Strip trailing "/" if (p[p.length() - 1] == '/') p = p.substr(0, p.length() - 1); // Check if running as an AppImage char *appdir = getenv("APPDIR"); if (appdir == NULL) { if (tQSL_RsrcDir) free(const_cast(tQSL_RsrcDir)); tQSL_RsrcDir = strdup(p.c_str()); } else { string p1 = appdir; // Strip trailing "/" if (p1[p1.length() - 1] == '/') p1 = p1.substr(0, p1.length() - 1); p1 = p1 + p; // Assume APPDIR is probably not an AppImage root if (tQSL_RsrcDir) free(const_cast(tQSL_RsrcDir)); tQSL_RsrcDir = strdup(p.c_str()); // See if it's likely to be an AppImage struct stat s; if (stat(p1.c_str(), &s) == 0) { if (S_ISDIR(s.st_mode)) { if (tQSL_RsrcDir) free(const_cast(tQSL_RsrcDir)); tQSL_RsrcDir = strdup(p1.c_str()); } } } #endif tqslTrace("tqsl_get_rsrc_dir", "rsrc_path=%s", tQSL_RsrcDir); } DLLEXPORT int CALLCONVENTION tqsl_init() { static char semaphore = 0; unsigned int i; ERR_clear_error(); tqsl_getErrorString(); /* Clear the error status */ if (semaphore) return 0; #ifdef _WIN32 static wchar_t path[TQSL_MAX_PATH_LEN]; // lets cin/out/err work in windows // AllocConsole(); // freopen("CONIN$", "r", stdin); // freopen("CONOUT$", "w", stdout); // freopen("CONOUT$", "w", stderr); // not used DWORD bsize = sizeof path; int wval; #else static char path[TQSL_MAX_PATH_LEN]; #endif #if !defined(_WIN32) && !defined(__APPLE__) // Work around ill-considered decision by Fedora to stop allowing // certificates with SHA-1 signatures setenv("OPENSSL_ENABLE_SHA1_SIGNATURES", "1", 0); #endif /* OpenSSL API tends to change between minor version numbers, so make sure * we're using the right version */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L unsigned long SSLver = OpenSSL_version_num(); #else long SSLver = SSLeay(); #endif int SSLmajor = (SSLver >> 28) & 0xff; int SSLminor = (SSLver >> 20) & 0xff; int TQSLmajor = (OPENSSL_VERSION_NUMBER >> 28) & 0xff; int TQSLminor = (OPENSSL_VERSION_NUMBER >> 20) & 0xff; if (SSLmajor != TQSLmajor || (SSLminor != TQSLminor && (SSLmajor != 9 && SSLminor != 7 && TQSLminor == 6))) { tqslTrace("tqsl_init", "version error - ssl %d.%d", SSLmajor, SSLminor); tQSL_Error = TQSL_OPENSSL_VERSION_ERROR; return 1; } #if OPENSSL_VERSION_MAJOR >= 3 // // OpenSSL 3.x moved several algorithms to "legacy" status and doesn't // enable them by default. Initialize the legacy provider to enable these. // Then enable the default provider. // OSSL_PROVIDER *def; OSSL_PROVIDER *legacy; legacy = OSSL_PROVIDER_load(NULL, "legacy"); if (legacy == NULL) { tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } def = OSSL_PROVIDER_load(NULL, "default"); if (def == NULL) { tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); #endif for (i = 0; i < (sizeof custom_objects / sizeof custom_objects[0]); i++) { if (OBJ_create(custom_objects[i][0], custom_objects[i][1], custom_objects[i][2]) == 0) { tqslTrace("tqsl_init", "Error making custom objects: %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } } if (tQSL_RsrcDir == NULL) { tqsl_get_rsrc_dir(); } if (tQSL_BaseDir == NULL) { #if defined(_WIN32) wchar_t *wcp; if ((wcp = _wgetenv(L"TQSLDIR")) != NULL && *wcp != '\0') { wcsncpy(path, wcp, sizeof(path) / sizeof(path[0])); #else char *cp; if ((cp = getenv("TQSLDIR")) != NULL && *cp != '\0') { strncpy(path, cp, sizeof path); #endif } else { #if defined(_WIN32) wval = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path); if (wval != ERROR_SUCCESS) wcsncpy(path, L"C:", sizeof(path) / sizeof(path[0])); wcsncat(path, L"\\TrustedQSL", sizeof(path) / sizeof(path[0]) - wcslen(path) - 1); #elif defined(LOTW_SERVER) strncpy(path, "/var/lotw/tqsl", sizeof path); #else // some unix flavor if (getenv("HOME") != NULL) { strncpy(path, getenv("HOME"), sizeof path); strncat(path, "/", sizeof path - strlen(path)-1); strncat(path, ".tqsl", sizeof path - strlen(path)-1); } else { strncpy(path, ".tqsl", sizeof path); } #endif } if (pmkdir(path, 0700)) { #if defined(_WIN32) char *p = wchar_to_utf8(path, false); strncpy(tQSL_ErrorFile, p, sizeof tQSL_ErrorFile); #else strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; #if defined(_WIN32) tqslTrace("tqsl_init", "Error creating working path %s: %s", p, strerror(errno)); free(p); #else tqslTrace("tqsl_init", "Error creating working path %s: %s", path, strerror(errno)); #endif return 1; } FILE *test; #if defined(_WIN32) tQSL_BaseDir = wchar_to_utf8(path, true); wcsncat(path, L"\\tmp.tmp", sizeof(path) / sizeof(path[0]) - wcslen(path) - 1); if ((test = _wfopen(path, L"wb")) == NULL) { tQSL_Errno = errno; char *p = wchar_to_utf8(path, false); snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Unable to create files in the TQSL working directory (%s): %s", p, strerror(errno)); tQSL_Error = TQSL_CUSTOM_ERROR; return 1; } fclose(test); _wunlink(path); #else if (tQSL_BaseDir) free (const_cast(tQSL_BaseDir)); tQSL_BaseDir = strdup(path); strncat(path, "/tmp.tmp", sizeof path -strlen(path) - 1); if ((test = fopen(path, "wb")) == NULL) { tQSL_Errno = errno; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Unable to create files in the TQSL working directory (%s): %s", tQSL_BaseDir, strerror(errno)); tQSL_Error = TQSL_CUSTOM_ERROR; return 1; } fclose(test); unlink(path); #endif } // // Ensure that tQSL_RsrcDir is set // Correction from JJ1BDX // if (!tQSL_RsrcDir) tQSL_RsrcDir = tQSL_BaseDir; semaphore = 1; return 0; } DLLEXPORT int CALLCONVENTION tqsl_setDirectory(const char *dir) { static char path[TQSL_MAX_PATH_LEN]; if (strlen(dir) >= TQSL_MAX_PATH_LEN) { tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(path, dir, sizeof path); tQSL_BaseDir = path; return 0; } DLLEXPORT const char* CALLCONVENTION tqsl_getErrorString_v(int err) { static char buf[512]; unsigned long openssl_err; int adjusted_err; if (err == 0) return "NO ERROR"; if (err == TQSL_CUSTOM_ERROR) { if (tQSL_CustomError[0] == 0) { return "Unknown custom error"; } else { strncpy(buf, tQSL_CustomError, sizeof buf); return buf; } } if (err == TQSL_DB_ERROR && tQSL_CustomError[0] != 0) { snprintf(buf, sizeof buf, "Database Error: %s", tQSL_CustomError); return buf; } if (err == TQSL_SYSTEM_ERROR || err == TQSL_FILE_SYSTEM_ERROR) { if (strlen(tQSL_ErrorFile) > 0) { snprintf(buf, sizeof buf, "System error: %s : %s", tQSL_ErrorFile, strerror(tQSL_Errno)); tQSL_ErrorFile[0] = '\0'; } else { snprintf(buf, sizeof buf, "System error: %s", strerror(tQSL_Errno)); } return buf; } if (err == TQSL_FILE_SYNTAX_ERROR) { tqslTrace("SyntaxError", "File (partial) content '%s'", tQSL_CustomError); if (strlen(tQSL_ErrorFile) > 0) { snprintf(buf, sizeof buf, "File syntax error: %s", tQSL_ErrorFile); tQSL_ErrorFile[0] = '\0'; } else { strncpy(buf, "File syntax error", sizeof buf); } return buf; } if (err == TQSL_OPENSSL_ERROR) { openssl_err = ERR_get_error(); strncpy(buf, "OpenSSL error: ", sizeof buf); if (openssl_err) ERR_error_string_n(openssl_err, buf + strlen(buf), sizeof buf - strlen(buf)-1); else strncat(buf, "[error code not available]", sizeof buf - strlen(buf)-1); return buf; } if (err == TQSL_ADIF_ERROR) { buf[0] = 0; if (strlen(tQSL_ErrorFile) > 0) { snprintf(buf, sizeof buf, "%s: %s", tQSL_ErrorFile, tqsl_adifGetError(tQSL_ADIF_Error)); tQSL_ErrorFile[0] = '\0'; } else { snprintf(buf, sizeof buf, "%s", tqsl_adifGetError(tQSL_ADIF_Error)); } return buf; } if (err == TQSL_CABRILLO_ERROR) { buf[0] = 0; if (strlen(tQSL_ErrorFile) > 0) { snprintf(buf, sizeof buf, "%s: %s", tQSL_ErrorFile, tqsl_cabrilloGetError(tQSL_Cabrillo_Error)); tQSL_ErrorFile[0] = '\0'; } else { snprintf(buf, sizeof buf, "%s", tqsl_cabrilloGetError(tQSL_Cabrillo_Error)); } return buf; } if (err == TQSL_OPENSSL_VERSION_ERROR) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L unsigned long SSLver = OpenSSL_version_num(); #else long SSLver = SSLeay(); #endif snprintf(buf, sizeof buf, "Incompatible OpenSSL Library version %d.%d.%d; expected %d.%d.%d", static_cast(SSLver >> 28) & 0xff, static_cast(SSLver >> 20) & 0xff, static_cast(SSLver >> 12) & 0xff, static_cast(OPENSSL_VERSION_NUMBER >> 28) & 0xff, static_cast(OPENSSL_VERSION_NUMBER >> 20) & 0xff, static_cast(OPENSSL_VERSION_NUMBER >> 12) & 0xff); return buf; } if ((err & 0xff) == TQSL_CERT_NOT_FOUND) { if (tQSL_ImportCall[0] == '\0') strncpy(tQSL_ImportCall, "unknown", sizeof tQSL_ImportCall); if ((err & TQSL_CERT_NOT_FOUND_SUPERCEDED)) { snprintf(buf, sizeof buf, "This is not the current callsign certificate file for %s - download the latest from https://lotw.arrl.org/lotwuser/certs.tq6", tQSL_ImportCall); tQSL_ImportCall[0] = '\0'; return buf; } if ((err & TQSL_CERT_NOT_FOUND_EXPIRED)) { snprintf(buf, sizeof buf, "You cannot install this Callsign Certificate as it has expired - download the latest from https://lotw.arrl.org/lotwuser/certs.tq6"); tQSL_ImportCall[0] = '\0'; return buf; } if ((err & TQSL_CERT_NOT_FOUND_INVALID)) { snprintf(buf, sizeof buf, "This TQ6 file is corrupt and cannot be installed. Download the latest from https://lotw.arrl.org/lotwuser/certs.tq6"); tQSL_ImportCall[0] = '\0'; return buf; } snprintf(buf, sizeof buf, "This file is related to a callsign certificate request from some other computer. You can only open this on the computer system logged in as the user that requested the callsign certificate for %s.", tQSL_ImportCall); tQSL_ImportCall[0] = '\0'; return buf; } adjusted_err = ((err & 0xff) - TQSL_ERROR_ENUM_BASE); if (adjusted_err < 0 || adjusted_err >= static_cast(sizeof error_strings / sizeof error_strings[0])) { snprintf(buf, sizeof buf, "Invalid error code: %d", err); return buf; } if (err == TQSL_CERT_MISMATCH || err == TQSL_LOCATION_MISMATCH) { const char *fld, *cert, *qso; char *state = NULL; fld = strtok_r(tQSL_CustomError, "|", &state); cert = strtok_r(NULL, "|", &state); qso = strtok_r(NULL, "|", &state); if (qso == NULL) { // Nothing in the cert qso = cert; cert = "none"; } snprintf(buf, sizeof buf, "%s\nThe %s '%s' has value '%s' while QSO has '%s'", error_strings[adjusted_err], err == TQSL_LOCATION_MISMATCH ? "Station Location" : "Callsign Certificate", fld, cert, qso); return buf; } if (err == (TQSL_LOCATION_MISMATCH | TQSL_MSG_FLAGGED)) { const char *fld, *val; char *state = NULL; fld = strtok_r(tQSL_CustomError, "|", &state); val = strtok_r(NULL, "|", &state); snprintf(buf, sizeof buf, "This log has invalid QSO information.\nThe log being signed has '%s' set to value '%s' which is not valid", fld, val); return buf; } if (err == (TQSL_CERT_NOT_FOUND | TQSL_MSG_FLAGGED)) { const char *call, *ent; err = TQSL_CERT_NOT_FOUND; char *state = NULL; call = strtok_r(tQSL_CustomError, "|", &state); ent = strtok_r(NULL, "|", &state); snprintf(buf, sizeof buf, "There is no valid callsign certificate for %s in entity %s available. This QSO cannot be signed", call, ent); return buf; } return error_strings[adjusted_err]; } DLLEXPORT const char* CALLCONVENTION tqsl_getErrorString() { const char *cp; cp = tqsl_getErrorString_v(tQSL_Error); tQSL_Error = TQSL_NO_ERROR; tQSL_Errno = 0; tQSL_ErrorFile[0] = 0; tQSL_CustomError[0] = 0; return cp; } DLLEXPORT int CALLCONVENTION tqsl_encodeBase64(const unsigned char *data, int datalen, char *output, int outputlen) { BIO *bio = NULL, *bio64 = NULL; int n; char *memp; int rval = 1; if (data == NULL || output == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_encodeBase64", "arg err data=0x%lx, output=0x%lx", data, output); return rval; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_encodeBase64", "BIO_new err %s", tqsl_openssl_error()); goto err; } if ((bio64 = BIO_new(BIO_f_base64())) == NULL) { tqslTrace("tqsl_encodeBase64", "BIO_new64 err %s", tqsl_openssl_error()); goto err; } bio = BIO_push(bio64, bio); if (BIO_write(bio, data, datalen) < 1) { tqslTrace("tqsl_encodeBase64", "BIO_write err %s", tqsl_openssl_error()); goto err; } if (BIO_flush(bio) != 1) { tqslTrace("tqsl_encodeBase64", "BIO_flush err %s", tqsl_openssl_error()); goto err; } n = BIO_get_mem_data(bio, &memp); if (n > outputlen-1) { tqslTrace("tqsl_encodeBase64", "buffer has %d, avail %d", n, outputlen); tQSL_Error = TQSL_BUFFER_ERROR; goto end; } memcpy(output, memp, n); output[n] = 0; BIO_free_all(bio); bio = NULL; rval = 0; goto end; err: tQSL_Error = TQSL_OPENSSL_ERROR; end: if (bio != NULL) BIO_free_all(bio); return rval; } DLLEXPORT int CALLCONVENTION tqsl_decodeBase64(const char *input, unsigned char *data, int *datalen) { BIO *bio = NULL, *bio64 = NULL; int n; int rval = 1; if (input == NULL || data == NULL || datalen == NULL) { tqslTrace("tqsl_decodeBase64", "arg error input=0x%lx, data=0x%lx, datalen=0x%lx", input, data, datalen); tQSL_Error = TQSL_ARGUMENT_ERROR; return rval; } if ((bio = BIO_new_mem_buf(const_cast(input), strlen(input))) == NULL) { tqslTrace("tqsl_decodeBase64", "BIO_new_mem_buf err %s", tqsl_openssl_error()); goto err; } BIO_set_mem_eof_return(bio, 0); if ((bio64 = BIO_new(BIO_f_base64())) == NULL) { tqslTrace("tqsl_decodeBase64", "BIO_new err %s", tqsl_openssl_error()); goto err; } bio = BIO_push(bio64, bio); // OpenSSL always adds a newline; account for cases where the base64 string isn't // newline terminated n = BIO_read(bio, data, *datalen); if (n < 0) { tqslTrace("tqsl_decodeBase64", "BIO_read error %s", tqsl_openssl_error()); goto err; } // Completely invalid input means no output. // return an appropriate error if (n == 0 && strlen(input) > 0) { tqslTrace("tqsl_decodeBase64", "Invalid input"); tQSL_Error = TQSL_ARGUMENT_ERROR; goto end; } if (BIO_ctrl_pending(bio) != 0) { tqslTrace("tqsl_decodeBase64", "ctrl_pending err %s", tqsl_openssl_error()); tQSL_Error = TQSL_BUFFER_ERROR; goto end; } *datalen = n; rval = 0; goto end; err: tQSL_Error = TQSL_OPENSSL_ERROR; end: if (bio != NULL) BIO_free_all(bio); return rval; } /* Convert a tQSL_Date field to an ISO-format date string */ DLLEXPORT char* CALLCONVENTION tqsl_convertDateToText(const tQSL_Date *date, char *buf, int bufsiz) { char lbuf[10]; int len; char *cp = buf; int bufleft = bufsiz-1; if (date == NULL || buf == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; if (buf) buf[0] = '\0'; return NULL; } if (date->year < 1 || date->year > 9999 || date->month < 1 || date->month > 12 || date->day < 1 || date->day > 31) { buf[0] = '\0'; return NULL; } len = snprintf(lbuf, sizeof lbuf, "%04d-", date->year); strncpy(cp, lbuf, bufleft); cp += len; bufleft -= len; len = snprintf(lbuf, sizeof lbuf, "%02d-", date->month); if (bufleft > 0) strncpy(cp, lbuf, bufleft); cp += len; bufleft -= len; len = snprintf(lbuf, sizeof lbuf, "%02d", date->day); if (bufleft > 0) strncpy(cp, lbuf, bufleft); bufleft -= len; if (bufleft < 0) return NULL; buf[bufsiz-1] = '\0'; return buf; } DLLEXPORT int CALLCONVENTION tqsl_isDateValid(const tQSL_Date *d) { static int mon_days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (d == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 0; } if (d->year < 1 || d->year > 9999) return 0; if (d->month < 1 || d->month > 12) return 0; if (d->day < 1 || d->day > 31) return 0; mon_days[2] = ((d->year % 4) == 0 && ((d->year % 100) != 0 || (d->year % 400) == 0)) ? 29 : 28; if (d->day > mon_days[d->month]) return 0; return 1; } DLLEXPORT int CALLCONVENTION tqsl_isDateNull(const tQSL_Date *d) { if (d == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } return (d->year == 0 && d->month == 0 && d->day == 0) ? 1 : 0; } /* Convert a tQSL_Time field to an ISO-format date string */ DLLEXPORT char* CALLCONVENTION tqsl_convertTimeToText(const tQSL_Time *time, char *buf, int bufsiz) { char lbuf[10]; int len; char *cp = buf; int bufleft = bufsiz-1; if (time == NULL || buf == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return NULL; } if (!tqsl_isTimeValid(time)) return NULL; len = snprintf(lbuf, sizeof lbuf, "%02d:", time->hour); strncpy(cp, lbuf, bufleft); cp += len; bufleft -= len; len = snprintf(lbuf, sizeof lbuf, "%02d:", time->minute); if (bufleft > 0) strncpy(cp, lbuf, bufleft); cp += len; bufleft -= len; len = snprintf(lbuf, sizeof lbuf, "%02d", time->second); if (bufleft > 0) strncpy(cp, lbuf, bufleft); cp += len; bufleft -= len; if (bufleft > 0) strncpy(cp, "Z", bufleft); bufleft -= 1; if (bufleft < 0) return NULL; buf[bufsiz-1] = '\0'; return buf; } DLLEXPORT int CALLCONVENTION tqsl_isTimeValid(const tQSL_Time *t) { if (t == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 0; } if (t->hour < 0 || t->hour > 23) return 0; if (t->minute < 0 || t->minute > 59) return 0; if (t->second < 0 || t->second > 59) return 0; return 1; } /* Compare two tQSL_Date values, returning -1, 0, 1 */ DLLEXPORT int CALLCONVENTION tqsl_compareDates(const tQSL_Date *a, const tQSL_Date *b) { if (a == NULL || b == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (a->year < b->year) return -1; if (a->year > b->year) return 1; if (a->month < b->month) return -1; if (a->month > b->month) return 1; if (a->day < b->day) return -1; if (a->day > b->day) return 1; return 0; } // Return the number of days for a given year/month (January=1) static int days_per_month(int year, int month) { switch (month) { case 2: if ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)) { return 29; } else { return 28; } case 4: case 6: case 9: case 11: return 30; default: return 31; } return 0; } // Return the julian day number for a given date. // One-based year/month/day static int julian_day(int year, int month, int day) { int jday = 0; for (int mon = 1; mon < month; mon ++) { jday += days_per_month(year, mon); } jday += day; return jday; } /* Calculate the difference between two tQSL_Date values */ DLLEXPORT int CALLCONVENTION tqsl_subtractDates(const tQSL_Date *a, const tQSL_Date *b, int *diff) { if (a == NULL || b == NULL || diff == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tQSL_Date first = *a; tQSL_Date last = *b; int mult = 1; // Ensure that the first is earliest if (tqsl_compareDates(&last, &first) < 0) { first = *b; last = *a; mult = -1; } int delta = 0; for (; first.year < last.year; first.year++) { int fday = julian_day(first.year, first.month, first.day); int fend = julian_day(first.year, 12, 31); delta += (fend - fday + 1); // days until next 1 Jan first.month = 1; first.day = 1; } // Now the years are the same - calculate delta int fjulian = julian_day(first.year, first.month, first.day); int ljulian = julian_day(last.year, last.month, last.day); delta += (ljulian - fjulian); *diff = (delta * mult); // Swap sign if necessary return 0; } /* Fill a tQSL_Date struct with the date from a text string */ DLLEXPORT int CALLCONVENTION tqsl_initDate(tQSL_Date *date, const char *str) { const char *cp; if (date == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (str == NULL) { date->year = date->month = date->day = 0; return 0; } if ((cp = strchr(str, '-')) != NULL) { /* Parse YYYY-MM-DD */ date->year = strtol(str, NULL, 10); cp++; date->month = strtol(cp, NULL, 10); cp = strchr(cp, '-'); if (cp == NULL) goto err; cp++; date->day = strtol(cp, NULL, 10); } else if (strlen(str) == 8) { /* Parse YYYYMMDD */ char frag[10]; strncpy(frag, str, 4); frag[4] = 0; date->year = strtol(frag, NULL, 10); strncpy(frag, str+4, 2); frag[2] = 0; date->month = strtol(frag, NULL, 10); date->day = strtol(str+6, NULL, 10); } else { /* Invalid ISO date string */ goto err; } if (date->year < 1 || date->year > 9999) goto err; if (date->month < 1 || date->month > 12) goto err; if (date->day < 1 || date->day > 31) goto err; return 0; err: tQSL_Error = TQSL_INVALID_DATE; return 1; } /* Fill a tQSL_Time struct with the time from a text string */ DLLEXPORT int CALLCONVENTION tqsl_initTime(tQSL_Time *time, const char *str) { const char *cp; int parts[3]; int i; if (time == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } time->hour = time->minute = time->second = 0; if (str == NULL) return 0; if (strlen(str) < 3) { tQSL_Error = TQSL_INVALID_TIME; return 1; } parts[0] = parts[1] = parts[2] = 0; for (i = 0, cp = str; i < static_cast(sizeof parts / sizeof parts[0]); i++) { if (strlen(cp) < 2) break; if (!isdigit(*cp) || !isdigit(*(cp+1))) goto err; if (i == 0 && strlen(str) == 3) { // Special case: HMM -- no colons, one-digit hour parts[i] = *cp - '0'; ++cp; } else { parts[i] = (*cp - '0') * 10 + *(cp+1) - '0'; cp += 2; } if (*cp == ':') cp++; } if (parts[0] < 0 || parts[0] > 23) goto err; if (parts[1] < 0 || parts[1] > 59) goto err; if (parts[2] < 0 || parts[2] > 59) goto err; time->hour = parts[0]; time->minute = parts[1]; time->second = parts[2]; return 0; err: tQSL_Error = TQSL_INVALID_TIME; return 1; } DLLEXPORT int CALLCONVENTION tqsl_getVersion(int *major, int *minor) { if (major) *major = TQSLLIB_VERSION_MAJOR; if (minor) *minor = TQSLLIB_VERSION_MINOR; return 0; } #ifdef _WIN32 DLLEXPORT wchar_t* CALLCONVENTION utf8_to_wchar(const char* str) { wchar_t* buffer; int needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0); buffer = static_cast(malloc(needed*sizeof(wchar_t) + 4)); if (!buffer) return NULL; MultiByteToWideChar(CP_UTF8, 0, str, -1, &buffer[0], needed); return buffer; } DLLEXPORT char* CALLCONVENTION wchar_to_utf8(const wchar_t* str, bool forceUTF8) { char* buffer; int needed = WideCharToMultiByte(forceUTF8 ? CP_UTF8 : CP_ACP, 0, str, -1, 0, 0, NULL, NULL); buffer = static_cast(malloc(needed + 2)); if (!buffer) return NULL; WideCharToMultiByte(forceUTF8 ? CP_UTF8 : CP_ACP, 0, str, -1, &buffer[0], needed, NULL, NULL); return buffer; } DLLEXPORT void CALLCONVENTION free_wchar(wchar_t* ptr) { free(ptr); } #endif DLLEXPORT void CALLCONVENTION tqslTrace(const char *name, const char *format, ...) { va_list ap; if (!tQSL_DiagFile) return; time_t t = time(0); char timebuf[50]; strncpy(timebuf, ctime(&t), sizeof timebuf); timebuf[strlen(timebuf) - 1] = '\0'; // Strip the newline if (!format) { fprintf(tQSL_DiagFile, "%s %s\r\n", timebuf, name); fflush(tQSL_DiagFile); return; } else { if (name) { fprintf(tQSL_DiagFile, "%s %s: ", timebuf, name); } } va_start(ap, format); vfprintf(tQSL_DiagFile, format, ap); va_end(ap); fprintf(tQSL_DiagFile, "\r\n"); fflush(tQSL_DiagFile); } DLLEXPORT void CALLCONVENTION tqsl_closeDiagFile(void) { if (tQSL_DiagFile) fclose(tQSL_DiagFile); tQSL_DiagFile = NULL; } DLLEXPORT int CALLCONVENTION tqsl_diagFileOpen(void) { return tQSL_DiagFile != NULL; } DLLEXPORT int CALLCONVENTION tqsl_openDiagFile(const char *fname) { #ifdef _WIN32 wchar_t* lfn = utf8_to_wchar(fname); tQSL_DiagFile = _wfopen(lfn, L"wb"); free_wchar(lfn); #else tQSL_DiagFile = fopen(fname, "wb"); #endif return (tQSL_DiagFile == NULL); } const char* tqsl_openssl_error(void) { static char buf[256]; unsigned long openssl_err; openssl_err = ERR_peek_error(); if (openssl_err) ERR_error_string_n(openssl_err, buf, sizeof buf); else strncpy(buf, "[error code not available]", sizeof buf); return buf; } tqsl-2.8.2/src/tqsllib-doc.h0000644000175000017500000000264415061653721015675 0ustar rmurphyrmurphy/*************************************************************************** tqsllib-doc.h - description ------------------- begin : Tue Jun 4 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ /** \mainpage * * The TrustedQSL library API is divided into several groups: * * \li \ref CertStuff - Request, load and retrieve digital certificates * \li \ref Data - Manage station-location data and produce signed data records * \li \ref Convert - Convert and sign ADIF and Cabrillo log files * \li \ref Util - Functions to operate on objects, set system parameters, and report errors * \li \ref Sign - Low-level digital signing * \li \ref ADIF - Low-level parsing and creation of ADIF files * \li \ref Cabrillo - Low-level parsing of Cabrillo files. * * Most of the library functions return an integer value that is * zero if there is no error and 1 if there is an error. The specific * error can be determined by examining #tQSL_Error and, possibly, * #tQSL_ADIF_Error, #tQSL_Cabrillo_Error, #tQSL_ErrorFile and * #tQSL_CustomError. The tqsl_getErrorString() and tqsl_getErrorString_v() * functions can be used to get error text strings. * */ tqsl-2.8.2/src/tqslexc.h0000644000175000017500000000173115061653721015137 0ustar rmurphyrmurphy/*************************************************************************** tqslexc.h - description ------------------- begin : Sat Dec 14 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef __tqslexc_h #define __tqslexc_h #include #include #include "tqsllib.h" using std::exception; using std::string; class myexc : public exception { public: explicit myexc(const string& err) : exception() { _err = err; } myexc(const myexc& x) { _err = x._err; } virtual const char *what() const throw () { return _err.c_str(); } virtual ~myexc() throw() {} private: string _err; }; class tqslexc : public myexc { public: tqslexc() : myexc(tqsl_getErrorString()) {} }; #endif // __tqslexc_h tqsl-2.8.2/src/tqslerrno.h0000644000175000017500000000676315061653721015517 0ustar rmurphyrmurphy/*************************************************************************** tqslerrno.h - description ------------------- begin : Tue May 28 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef __TQSLERRNO_H #define __TQSLERRNO_H /** \file * #tQSL_Error values */ #define TQSL_NO_ERROR 0 ///< No error #define TQSL_SYSTEM_ERROR 1 ///< System Error #define TQSL_OPENSSL_ERROR 2 ///< Error in OpenSSL calls #define TQSL_ADIF_ERROR 3 ///< ADIF Errors #define TQSL_CUSTOM_ERROR 4 ///< Custom errors - output to tQSL_CustomError #define TQSL_CABRILLO_ERROR 5 ///< Cabrillo handler error #define TQSL_OPENSSL_VERSION_ERROR 6 ///< OpenSSL version obsolete #define TQSL_ERROR_ENUM_BASE 16 ///< Base for enumerated errors #define TQSL_ALLOC_ERROR 16 ///< Memory allocation error #define TQSL_RANDOM_ERROR 17 ///< Error initializing random number generator #define TQSL_ARGUMENT_ERROR 18 ///< Invalid arguments #define TQSL_OPERATOR_ABORT 19 ///< Aborted by operator #define TQSL_NOKEY_ERROR 20 ///< No key available #define TQSL_BUFFER_ERROR 21 ///< Insufficient buffer space #define TQSL_INVALID_DATE 22 ///< Date string invalid #define TQSL_SIGNINIT_ERROR 23 ///< Error initializing signing routine #define TQSL_PASSWORD_ERROR 24 ///< Invalid password #define TQSL_EXPECTED_NAME 25 ///< Name expected but not supplied #define TQSL_NAME_EXISTS 26 ///< Entity name exists already #define TQSL_NAME_NOT_FOUND 27 ///< Entity name does not exist #define TQSL_INVALID_TIME 28 ///< Time format is invalid #define TQSL_CERT_DATE_MISMATCH 29 ///< Certificate date mismatch #define TQSL_PROVIDER_NOT_FOUND 30 ///< Certificate provider unknown #define TQSL_CERT_KEY_ONLY 31 ///< No signed public key is installed #define TQSL_CONFIG_ERROR 32 ///< There is an error in the configuration file #define TQSL_CERT_NOT_FOUND 33 ///< The certificate could not be found #define TQSL_PKCS12_ERROR 34 ///< There is an error parsing the .p12 file #define TQSL_CERT_TYPE_ERROR 35 ///< The certificate type is invalid #define TQSL_DATE_OUT_OF_RANGE 36 ///< The date is out of the valid range #define TQSL_DUPLICATE_QSO 37 ///< This QSO is previously signed #define TQSL_DB_ERROR 38 ///< The dupe database could not be accessed #define TQSL_LOCATION_NOT_FOUND 39 ///< The station location is invalid #define TQSL_CALL_NOT_FOUND 40 ///< The callsign could not be located #define TQSL_CONFIG_SYNTAX_ERROR 41 ///< The config file has a syntax error #define TQSL_FILE_SYSTEM_ERROR 42 ///< There was a file system I/O error #define TQSL_FILE_SYNTAX_ERROR 43 ///< The file format is invalid #define TQSL_CERT_ERROR 44 ///< Callsign certificate could not be installed #define TQSL_CERT_MISMATCH 45 ///< Callsign Certificate does not match QSO details #define TQSL_LOCATION_MISMATCH 46 ///< Station Location does not match QSO details #define TQSL_NEW_UPLOAD_DB 47 ///< New upload database created, try to re-load it #define TQSL_INCONSISTENT_GRID 48 ///< Gridsquare inconsistent with location #define TQSL_INVALID_ADIF 49 ///< ADIF field value is invalid #define TQSL_CERT_NOT_FOUND_INVALID 0x10000 ///< Certificate is invalid #define TQSL_CERT_NOT_FOUND_EXPIRED 0x20000 ///< Certificate has expired #define TQSL_CERT_NOT_FOUND_SUPERCEDED 0x40000 ///< Certificate has been replaced with a newer one #endif /* __TQSLERRNO_H */ tqsl-2.8.2/src/tqslconvert.h0000644000175000017500000002127115061653721016041 0ustar rmurphyrmurphy/*************************************************************************** convert.h - description ------------------- begin : Sun Nov 17 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef __tqslconvert_h #define __tqslconvert_h #include "tqsllib.h" /** \file * tQSL library converter functions. */ /** \defgroup Convert Converter API * * The Converter API provides the capability of converting Cabrillo * and ADIF files to GABBI output. */ /** @{ */ typedef void * tQSL_Converter; //!< Opaque converter type used by applications //!< to access conversion functions //!< #ifdef __cplusplus extern "C" { #endif /** Create a simple converter object * * Allocates resources for converting logs and processing duplicate records. */ DLLEXPORT int CALLCONVENTION tqsl_beginConverter(tQSL_Converter *convp); /** Initiates the conversion process for an ADIF file. * * \c certs and \c ncerts define a set of certificates that are available to the * converter for signing records. Typically, this list will be obtained by * calling tqsl_selectCertificates(). * * tqsl_endConverter() should be called to free the resources when the conversion * is finished. */ DLLEXPORT int CALLCONVENTION tqsl_beginADIFConverter(tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc); /** Initiates the conversion process for a Cabrillo file. * * \c certs and \c ncerts define a set of certificates that are available to the * converter for signing records. Typically, this list will be obtained by * calling tqsl_selectCertificates(). * * tqsl_endConverter() should be called to free the resources when the conversion * is finished. */ DLLEXPORT int CALLCONVENTION tqsl_beginCabrilloConverter(tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc); /** End the conversion process by freeing the used resources. */ DLLEXPORT int CALLCONVENTION tqsl_endConverter(tQSL_Converter *conv); /** Configure the converter to allow (allow != 0) or disallow (allow == 0) * nonamateur call signs in the CALL field. (Note: the test for * validity is fairly trivial and will allow some nonamateur calls to * get through, but it does catch most common errors.) * * \c allow defaults to 0 when tqsl_beginADIFConverter or * tqsl_beginCabrilloConverter is called. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowBadCall(tQSL_Converter conv, int allow); #define TQSL_LOC_IGNORE 0 ///< Ignore MY_ ADIF fields #define TQSL_LOC_REPORT 1 ///< Report on MY_ ADIF fields not matching cert/location #define TQSL_LOC_UPDATE 2 ///< Update Cert/Loc to track MY_ ADIF fields /** Configure the converter's handing of QTH fields in an adif input file * * \c allow defaults to 0 when tqsl_beginADIFConverter or * tqsl_beginCabrilloConverter is called. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterQTHDetails(tQSL_Converter conv, int logverify); /** Configure the converter to allow (allow != 0) or disallow (allow == 0) * duplicate QSOs in a signed log. * Duplicate detection is done using QSO details, location details, and * certificate serial number. * * \c allow defaults to 1 for backwards compatibility when tqsl_beginADIFConverter or * tqsl_beginCabrilloConverter is called. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowDuplicates(tQSL_Converter convp, int ignore); /** Configure the converter to ignore (ignore != 0) or include (ignore == 0) * seconds in times when detecting duplicate QSOs in a signed log. * Duplicate detection is done using QSO details, location details, and * certificate serial number. * * \c ignore defaults to 0. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreSeconds(tQSL_Converter convp, int ignore); /** Configure the converter to ignore (ignore != 0) or include (ignore == 0) * callsigns in ADIF logs, * * \c ignore defaults to 0. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreCallsigns(tQSL_Converter convp, int ignore); /** Specify the name of the application using the conversion library. * This is output in a header record in the exported log file. * Call this before calling tqsl_getConverterGABBI. * * \c app is a c string containing the application name. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterAppName(tQSL_Converter convp, const char *app); /** Configure the converter to just write duplicate database records * No signing, etc. * * \c dupesOnly defaults to 0. */ DLLEXPORT int CALLCONVENTION tqsl_setConverterDupesOnly(tQSL_Converter convp, int dupesOnly); /** Roll back insertions into the duplicates database. * * This is called when cancelling creating a log, and causes any records * added to the duplicates database to be removed so re-processing that * log does not cause the records to be mis-marked as duplicates. */ DLLEXPORT int CALLCONVENTION tqsl_converterRollBack(tQSL_Converter convp); /** Commits insertions into the duplicates database. * * This is called when a log is created normally and without issue, and so * the presumption is that we are "done" with these QSOs. */ DLLEXPORT int CALLCONVENTION tqsl_converterCommit(tQSL_Converter convp); /** Bulk read the duplicate DB records * * This is called to retrieve the QSO records from the dupe database. * It returns the key/value pair upon each call. * Return -1 for end of file, 0 for success, 1 for errors. */ DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecords(tQSL_Converter convp, char *key, char *data, int keylen); /** Bulk read the duplicate DB records * * This is called to retrieve the QSO records from the dupe database. * It returns the key/value pair upon each call. * Return -1 for end of file, 0 for success, 1 for errors. * V2 expects a 256 byte buffer for the "data" string. */ DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecordsV2(tQSL_Converter convp, char *key, char *data, int keylen); /** Bulk write duplicate DB records * * This is called to store a QSO record into the dupe database. * * Return -1 for duplicate insertion, 0 for success, 1 for errors. */ DLLEXPORT int CALLCONVENTION tqsl_putDuplicateRecord(tQSL_Converter convp, const char *key, const char *data, int keylen); /** Set QSO date filtering in the converter. * * If \c start points to a valid date, QSOs prior to that date will be ignored * by the converter. Similarly, if \c end points to a valid date, QSOs after * that date will be ignored. Either or both may be NULL (or point to an * invalid date) to disable date filtering for the respective range. */ DLLEXPORT int CALLCONVENTION tqsl_setADIFConverterDateFilter(tQSL_Converter conv, tQSL_Date *start, tQSL_Date *end); /** This is the main converter function. It returns a single GABBI * record. * * Returns the NULL pointer on error or EOF. (Test tQSL_Error to determine which.) * * tQSL_Error is set to TQSL_DATE_OUT_OF_RANGE if QSO date range checking * is active and the QSO date is outside the specified range. * This is a non-fatal error. * * tQSL_Error is set to TQSL_DUPLICATE_QSO if the QSO has already been * processed on the current computer. * * tQSL_Error is set to TQSL_NEW_UPLOAD_DB if a new uploads database was * created. This allows TQSL to attempt to re-load the QSOs from the most recent * automatic backup (if it exists). * * N.B. On systems that distinguish text-mode files from binary-mode files, * notably Windows, the GABBI records should be written in binary mode. * * N.B. If the selected certificate has not been initialized for signing via * tqsl_beginSigning(), this function will return a TQSL_SIGNINIT_ERROR. * The cert that caused the error can be obtained via tqsl_getConverterCert(), * initialized for signing, and then this function can be called again. No * data records will be lost in this process. */ DLLEXPORT const char* CALLCONVENTION tqsl_getConverterGABBI(tQSL_Converter conv); /** Get the certificate used to sign the most recent QSO record. */ DLLEXPORT int CALLCONVENTION tqsl_getConverterCert(tQSL_Converter conv, tQSL_Cert *certp); /** Get the input-file line number last read by the converter, starting * at line 1. */ DLLEXPORT int CALLCONVENTION tqsl_getConverterLine(tQSL_Converter conv, int *lineno); /** Get the text of the last record read by the converter. * * Returns NULL on error. */ DLLEXPORT const char* CALLCONVENTION tqsl_getConverterRecordText(tQSL_Converter conv); /** @} */ #ifdef __cplusplus } #endif #endif /* __tqslconvert_h */ tqsl-2.8.2/src/tqslconvert.cpp0000644000175000017500000021000315061653721016365 0ustar rmurphyrmurphy/*************************************************************************** tqslconvert.cpp - description ------------------- begin : Sun Nov 17 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #define TQSLLIB_DEF #include "tqslconvert.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tqslerrno.h" #include "tqsllib.h" //#include #ifndef _WIN32 #include #include #else #include #include "windirent.h" #endif #include "winstrdefs.h" using std::set; using std::string; using std::vector; using std::sort; using std::map; static bool checkCallSign(const string& call); namespace tqsllib { class TQSL_CONVERTER { public: TQSL_CONVERTER(); ~TQSL_CONVERTER(); void clearRec(); int sentinel; // FILE *file; tQSL_ADIF adif; tQSL_Cabrillo cab; tQSL_Cert *certs; int ncerts; tQSL_Location loc; TQSL_QSO_RECORD rec; bool rec_done; int cert_idx; int next_cert_uid; int cert_uid; int loc_uid; bool need_station_rec; int *cert_uids; bool allow_bad_calls; set modes; set bands; set propmodes; set satellites; string rec_text; tQSL_Date start, end; int location_handling; bool db_open; sqlite3 *seendb; sqlite3_stmt *bulk_read; bool txn; char *dbpath; FILE* errfile; char serial[512]; char callsign[64]; bool allow_dupes; bool ignore_secs; bool ignore_calls; bool need_ident_rec; bool dupes_only; char *appName; int dxcc; bool newstation; map taglines; int err_tag_line; }; #if !defined(__APPLE__) && !defined(_WIN32) && !defined(__clang__) #pragma GCC diagnostic ignored "-Wformat-truncation" #endif inline TQSL_CONVERTER::TQSL_CONVERTER() : sentinel(0x4445) { // file = 0; adif = 0; cab = 0; cert_idx = -1; dxcc = -1; loc_uid = 0; cert_uid = 0; next_cert_uid = 1; cert_uids = NULL; need_station_rec = false; rec_done = true; allow_bad_calls = false; location_handling = TQSL_LOC_UPDATE; allow_dupes = true; //by default, don't change existing behavior (also helps with commit) ignore_secs = false; // Use full time ignore_calls = false; // Use calls in adif file dupes_only = false; // Not just writing tracking records memset(&rec, 0, sizeof rec); memset(&start, 0, sizeof start); memset(&end, 0, sizeof end); db_open = false; seendb = NULL; bulk_read = NULL; txn = false; dbpath = NULL; errfile = NULL; memset(&serial, 0, sizeof serial); memset(&callsign, 0, sizeof callsign); appName = NULL; need_ident_rec = true; err_tag_line = 0; // Init the band data const char *val; int n = 0; tqsl_getNumBand(&n); for (int i = 0; i < n; i++) { val = 0; tqsl_getBand(i, &val, 0, 0, 0); if (val) bands.insert(val); } // Init the mode data n = 0; tqsl_getNumMode(&n); for (int i = 0; i < n; i++) { val = 0; tqsl_getMode(i, &val, 0); if (val) modes.insert(val); } // Init the propagation mode data n = 0; tqsl_getNumPropagationMode(&n); for (int i = 0; i < n; i++) { val = 0; tqsl_getPropagationMode(i, &val, 0); if (val) propmodes.insert(val); } // Init the satellite data n = 0; tqsl_getNumSatellite(&n); for (int i = 0; i < n; i++) { val = 0; tqsl_getSatellite(i, &val, 0, 0, 0); if (val) satellites.insert(val); } } inline TQSL_CONVERTER::~TQSL_CONVERTER() { clearRec(); // if (file) // fclose(file); tqsl_endADIF(&adif); if (cert_uids) delete[] cert_uids; sentinel = 0; } inline void TQSL_CONVERTER::clearRec() { memset(&rec, 0, sizeof rec); rec_text = ""; err_tag_line = 0; } #define CAST_TQSL_CONVERTER(x) ((tqsllib::TQSL_CONVERTER *)(x)) } // namespace tqsllib using tqsllib::TQSL_CONVERTER; template static void add_to_container(const char *str, size_t len, void *data) { Container *cont = static_cast(data); cont->push_back(string(str, len)); } typedef void(*split_fn)(const char *, size_t, void *); static void split(const char *str, char sep, split_fn fun, void *data) { unsigned int start = 0, stop; for (stop = 0; str[stop]; stop++) { if (str[stop] == sep) { fun(str + start, stop - start, data); start = stop + 1; } } fun(str + start, stop - start, data); } template static void splitStr(const string& str, Container& cont, char delim = ' ') { split(str.c_str(), delim, static_cast(add_to_container), &cont); } static char * fix_freq(const char *in) { static char out[128]; const char *p = in; bool decimal = false; char *o = out; while (*p) { if (*p == '.') { if (decimal) { p++; continue; } decimal = true; } *o++ = *p++; } *o = '\0'; return out; } static char * tqsl_strtoupper(char *str) { for (char *cp = str; *cp != '\0'; cp++) *cp = toupper(*cp); return str; } static TQSL_CONVERTER * check_conv(tQSL_Converter conv) { if (tqsl_init()) return 0; if (conv == 0 || CAST_TQSL_CONVERTER(conv)->sentinel != 0x4445) return 0; return CAST_TQSL_CONVERTER(conv); } static tqsl_adifFieldDefinitions adif_qso_record_fields[] = { { "CALL", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_CALLSIGN_MAX, 0, 0, NULL }, { "BAND", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_BAND_MAX, 0, 0, NULL }, { "MODE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_MODE_MAX, 0, 0, NULL }, { "SUBMODE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_MODE_MAX, 0, 0, NULL }, { "QSO_DATE", "", TQSL_ADIF_RANGE_TYPE_NONE, 10, 0, 0, NULL }, { "TIME_ON", "", TQSL_ADIF_RANGE_TYPE_NONE, 10, 0, 0, NULL }, { "FREQ", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_FREQ_MAX, 0, 0, NULL }, { "FREQ_RX", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_FREQ_MAX, 0, 0, NULL }, { "BAND_RX", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_BAND_MAX, 0, 0, NULL }, { "SAT_NAME", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_SATNAME_MAX, 0, 0, NULL }, { "PROP_MODE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_PROPMODE_MAX, 0, 0, NULL }, /* Fields specifying contents of the location for a QSO */ { "MY_CNTY", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_CNTY_MAX, 0, 0, NULL }, { "MY_COUNTRY", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_COUNTRY_MAX, 0, 0, NULL }, { "MY_CQ_ZONE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_ZONE_MAX, 0, 0, NULL }, { "MY_DXCC", "", TQSL_ADIF_RANGE_TYPE_NONE, 10, 0, 0, NULL }, { "MY_GRIDSQUARE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_GRID_MAX, 0, 0, NULL }, { "MY_IOTA", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_IOTA_MAX, 0, 0, NULL }, { "MY_ITU_ZONE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_ZONE_MAX, 0, 0, NULL }, { "MY_STATE", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_STATE_MAX, 0, 0, NULL }, { "MY_VUCC_GRIDS", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_GRID_MAX, 0, 0, NULL }, // Operator - make it long as some people use it as a name { "OPERATOR", "", TQSL_ADIF_RANGE_TYPE_NONE, 100, 0, 0, NULL }, { "STATION_CALLSIGN", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_CALLSIGN_MAX, 0, 0, NULL }, #ifdef USE_OWNER_CALLSIGN { "OWNER_CALLSIGN", "", TQSL_ADIF_RANGE_TYPE_NONE, TQSL_CALLSIGN_MAX, 0, 0, NULL }, #endif { "eor", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL }, { "", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL }, // Correction from JJ1BDX }; static void tqsl_db_get_errstr(TQSL_CONVERTER *conv) { if (sqlite3_errcode(conv->seendb) == SQLITE_BUSY) { strncpy(tQSL_CustomError, "The uploads database is busy. You must exit any running copies of TQSL to be able to sign a log", sizeof tQSL_CustomError); } else { strncpy(tQSL_CustomError, sqlite3_errmsg(conv->seendb), sizeof tQSL_CustomError); } } static void close_db(TQSL_CONVERTER *conv) { tqslTrace("close_db", NULL); if (conv->txn) { if (SQLITE_OK != sqlite3_exec(conv->seendb, "END;", NULL, NULL, NULL)) { tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; tqsl_db_get_errstr(conv); tqslTrace("close_db", "Error ending transaction: %s", tQSL_CustomError); } conv->txn = false; } if (conv->db_open) { if (SQLITE_OK != sqlite3_close(conv->seendb)) { tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; tqsl_db_get_errstr(conv); tqslTrace("close_db", "Error closing database: %s", tQSL_CustomError); } // close files and clean up converters, if any if (conv->adif) tqsl_endADIF(&conv->adif); if (conv->cab) tqsl_endCabrillo(&conv->cab); if (conv->errfile) fclose(conv->errfile); conv->errfile = NULL; } conv->db_open = false; return; } DLLEXPORT int CALLCONVENTION tqsl_beginConverter(tQSL_Converter *convp) { tqslTrace("tqsl_beginConverter", NULL); if (tqsl_init()) return 0; if (!convp) { tqslTrace("tqsl_beginConverter", "convp=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_CONVERTER *conv = new TQSL_CONVERTER(); if (!conv) { tqslTrace("tqs;_beginConverter", "Out of memory!"); return 1; } *convp = conv; return 0; } DLLEXPORT int CALLCONVENTION tqsl_beginADIFConverter(tQSL_Converter *convp, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc) { tqslTrace("tqsl_beginADIFConverter", NULL); if (tqsl_init()) return 0; if (!convp || !filename) { tqslTrace("tqsl_beginADIFConverter", "arg err convp=0x%lx filename=0x%lx certs=0x%lx", convp, filename, certs); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tQSL_ADIF adif; if (tqsl_beginADIF(&adif, filename)) { tqslTrace("tqsl_beginADIFConverter", "tqsl_beginADIF fail %d", tQSL_Error); return 1; } TQSL_CONVERTER *conv = new TQSL_CONVERTER(); if (!conv) { tqslTrace("tqsl_beginADIFConverter", "Out of memory!"); return 1; } conv->adif = adif; conv->certs = certs; conv->ncerts = ncerts; if (ncerts > 0) { conv->cert_uids = new int[ncerts]; for (int i = 0; i < ncerts; i++) conv->cert_uids[i] = -1; } conv->loc = loc; *convp = conv; tqsl_getLocationCallSign(loc, conv->callsign, sizeof conv->callsign); tqsl_getLocationDXCCEntity(loc, &conv->dxcc); return 0; } DLLEXPORT int CALLCONVENTION tqsl_beginCabrilloConverter(tQSL_Converter *convp, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc) { tqslTrace("tqsl_beginCabrilloConverter", NULL); if (tqsl_init()) return 0; if (!convp || !filename) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_beginCabrilloConverter", "arg error convp=0x%lx, filename=0x%lx, certs=0x%lx", convp, filename, certs); return 1; } tQSL_Cabrillo cab; if (tqsl_beginCabrillo(&cab, filename)) { tqslTrace("tqsl_beginCabrilloConverter", "tqsl_beginCabrillo fail %d", tQSL_Error); return 1; } TQSL_CONVERTER *conv = new TQSL_CONVERTER(); if (!conv) { tqslTrace("tqsl_beginCabrilloConverter", "Out of memory!"); return 1; } conv->cab = cab; conv->certs = certs; conv->ncerts = ncerts; if (ncerts > 0) { conv->cert_uids = new int[ncerts]; for (int i = 0; i < ncerts; i++) conv->cert_uids[i] = -1; } conv->loc = loc; *convp = conv; tqsl_getLocationCallSign(loc, conv->callsign, sizeof conv->callsign); tqsl_getLocationDXCCEntity(loc, &conv->dxcc); return 0; } /* * Get a dupes db record by key. * Return: * 0 = Retrieved OK * 1 = No record * -1 = Error */ static int get_dbrec(sqlite3 *db, const char *key, char **result) { int rc; sqlite3_stmt *pstmt; rc = sqlite3_prepare_v2(db, "SELECT * from QSOs where tContact = ?;", 256, &pstmt, NULL); if (SQLITE_OK != rc) { return -1; } rc = sqlite3_bind_text(pstmt, 1, key, strlen(key), NULL); if (SQLITE_OK != rc) { sqlite3_finalize(pstmt); return -1; } rc = sqlite3_step(pstmt); if (SQLITE_DONE == rc) { // No record matches sqlite3_finalize(pstmt); return 1; } if (SQLITE_ROW != rc) { sqlite3_finalize(pstmt); return -1; } *result = strdup(reinterpret_cast(sqlite3_column_text(pstmt, 1))); sqlite3_finalize(pstmt); pstmt = NULL; return 0; } static int put_dbrec(sqlite3 *db, const char *key, const char *data) { int rc; sqlite3_stmt *pstmt; rc = sqlite3_prepare_v2(db, "INSERT OR IGNORE INTO QSOs VALUES(?, ?);", 256, &pstmt, NULL); if (SQLITE_OK != rc) { return -1; } rc = sqlite3_bind_text(pstmt, 1, key, strlen(key), NULL); if (SQLITE_OK != rc) { sqlite3_finalize(pstmt); return -1; } rc = sqlite3_bind_text(pstmt, 2, data, strlen(reinterpret_cast(data)), NULL); if (SQLITE_OK != rc) { return -1; } rc = sqlite3_step(pstmt); if (SQLITE_DONE == rc) { sqlite3_finalize(pstmt); return 0; } sqlite3_finalize(pstmt); return -1; } static int del_dbrec(sqlite3 *db, const char *key) { int rc; sqlite3_stmt *pstmt; rc = sqlite3_prepare_v2(db, "DELETE QSOs WHERE tContact = ?;", 256, &pstmt, NULL); if (SQLITE_OK != rc) { return -1; } rc = sqlite3_bind_text(pstmt, 1, key, strlen(key), NULL); if (SQLITE_OK != rc) { sqlite3_finalize(pstmt); return -1; } rc = sqlite3_step(pstmt); if (SQLITE_DONE == rc) { sqlite3_finalize(pstmt); return 0; } sqlite3_finalize(pstmt); return -1; } DLLEXPORT int CALLCONVENTION tqsl_endConverter(tQSL_Converter *convp) { tqslTrace("tqsl_endConverter", NULL); if (!convp || CAST_TQSL_CONVERTER(*convp) == 0) return 0; TQSL_CONVERTER* conv; if ((conv = check_conv(*convp))) { if (conv->txn) { sqlite3_exec(conv->seendb, "ROLLBACK;", NULL, NULL, NULL); conv->txn = false; } if (conv->db_open) { close_db(conv); } conv->db_open = false; // close files and clean up converters, if any if (conv->adif) tqsl_endADIF(&conv->adif); if (conv->cab) tqsl_endCabrillo(&conv->cab); if (conv->dbpath) free(conv->dbpath); if (conv->errfile) fclose(conv->errfile); conv->errfile = NULL; } if (conv->appName) free(conv->appName); if (CAST_TQSL_CONVERTER(*convp)->sentinel == 0x4445) delete CAST_TQSL_CONVERTER(*convp); *convp = 0; return 0; } static unsigned char * adif_allocate(size_t size) { return new unsigned char[size]; } static int find_matching_cert(TQSL_CONVERTER *conv, int targetdxcc, bool *anyfound) { int i; *anyfound = false; for (i = 0; i < conv->ncerts; i++) { tQSL_Date cdate; char call[256]; int dxcc; if (tqsl_getCertificateCallSign(conv->certs[i], call, sizeof call)) return -1; if (strcasecmp(conv->callsign, call)) // Not for this call continue; if (tqsl_getCertificateDXCCEntity(conv->certs[i], &dxcc)) return -1; if (dxcc != targetdxcc) continue; // Not for this call and DXCC *anyfound = true; if (tqsl_getCertificateQSONotBeforeDate(conv->certs[i], &cdate)) continue; if (tqsl_compareDates(&(conv->rec.date), &cdate) < 0) continue; if (tqsl_getCertificateQSONotAfterDate(conv->certs[i], &cdate)) continue; if (tqsl_compareDates(&(conv->rec.date), &cdate) > 0) continue; return i; } return -1; } static const char *notypes[] = { "D", "T", "M", "C", "N", "S", "B", "E", "L", "" }; // "C" is ADIF 1.0 for "S"; also "I" and "G" in ADIX static const char * tqsl_infer_band(const char* infreq) { char *oldlocale = setlocale(LC_NUMERIC, "C"); double freq = atof(infreq); setlocale(LC_NUMERIC, oldlocale); double freq_khz = freq * 1000.0; int nband = 0; tqsl_getNumBand(&nband); for (int i = 0; i < nband; i++) { const char *name; const char *spectrum; int low, high; if (tqsl_getBand(i, &name, &spectrum, &low, &high)) break; bool match = false; if (!strcmp(spectrum, "HF")) { // Allow for cases where loggers that don't log the // real frequency. if (low == 10100) low = 10000; else if (low == 18068) low = 18000; else if (low == 24890) low = 24000; if (freq_khz >= low && freq_khz <= high) { match = true; } } else { if (freq >= low && freq <= high) match = true; if (freq >= low && high == 0) match = true; } if (match) return name; } return ""; } DLLEXPORT int CALLCONVENTION tqsl_setADIFConverterDateFilter(tQSL_Converter convp, tQSL_Date *start, tQSL_Date *end) { TQSL_CONVERTER *conv; tqslTrace("tqsl_setADIFConverterDateFilter", NULL); if (!(conv = check_conv(convp))) return 1; if (start == NULL) conv->start.year = conv->start.month = conv->start.day = 0; else conv->start = *start; if (end == NULL) conv->end.year = conv->end.month = conv->end.day = 0; else conv->end = *end; return 0; } // Remove the dupes db files static void remove_db(const char *path) { tqslTrace("remove_db", "path=%s", path); #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); _WDIR *dir = _wopendir(wpath); free_wchar(wpath); #else DIR *dir = opendir(path); #endif if (dir != NULL) { #ifdef _WIN32 struct _wdirent *ent = NULL; while ((ent = _wreaddir(dir)) != NULL) { if (!wcscmp(ent->d_name, L"data.mdb") || !wcscmp(ent->d_name, L"lock.mdb") || !wcscmp(ent->d_name, L"uploaded.db") || !wcscmp(ent->d_name, L"uploaded.db-shm") || !wcscmp(ent->d_name, L"uploaded.db-wal")) { #else struct dirent *ent = NULL; while ((ent = readdir(dir)) != NULL) { if (!strcmp(ent->d_name, "data.mdb") || !strcmp(ent->d_name, "lock.mdb") || !strcmp(ent->d_name, "uploaded.db") || !strcmp(ent->d_name, "uploaded.db-shm") || !strcmp(ent->d_name, "uploaded.db-wal")) { #endif string fname = path; int rstat; #ifdef _WIN32 char dname[TQSL_MAX_PATH_LEN]; wcstombs(dname, ent->d_name, TQSL_MAX_PATH_LEN); fname = fname + "/" + dname; wchar_t* wfname = utf8_to_wchar(fname.c_str()); tqslTrace("remove_db", "unlinking %s", fname.c_str()); rstat = _wunlink(wfname); free_wchar(wfname); #else fname = fname + "/" + ent->d_name; tqslTrace("remove_db", "unlinking %s", fname.c_str()); rstat = unlink(fname.c_str()); #endif if (rstat < 0) { tqslTrace("remove_db", "can't unlink %s: %s", fname.c_str(), strerror(errno)); } } } #ifdef _WIN32 _wclosedir(dir); #else closedir(dir); #endif } return; } // Open the uploaded database static bool open_db(TQSL_CONVERTER *conv, bool readonly) { bool dbinit_cleanup = false; bool dblocked = false; int dbret; bool triedRemove = false; bool triedDelete = false; conv->dbpath = strdup(tQSL_BaseDir); #ifndef _WIN32 // Clean up junk in that directory DIR *dir = opendir(conv->dbpath); if (dir != NULL) { struct dirent *ent; while ((ent = readdir(dir)) != NULL) { if (ent->d_name[0] == '.') continue; struct stat s; // If it's a symlink pointing to itself, remove it. string fname = conv->dbpath; fname += "/"; fname += ent->d_name; if (stat(fname.c_str(), &s)) { if (errno == ELOOP) { #ifdef _WIN32 _wunlink(ConvertFromUtf8ToUtf16(fname.c_str())); #else unlink(fname.c_str()); #endif } } } closedir(dir); } #endif string logpath = conv->dbpath; #ifdef _WIN32 logpath += "\\dberr.log"; wchar_t* wlogpath = utf8_to_wchar(logpath.c_str()); conv->errfile = _wfopen(wlogpath, L"wb"); free_wchar(wlogpath); #else logpath += "/dberr.log"; conv->errfile = fopen(logpath.c_str(), "wb"); #endif reopen: while(1) { // Open the database string dbfilename = conv->dbpath; #ifdef _WIN32 dbfilename += "\\uploaded.db"; #else dbfilename += "/uploaded.db"; #endif tqslTrace("open_db", "Opening the database at %s", dbfilename.c_str()); if ((dbret = sqlite3_open_v2(dbfilename.c_str(), &conv->seendb, SQLITE_OPEN_READWRITE, NULL)) != SQLITE_OK) { /* // Tried looking for ENOENT here, but that's not returned. CANTOPEN doesn't have any detail provided. */ if (SQLITE_CANTOPEN == dbret) { tqslTrace("open_db", "DB not found, making a new one"); dbret = sqlite3_open_v2(dbfilename.c_str(), &conv->seendb, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, NULL); if (SQLITE_OK == dbret) { const char *sql = "DROP TABLE IF EXISTS QSOs;" "CREATE TABLE QSOs(tContact TEXT, QTH TEXT);" "CREATE UNIQUE INDEX IF NOT EXISTS tc ON QSOs(tContact);"; char *err_msg; dbret = sqlite3_exec(conv->seendb, sql, 0, 0, &err_msg); if (SQLITE_OK != dbret) { tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; tqsl_db_get_errstr(conv); tqslTrace("open_db", "Error creating table: %s", tQSL_CustomError); break; } else { close_db(conv); tQSL_Error = TQSL_NEW_UPLOAD_DB; return false; } } // Fall through so this doesn't repeat dbinit_cleanup = true; break; } // can't open the db if (!triedRemove) { tqslTrace("open_db", "can't open, removing %s errno %d", sqlite3_errmsg(conv->seendb), errno); remove_db(conv->dbpath); triedRemove = true; continue; } tqslTrace("open_db", "create failed with %s errno %d", sqlite3_errmsg(conv->seendb), errno); if (conv->errfile) fprintf(conv->errfile, "create failed with %s errno %d", sqlite3_errmsg(conv->seendb), errno); dbinit_cleanup = true; break; } else { // Opened OK. Let's make a database table just in case const char *sql = "CREATE TABLE IF NOT EXISTS QSOs(tContact TEXT, QTH TEXT);" "CREATE UNIQUE INDEX IF NOT EXISTS tc ON QSOs(tContact);"; char *err_msg; dbret = sqlite3_exec(conv->seendb, sql, 0, 0, &err_msg); if (SQLITE_OK != dbret) { if (SQLITE_BUSY == dbret) { dbinit_cleanup = true; dblocked = true; break; } // Something is just not right. if (!triedRemove) { tqslTrace("open_db", "can't create tables, error %s - %s errno %d", err_msg, sqlite3_errmsg(conv->seendb), errno); sqlite3_close(conv->seendb); remove_db(conv->dbpath); triedRemove = true; continue; } } // is it really a DB? Try an get dbret = sqlite3_exec(conv->seendb, "SELECT * FROM QSOs LIMIT 1;", NULL, NULL, NULL); if (SQLITE_OK == dbret) { sqlite3_exec(conv->seendb, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL); sqlite3_exec(conv->seendb, "CREATE UNIQUE INDEX IF NOT EXISTS tc ON QSOs(tContact);", NULL, NULL, NULL); break; // All OK } if (SQLITE_BUSY == dbret) { dbinit_cleanup = true; dblocked = true; break; } // probably SQLITE_NOTADB here. Kill it. if (!triedRemove) { tqslTrace("open_db", "can't open, removing %s errno %d", sqlite3_errmsg(conv->seendb), errno); sqlite3_close(conv->seendb); remove_db(conv->dbpath); triedRemove = true; continue; } dbinit_cleanup = true; break; } } if (dbinit_cleanup) { tqslTrace("open_db", "DB open failed, triedDelete=%d", triedDelete); tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; if (dblocked) { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "dblocked"); } else { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "%s: %s", sqlite3_errmsg(conv->seendb), strerror(errno)); } tqslTrace("open_db", "Error opening db: %s", tQSL_CustomError); conv->txn = false; if (conv->db_open) { close_db(conv); } if (conv->errfile) fclose(conv->errfile); conv->errfile = NULL; // Handle case where the database is just broken if ((SQLITE_NOTADB == dbret) && !triedDelete) { tqslTrace("open_db", "Not a database file. Removing db"); remove_db(conv->dbpath); triedDelete = true; goto reopen; } conv->db_open = false; return false; } if (!readonly) { conv->txn = true; dbret = sqlite3_exec(conv->seendb, "BEGIN;", NULL, NULL, NULL); if (SQLITE_OK != dbret) { tqslTrace("open_db", "Can't start transaction!"); } } conv->db_open = true; return true; } static const char* get_ident_rec(TQSL_CONVERTER *conv) { int major = 0, minor = 0, config_major = 0, config_minor = 0; tqsl_getVersion(&major, &minor); tqsl_getConfigVersion(&config_major, &config_minor); char temp[512]; static char ident[512]; snprintf(temp, sizeof temp, "%s Lib: V%d.%d Config: V%d.%d AllowDupes: %s", conv->appName ? conv->appName : "Unknown", major, minor, config_major, config_minor, conv->allow_dupes ? "true" : "false"); temp[sizeof temp - 1] = '\0'; int len = strlen(temp); snprintf(ident, sizeof ident, "%s\n", len, temp); ident[sizeof ident - 1] = '\0'; conv->need_ident_rec = false; return ident; } static const char* get_station_rec(TQSL_CONVERTER *conv) { conv->need_station_rec = false; const char *tStation = tqsl_getGABBItSTATION(conv->loc, conv->loc_uid, conv->cert_uid); tqsl_getCertificateSerialExt(conv->certs[conv->cert_idx], conv->serial, sizeof conv->serial); tqsl_getCertificateCallSign(conv->certs[conv->cert_idx], conv->callsign, sizeof conv->callsign); tqsl_getCertificateDXCCEntity(conv->certs[conv->cert_idx], &conv->dxcc); return tStation; } static bool set_tagline(TQSL_CONVERTER *conv, const char *tag) { if (conv->taglines.find(tag) != conv->taglines.end()) { conv->err_tag_line = conv->taglines[tag]; return true; } return false; } static void parse_adif_qso(TQSL_CONVERTER *conv, int *saveErr, TQSL_ADIF_GET_FIELD_ERROR *stat) { int cstat = 0; conv->taglines.clear(); conv->err_tag_line = 0; while (1) { tqsl_adifFieldResults result; conv->taglines[result.name] = result.line_no; if (tqsl_getADIFField(conv->adif, &result, stat, adif_qso_record_fields, notypes, adif_allocate)) break; if (*stat != TQSL_ADIF_GET_FIELD_SUCCESS && *stat != TQSL_ADIF_GET_FIELD_NO_NAME_MATCH) break; if (!strcasecmp(result.name, "eor")) break; char *resdata = reinterpret_cast(result.data); // Strip leading whitespace if (resdata) { while (isspace(*resdata)) resdata++; // Strip trailing whitespace char *end = resdata + strlen(resdata) - 1; while (isspace(*end)) *end-- = '\0'; } if (!strcasecmp(result.name, "CALL") && resdata) { tqsl_strtoupper(resdata); conv->rec.callsign_set = true; strncpy(conv->rec.callsign, resdata, sizeof conv->rec.callsign); } else if (!strcasecmp(result.name, "BAND") && resdata) { conv->rec.band_set = true; strncpy(conv->rec.band, resdata, sizeof conv->rec.band); } else if (!strcasecmp(result.name, "MODE") && resdata) { tqsl_strtoupper(resdata); conv->rec.mode_set = true; strncpy(conv->rec.mode, resdata, sizeof conv->rec.mode); } else if (!strcasecmp(result.name, "SUBMODE") && resdata) { tqsl_strtoupper(resdata); strncpy(conv->rec.submode, resdata, sizeof conv->rec.submode); } else if (!strcasecmp(result.name, "FREQ") && resdata) { conv->rec.band_set = true; strncpy(conv->rec.freq, fix_freq(resdata), sizeof conv->rec.freq); if (atof(conv->rec.freq) == 0.0) conv->rec.freq[0] = '\0'; } else if (!strcasecmp(result.name, "FREQ_RX") && resdata) { strncpy(conv->rec.rxfreq, fix_freq(resdata), sizeof conv->rec.rxfreq); if (atof(conv->rec.rxfreq) == 0.0) conv->rec.rxfreq[0] = '\0'; } else if (!strcasecmp(result.name, "BAND_RX") && resdata) { strncpy(conv->rec.rxband, resdata, sizeof conv->rec.rxband); } else if (!strcasecmp(result.name, "SAT_NAME") && resdata) { tqsl_strtoupper(resdata); // Two-Line Elements (TLEs) call this AO-07, LoTW wants AO-7. if (!strcasecmp(resdata, "AO-07")) strncpy(conv->rec.satname, "AO-7", sizeof conv->rec.satname); else strncpy(conv->rec.satname, resdata, sizeof conv->rec.satname); } else if (!strcasecmp(result.name, "PROP_MODE") && resdata) { tqsl_strtoupper(resdata); strncpy(conv->rec.propmode, resdata, sizeof conv->rec.propmode); } else if (!strcasecmp(result.name, "QSO_DATE") && resdata) { conv->rec.date_set = true; cstat = tqsl_initDate(&(conv->rec.date), resdata); if (cstat) *saveErr = tQSL_Error; } else if (!strcasecmp(result.name, "TIME_ON") && resdata) { conv->rec.time_set = true; cstat = tqsl_initTime(&(conv->rec.time), resdata); if (cstat) *saveErr = tQSL_Error; if (conv->ignore_secs) conv->rec.time.second = 0; } else if (!strcasecmp(result.name, "MY_CNTY") && resdata) { tqsl_strtoupper(resdata); char *p = strstr(resdata, ","); // Find the comma in "VA,Fairfax" if (p) { char *p1 = p; *p++ = '\0'; strncpy(conv->rec.my_cnty_state, resdata, sizeof conv->rec.my_cnty_state); while (isspace(*p)) p++; // Skip spaces and comma strncpy(conv->rec.my_county, p, sizeof conv->rec.my_county); *p1 = ','; // Put the comma back } else { strncpy(conv->rec.my_county, resdata, sizeof conv->rec.my_county); } } else if (!strcasecmp(result.name, "MY_COUNTRY") && resdata) { if (strcasecmp(resdata, "United States") == 0) { strncpy(conv->rec.my_country, "UNITED STATES OF AMERICA", sizeof conv->rec.my_country); } else { strncpy(conv->rec.my_country, resdata, sizeof conv->rec.my_country); } } else if (!strcasecmp(result.name, "MY_CQ_ZONE") && resdata) { char *endptr; long zone = strtol(resdata, &endptr, 10); if (*endptr == '\0') { // If the conversion was correct snprintf(conv->rec.my_cq_zone, sizeof conv->rec.my_cq_zone, "%ld", zone); } else { // It wasn't a valid number strncpy(conv->rec.my_cq_zone, resdata, sizeof conv->rec.my_cq_zone); } } else if (!strcasecmp(result.name, "MY_DXCC") && resdata) { conv->rec.my_dxcc = strtol(resdata, NULL, 10); } else if (!strcasecmp(result.name, "MY_GRIDSQUARE") && resdata) { strncpy(conv->rec.my_gridsquare, resdata, sizeof conv->rec.my_gridsquare); } else if (!strcasecmp(result.name, "MY_IOTA") && resdata) { tqsl_strtoupper(resdata); strncpy(conv->rec.my_iota, resdata, sizeof conv->rec.my_iota); } else if (!strcasecmp(result.name, "MY_ITU_ZONE") && resdata) { char *endptr; long zone = strtol(resdata, &endptr, 10); if (*endptr == '\0') { // If the conversion was correct snprintf(conv->rec.my_itu_zone, sizeof conv->rec.my_itu_zone, "%ld", zone); } else { // It wasn't a valid number strncpy(conv->rec.my_itu_zone, resdata, sizeof conv->rec.my_itu_zone); } } else if (!strcasecmp(result.name, "MY_STATE") && resdata) { tqsl_strtoupper(resdata); strncpy(conv->rec.my_state, resdata, sizeof conv->rec.my_state); } else if (!strcasecmp(result.name, "MY_VUCC_GRIDS") && resdata) { strncpy(conv->rec.my_vucc_grids, resdata, sizeof conv->rec.my_vucc_grids); } else if (!strcasecmp(result.name, "OPERATOR") && resdata) { // Only use the OPERATOR field if it looks like a callsign tqsl_strtoupper(resdata); string op(resdata); if (!conv->ignore_calls && checkCallSign(op)) { strncpy(conv->rec.my_operator, resdata, sizeof conv->rec.my_operator); conv->rec.my_operator[TQSL_CALLSIGN_MAX] = '\0'; } #ifdef USE_OWNER_CALLSIGN } else if (!strcasecmp(result.name, "OWNER_CALLSIGN") && resdata) { // Only use the OWNER_CALLSIGN field if it looks like a callsign tqsl_strtoupper(resdata); string op(resdata); if (!conv->ignore_calls && checkCallSign(op)) { strncpy(conv->rec.my_owner, resdata, sizeof conv->rec.my_owner); } #endif } else if (!strcasecmp(result.name, "STATION_CALLSIGN") && resdata) { // Only use the STATION_CALLSIGN field if it looks like a callsign tqsl_strtoupper(resdata); string op(resdata); if (!conv->ignore_calls && checkCallSign(op)) { strncpy(conv->rec.my_call, resdata, sizeof conv->rec.my_call); } } else { tqslTrace("parse_adif_qso", "Unknown ADIF field %s", result.name); } if (*stat == TQSL_ADIF_GET_FIELD_SUCCESS) { conv->rec_text += string(reinterpret_cast(result.name)) + ": "; if (resdata) conv->rec_text += string(resdata); conv->rec_text += "\n"; } if (result.data) delete[] result.data; } return; } static int check_station(TQSL_CONVERTER *conv, const char *field, const char *my_field, char *my, size_t len, const char *errfmt, bool update) { // // UPDATE is a boolean that when a change is made, that change // is propagated to the downstream values. STATE -> COUNTY and STATE->ZONES // char val[256]; char label[256]; const char *newProvince = NULL; const char *newOblast = NULL; // CA_PROVINCE can be QC but TQSL lookup expects PQ if (!strcasecmp(field, "CA_PROVINCE") && !strcasecmp(my, "QC")) { newProvince = "PQ"; strncpy(my, "PQ", len); } // CA_PROVINCE can be NL but TQSL lookup expects NF if (!strcasecmp(field, "CA_PROVINCE") && !strcasecmp(my, "NL")) { newProvince = "NF"; strncpy(my, "NF", len); } // RU_OBLAST can be YR but TQSL lookup expects JA if (!strcasecmp(field, "RU_OBLAST") && !strcasecmp(my, "YR")) { newOblast = "JA"; strncpy(my, "JA", len); } // RU_OBLAST can be YN but TQSL lookup expects JN if (!strcasecmp(field, "RU_OBLAST") && !strcasecmp(my, "YN")) { newOblast = "JN"; strncpy(my, "JN", len); } if (my[0] && !tqsl_getLocationField(conv->loc, field, val, sizeof val) && !tqsl_getLocationFieldLabel(conv->loc, field, label, sizeof label)) { if (!strcasecmp(my, label)) { // Label is correct, ADIF is not strncpy(my, val, len); // So use the value } if (strcasecmp(my, val)) { if (conv->location_handling == TQSL_LOC_UPDATE) { int res = tqsl_setLocationField(conv->loc, field, my); // -1 means trying to set a value that is not in the enumeration if (res == -1) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, errfmt, my, val); tQSL_Error = TQSL_LOCATION_MISMATCH | TQSL_MSG_FLAGGED; set_tagline(conv, my_field); return 1; } // -2 means that the label matched, so use that if (res == -2) { strncpy(my, tQSL_CustomError, len); } if (update) tqsl_updateStationLocationCapture(conv->loc); conv->newstation = true; } else if (strlen(val) > 0) { conv->rec_done = true; if (newProvince) { strncpy(my, newProvince, len); } if (newOblast) { strncpy(my, newOblast, len); } snprintf(tQSL_CustomError, sizeof tQSL_CustomError, errfmt, val, my); tQSL_Error = TQSL_LOCATION_MISMATCH; set_tagline(conv, my_field); return 1; } else { tqsl_setLocationField(conv->loc, field, my); if (update) tqsl_updateStationLocationCapture(conv->loc); conv->newstation = true; } } } return 0; // OK } DLLEXPORT const char* CALLCONVENTION tqsl_getConverterGABBI(tQSL_Converter convp) { TQSL_CONVERTER *conv; char signdata[1024]; int cstat = 0; if (!(conv = check_conv(convp))) return 0; if (conv->need_ident_rec) { return get_ident_rec(conv); } if (!conv->allow_dupes && !conv->db_open) { if (!open_db(conv, false)) { // If can't open dupes DB return 0; } } TQSL_ADIF_GET_FIELD_ERROR stat; if (conv->rec_done) { conv->rec_done = false; conv->clearRec(); int saveErr = 0; if (conv->adif) { parse_adif_qso(conv, &saveErr, &stat); if (saveErr) { tQSL_Error = saveErr; conv->rec_done = true; return 0; } if (stat == TQSL_ADIF_GET_FIELD_EOF) return 0; if (stat != TQSL_ADIF_GET_FIELD_SUCCESS) { tQSL_ADIF_Error = stat; tQSL_Error = TQSL_ADIF_ERROR; return 0; } conv->err_tag_line = 0; // ADIF record is complete. See if we need to infer the BAND fields. if (conv->rec.band[0] == 0) strncpy(conv->rec.band, tqsl_infer_band(conv->rec.freq), sizeof conv->rec.band); if (conv->rec.rxband[0] == 0) strncpy(conv->rec.rxband, tqsl_infer_band(conv->rec.rxfreq), sizeof conv->rec.rxband); // Normalize the DXCC country if (conv->rec.my_country[0] != 0) { int num_dxcc = 0; tqsl_getNumDXCCEntity(&num_dxcc); const char *entity = NULL; int ent_num; bool found = false; for (int i = 0; i < num_dxcc; i++) { tqsl_getDXCCEntity(i, &ent_num, &entity); if (entity && strcasecmp(entity, conv->rec.my_country) == 0) { found = true; // Consistent DXCC ? if (conv->rec.my_dxcc == 0) { conv->rec.my_dxcc = ent_num; } else { // MY_DXCC and MY_COUNTRY do not match. Report this. if (conv->rec.my_dxcc != ent_num) { conv->rec_done = true; const char *d1; tqsl_getDXCCEntityName(conv->rec.my_dxcc, &d1); snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "DXCC Entity|%s (%d)|%s (%d)", d1, conv->rec.my_dxcc, conv->rec.my_country, i); tQSL_Error = TQSL_CERT_MISMATCH; return 0; } } break; } } if (!found) { // Country name is bogus conv->rec.my_country[0] = '\0'; } } // Normalize the grids if (conv->rec.my_vucc_grids[0] != 0) { strncpy(conv->rec.my_gridsquare, conv->rec.my_vucc_grids, TQSL_GRID_MAX); } // Normalize callsign // Priority - STATION_CALLSIGN, then OPERATOR, then OWNER_CALLSIGN // my_call has STATION_CALLSIGN already. if (!conv->ignore_calls && conv->rec.my_call[0] == '\0' && conv->rec.my_operator[0] != 0) { // OPERATOR set strncpy(conv->rec.my_call, conv->rec.my_operator, TQSL_CALLSIGN_MAX); } #ifdef USE_OWNER_CALLSIGN if (!conv->ignore_calls && conv->rec.my_call[0] == '\0' && conv->rec.my_owner[0] != 0) { // OWNER_CALLSIGN set strncpy(conv->rec.my_call, conv->rec.my_owner, TQSL_CALLSIGN_MAX); } #endif if (conv->location_handling == TQSL_LOC_UPDATE && conv->rec.my_call[0] != '\0') { // If any of these strncpy(conv->callsign, conv->rec.my_call, sizeof conv->callsign); // got a callsign } } else if (conv->cab) { TQSL_CABRILLO_ERROR_TYPE stat; do { tqsl_cabrilloField field; if (tqsl_getCabrilloField(conv->cab, &field, &stat)) return 0; if (stat == TQSL_CABRILLO_NO_ERROR || stat == TQSL_CABRILLO_EOR) { // Field found if (!strcasecmp(field.name, "CALL")) { conv->rec.callsign_set = true; strncpy(conv->rec.callsign, field.value, sizeof conv->rec.callsign); } else if (!strcasecmp(field.name, "BAND")) { conv->rec.band_set = true; strncpy(conv->rec.band, field.value, sizeof conv->rec.band); } else if (!strcasecmp(field.name, "MODE")) { conv->rec.mode_set = true; strncpy(conv->rec.mode, field.value, sizeof conv->rec.mode); } else if (!strcasecmp(field.name, "FREQ")) { conv->rec.band_set = true; strncpy(conv->rec.freq, field.value, sizeof conv->rec.freq); } else if (!strcasecmp(field.name, "QSO_DATE")) { conv->rec.date_set = true; cstat = tqsl_initDate(&(conv->rec.date), field.value); if (cstat) saveErr = tQSL_Error; } else if (!strcasecmp(field.name, "TIME_ON")) { conv->rec.time_set = true; cstat = tqsl_initTime(&(conv->rec.time), field.value); if (conv->ignore_secs) conv->rec.time.second = 0; if (cstat) saveErr = tQSL_Error; } else if (!conv->ignore_calls && !strcasecmp(field.name, "MYCALL")) { strncpy(conv->rec.my_call, field.value, sizeof conv->rec.my_call); tqsl_strtoupper(conv->rec.my_call); } if (conv->rec_text != "") conv->rec_text += "\n"; conv->rec_text += string(field.name) + ": " + field.value; } } while (stat == TQSL_CABRILLO_NO_ERROR); if (saveErr) tQSL_Error = saveErr; if (saveErr || stat != TQSL_CABRILLO_EOR) { conv->rec_done = true; return 0; } } else { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "Converter not initialized", sizeof tQSL_CustomError); tqslTrace("tqsl_getConverterGABBI", "Converter not initialized"); return 0; } } // Does the QSO have the basic required elements? if (!conv->rec.callsign_set) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid contact - QSO does not specify a Callsign"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (!conv->rec.band_set) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid contact - QSO does not specify a band or frequency"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (!conv->rec.mode_set) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid contact - QSO does not specify a mode"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (!conv->rec.date_set) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid contact - QSO does not specify a date"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (!conv->rec.time_set) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid contact - QSO does not specify a time"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } // Check QSO date against user-specified date range. if (tqsl_isDateValid(&(conv->rec.date))) { if (tqsl_isDateValid(&(conv->start)) && tqsl_compareDates(&(conv->rec.date), &(conv->start)) < 0) { conv->rec_done = true; tQSL_Error = TQSL_DATE_OUT_OF_RANGE; set_tagline(conv, "QSO_DATE"); return 0; } if (tqsl_isDateValid(&(conv->end)) && tqsl_compareDates(&(conv->rec.date), &(conv->end)) > 0) { conv->rec_done = true; tQSL_Error = TQSL_DATE_OUT_OF_RANGE; set_tagline(conv, "QSO_DATE"); return 0; } } // Do field value mapping tqsl_strtoupper(conv->rec.callsign); if (!conv->allow_bad_calls) { if (!checkCallSign(conv->rec.callsign)) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid amateur CALL (%s)", conv->rec.callsign); set_tagline(conv, "CALL"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } } tqsl_strtoupper(conv->rec.band); tqsl_strtoupper(conv->rec.rxband); tqsl_strtoupper(conv->rec.mode); tqsl_strtoupper(conv->rec.submode); char val[256]; val[0] = '\0'; // Try to find the GABBI mode several ways. if (conv->rec.submode[0] != '\0') { char modeSub[256]; strncpy(modeSub, conv->rec.mode, sizeof modeSub); size_t left = sizeof modeSub - strlen(modeSub); strncat(modeSub, "%", left); left = sizeof modeSub - strlen(modeSub); strncat(modeSub, conv->rec.submode, left); if (tqsl_getADIFMode(modeSub, val, sizeof val)) { // mode%submode lookup failed // Try just the submode. if (tqsl_getADIFMode(conv->rec.submode, val, sizeof val)) { // bare submode failed if (tqsl_getADIFMode(conv->rec.mode, val, sizeof val)) { val[0] = '\0'; } } } } else { // Just a mode, no submode. Look that up. tqsl_getADIFMode(conv->rec.mode, val, sizeof val); } if (val[0] != '\0') strncpy(conv->rec.mode, val, sizeof conv->rec.mode); // Check field validities if (conv->modes.find(conv->rec.mode) == conv->modes.end()) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid MODE (%s)", conv->rec.mode); set_tagline(conv, "MODE"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (conv->bands.find(conv->rec.band) == conv->bands.end()) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid BAND (%s)", conv->rec.band); set_tagline(conv, "BAND"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (conv->rec.rxband[0] && (conv->bands.find(conv->rec.rxband) == conv->bands.end())) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid RX BAND (%s)", conv->rec.rxband); set_tagline(conv, "BAND_RX"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (conv->rec.freq[0] && strcmp(conv->rec.band, "SUBMM") && strcmp(conv->rec.band, tqsl_infer_band(conv->rec.freq))) { // Have a BAND and FREQ. // Frequency is not in that band - ignore it. conv->rec.freq[0] = '\0'; } if (conv->rec.rxfreq[0] && strcmp(conv->rec.rxband, "SUBMM") && strcmp(conv->rec.rxband, tqsl_infer_band(conv->rec.rxfreq))) { // Have a RX_BAND and RX_FREQ. Frequency is not in that band - ignore it. conv->rec.rxfreq[0] = '\0'; } if (conv->rec.propmode[0] != '\0' && conv->propmodes.find(conv->rec.propmode) == conv->propmodes.end()) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid PROP_MODE (%s)", conv->rec.propmode); set_tagline(conv, "PROP_MODE"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (conv->rec.satname[0] != '\0' && conv->satellites.find(conv->rec.satname) == conv->satellites.end()) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Invalid SAT_NAME (%s)", conv->rec.satname); set_tagline(conv, "SAT_NAME"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (!strcmp(conv->rec.propmode, "SAT") && conv->rec.satname[0] == '\0') { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "PROP_MODE = 'SAT' but no SAT_NAME"); set_tagline(conv, "PROP_MODE"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } if (strcmp(conv->rec.propmode, "SAT") && conv->rec.satname[0] != '\0') { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "SAT_NAME set but PROP_MODE is not 'SAT'"); set_tagline(conv, "SAT_NAME"); tQSL_Error = TQSL_CUSTOM_ERROR; return 0; } // Check cert if (!conv->dupes_only && (conv->location_handling != TQSL_LOC_UPDATE && conv->ncerts <= 0)) { conv->rec_done = true; tQSL_Error = TQSL_CERT_NOT_FOUND; return 0; } if (conv->location_handling == TQSL_LOC_UPDATE) { // Is the call right? if (conv->rec.my_call[0]) { strncpy(conv->callsign, conv->rec.my_call, sizeof conv->callsign); } } // For check-only case, need to check callsign now. if (conv->location_handling == TQSL_LOC_REPORT) { // Is the call right? if (conv->rec.my_call[0]) { // Update case handled above when switching certs if (strcmp(conv->rec.my_call, conv->callsign)) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Callsign|%s|%s", conv->callsign, conv->rec.my_call); if (!set_tagline(conv, "STATION_CALLSIGN")) set_tagline(conv, "OPERATOR"); tQSL_Error = TQSL_CERT_MISMATCH; return 0; } } } // Lookup cert - start with conv->dxcc int targetdxcc; targetdxcc = conv->dxcc; // If we're in update mode, use the DXCC from the log if (conv->location_handling == TQSL_LOC_UPDATE) { if (conv->rec.my_dxcc != 0) { targetdxcc = conv->rec.my_dxcc; } } bool anyfound; int cidx; if (conv->dupes_only) { cidx = 0; } else { cidx = find_matching_cert(conv, targetdxcc, &anyfound); } if (cidx < 0) { conv->rec_done = true; const char *entName = NULL; if (tqsl_getDXCCEntityName(targetdxcc, &entName) || entName == NULL) { set_tagline(conv, "MY_DXCC"); snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "MY_DXCC|%d", conv->rec.my_dxcc); conv->rec.my_dxcc = 0; tQSL_Error = TQSL_INVALID_ADIF; return 0; } snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "%s|%s", conv->callsign, entName); tQSL_Error = TQSL_CERT_NOT_FOUND | TQSL_MSG_FLAGGED; if (anyfound) { tQSL_Error = TQSL_CERT_DATE_MISMATCH; set_tagline(conv, "QSO_DATE"); } if (conv->location_handling == TQSL_LOC_UPDATE) { if (conv->rec.my_call[0]) { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "%s|%s", conv->rec.my_call, entName); } } return 0; } if (cidx != conv->cert_idx) { // Switching certs if (conv->dxcc != -1) { conv->dxcc = targetdxcc; tqsl_setLocationCallSign(conv->loc, conv->callsign, conv->dxcc); // Set callsign and DXCC tqsl_setStationLocationCapturePage(conv->loc, 1); // Update to relevant fields tqsl_updateStationLocationCapture(conv->loc); } conv->cert_idx = cidx; if (conv->cert_uids[conv->cert_idx] == -1) { // Need to output tCERT, tSTATION conv->need_station_rec = true; // Need a new station record conv->cert_uid = conv->cert_uids[conv->cert_idx] = conv->next_cert_uid; conv->next_cert_uid++; return tqsl_getGABBItCERT(conv->certs[conv->cert_idx], conv->cert_uid); } else { conv->cert_uid = conv->cert_uids[conv->cert_idx]; } } if (!conv->dupes_only && conv->location_handling != TQSL_LOC_IGNORE) { // Care about MY_* fields // At this point, conv->certs[conv->cert_idx] has the certificate // conv->loc has the location. // First, refresh the certificate data tqsl_getCertificateSerialExt(conv->certs[conv->cert_idx], conv->serial, sizeof conv->serial); tqsl_getCertificateCallSign(conv->certs[conv->cert_idx], conv->callsign, sizeof conv->callsign); tqsl_getCertificateDXCCEntity(conv->certs[conv->cert_idx], &conv->dxcc); // Is the call right? if (conv->rec.my_call[0]) { // Update case handled above when switching certs if (strcmp(conv->rec.my_call, conv->callsign)) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Callsign|%s|%s", conv->callsign, conv->rec.my_call); if (!set_tagline(conv, "STATION_CALLSIGN")) set_tagline(conv, "OPERATOR"); tQSL_Error = TQSL_CERT_MISMATCH; return 0; } } // Is the DXCC right? if (conv->rec.my_dxcc) { if (conv->rec.my_dxcc != conv->dxcc) { if (conv->location_handling == TQSL_LOC_UPDATE) { // Care about MY_* fields tqsl_setLocationField(conv->loc, "CALL", conv->callsign); tqsl_updateStationLocationCapture(conv->loc); } else { conv->rec_done = true; const char *d1, *d2 = NULL; tqsl_getDXCCEntityName(conv->dxcc, &d1); tqsl_getDXCCEntityName(conv->rec.my_dxcc, &d2); snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "DXCC Entity|%s (%d)|%s (%d)", d1 ? d1 : "Invalid", conv->dxcc, d2 ? d2 : "Invalid", conv->rec.my_dxcc); set_tagline(conv, "MY_DXCC"); tQSL_Error = TQSL_CERT_MISMATCH; return 0; } } } conv->newstation = false; /* * Gridsquare handling - if the four-character grid matches the station loc * then don't complain; this is common for FT8/FT4 which have four char grids * and we don't want to reject every WSJT-X QSO just because the station * location has a higher precision grid. Similarly, if the Station Location has * a six-character grid and the log has 8, then just compare 6 for report mode. */ int rc = tqsl_getLocationField(conv->loc, "GRIDSQUARE", val, sizeof val); // Have both my_gridsquare and a grid in the stn loc if (conv->rec.my_gridsquare[0] && (rc == 0)) { bool okgrid = true; unsigned int stnLen = strlen(val); unsigned int logLen = strlen(conv->rec.my_gridsquare); unsigned int compareLen = 99; if (stnLen > 4 && logLen == 4) { // Fix the FT8 case compareLen = 4; } char locstate[50]; locstate[0] = '\0'; tqsl_getLocationField(conv->loc, "US_STATE", locstate, sizeof locstate); int ent; tqsl_getLocationDXCCEntity(conv->loc, &ent); int consistentGrid; char grid4[5]; if (strstr(val, ",") || strstr(conv->rec.my_gridsquare, ",")) { // If it's a corner/edge bool matches = false; vectorstngrids; vectorqsogrids; splitStr(val, stngrids, ','); splitStr(conv->rec.my_gridsquare, qsogrids, ','); size_t nstn = stngrids.size(); size_t nqso = qsogrids.size(); if (nstn != nqso) { matches = false; } else { sort(stngrids.begin(), stngrids.end()); sort(qsogrids.begin(), qsogrids.end()); for (size_t i = 0; i < nstn; i++) { char reformatted[TQSL_GRID_MAX + 1]; if (tqsl_verifyGridFormat(qsogrids[i].c_str(), false, reformatted, sizeof reformatted)) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Gridsquare|%s", conv->rec.my_gridsquare); set_tagline(conv, "GRIDSQUARE"); tQSL_Error = TQSL_INVALID_ADIF; return 0; } else { qsogrids[i] = string(reformatted); } strncpy(grid4, qsogrids[i].c_str(), 4); grid4[4] = '\0'; // truncate to four if (!tqsl_validateVUCCGrid(ent, locstate, grid4, &consistentGrid)) { if (consistentGrid == 0) { // Not valid for Entity and PAS set_tagline(conv, "MY_VUCC_GRIDS"); tQSL_Error = TQSL_INCONSISTENT_GRID | consistentGrid; conv->rec_done = true; return 0; } } if (strcasecmp(stngrids[i].c_str(), qsogrids[i].c_str())) { compareLen = 99; // Doesn't match, so error out if appropriate break; } } matches = true; } if (!matches && check_station(conv, "GRIDSQUARE", "MY_GRIDSQUARE", conv->rec.my_gridsquare, sizeof conv->rec.my_gridsquare, "Gridsquare|%s|%s", false)) return 0; } else { /* Single gridsquare */ if (tqsl_verifyGridFormat(conv->rec.my_gridsquare, true, conv->rec.my_gridsquare, sizeof conv->rec.my_gridsquare)) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Gridsquare|%s", conv->rec.my_gridsquare); set_tagline(conv, "GRIDSQUARE"); tQSL_Error = TQSL_INVALID_ADIF; return 0; } /* * FT8 four-char grid handling. * For station location set to AA01aa and FT8 saying AA01 * Treat that as a match */ okgrid = (strncasecmp(conv->rec.my_gridsquare, val, compareLen) == 0); if (!okgrid) { if (conv->location_handling == TQSL_LOC_UPDATE) { tqsl_setLocationField(conv->loc, "GRIDSQUARE", conv->rec.my_gridsquare); conv->newstation = true; } else { if (val[0] == '\0') { // If station location has an empty grid tqsl_setLocationField(conv->loc, "GRIDSQUARE", conv->rec.my_gridsquare); conv->newstation = true; } else { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Gridsquare|%s|%s", val, conv->rec.my_gridsquare); set_tagline(conv, "GRIDSQUARE"); tQSL_Error = TQSL_LOCATION_MISMATCH; return 0; } } } } } switch (conv->dxcc) { case 6: // Alaska case 110: // Hawaii case 291: // Cont US if (check_station(conv, "US_STATE", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "US State|%s|%s", true)) return 0; if (check_station(conv, "US_COUNTY", "MY_CNTY", conv->rec.my_county, sizeof conv->rec.my_county, "US County|%s|%s", false)) return 0; break; case 1: // Canada if (check_station(conv, "CA_PROVINCE", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "CA Province|%s|%s", true)) return 0; break; case 15: // Asiatic Russia case 54: // European Russia case 61: // FJL case 125: // Juan Fernandez case 151: // Malyj Vysotskij if (check_station(conv, "RU_OBLAST", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "RU Oblast|%s|%s", true)) return 0; break; case 318: // China if (check_station(conv, "CN_PROVINCE", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "CN Province|%s|%s", true)) return 0; break; case 150: // Australia if (check_station(conv, "AU_STATE", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "AU State|%s|%s", true)) return 0; break; case 339: // Japan if (check_station(conv, "JA_PREFECTURE", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "JA Prefecture|%s|%s", true)) return 0; if (check_station(conv, "JA_CITY_GUN_KU", "MY_CNTY", conv->rec.my_county, sizeof conv->rec.my_county, "JA City/Gun/Ku|%s|%s", false)) return 0; break; case 5: // Finland if (check_station(conv, "FI_KUNTA", "MY_STATE", conv->rec.my_state, sizeof conv->rec.my_state, "FI Kunta|%s|%s", true)) return 0; break; } if (check_station(conv, "ITUZ", "MY_ITU_ZONE", conv->rec.my_itu_zone, sizeof conv->rec.my_itu_zone, "ITU Zone|%s|%s", false)) return 0; if (check_station(conv, "CQZ", "MY_CQ_ZONE", conv->rec.my_cq_zone, sizeof conv->rec.my_cq_zone, "CQ Zone|%s|%s", false)) return 0; if (conv->rec.my_iota[0] != '\0') { // IOTA identifiers: AF-123 form. int num = strtol(conv->rec.my_iota + 3, NULL, 10); if ((num == 0) || (strlen(conv->rec.my_iota) != 6) || (strncmp(conv->rec.my_iota, "AF-", 3) && strncmp(conv->rec.my_iota, "AN-", 3) && strncmp(conv->rec.my_iota, "AS-", 3) && strncmp(conv->rec.my_iota, "EU-", 3) && strncmp(conv->rec.my_iota, "NA-", 3) && strncmp(conv->rec.my_iota, "OC-", 3) && strncmp(conv->rec.my_iota, "SA-", 3))) { conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "MY_IOTA|%s", conv->rec.my_iota); tQSL_Error = TQSL_INVALID_ADIF; set_tagline(conv, "MY_IOTA"); return 0; } if (check_station(conv, "IOTA", "MY_IOTA", conv->rec.my_iota, sizeof conv->rec.my_iota, "IOTA|%s|%s", false)) return 0; } char locstate[5]; locstate[0] = '\0'; if (conv->rec.my_cnty_state[0] != '\0') { tqsl_getLocationField(conv->loc, "US_STATE", locstate, sizeof locstate); if (strcasecmp(conv->rec.my_cnty_state, locstate)) { // County does not match state conv->rec_done = true; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "US County State|%s|%s", conv->rec.my_cnty_state, locstate); set_tagline(conv, "US_STATE"); tQSL_Error = TQSL_LOCATION_MISMATCH | TQSL_MSG_FLAGGED; return 0; } } if (conv->newstation) { conv->newstation = false; conv->loc_uid++; return get_station_rec(conv); } } // if ignoring MY_ fields if (conv->need_station_rec) { conv->loc_uid++; return get_station_rec(conv); } if (conv->dupes_only) conv->rec.do_not_sign = true; const char *grec = tqsl_getGABBItCONTACTData(conv->certs[conv->cert_idx], conv->loc, &(conv->rec), conv->loc_uid, signdata, sizeof(signdata)); if (conv->dupes_only || grec) { conv->rec_done = true; if (!conv->allow_dupes) { char stnloc[128]; unsigned char qso[128]; if (tqsl_getLocationStationDetails(conv->loc, stnloc, sizeof stnloc)) { stnloc[0] = '\0'; } if (tqsl_getLocationQSODetails(conv->loc, reinterpret_cast (qso), sizeof qso)) { qso[0] = '\0'; } // Old-style Lookup uses signdata and cert serial number // append signing key serial strncat(signdata, conv->serial, sizeof(signdata) - strlen(signdata)-1); // Updated dupe database entry. Key is formed from // local callsign concatenated with the QSO details char dupekey[128]; snprintf(dupekey, sizeof dupekey, "%s%s", conv->callsign, qso); char * dupedata = NULL; int rc = get_dbrec(conv->seendb, signdata, &dupedata); if (rc == 0) { if (dupedata) free(dupedata); //lookup was successful; thus this is a duplicate. tqslTrace("tqsl_getConverterGABBI", "Duplicate QSO signdata=%s", signdata); tQSL_Error = TQSL_DUPLICATE_QSO; tQSL_CustomError[0] = '\0'; // delete the old record del_dbrec(conv->seendb, signdata); // Update this to the current format int dbput_err = put_dbrec(conv->seendb, dupekey, stnloc); if (0 != dbput_err) { strncpy(tQSL_CustomError, sqlite3_errmsg(conv->seendb), sizeof tQSL_CustomError); if (SQLITE_NOTADB == dbput_err) { close_db(conv); remove_db(conv->dbpath); free(conv->dbpath); } tqsl_db_get_errstr(conv); tQSL_Error = TQSL_DB_ERROR; return 0; } return 0; } else if (rc < 0) { //non-zero return, but not "not found" - thus error tqsl_db_get_errstr(conv); if (SQLITE_NOTADB == rc) { // This isn't a database close_db(conv); remove_db(conv->dbpath); free(conv->dbpath); } tQSL_Error = TQSL_DB_ERROR; return 0; // could be more specific but there's very little the user can do at this point anyway } rc = get_dbrec(conv->seendb, dupekey, &dupedata); if (rc == 0) { //lookup was successful; thus this is a duplicate. tqslTrace("tqsl_getConverterGABBI", "Duplicate QSO dupekey=%s", dupekey); tQSL_Error = TQSL_DUPLICATE_QSO; // Save the original and new station location details so those can be provided // with an error by the caller // here dupedata = "GRIDSQUARE: ML01OX", stnloc "GRIDSQUARE: MLO2oa". // Station loc details like "CQZ: 5, GRIDSQUARE: FM18ju, ITUZ: 8, US_COUNTY: Fairfax, US_STATE: VA" // If the same, it's just a dupe. if (!strcasecmp(dupedata, stnloc)) { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "%s|%s", dupedata, stnloc); free(dupedata); return 0; } // Strip spaces string olds = dupedata; size_t found = olds.find(' '); while (found != string::npos) { olds.replace(found, 1, ""); found = olds.find(' '); } string news = stnloc; found = news.find(' '); while (found != string::npos) { news.replace(found, 1, ""); found = news.find(' '); } // Iterate the previous and current station locations. vectoroldstn; vectorqsostn; splitStr(olds, oldstn, ','); splitStr(news, qsostn, ','); // What we have now is the vectors having "GRIDSQUARE:ML10X" in each entry. Look for changes. bool changed = false; for (size_t i = 0; i < oldstn.size(); i++) { size_t cp = oldstn[i].find(":"); string key = oldstn[i].substr(0, cp+1); for (size_t j = 0; j < qsostn.size(); j++) { cp = qsostn[j].find(":"); string qsokey = qsostn[j].substr(0, cp+1); // Finally - is the key the same? if (key == qsokey) { if (oldstn[i] != qsostn[j] && key != oldstn[i]) { changed = true; } break; } } if (changed) break; } if (changed) { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "%s|%s", dupedata, stnloc); free(dupedata); return 0; } free(dupedata); // This is a valid update, delete the old one and let it update. del_dbrec(conv->seendb, dupekey); } else if (rc < 0) { //non-zero return, but not "not found" - thus error tqsl_db_get_errstr(conv); if (SQLITE_NOTADB == rc) { // Not a database close_db(conv); remove_db(conv->dbpath); free(conv->dbpath); } tQSL_Error = TQSL_DB_ERROR; return 0; // could be more specific but there's very little the user can do at this point anyway } int dbput_err; dbput_err = put_dbrec(conv->seendb, dupekey, reinterpret_cast(stnloc)); if (0 != dbput_err) { tqsl_db_get_errstr(conv); if (SQLITE_NOTADB == dbput_err) { close_db(conv); remove_db(conv->dbpath); free(conv->dbpath); } tQSL_Error = TQSL_DB_ERROR; return 0; } } } return grec; } // NOLINT(readability/fn_size) DLLEXPORT int CALLCONVENTION tqsl_getConverterCert(tQSL_Converter convp, tQSL_Cert *certp) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; if (certp == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *certp = conv->certs[conv->cert_idx]; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getConverterLine(tQSL_Converter convp, int *lineno) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; if (lineno == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (conv->err_tag_line) { *lineno = conv->err_tag_line; return 0; } if (conv->cab) return tqsl_getCabrilloLine(conv->cab, lineno); else if (conv->adif) return tqsl_getADIFLine(conv->adif, lineno); *lineno = 0; return 0; } DLLEXPORT const char* CALLCONVENTION tqsl_getConverterRecordText(tQSL_Converter convp) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 0; return conv->rec_text.c_str(); } DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowBadCall(tQSL_Converter convp, int allow) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; conv->allow_bad_calls = (allow != 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowDuplicates(tQSL_Converter convp, int allow) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; conv->allow_dupes = (allow != 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreSeconds(tQSL_Converter convp, int ignore) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; conv->ignore_secs = (ignore != 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreCallsigns(tQSL_Converter convp, int ignore) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; conv->ignore_calls = (ignore != 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setConverterAppName(tQSL_Converter convp, const char *app) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; if (!app) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } conv->appName = strdup(app); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setConverterDupesOnly(tQSL_Converter convp, int dupesOnly) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; conv->dupes_only = (dupesOnly != 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setConverterQTHDetails(tQSL_Converter convp, int logverify) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; conv->location_handling = logverify; return 0; } DLLEXPORT int CALLCONVENTION tqsl_converterRollBack(tQSL_Converter convp) { TQSL_CONVERTER *conv; tqslTrace("tqsl_converterRollBack", NULL); if (!(conv = check_conv(convp))) return 1; if (!conv->db_open) return 0; if (conv->txn) sqlite3_exec(conv->seendb, "ROLLBACK;", NULL, NULL, NULL); conv->txn = false; return 0; } DLLEXPORT int CALLCONVENTION tqsl_converterCommit(tQSL_Converter convp) { TQSL_CONVERTER *conv; tqslTrace("tqsl_converterCommit", NULL); if (!(conv = check_conv(convp))) return 1; if (!conv->db_open) return 0; if (conv->txn) sqlite3_exec(conv->seendb, "COMMIT;", NULL, NULL, NULL); conv->txn = false; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecords(tQSL_Converter convp, char *key, char *data, int keylen) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; if (!conv->db_open) { if (!open_db(conv, true)) { // If can't open dupes DB return 1; } } // First time setup if (conv->bulk_read == NULL) { int rc = sqlite3_prepare_v2(conv->seendb, "SELECT * from QSOs;", 256, &conv->bulk_read, NULL); if (SQLITE_OK != rc) { return 1; } } // Get a record int rc = sqlite3_step(conv->bulk_read); if (SQLITE_DONE == rc) { sqlite3_finalize(conv->bulk_read); conv->bulk_read = NULL; return -1; // No more } if (SQLITE_ROW != rc) { fprintf(stderr, "SQL error in step: %s\n", sqlite3_errmsg(conv->seendb)); sqlite3_finalize(conv->bulk_read); conv->bulk_read = NULL; return 1; } const unsigned char* result = sqlite3_column_text(conv->bulk_read, 1); if (!result) { tqsl_db_get_errstr(conv); tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; return 1; } strncpy(data, reinterpret_cast(result), keylen); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecordsV2(tQSL_Converter convp, char *key, char *data, int keylen) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 1; if (!conv->db_open) { if (!open_db(conv, true)) { // If can't open dupes DB return 1; } } if (!conv->bulk_read) { int rc = sqlite3_prepare_v2(conv->seendb, "SELECT * from QSOs;", 256, &conv->bulk_read, NULL); if (SQLITE_OK != rc) { return 1; } } // Get a record int rc = sqlite3_step(conv->bulk_read); if (SQLITE_DONE == rc) { sqlite3_finalize(conv->bulk_read); return -1; // No more } if (SQLITE_ROW != rc) { sqlite3_finalize(conv->bulk_read); tqsl_db_get_errstr(conv); tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; return 1; } const unsigned char* rkey = sqlite3_column_text(conv->bulk_read, 0); if (!rkey) { tqsl_db_get_errstr(conv); tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; return 1; } const unsigned char* rdata = sqlite3_column_text(conv->bulk_read, 1); if (!rdata) { tqsl_db_get_errstr(conv); tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; return 1; } strncpy(key, reinterpret_cast(rkey), keylen); strncpy(data, reinterpret_cast(rdata), keylen); return 0; } DLLEXPORT int CALLCONVENTION tqsl_putDuplicateRecord(tQSL_Converter convp, const char *key, const char *data, int keylen) { TQSL_CONVERTER *conv; if (!(conv = check_conv(convp))) return 0; if (!conv->db_open) { if (!open_db(conv, false)) { // If can't open dupes DB return 0; // Head back - possibly new DB created } } if (key == NULL || data == NULL || keylen <= 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; close_db(conv); // The initial probe for a good dupes database uses this return 0; } int status = put_dbrec(conv->seendb, key, data); if (0 != status) { tqsl_db_get_errstr(conv); tQSL_Error = TQSL_DB_ERROR; tQSL_Errno = errno; return 1; } return 0; } static bool hasValidCallSignChars(const string& call) { // Check for invalid characters if (call.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/") != string::npos) return false; // Need at least one letter if (call.find_first_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ") == string::npos) return false; // Need at least one number if (call.find_first_of("0123456789") == string::npos) return false; // Invalid callsign patterns // Starting with 0, Q // 1x other than 1A, 1M, 1S string first = call.substr(0, 1); string second = call.substr(1, 1); if (first == "0" || first == "Q" || #ifdef MARK_C7_4Y_INVALID (first == "C" && second == "7") || (first == "4" && second == "Y") || #endif (first == "1" && second != "A" && second != "M" && second != "S")) return false; return true; } static bool checkCallSign(const string& call) { if (!hasValidCallSignChars(call)) return false; if (call.length() < 3) return false; string::size_type idx, newidx; for (idx = 0; idx != string::npos; idx = newidx+1) { string s; newidx = call.find('/', idx); if (newidx == string::npos) s = call.substr(idx); else s = call.substr(idx, newidx - idx); if (s.length() == 0) return false; // Leading or trailing '/' is bad, bad! if (newidx == string::npos) break; } return true; } DLLEXPORT void CALLCONVENTION tqsl_removeUploadDatabase(void) { char *path = strdup(tQSL_BaseDir); remove_db(path); free(path); return; } tqsl-2.8.2/src/station_loc.cpp0000644000175000017500000000552315061653721016330 0ustar rmurphyrmurphy/*************************************************************************** station_loc.cpp - description ------------------- begin : Sat Dec 14 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "sysconfig.h" #endif #include #include #include #include #include "tqsllib.h" #include "tqslexc.h" using std::string; using std::ios; using std::cerr; using std::cout; using std::endl; int usage() { cerr << "Usage: station_loc callsign [dxcc]" << endl; exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { try { string call, dxcc; if (argc < 2) usage(); call = argv[1]; if (argc > 2) dxcc = argv[2]; if (tqsl_init()) throw tqslexc(); tQSL_Location loc; if (tqsl_initStationLocationCapture(&loc)) throw tqslexc(); if (tqsl_setStationLocationCapturePage(loc, 1)) throw tqslexc(); // We know that the first field of page 1 is always call and the 2nd is DXCC int nfield; tqsl_getNumLocationFieldListItems(loc, 0, &nfield); int i; for (i = 0; i < nfield; i++) { char buf[256]; if (tqsl_getLocationFieldListItem(loc, 0, i, buf, sizeof buf)) throw tqslexc(); if (!strcasecmp(buf, call.c_str())) break; } if (i == nfield) throw myexc(string("Can't init station location for call = ") + call); if (tqsl_setLocationFieldIndex(loc, 0, i)) throw tqslexc(); if (tqsl_updateStationLocationCapture(loc)) throw tqslexc(); if (dxcc != "") { int nfield; tqsl_getNumLocationFieldListItems(loc, 1, &nfield); //cerr << nfield << endl; for (i = 0; i < nfield; i++) { char buf[256]; if (tqsl_setLocationFieldIndex(loc, 1, i)) throw tqslexc(); if (tqsl_getLocationFieldCharData(loc, 1, buf, sizeof buf)) throw tqslexc(); //cerr << buf << endl; if (!strcasecmp(buf, dxcc.c_str())) break; } if (i == nfield) throw myexc(string("Can't init location for DXCC = ") + dxcc); if (tqsl_setLocationFieldIndex(loc, 1, i)) throw tqslexc(); } int dxcc_idx; if (tqsl_getLocationFieldIndex(loc, 1, &dxcc_idx)) throw tqslexc(); char buf[256]; if (tqsl_getLocationFieldListItem(loc, 1, dxcc_idx, buf, sizeof buf)) throw tqslexc(); string lname = call + "_auto"; if (tqsl_setStationLocationCaptureName(loc, lname.c_str())) throw tqslexc(); if (tqsl_saveStationLocationCapture(loc, 1)) throw tqslexc(); tqsl_endStationLocationCapture(&loc); cout << "Wrote station location for " << call << " - " << buf << endl; } catch(exception& x) { cerr << "Aborted: " << x.what() << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } tqsl-2.8.2/src/openssl_cert.h0000644000175000017500000001162215061653721016154 0ustar rmurphyrmurphy/*************************************************************************** openssl_cert.h - description ------------------- begin : Tue May 14 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef OPENSSL_CERT_H #define OPENSSL_CERT_H /** \file * OpenSSL X509 certificate interface functions. */ #include #if (OPENSSL_VERSION_NUMBER == 0x10000003L) /* broken header file - fix by override */ #define i2d_ASN1_SET i2d_ASN1_SET_buggy #define d2i_ASN1_SET d2i_ASN1_SET_buggy #define ASN1_seq_unpack ASN1_seq_unpack_buggy #define ASN1_seq_pack ASN1_seq_pack_buggy #include #undef i2d_ASN1_SET #undef d2i_ASN1_SET #undef ASN1_seq_unpack #undef ASN1_seq_pack #ifdef __cplusplus extern "C" { #endif int i2d_ASN1_SET(void *a, unsigned char **pp, i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); void *d2i_ASN1_SET(void *a, const unsigned char **pp, long length, d2i_of_void *d2i, void (*free_func)(void*), int ex_tag, // NOLINT(readability/casting) int ex_class); void *ASN1_seq_unpack(const unsigned char *buf, int len, d2i_of_void *d2i, void (*free_func)(void* dummy)); unsigned char *ASN1_seq_pack(void *safes, i2d_of_void *i2d, unsigned char **buf, int *len); #ifdef __cplusplus } #endif #endif /* buggy openssl header */ #include #include #undef CLIENT_STATIC #ifndef LOTW_SERVER #define CLIENT_STATIC static #else #define CLIENT_STATIC #endif typedef STACK_OF(X509) TQSL_X509_STACK; typedef struct { char *name_buf; int name_buf_size; char *value_buf; int value_buf_size; } TQSL_X509_NAME_ITEM; namespace tqsllib { typedef enum { ROOTCERT = 0, CACERT, USERCERT } certtype; int tqsl_import_cert(const char *cert, certtype type, int(*cb)(int, const char *, void *), void *); int tqsl_get_pem_serial(const char *pem, long *serial); } // namespace tqsllib #if defined(LOTW_SERVER) || defined(OPENSSL_CERT_SOURCE) #ifdef __cplusplus extern "C" { #endif /// Loads a stack of certificates from the caller-supplied BIO /** See the OpenSSL documentation for background on BIO operations. * * Returns a pointer to an OpenSSL X509 stack, as used by * tqsl_ssl_verify_cert() */ CLIENT_STATIC TQSL_X509_STACK *tqsl_ssl_load_certs_from_BIO(BIO *in); /// Loads a stack of certificates from a file /** See tqsl_ssl_load_certs_from_BIO() */ CLIENT_STATIC TQSL_X509_STACK *tqsl_ssl_load_certs_from_file(const char *filename); /// Verifies a certificate using stacks of certificates /** The user supplies the X509 certificate to verify (the test certificate) * along with two stacks of certificates. The \c cacerts stack is a list * of certificates, one of which was used to sign the test certificate. * The \c rootcerts are considered "trusted." One of them must have been used * to sign either the test certificate itself or the CA cert that signed * the test certificate. * * Returns NULL if the test certificate is valid, otherwise returns an error message. */ CLIENT_STATIC const char *tqsl_ssl_verify_cert(X509 *cert, TQSL_X509_STACK *cacerts, TQSL_X509_STACK *rootcerts, int purpose, int (*cb)(int ok, X509_STORE_CTX *ctx), TQSL_X509_STACK **chain = 0); /// Retrieve a name entry from an X509 name object by name CLIENT_STATIC int tqsl_get_name_entry(X509_NAME *name, const char *obj_name, TQSL_X509_NAME_ITEM *name_item); /// Retrieve a name entry from an X509 cert's subject name by name CLIENT_STATIC int tqsl_cert_get_subject_name_entry(X509 *cert, const char *obj_name, TQSL_X509_NAME_ITEM *name_item); /// Convert an ASN date CLIENT_STATIC int tqsl_get_asn1_date(const ASN1_TIME *tm, tQSL_Date *date); /// Filter a list (stack) of certs based on (optional) call sign, qso date and issuer criteria /** Returns a (possibly empty) stack of certificates that match the criteria. Returns NULL * on error. * * The returned stack contains \em copies of the certs from the input stack. The input * stack is not altered. */ CLIENT_STATIC TQSL_X509_STACK *tqsl_filter_cert_list(TQSL_X509_STACK *sk, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int isvalid); CLIENT_STATIC EVP_PKEY *tqsl_new_rsa_key(int nbits); CLIENT_STATIC int tqsl_store_cert(const char *pem, X509 *cert, const char *certfile, int type, bool force, int (*cb)(int, const char *, void *), void *); CLIENT_STATIC int tqsl_write_adif_field(FILE *fp, const char *fieldname, char type, const unsigned char *value, int len); CLIENT_STATIC int tqsl_bio_write_adif_field(BIO *bio, const char *fieldname, char type, const unsigned char *value, int len); #ifdef __cplusplus } #endif #endif /* defined(LOTW_SERVER) || defined(OPENSSL_CERT_SOURCE) */ #endif /* OPENSSL_CERT_H */ tqsl-2.8.2/src/openssl_cert.cpp0000644000175000017500000056061615061653721016523 0ustar rmurphyrmurphy/*************************************************************************** openssl_cert.c - description ------------------- begin : Tue May 14 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ /* Routines to massage X.509 certs for tQSL. See openssl_cert.h for overview */ /* 2004-04-10 Fixed tqsl_add_bag_attribute error for OpenSSL > 0.96 (Thanks to Kenji, JJ1BDX for the fix) */ /* Portions liberally copied from OpenSSL's apps source code */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #define OPENSSL_CERT_SOURCE #define TQSLLIB_DEF #include #include #include #include #include #include #include #ifdef _WIN32 #include #define MKDIR(x, y) _wmkdir(x) #else #define MKDIR(x, y) mkdir(x, y) #include #include #endif #define OPENSSL_SUPPRESS_DEPRECATED // Suppress warnings for deprecated functions #include #if OPENSSL_VERSION_MAJOR >= 3 #include #include #endif #include #include #undef X509_NAME //http://www.mail-archive.com/openssl-users@openssl.org/msg59116.html #include #include #include #include #include #include /* Ugly workaround for Openssl 1.0 bug per: * http://rt.openssl.org/Ticket/Display.html?user=guest&pass=guest&id=2123 */ #if (OPENSSL_VERSION_NUMBER == 0x10000003L) #define i2d_ASN1_SET i2d_ASN1_SET_buggy #define d2i_ASN1_SET d2i_ASN1_SET_buggy #define ASN1_seq_unpack ASN1_seq_unpack_buggy #define ASN1_seq_pack ASN1_seq_pack_buggy #include #undef i2d_ASN1_SET #undef d2i_ASN1_SET #undef ASN1_seq_unpack #undef ASN1_seq_pack #include #include #ifdef __cplusplus extern "C" { #endif int i2d_ASN1_SET(void *a, unsigned char **pp, i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); void *d2i_ASN1_SET(void *a, const unsigned char **pp, long length, d2i_of_void *d2i, void (*free_func)(void* p), int ex_tag, int ex_class); void *ASN1_seq_unpack(const unsigned char *buf, int len, d2i_of_void *d2i, void (*free_func)(void* dummy)); unsigned char *ASN1_seq_pack(void *safes, i2d_of_void *i2d, unsigned char **buf, int *len); #ifdef __cplusplus } #endif #endif // OpenSSL v1.0 // Work with OpenSSL 1.1.0 and later #if OPENSSL_VERSION_NUMBER >= 0x10100000L #ifndef M_PKCS12_bag_type # define M_PKCS12_bag_type PKCS12_bag_type #endif #ifndef M_PKCS12_cert_bag_type # define M_PKCS12_cert_bag_type PKCS12_cert_bag_type #endif #ifndef M_PKCS12_crl_bag_type # define M_PKCS12_crl_bag_type PKCS12_cert_bag_type #endif #ifndef M_PKCS12_certbag2x509 # define M_PKCS12_certbag2x509 PKCS12_SAFEBAG_get1_cert #endif #ifndef M_PKCS12_decrypt_skey # define M_PKCS12_decrypt_skey PKCS12_decrypt_skey #endif #ifndef M_PKCS12_unpack_authsafes # define M_PKCS12_unpack_authsafes PKCS12_unpack_authsafes #endif #ifndef M_PKCS12_pack_authsafes # define M_PKCS12_pack_authsafes PKCS12_pack_authsafes #endif #ifndef PKCS12_get_attr # define PKCS12_get_attr PKCS12_SAFEBAG_get0_attr #endif #ifndef PKCS12_bag_type # define PKCS12_bag_type PKCS12_SAFEBAG_get_nid #endif #ifndef PKCS12_cert_bag_type # define PKCS12_cert_bag_type PKCS12_SAFEBAG_get_bag_nid #endif #if !defined(PKCS12_x5092certbag) && !defined(LIBRESSL_VERSION_NUMBER) # define PKCS12_x5092certbag PKCS12_SAFEBAG_create_cert #endif #ifndef PKCS12_x509crl2certbag # define PKCS12_x509crl2certbag PKCS12_SAFEBAG_create_crl #endif #ifndef X509_STORE_CTX_trusted_stack # define X509_STORE_CTX_trusted_stack X509_STORE_CTX_set0_trusted_stack #endif #ifndef X509_get_notAfter # define X509_get_notAfter X509_get0_notAfter #endif #ifndef X509_get_notBefore # define X509_get_notBefore X509_get0_notBefore #endif #if !defined (PKCS12_MAKE_SHKEYBAG) && !defined(LIBRESSL_VERSION_NUMBER) # define PKCS12_MAKE_SHKEYBAG PKCS12_SAFEBAG_create_pkcs8_encrypt #endif #ifndef X509_V_FLAG_CB_ISSUER_CHECK # define X509_V_FLAG_CB_ISSUER_CHECK 0x0 #endif #else # define ASN1_STRING_get0_data ASN1_STRING_data #endif #include #include #include #include #include #include #include "tqsllib.h" #include "tqslerrno.h" #include "xml.h" #include "winstrdefs.h" #ifdef _MSC_VER //is a visual studio compiler #include "windirent.h" #endif #define tqsl_malloc malloc #define tqsl_realloc realloc #define tqsl_calloc calloc #define tqsl_free free #define TQSL_OBJ_TO_API(x) (reinterpret_cast((x))) #define TQSL_API_TO_OBJ(x, type) ((type)(x)) #define TQSL_API_TO_CERT(x) TQSL_API_TO_OBJ((x), tqsl_cert *) #include "openssl_cert.h" using std::vector; using std::map; using std::set; using std::string; using std::ofstream; using std::ios; using std::endl; using std::exception; using tqsllib::XMLElement; using tqsllib::XMLElementList; #ifdef _WIN32 #define TQSL_OPEN_READ L"rb" #define TQSL_OPEN_WRITE L"wb" #define TQSL_OPEN_APPEND L"ab" #else #define TQSL_OPEN_READ "r" #define TQSL_OPEN_WRITE "w" #define TQSL_OPEN_APPEND "a" #endif #if (OPENSSL_VERSION_NUMBER & 0xfffff000) >= 0x10000000L #define uni2asc OPENSSL_uni2asc #define asc2uni OPENSSL_asc2uni #endif static char *tqsl_trim(char *buf); static int tqsl_check_parm(const char *p, const char *parmName); static TQSL_CERT_REQ *tqsl_copy_cert_req(TQSL_CERT_REQ *userreq); static TQSL_CERT_REQ *tqsl_free_cert_req(TQSL_CERT_REQ *req, int seterr); static char *tqsl_make_key_path(const char *callsign, char *path, int size); static int tqsl_make_key_list(vector< map > & keys); static int tqsl_find_matching_key(X509 *cert, EVP_PKEY **keyp, TQSL_CERT_REQ **crq, const char *password, int (*cb)(char *, int, void *), void *); static char *tqsl_make_cert_path(const char *filename, char *path, int size); static char *tqsl_make_backup_path(const char *filename, char *path, int size); static int tqsl_get_cert_ext(X509 *cert, const char *ext, unsigned char *userbuf, int *buflen, int *crit); CLIENT_STATIC int tqsl_get_asn1_date(const ASN1_TIME *tm, tQSL_Date *date); static char *tqsl_sign_base64_data(tQSL_Cert cert, char *b64data); static int fixed_password_callback(char *buf, int bufsiz, int verify, void *userdata); static int prompted_password_callback(char *buf, int bufsiz, int verify, void *userfunc); static int tqsl_check_crq_field(tQSL_Cert cert, char *buf, int bufsiz); static bool safe_strncpy(char *dest, const char *src, int size); static int tqsl_ssl_error_is_nofile(); static int tqsl_unlock_key(const char *pem, EVP_PKEY **keyp, const char *password, int (*cb)(char *, int, void *), void *); static int tqsl_replace_key(const char *callsign, const char *path, map& newfields, int (*cb)(int, const char *, void *), void *userdata); static int tqsl_self_signed_is_ok(int ok, X509_STORE_CTX *ctx); static int tqsl_expired_is_ok(int ok, X509_STORE_CTX *ctx); static int tqsl_clear_deleted(const char *callsign, const char *path, EVP_PKEY *cert_key); static int tqsl_key_exists(const char *callsign, EVP_PKEY *cert_key); static int tqsl_open_key_file(const char *path); static int tqsl_read_key(map& fields); static void tqsl_close_key_file(void); extern const char* tqsl_openssl_error(void); /* Private data structures */ typedef struct { long id; X509 *cert; EVP_PKEY *key; TQSL_CERT_REQ *crq; char *pubkey; char *privkey; unsigned char keyonly; } tqsl_cert; typedef struct { long id; X509 *cert; } tqsl_crq; static tqsl_cert * tqsl_cert_new(); static void tqsl_cert_free(tqsl_cert *p); static int tqsl_cert_check(tqsl_cert *p, bool needcert = true); struct tqsl_loadcert_handler { int type; int (*func)(const char *pem, X509 *x, int(*cb)(int type, const char *, void *), void *); }; static int tqsl_handle_root_cert(const char *, X509 *, int (*cb)(int, const char *, void *), void *); static int tqsl_handle_ca_cert(const char *, X509 *, int (*cb)(int, const char *, void *), void *); static int tqsl_handle_user_cert(const char *, X509 *, int (*cb)(int, const char *, void *), void *); static struct tqsl_loadcert_handler tqsl_loadcert_handlers[] = { { TQSL_CERT_CB_ROOT, &tqsl_handle_root_cert }, { TQSL_CERT_CB_CA, &tqsl_handle_ca_cert }, { TQSL_CERT_CB_USER, &tqsl_handle_user_cert } }; static const char *notypes[] = { "" }; /* static tqsl_adifFieldDefinitions tqsl_cert_file_fields[] = { { "TQSL_CERT", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL, NULL }, { "TQSL_CERT_USER", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, &tqsl_load_user_cert }, { "TQSL_CERT_CA", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, &tqsl_load_ca_cert }, { "TQSL_CERT_ROOT", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, &tqsl_load_root_cert }, }; */ static unsigned char tqsl_static_buf[2001]; static char ImportCall[256]; #if !defined(__APPLE__) && !defined(_WIN32) && !defined(__clang__) #pragma GCC diagnostic ignored "-Wformat-truncation" #endif static unsigned char * tqsl_static_alloc(size_t size) { if (size > sizeof tqsl_static_buf) return NULL; strncpy(reinterpret_cast(tqsl_static_buf), "", sizeof tqsl_static_buf); return tqsl_static_buf; } namespace tqsllib { int tqsl_import_cert(const char *data, certtype type, int(*cb)(int, const char *, void *), void *userdata) { BIO *bio; X509 *cert; int stat; struct tqsl_loadcert_handler *handler = &(tqsl_loadcert_handlers[type]); /* This is a certificate, supposedly. Let's make sure */ tqslTrace("tqsl_import_cert", NULL); bio = BIO_new_mem_buf(reinterpret_cast(const_cast(data)), strlen(data)); if (bio == NULL) { tqslTrace("tqsl_import_cert", "BIO mem buf error %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); BIO_free(bio); if (cert == NULL) { tqslTrace("tqsl_import_cert", "BIO read error, err=%s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } /* It's a certificate. Let's try to add it. Any errors will be * reported via the callback (if any) but will not be fatal unless * the callback says so. */ ImportCall[0] = '\0'; tQSL_ImportSerial = 0; stat = (*(handler->func))(data, cert, cb, userdata); X509_free(cert); if (stat) { if (tQSL_Error == TQSL_CERT_ERROR) { return 1; } if (cb != NULL) { stat = (*cb)(handler->type | TQSL_CERT_CB_RESULT | TQSL_CERT_CB_ERROR, tqsl_getErrorString_v(tQSL_Error), userdata); if (stat) { tqslTrace("tqsl_import_cert", "import error %d", tQSL_Error); return 1; } else { tqslTrace("tqsl_import_cert", "import error. Handler suppressed."); } } else { /* No callback -- any errors are fatal */ tqslTrace("tqsl_import_cert", "import error %d", tQSL_Error); return 1; } return stat; } strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall); return 0; } int tqsl_get_pem_serial(const char *pem, long *serial) { BIO *bio; X509 *cert; tqslTrace("tqsl_get_pem_serial", NULL); if (tqsl_init()) return 1; if (pem == NULL || serial == NULL) { tqslTrace("tqsl_get_pem_serial", "arg error pem=0x%lx, serial=0x%lx", pem, serial); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } bio = BIO_new_mem_buf(reinterpret_cast(const_cast(pem)), strlen(pem)); if (bio == NULL) { tqslTrace("tqsl_get_pem_serial", "mem buf error %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); BIO_free(bio); if (cert == NULL) { tqslTrace("tqsl_get_pem_serial", "cert read error %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } *serial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); return 0; } } // namespace tqsllib /********** PUBLIC API FUNCTIONS ***********/ DLLEXPORT int CALLCONVENTION tqsl_createCertRequest(const char *filename, TQSL_CERT_REQ *userreq, int (*pwcb)(char *pwbuf, int pwsize, void *), void *userdata) { TQSL_CERT_REQ *req = NULL; EVP_PKEY *key = NULL; X509_REQ *xr = NULL; X509_NAME *subj = NULL; int nid, len; int rval = 1; FILE *out = NULL; BIO *bio = NULL; const EVP_MD *digest = NULL; char buf[200]; char path[TQSL_MAX_PATH_LEN]; char *cp; const EVP_CIPHER *cipher = NULL; char *password; const char *type; tqslTrace("tqsl_createCertRequest", NULL); if (tqsl_init()) return 1; if (filename == NULL || userreq == NULL) { tqslTrace("tqsl_createCertRequest", "arg error filename=0x%lx, userreq=0x%lx", filename, userreq); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (userreq->signer != NULL && (!tqsl_cert_check(TQSL_API_TO_CERT(userreq->signer)) || TQSL_API_TO_CERT(userreq->signer)->key == NULL)) { tqslTrace("tqsl_createCertRequest", "arg error signer/key"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if ((req = tqsl_copy_cert_req(userreq)) == NULL) { tqslTrace("tqsl_createCertRequest", "Error copying %d", tQSL_Error); goto end; } /* Check parameters for validity */ tqsl_trim(req->providerName); tqsl_trim(req->providerUnit); tqsl_trim(req->name); if (tqsl_check_parm(req->name, "Name")) { tqslTrace("tqsl_createCertRequest", "check_parm Name"); goto end; } tqsl_trim(req->callSign); if (tqsl_check_parm(req->callSign, "Call Sign")) { tqslTrace("tqsl_createCertRequest", "check_parm Call Sign"); goto end; } tqsl_trim(req->address1); if (tqsl_check_parm(req->address1, "Address")) { tqslTrace("tqsl_createCertRequest", "check_parm Address1"); goto end; } tqsl_trim(req->address2); tqsl_trim(req->city); if (tqsl_check_parm(req->city, "City")) { tqslTrace("tqsl_createCertRequest", "check_parm City"); goto end; } tqsl_trim(req->state); tqsl_trim(req->country); if (tqsl_check_parm(req->country, "Country")) { tqslTrace("tqsl_createCertRequest", "check_parm Country"); goto end; } tqsl_trim(req->postalCode); tqsl_trim(req->emailAddress); if (tqsl_check_parm(req->emailAddress, "Email address")) { tqslTrace("tqsl_createCertRequest", "check_parm email"); goto end; } if ((cp = strchr(req->emailAddress, '@')) == NULL || strchr(cp, '.') == NULL) { strncpy(tQSL_CustomError, "Invalid email address", sizeof tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; tqslTrace("tqsl_createCertRequest", "check_parm email: %s %s", req->emailAddress, tQSL_CustomError); goto end; } if (!tqsl_isDateValid(&(req->qsoNotBefore))) { strncpy(tQSL_CustomError, "Invalid date (qsoNotBefore)", sizeof tQSL_CustomError); tqslTrace("tqsl_createCertRequest", "check_parm not before: %s %s", req->qsoNotBefore, tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; goto end; } if (!tqsl_isDateNull(&(req->qsoNotAfter))) { if (!tqsl_isDateValid(&(req->qsoNotAfter))) { strncpy(tQSL_CustomError, "Invalid date (qsoNotAfter)", sizeof tQSL_CustomError); tqslTrace("tqsl_createCertRequest", "check_parm not after: %s %s", req->qsoNotAfter, tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; goto end; } if (tqsl_compareDates(&(req->qsoNotAfter), &(req->qsoNotBefore)) < 0) { strncpy(tQSL_CustomError, "qsoNotAfter date is earlier than qsoNotBefore", sizeof tQSL_CustomError); tqslTrace("tqsl_createCertRequest", "check_parm not after: %s %s", req->qsoNotAfter, tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; goto end; } } /* Try opening the output stream */ #ifdef _WIN32 wchar_t* wfilename = utf8_to_wchar(filename); if ((out = _wfopen(wfilename, TQSL_OPEN_WRITE)) == NULL) { free_wchar(wfilename); #else if ((out = fopen(filename, TQSL_OPEN_WRITE)) == NULL) { #endif strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile); tqslTrace("tqsl_createCertRequest", "Open file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; goto end; } #ifdef _WIN32 free_wchar(wfilename); #endif if (fputs("\ntQSL certificate request\n\n", out) == EOF) { strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile); tqslTrace("tqsl_createCertRequest", "Write request file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; goto end; } tqsl_write_adif_field(out, "eoh", 0, NULL, 0); type = (req->signer != NULL) ? (req->renew ? "TQSL_CRQ_RENEWAL" : "TQSL_CRQ_ADDITIONAL") : "TQSL_CRQ_NEW"; int libmaj, libmin, configmaj, configmin; tqsl_getVersion(&libmaj, &libmin); tqsl_getConfigVersion(&configmaj, &configmin); snprintf(buf, sizeof buf, "TQSL: %d.%d.%d, Lib: V%d.%d, Config: %d.%d", TQSL_VERSION_MAJOR, TQSL_VERSION_MINOR, TQSL_VERSION_UPDATE, libmaj, libmin, configmaj, configmin); tqsl_write_adif_field(out, "TQSL_IDENT", 0, (unsigned char *)buf, -1); tqsl_write_adif_field(out, type, 0, NULL, 0); tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER", 0, (unsigned char *)req->providerName, -1); tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER_UNIT", 0, (unsigned char *)req->providerUnit, -1); tqsl_write_adif_field(out, "TQSL_CRQ_EMAIL", 0, (unsigned char *)req->emailAddress, -1); tqsl_write_adif_field(out, "TQSL_CRQ_NAME", 0, (unsigned char *)req->name, -1); tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS1", 0, (unsigned char *)req->address1, -1); tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS2", 0, (unsigned char *)req->address2, -1); tqsl_write_adif_field(out, "TQSL_CRQ_CITY", 0, (unsigned char *)req->city, -1); tqsl_write_adif_field(out, "TQSL_CRQ_STATE", 0, (unsigned char *)req->state, -1); tqsl_write_adif_field(out, "TQSL_CRQ_POSTAL", 0, (unsigned char *)req->postalCode, -1); tqsl_write_adif_field(out, "TQSL_CRQ_COUNTRY", 0, (unsigned char *)req->country, -1); snprintf(buf, sizeof buf, "%d", req->dxccEntity); tqsl_write_adif_field(out, "TQSL_CRQ_DXCC_ENTITY", 0, (unsigned char *)buf, -1); tqsl_convertDateToText(&(req->qsoNotBefore), buf, sizeof buf); tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_BEFORE", 0, (unsigned char *)buf, -1); if (!tqsl_isDateNull(&(req->qsoNotAfter))) { tqsl_convertDateToText(&(req->qsoNotAfter), buf, sizeof buf); tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_AFTER", 0, (unsigned char *)buf, -1); } /* Generate a new key pair */ if ((key = tqsl_new_rsa_key(1024)) == NULL) { tqslTrace("tqsl_createCertRequest", "key create error %d", tQSL_Error); goto end; } /* Make the X.509 certificate request */ if ((xr = X509_REQ_new()) == NULL) { tqslTrace("tqsl_createCertRequest", "req create error %s", tqsl_openssl_error()); goto err; } if (!X509_REQ_set_version(xr, 0L)) { tqslTrace("tqsl_createCertRequest", "version set error %s", tqsl_openssl_error()); goto err; } subj = X509_REQ_get_subject_name(xr); nid = OBJ_txt2nid("AROcallsign"); if (nid != NID_undef) X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char *)req->callSign, -1, -1, 0); nid = OBJ_txt2nid("commonName"); if (nid != NID_undef) X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char *)req->name, -1, -1, 0); nid = OBJ_txt2nid("emailAddress"); if (nid != NID_undef) X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char *)req->emailAddress, -1, -1, 0); X509_REQ_set_pubkey(xr, key); if ((digest = EVP_sha256()) == NULL) { tqslTrace("tqsl_createCertRequest", "evp_sha256 error %s", tqsl_openssl_error()); goto err; } if (!X509_REQ_sign(xr, key, digest)) { tqslTrace("tqsl_createCertRequest", "req_sign error %s", tqsl_openssl_error()); goto err; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_createCertRequest", "bio_new error %s", tqsl_openssl_error()); goto err; } if (!PEM_write_bio_X509_REQ(bio, xr)) { tqslTrace("tqsl_createCertRequest", "write_bio error %s", tqsl_openssl_error()); goto err; } len = static_cast(BIO_get_mem_data(bio, &cp)); tqsl_write_adif_field(out, "TQSL_CRQ_REQUEST", 0, (unsigned char *)cp, len); if (req->signer != NULL) { char *b64; char ibuf[256]; if ((b64 = tqsl_sign_base64_data(req->signer, cp)) == NULL) { fclose(out); out = NULL; tqslTrace("tqsl_createCertRequest", "tqsl_sign_base64 error %s", tqsl_openssl_error()); goto end; } tqsl_write_adif_field(out, "TQSL_CRQ_SIGNATURE", 0, (unsigned char *)b64, -1); tqsl_getCertificateIssuer(req->signer, ibuf, sizeof ibuf); tqsl_write_adif_field(out, "TQSL_CRQ_SIGNATURE_CERT_ISSUER", 0, (unsigned char *)ibuf, -1); snprintf(ibuf, sizeof ibuf, "%ld", ASN1_INTEGER_get(X509_get_serialNumber(TQSL_API_TO_CERT(req->signer)->cert))); tqsl_write_adif_field(out, "TQSL_CRQ_SIGNATURE_CERT_SERIAL", 0, (unsigned char *)ibuf, -1); } BIO_free(bio); bio = NULL; tqsl_write_adif_field(out, "eor", 0, NULL, 0); if (fclose(out) == EOF) { strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_createCertRequest", "write error %d", errno); out = NULL; goto end; } out = NULL; /* Write the key to the key store */ if (!tqsl_make_key_path(req->callSign, path, sizeof path)) { tqslTrace("tqsl_createCertRequest", "make_key_path error %d", errno); goto end; } #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); if ((out = _wfopen(wpath, TQSL_OPEN_APPEND)) == NULL) { free_wchar(wpath); #else if ((out = fopen(path, TQSL_OPEN_APPEND)) == NULL) { #endif strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_createCertRequest", "opening file error %s", strerror(errno)); goto end; } #ifdef _WIN32 free_wchar(wpath); #endif tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER", 0, (unsigned char *)req->providerName, -1); tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER_UNIT", 0, (unsigned char *)req->providerUnit, -1); tqsl_write_adif_field(out, "TQSL_CRQ_EMAIL", 0, (unsigned char *)req->emailAddress, -1); tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS1", 0, (unsigned char *)req->address1, -1); tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS2", 0, (unsigned char *)req->address2, -1); tqsl_write_adif_field(out, "TQSL_CRQ_CITY", 0, (unsigned char *)req->city, -1); tqsl_write_adif_field(out, "TQSL_CRQ_STATE", 0, (unsigned char *)req->state, -1); tqsl_write_adif_field(out, "TQSL_CRQ_POSTAL", 0, (unsigned char *)req->postalCode, -1); tqsl_write_adif_field(out, "TQSL_CRQ_COUNTRY", 0, (unsigned char *)req->country, -1); tqsl_write_adif_field(out, "CALLSIGN", 0, (unsigned char *)req->callSign, -1); snprintf(buf, sizeof buf, "%d", req->dxccEntity); tqsl_write_adif_field(out, "TQSL_CRQ_DXCC_ENTITY", 0, (unsigned char *)buf, -1); tqsl_convertDateToText(&(req->qsoNotBefore), buf, sizeof buf); tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_BEFORE", 0, (unsigned char *)buf, -1); if (!tqsl_isDateNull(&(req->qsoNotAfter))) { tqsl_convertDateToText(&(req->qsoNotAfter), buf, sizeof buf); tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_AFTER", 0, (unsigned char *)buf, -1); } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_createCertRequest", "bio_new error %s", tqsl_openssl_error()); goto err; } password = const_cast(req->password); if (password == NULL && pwcb != NULL) { if ((*pwcb)(buf, TQSL_MAX_PW_LENGTH, userdata)) { tqslTrace("tqsl_createCertRequest", "password abort"); tQSL_Error = TQSL_OPERATOR_ABORT; goto end; } password = buf; } if (password != NULL && *password != '\0') { if ((cipher = EVP_des_ede3_cbc()) == NULL) { tqslTrace("tqsl_createCertRequest", "password error"); goto err; } len = strlen(password); } else { password = NULL; len = 0; } if (!PEM_write_bio_PrivateKey(bio, key, cipher, (unsigned char *)password, len, NULL, NULL)) { tqslTrace("tqsl_createCertRequest", "write priv key error %s", tqsl_openssl_error()); goto err; } len = static_cast(BIO_get_mem_data(bio, &cp)); tqsl_write_adif_field(out, "PRIVATE_KEY", 0, (unsigned char *)cp, len); BIO_free(bio); if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_createCertRequest", "bio_new error %s", tqsl_openssl_error()); goto err; } if (!PEM_write_bio_PUBKEY(bio, key)) { tqslTrace("tqsl_createCertRequest", "write pubkey %s", tqsl_openssl_error()); goto err; } len = static_cast(BIO_get_mem_data(bio, &cp)); tqsl_write_adif_field(out, "PUBLIC_KEY", 0, (unsigned char *)cp, len); BIO_free(bio); bio = NULL; tqsl_write_adif_field(out, "eor", 0, NULL, 0); if (fclose(out) == EOF) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_createCertRequest", "write file error %s", strerror(tQSL_Errno)); goto end; } out = NULL; rval = 0; goto end; err: tQSL_Error = TQSL_OPENSSL_ERROR; end: if (bio != NULL) BIO_free(bio); if (out != NULL) fclose(out); if (xr != NULL) X509_REQ_free(xr); if (key != NULL) EVP_PKEY_free(key); if (req != NULL) tqsl_free_cert_req(req, 0); return rval; } DLLEXPORT int CALLCONVENTION tqsl_getSelectedCertificate(tQSL_Cert *cert, const tQSL_Cert **certlist, int idx) { tqslTrace("tqsl_getSelectedCertificate", NULL); if (tqsl_init()) return 1; if (certlist == NULL || cert == NULL || idx < 0) { tqslTrace("tqsl_getSelectedCertificate", "arg error certlist=0x%lx, cert=0x%lx, idx=%d", certlist, cert, idx); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *cert = (*certlist)[idx]; return 0; } DLLEXPORT int CALLCONVENTION tqsl_isCertificateExpired(tQSL_Cert cert, int *status) { tqslTrace("tqsl_isCertificateExpired", NULL); if (tqsl_init()) return 1; if (cert == NULL || status == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_isCertificateExpired", "arg error cert=0x%lx status=0x%lx", cert, status); tQSL_Error = TQSL_ARGUMENT_ERROR; if (status) *status = false; return 1; } int keyonly; if (tqsl_getCertificateKeyOnly(cert, &keyonly) == 0 && keyonly) { *status = false; return 0; } long serial = 0; tqsl_getCertificateSerial(cert, &serial); int sts = tqsl_getCertificateStatus(serial); if (sts == TQSL_CERT_STATUS_EXP || sts == TQSL_CERT_STATUS_INV) { *status = true; return 0; } *status = false; /* Check for expired */ struct tm *tm; #ifdef _WIN32 __time32_t t = _time32(0); tm = _gmtime32(&t); #else time_t t = time(0); struct tm tmr; tm = &tmr; tm = gmtime_r(&t, tm); #endif tQSL_Date d; d.year = tm->tm_year + 1900; d.month = tm->tm_mon + 1; d.day = tm->tm_mday; const ASN1_TIME *ctm; if ((ctm = X509_get_notAfter(TQSL_API_TO_CERT(cert)->cert)) == NULL) { *status = true; return 0; } else { tQSL_Date cert_na; tqsl_get_asn1_date(ctm, &cert_na); if (tqsl_compareDates(&cert_na, &d) < 0) { *status = true; return 0; } } return 0; } DLLEXPORT int CALLCONVENTION tqsl_isCertificateRenewable(tQSL_Cert cert, int *status) { static int window = 180; // Allow renewal out to 180 days tqslTrace("tqsl_isCertificateRenewable", NULL); if (tqsl_init()) return 1; if (cert == NULL) { window = *status; return 0; } if (cert == NULL || status == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_isCertificateRenewable", "arg error cert=0x%lx status=0x%lx", cert, status); tQSL_Error = TQSL_ARGUMENT_ERROR; if (status) *status = false; return 1; } // If there's a newer one, can't renew this int superceded; if (tqsl_isCertificateSuperceded(cert, &superceded) == 0 && superceded) { *status = false; return 0; } // Is it expired? If not, OK to renew. int expired; if (tqsl_isCertificateExpired(cert, &expired) == 0 && !expired) { *status = true; return 0; } // Also for keyonly int keyonly; if (tqsl_getCertificateKeyOnly(cert, &keyonly) == 0 && keyonly) { *status = false; return 0; } long serial = 0; tqsl_getCertificateSerial(cert, &serial); int sts = tqsl_getCertificateStatus(serial); if (sts == TQSL_CERT_STATUS_INV) { *status = true; return 0; } *status = false; /* Check for expired */ struct tm *tm; #ifdef _WIN32 __time32_t t = _time32(0); tm = _gmtime32(&t); #else time_t t = time(0); struct tm tmr; tm = &tmr; tm = gmtime_r(&t, tm); #endif tQSL_Date d; d.year = tm->tm_year + 1900; d.month = tm->tm_mon + 1; d.day = tm->tm_mday; const ASN1_TIME *ctm; if ((ctm = X509_get_notAfter(TQSL_API_TO_CERT(cert)->cert)) == NULL) { *status = true; return 0; } else { tQSL_Date cert_na; tqsl_get_asn1_date(ctm, &cert_na); int diff = 0; if (!tqsl_subtractDates(&cert_na, &d, &diff)) { if (diff < window) { *status = true; } else { *status = false; } return 0; } } return 0; } static TQSL_X509_STACK *xcerts = NULL; DLLEXPORT int CALLCONVENTION tqsl_isCertificateSuperceded(tQSL_Cert cert, int *status) { char path[TQSL_MAX_PATH_LEN]; int i; X509 *x = NULL; char *cp; vector< map > keylist; vector< map >::iterator it; set superceded_certs; int len; bool superceded = false; char buf[256]; tqslTrace("tqsl_isCertificateSuperceded", NULL); if (tqsl_init()) return 1; if (cert == NULL || status == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_isCertificateSuperceded", "arg error cert=0x%lx, status=0x%lx", cert, status); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *status = false; int keyonly; if (tqsl_getCertificateKeyOnly(cert, &keyonly) == 0 && keyonly) { return 0; } long serial = 0; tqsl_getCertificateSerial(cert, &serial); if (tqsl_getCertificateStatus(serial) == TQSL_CERT_STATUS_SUP) { *status = true; tqslTrace("tqsl_isCertificateSuperceded", "returning true"); return 0; } /* Get the certs from the cert store */ tqsl_make_cert_path("user", path, sizeof path); if (xcerts == NULL) xcerts = tqsl_ssl_load_certs_from_file(path); if (xcerts == NULL) { if (tQSL_Error == TQSL_OPENSSL_ERROR) { tqslTrace("tqsl_isCertificateSuperceded", "openssl error loading certs %d", tQSL_Error); return 1; } } /* Make a list of superceded certs */ for (i = 0; i < sk_X509_num(xcerts); i++) { x = sk_X509_value(xcerts, i); len = sizeof buf-1; if (!tqsl_get_cert_ext(x, "supercededCertificate", (unsigned char *)buf, &len, NULL)) { buf[len] = 0; string sup = buf; superceded_certs.insert(sup); /* Fix - the extension as inserted by ARRL * reads ".../Email=lotw@arrl.org", not * the expected ".../emailAddress=". * save both forms in case this gets * changed at the LoTW site */ size_t pos = sup.find("/Email"); if (pos != string::npos) { sup.replace(pos, 6, "/emailAddress"); superceded_certs.insert(sup); } } } // "supercededCertificate" extension is ; cp = X509_NAME_oneline(X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert), buf, sizeof(buf)); if (cp == NULL) { superceded = false; tqslTrace("tqsl_isCertificateSuperceded", "returning false"); } else { string sup = buf; sup += ";"; long serial = 0; tqsl_getCertificateSerial(cert, &serial); snprintf(buf, sizeof buf, "%ld", serial); sup += buf; if (superceded_certs.find(sup) != superceded_certs.end()) { tqslTrace("tqsl_isCertificateSuperceded", "returning true"); superceded = true; } } *status = superceded; return 0; } DLLEXPORT int CALLCONVENTION tqsl_selectCertificates(tQSL_Cert **certlist, int *ncerts, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flags) { int withkeys = flags & TQSL_SELECT_CERT_WITHKEYS; TQSL_X509_STACK *selcerts = NULL; char path[TQSL_MAX_PATH_LEN]; int i; X509 *x; int rval = 1; tqsl_cert *cp; TQSL_CERT_REQ *crq; BIO *bio = NULL; EVP_PKEY *pubkey = NULL; EVP_PKEY *curkey = NULL; vector< map > keylist; vector< map >::iterator it; bool keyerror = false; int savedError = 0; int savedErrno = 0; tqslTrace("tqsl_selectCertificates", "callsign=%s, dxcc=%d, flags=%d", callsign ? callsign : "NULL", dxcc, flags); if (tqsl_init()) return 1; if (ncerts == NULL) { tqslTrace("tqsl_selectCertificates", "arg error ncerts=0x%lx", ncerts); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *ncerts = 0; if (certlist) *certlist = NULL; /* Convert the dates to tQSL_Date objects */ if (date && !tqsl_isDateNull(date) && !tqsl_isDateValid(date)) { tqslTrace("tqsl_selectCertificates", "arg error - bad date"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } /* Get the certs from the cert store */ tqsl_make_cert_path("user", path, sizeof path); if (xcerts == NULL) xcerts = tqsl_ssl_load_certs_from_file(path); if (xcerts == NULL) { if (tQSL_Error == TQSL_OPENSSL_ERROR) { tqslTrace("tqsl_selectCertificates", "openssl error"); return 1; } else if (tQSL_Error != TQSL_SYSTEM_ERROR || tQSL_Errno != ENOENT) { // No file tqslTrace("tqsl_selectCertificates", "other error %d", tQSL_Error); return 1; } } else { selcerts = tqsl_filter_cert_list(xcerts, callsign, dxcc, date, issuer, flags); } // Get a list of keys and find any unmatched (no cert) ones if (withkeys) { if (tqsl_make_key_list(keylist)) { keyerror = true; // Remember that an error occurred savedError = tQSL_Error; // but allow the rest of the certs to load savedErrno = tQSL_Errno; tqslTrace("tqsl_selectCertificates", "make_key_list error %d %d", tQSL_Error, tQSL_Errno); } if (xcerts != NULL) { for (i = 0; i < sk_X509_num(xcerts); i++) { x = sk_X509_value(xcerts, i); if ((pubkey = X509_get_pubkey(x)) == NULL) { tqslTrace("tqsl_selectCertificates", "can't get pubkey"); goto err; } for (it = keylist.begin(); it != keylist.end(); it++) { int match = 0; /* Compare the keys */ string& keystr = (*it)["PUBLIC_KEY"]; if ((bio = BIO_new_mem_buf(static_cast(const_cast(keystr.c_str())), keystr.length())) == NULL) { tqslTrace("tqsl_selectCertifcates", "bio_new error %s", tqsl_openssl_error()); goto err; } if ((curkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { tqslTrace("tqsl_selectCertificates", "pem_read_bio err %s", tqsl_openssl_error()); goto err; } BIO_free(bio); bio = NULL; if (EVP_PKEY_cmp(curkey, pubkey) == 1) match = 1; EVP_PKEY_free(curkey); curkey = NULL; if (match) { // Remove matched key from list keylist.erase(it); break; } } EVP_PKEY_free(pubkey); pubkey = NULL; } } // Filter keylist for (it = keylist.begin(); it != keylist.end(); ) { if ((*it)["TQSL_CRQ_PROVIDER"] == "") it = keylist.erase(it); else if (callsign && (*it)["CALLSIGN"] != callsign) it = keylist.erase(it); else if (dxcc && strtol((*it)["TQSL_CRQ_DXCC_ENTITY"].c_str(), NULL, 10) != dxcc) it = keylist.erase(it); else if (issuer && (*it)["TQSL_CRQ_PROVIDER"] != issuer->organizationName) it = keylist.erase(it); else if (issuer && (*it)["TQSL_CRQ_PROVIDER_UNIT"] != issuer->organizationalUnitName) it = keylist.erase(it); else it++; } } //cerr << keylist.size() << " unmatched keys" << endl; *ncerts = (selcerts ? sk_X509_num(selcerts) : 0) + keylist.size(); tqslTrace("tqsl_selectCertificates", "ncerts=%d", *ncerts); if (certlist == NULL) { // Only want certificate count rval = 0; goto end; } *certlist = reinterpret_cast(tqsl_calloc(*ncerts, sizeof(tQSL_Cert))); if (selcerts != NULL) { for (i = 0; i < sk_X509_num(selcerts); i++) { x = sk_X509_value(selcerts, i); if ((cp = tqsl_cert_new()) == NULL) { tqslTrace("tqsl_selectCertificates", "error making new cert - %s", tqsl_openssl_error()); goto end; } X509_up_ref(x); cp->cert = x; (*certlist)[i] = TQSL_OBJ_TO_API(cp); } } else { i = 0; } for (it = keylist.begin(); it != keylist.end(); it++) { if ((cp = tqsl_cert_new()) == NULL) { tqslTrace("tqsl_selectCertificates", "error making new cert - %s", tqsl_openssl_error()); goto end; } crq = reinterpret_cast(tqsl_calloc(1, sizeof(TQSL_CERT_REQ))); if (crq != NULL) { tQSL_Error = TQSL_BUFFER_ERROR; if (!safe_strncpy(crq->providerName, (*it)["TQSL_CRQ_PROVIDER"].c_str(), sizeof crq->providerName)) goto end; if (!safe_strncpy(crq->providerUnit, (*it)["TQSL_CRQ_PROVIDER_UNIT"].c_str(), sizeof crq->providerUnit)) goto end; if (!safe_strncpy(crq->callSign, (*it)["CALLSIGN"].c_str(), sizeof crq->callSign)) goto end; if (!safe_strncpy(crq->name, (*it)["TQSL_CRQ_NAME"].c_str(), sizeof crq->name)) goto end; if (!safe_strncpy(crq->emailAddress, (*it)["TQSL_CRQ_EMAIL"].c_str(), sizeof crq->emailAddress)) goto end; if (!safe_strncpy(crq->address1, (*it)["TQSL_CRQ_ADDRESS1"].c_str(), sizeof crq->address1)) goto end; if (!safe_strncpy(crq->address2, (*it)["TQSL_CRQ_ADDRESS2"].c_str(), sizeof crq->address2)) goto end; if (!safe_strncpy(crq->city, (*it)["TQSL_CRQ_CITY"].c_str(), sizeof crq->city)) goto end; if (!safe_strncpy(crq->state, (*it)["TQSL_CRQ_STATE"].c_str(), sizeof crq->state)) goto end; if (!safe_strncpy(crq->postalCode, (*it)["TQSL_CRQ_POSTAL"].c_str(), sizeof crq->postalCode)) goto end; if (!safe_strncpy(crq->country, (*it)["TQSL_CRQ_COUNTRY"].c_str(), sizeof crq->country)) goto end; crq->dxccEntity = strtol((*it)["TQSL_CRQ_DXCC_ENTITY"].c_str(), NULL, 10); tqsl_initDate(&(crq->qsoNotBefore), (*it)["TQSL_CRQ_QSO_NOT_BEFORE"].c_str()); tqsl_initDate(&(crq->qsoNotAfter), (*it)["TQSL_CRQ_QSO_NOT_AFTER"].c_str()); tQSL_Error = 0; } cp->crq = crq; int len = strlen((*it)["PUBLIC_KEY"].c_str()); if (len) { cp->pubkey = new char[len+1]; strncpy(cp->pubkey, (*it)["PUBLIC_KEY"].c_str(), len+1); } len = strlen((*it)["PRIVATE_KEY"].c_str()); if (len) { cp->privkey = new char[len+1]; strncpy(cp->privkey, (*it)["PRIVATE_KEY"].c_str(), len+1); } cp->keyonly = 1; (*certlist)[i++] = TQSL_OBJ_TO_API(cp); } if (keyerror) { // If an error happened with private key scan tQSL_Error = savedError; // Restore the error status from that tQSL_Errno = savedErrno; rval = 1; } else { rval = 0; } goto end; err: tQSL_Error = TQSL_OPENSSL_ERROR; end: if (selcerts != NULL) sk_X509_free(selcerts); if (bio != NULL) BIO_free(bio); if (pubkey != NULL) EVP_PKEY_free(pubkey); if (curkey != NULL) EVP_PKEY_free(curkey); return rval; } DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates(tQSL_Cert **certlist, int *ncerts, const char *type) { TQSL_X509_STACK *cacerts = NULL; int rval = 1; char path[TQSL_MAX_PATH_LEN]; int i; X509 *x; tqsl_cert *cp; vector< map > keylist; vector< map >::iterator it; tqslTrace("tqsl_selectCACertificates", NULL); if (tqsl_init()) return 1; if (certlist == NULL || ncerts == NULL) { tqslTrace("tqsl_selectCACertificates", "arg error certlist=0x%lx, ncerts=0x%lx", certlist, ncerts); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } /* Get the certs from the cert store */ tqsl_make_cert_path(type, path, sizeof path); cacerts = tqsl_ssl_load_certs_from_file(path); if (cacerts == NULL) { if (tQSL_Error == TQSL_OPENSSL_ERROR) { tqslTrace("tqsl_selectCACertificates", "cacerts openssl error"); return 1; } } *ncerts = (cacerts ? sk_X509_num(cacerts) : 0) + keylist.size(); *certlist = reinterpret_cast(tqsl_calloc(*ncerts, sizeof(tQSL_Cert))); if (cacerts != NULL) { for (i = 0; i < sk_X509_num(cacerts); i++) { x = sk_X509_value(cacerts, i); if ((cp = tqsl_cert_new()) == NULL) { tqslTrace("tqsl_selectCACertificates", "cert_new error %s", tqsl_openssl_error()); goto end; } if (cp->cert) X509_free(cp->cert); X509_up_ref(x); cp->cert = x; (*certlist)[i] = TQSL_OBJ_TO_API(cp); } } rval = 0; end: if (cacerts != NULL) sk_X509_free(cacerts); return rval; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateKeyOnly(tQSL_Cert cert, int *keyonly) { tqslTrace("tqsl_getCertificateKeyOnly", "cert=0x%lx, keyonly=0x%lx", cert, keyonly); if (tqsl_init()) return 1; if (cert == NULL || keyonly == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateKeyOnly", "arg error"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *keyonly = TQSL_API_TO_CERT(cert)->keyonly; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateEncoded(tQSL_Cert cert, char *buf, int bufsiz) { BIO *bio = NULL; int len; char *cp; int rval = 1; tqslTrace("tqsl_getCertificateEncoded", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateEncoded", "arg error cert=0x%lx, buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_getCertificateEncoded", "bio_new err %s", tqsl_openssl_error()); goto err; } if (!PEM_write_bio_X509(bio, TQSL_API_TO_CERT(cert)->cert)) { tqslTrace("tqsl_getCertificateEncoded", "pem_write_bio err %s", tqsl_openssl_error()); goto err; } len = static_cast(BIO_get_mem_data(bio, &cp)); if (len < bufsiz) { memcpy(buf, cp, len); buf[len] = 0; } else { tqslTrace("tqsl_getCertificateEncoded", "buffer error %d needed %d there", len, bufsiz); tQSL_Error = TQSL_BUFFER_ERROR; goto end; } rval = 0; goto end; err: tQSL_Error = TQSL_OPENSSL_ERROR; end: if (bio != NULL) BIO_free(bio); return rval; } DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded(tQSL_Cert cert, char *buf, int bufsiz) { BIO *b64 = NULL; BIO *bio = NULL; BIO *out = NULL; char callsign[40]; long len; char *cp; vector< map > keylist; vector< map >::iterator it; EVP_PKEY *pubkey = NULL; EVP_PKEY *curkey = NULL; tqslTrace("tqsl_getKeyEncoded", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getKeyEncoded", "arg error cert=0x%lx, buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tQSL_Error = TQSL_OPENSSL_ERROR; // If it's 'keyonly', then there's no public key - use the one in the cert. if (TQSL_API_TO_CERT(cert)->keyonly) { if (TQSL_API_TO_CERT(cert)->privkey == 0) { tqslTrace("tqsl_getKeyEncoded", "arg error no private key"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(callsign, TQSL_API_TO_CERT(cert)->crq->callSign, sizeof callsign); b64 = BIO_new(BIO_f_base64()); out = BIO_new(BIO_s_mem()); out = BIO_push(b64, out); tQSL_Error = TQSL_SYSTEM_ERROR; if (tqsl_bio_write_adif_field(out, "CALLSIGN", 0, (const unsigned char *)callsign, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "PRIVATE_KEY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->privkey, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "PUBLIC_KEY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->pubkey, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } char numbuf[10]; snprintf(numbuf, sizeof numbuf, "%d", TQSL_API_TO_CERT(cert)->crq->dxccEntity); if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_DXCC_ENTITY", 0, (const unsigned char *)numbuf, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_PROVIDER", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->providerName, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_PROVIDER_UNIT", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->providerUnit, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_EMAIL", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->emailAddress, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_ADDRESS1", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->address1, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_ADDRESS2", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->address2, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_CITY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->city, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_STATE", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->state, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_POSTAL", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->postalCode, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_COUNTRY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->country, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); return 1; } char datebuf[20]; tqsl_convertDateToText(&(TQSL_API_TO_CERT(cert)->crq->qsoNotAfter), datebuf, sizeof datebuf); if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_QSO_NOT_AFTER", 0, (const unsigned char *)datebuf, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } tqsl_convertDateToText(&(TQSL_API_TO_CERT(cert)->crq->qsoNotBefore), datebuf, sizeof datebuf); if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_QSO_NOT_BEFORE", 0, (const unsigned char *)datebuf, -1)) { tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } tqsl_bio_write_adif_field(out, "eor", 0, NULL, 0); if (BIO_flush(out) != 1) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "Error encoding certificate", sizeof tQSL_CustomError); BIO_free_all(out); tqslTrace("tqsl_getKeyEncoded", "BIO_flush error %s", tqsl_openssl_error()); return 1; } len = BIO_get_mem_data(out, &cp); if (len > bufsiz) { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Private key buffer size %d is too small - %ld needed", bufsiz, len); BIO_free_all(out); tqslTrace("tqsl_getKeyEncoded", "buffer size err: %s", tQSL_CustomError); return 1; } memcpy(buf, cp, len); buf[len] = '\0'; BIO_free_all(out); return 0; } if (tqsl_getCertificateCallSign(cert, callsign, sizeof callsign)) { tqslTrace("tqsl_getKeyEncoded", "Error getting callsign %d", tQSL_Error); return 1; } if (tqsl_make_key_list(keylist)) { tqslTrace("tqsl_getKeyEncoded", "Error making keylist %d", tQSL_Error); tQSL_Error = TQSL_SYSTEM_ERROR; return 1; } if ((pubkey = X509_get_pubkey(TQSL_API_TO_CERT(cert)->cert)) == 0) { tqslTrace("tqsl_getKeyEncoded", "Error getting pubkey %d", tQSL_Error); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } // Find the matching private key for (it = keylist.begin(); it != keylist.end(); it++) { string& keystr = (*it)["PUBLIC_KEY"]; if ((bio = BIO_new_mem_buf(static_cast(const_cast(keystr.c_str())), keystr.length())) == NULL) { tqslTrace("tqsl_getKeyEncoded", "Error getting buffer %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } if ((curkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { BIO_free(bio); tqslTrace("tqsl_getKeyEncoded", "Error reading PUBKEY %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } BIO_free(bio); bio = NULL; if (EVP_PKEY_cmp(curkey, pubkey) == 1) { // This is the matching private key. Let's feed it back. EVP_PKEY_free(curkey); curkey = NULL; EVP_PKEY_free(pubkey); pubkey = NULL; b64 = BIO_new(BIO_f_base64()); out = BIO_new(BIO_s_mem()); out = BIO_push(b64, out); map::iterator mit; for (mit = it->begin(); mit != it->end(); mit++) { if (tqsl_bio_write_adif_field(out, mit->first.c_str(), 0, (const unsigned char *)mit->second.c_str(), -1)) { tQSL_Error = TQSL_SYSTEM_ERROR; tqslTrace("tqsl_getKeyEncoded", "Error writing field %s", tqsl_openssl_error()); return 1; } } tqsl_bio_write_adif_field(out, "eor", 0, NULL, 0); if (BIO_flush(out) != 1) { tQSL_Error = TQSL_CUSTOM_ERROR; tqslTrace("tqsl_getKeyEncoded", "Error flushing write %s", tqsl_openssl_error()); strncpy(tQSL_CustomError, "Error encoding certificate", sizeof tQSL_CustomError); BIO_free_all(out); return 1; } len = BIO_get_mem_data(out, &cp); if (len > bufsiz) { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Private key buffer size %d is too small - %ld needed", bufsiz, len); tqslTrace("tqsl_getKeyEncoded", "Buffer err %s", tQSL_CustomError); BIO_free_all(out); return 1; } memcpy(buf, cp, len); buf[len] = '\0'; BIO_free_all(out); return 0; } else { EVP_PKEY_free(curkey); curkey = NULL; } } if (pubkey != NULL) EVP_PKEY_free(pubkey); tqslTrace("tqsl_getKeyEncoded", "private key not found"); tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Private key not found for callsign %s", callsign); return 1; // Private key not found } DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded(const char *callsign, const char *type, const char *keybuf, const char *certbuf) { BIO *in = NULL; BIO *b64 = NULL; BIO *pub = NULL; X509 *cert; char path[TQSL_MAX_PATH_LEN]; char temppath[TQSL_MAX_PATH_LEN]; char biobuf[4096]; int cb = 0; map fields; void* userdata = NULL; tqslTrace("tqsl_importKeyPairEncoded", NULL); if (tqsl_init()) return 1; if (certbuf == NULL || type == NULL) { tqslTrace("tqsl_importKeyPairEncoded", "arg error certbuf=0x%lx, type=0x%lx", certbuf, type); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (strcmp(type, "user") == 0) { if (keybuf == NULL) { tqslTrace("tqsl_importKeyPairEncoded", "arg error user cert keybuf null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } cb = TQSL_CERT_CB_USER; } else if (strcmp(type, "root") == 0) { cb = TQSL_CERT_CB_ROOT; } else if (strcmp(type, "authorities") == 0) { cb = TQSL_CERT_CB_CA; } else { tqslTrace("tqsl_importKeyPairEncoded", "arg error type unknown"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (keybuf) { if (!tqsl_make_key_path(callsign, path, sizeof path)) { goto noprv; } in = BIO_new_mem_buf(static_cast(const_cast(keybuf)), strlen(keybuf)); if (in == NULL) { goto noprv; } b64 = BIO_new(BIO_f_base64()); in = BIO_push(b64, in); size_t bloblen; bloblen = BIO_read(in, biobuf, strlen(keybuf)); biobuf[bloblen] = '\0'; strncpy(temppath, tQSL_BaseDir, sizeof temppath); FILE *temp = NULL; #ifdef _WIN32 strncat(temppath, "\\pk.tmp", sizeof temppath - strlen(temppath) -1); wchar_t* wpath = utf8_to_wchar(temppath); if ((temp = _wfopen(wpath, TQSL_OPEN_WRITE)) == NULL) { free_wchar(wpath); #else strncat(temppath, "/pk.tmp", sizeof temppath - strlen(temppath) -1); if ((temp = fopen(temppath, TQSL_OPEN_WRITE)) == NULL) { #endif strncpy(tQSL_ErrorFile, temppath, sizeof tQSL_ErrorFile); tqslTrace("tqsl_importKeyPairEncoded", "Open file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; return 1; } #ifdef _WIN32 free_wchar(wpath); #endif if (fputs(biobuf, temp) == EOF) { strncpy(tQSL_ErrorFile, temppath, sizeof tQSL_ErrorFile); tqslTrace("tqsl_importKeyPairEncoded", "Write request file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; return 1; } if (fclose(temp) == EOF) { strncpy(tQSL_ErrorFile, temppath, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_importKeyPairEncoded", "write error %d", errno); return 1; } // Now is there a private key already with this serial? char *pubkey = strstr(biobuf, "-----BEGIN PUBLIC KEY-----"); char *endpub = strstr(biobuf, "-----END PUBLIC KEY-----"); int publen = endpub - pubkey + strlen("-----END PUBLIC KEY-----"); if (pubkey) { EVP_PKEY *new_key = NULL; if ((pub = BIO_new_mem_buf(reinterpret_cast(pubkey), publen)) == NULL) { goto noprv; } if ((new_key = PEM_read_bio_PUBKEY(pub, NULL, NULL, NULL)) == NULL) { goto noprv; } BIO_free(pub); pub = 0; if (!tqsl_key_exists(callsign, new_key)) { // Populate fields from the temp file if (!tqsl_open_key_file(temppath)) { if (!tqsl_read_key(fields)) { tqsl_replace_key(callsign, path, fields, NULL, userdata); } tqsl_close_key_file(); } } BIO_free_all(in); } } // Import of private key noprv: if (strlen(certbuf) == 0) // Keyonly 'certificates' return 0; // Now process the certificate in = BIO_new_mem_buf(static_cast(const_cast(certbuf)), strlen(certbuf)); if (in == NULL) { tqslTrace("tqsl_importKeyPairEncoded", "cert new_mem_buf err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } cert = PEM_read_bio_X509(in, NULL, NULL, NULL); BIO_free(in); if (cert == NULL) { tqslTrace("tqsl_importKeyPairEncoded", "read_bio_x509 err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } int ret = tqsl_store_cert(certbuf, cert, type, cb, true, NULL, NULL); // it's OK if installing the cert gets a dupe if (ret != 0 && tQSL_Error == TQSL_CERT_ERROR) { ret = 0; } return ret; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateCallSign(tQSL_Cert cert, char *buf, int bufsiz) { char nbuf[40]; TQSL_X509_NAME_ITEM item; tqslTrace("tqsl_getCertificateCallSign", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateCallSign", "arg err cert=0x%lx buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) { // Handle the key-only case if (bufsiz <= static_cast(strlen(TQSL_API_TO_CERT(cert)->crq->callSign))) { tqslTrace("tqsl_getCertificateCallSign", "bufsiz=%d, needed=%d", bufsiz, static_cast(strlen(TQSL_API_TO_CERT(cert)->crq->callSign))); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(buf, TQSL_API_TO_CERT(cert)->crq->callSign, bufsiz); tqslTrace("tqsl_getCertificateCallSign", "KeyOnly, call=%s", buf); return 0; } item.name_buf = nbuf; item.name_buf_size = sizeof nbuf; item.value_buf = buf; item.value_buf_size = bufsiz; int ret = tqsl_cert_get_subject_name_entry(TQSL_API_TO_CERT(cert)->cert, "AROcallsign", &item); tqslTrace("tqsl_getCertificateCallSign", "Result=%d, call=%s", ret, buf); return !ret; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateAROName(tQSL_Cert cert, char *buf, int bufsiz) { char nbuf[40]; TQSL_X509_NAME_ITEM item; tqslTrace("tqsl_getCertificateAROName", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateAROName", "cert=0x%lx, buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } item.name_buf = nbuf; item.name_buf_size = sizeof nbuf; item.value_buf = buf; item.value_buf_size = bufsiz; return !tqsl_cert_get_subject_name_entry(TQSL_API_TO_CERT(cert)->cert, "commonName", &item); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateEmailAddress(tQSL_Cert cert, char *buf, int bufsiz) { char nbuf[40]; TQSL_X509_NAME_ITEM item; tqslTrace("tqsl_getCertificateEmailAddress", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateEmailAddress", "arg err cert=0x%lx, buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } item.name_buf = nbuf; item.name_buf_size = sizeof nbuf; item.value_buf = buf; item.value_buf_size = bufsiz; return !tqsl_cert_get_subject_name_entry(TQSL_API_TO_CERT(cert)->cert, "emailAddress", &item); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerial(tQSL_Cert cert, long *serial) { tqslTrace("tqsl_getCertificateSerial", NULL); if (tqsl_init()) return 1; if (cert == NULL || serial == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateSerial", "arg err cert=0x%lx, serial=0x%lx", cert, serial); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *serial = ASN1_INTEGER_get(X509_get_serialNumber(TQSL_API_TO_CERT(cert)->cert)); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt(tQSL_Cert cert, char *serial, int serialsiz) { tqslTrace("tqsl_getCertificateSerialExt", NULL); if (tqsl_init()) return 1; if (cert == NULL || serial == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert)) || serialsiz < 1) { tqslTrace("tqsl_getCertificateSerialExt", "arg err cert=0x%lx, serial=0x%lx", cert, serial); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } BIGNUM *bn = BN_new(); ASN1_INTEGER_to_BN(X509_get_serialNumber(TQSL_API_TO_CERT(cert)->cert), bn); char *s = BN_bn2hex(bn); strncpy(serial, s, serialsiz); serial[serialsiz-1] = 0; OPENSSL_free(s); BN_free(bn); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialLength(tQSL_Cert cert) { int rval; tqslTrace("tqsl_getCertificateSerialLength", NULL); if (tqsl_init()) return 1; if (cert == NULL) { tqslTrace("tqsl_getCertificateSerialLength", "arg error,cert=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } BIGNUM *bn = BN_new(); ASN1_INTEGER_to_BN(X509_get_serialNumber(TQSL_API_TO_CERT(cert)->cert), bn); char *s = BN_bn2hex(bn); rval = strlen(s); OPENSSL_free(s); BN_free(bn); return rval; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuer(tQSL_Cert cert, char *buf, int bufsiz) { char *cp; tqslTrace("tqsl_getCertificateIssuer", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateIssuer", "arg err cert=0x%lx, buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } cp = X509_NAME_oneline(X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert), buf, bufsiz); if (cp == NULL) { tqslTrace("tqsl_getCertificateIssuer", "X509_NAME_oneline error %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; } return (cp == NULL); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganization(tQSL_Cert cert, char *buf, int bufsiz) { char nbuf[40]; TQSL_X509_NAME_ITEM item; X509_NAME *iss; tqslTrace("tqsl_getCertificateIssuerOrganization", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateIssuerOrganization", "arg error cert=0x%lx buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) { // Handle the key-only case if (bufsiz <= static_cast(strlen(TQSL_API_TO_CERT(cert)->crq->providerName))) { tqslTrace("tqsl_getCertificateIssuerOrganization", "bufsiz error have=%d need=%d", bufsiz, static_cast(strlen(TQSL_API_TO_CERT(cert)->crq->providerName))); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(buf, TQSL_API_TO_CERT(cert)->crq->providerName, bufsiz); return 0; } item.name_buf = nbuf; item.name_buf_size = sizeof nbuf; item.value_buf = buf; item.value_buf_size = bufsiz; if ((iss = X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert)) == NULL) { tqslTrace("tqsl_getCertificateIssuerOrganization", "get_issuer_name err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } return !tqsl_get_name_entry(iss, "organizationName", &item); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganizationalUnit(tQSL_Cert cert, char *buf, int bufsiz) { char nbuf[40]; TQSL_X509_NAME_ITEM item; X509_NAME *iss; tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", NULL); if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", "arg err cert=0x%lx, buf=0x%lx", cert, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) { // Handle the key-only case if (bufsiz <= static_cast(strlen(TQSL_API_TO_CERT(cert)->crq->providerUnit))) { tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", "bufsize error have=%d need=%d", bufsiz, static_cast(strlen(TQSL_API_TO_CERT(cert)->crq->providerUnit))); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(buf, TQSL_API_TO_CERT(cert)->crq->providerUnit, bufsiz); return 0; } item.name_buf = nbuf; item.name_buf_size = sizeof nbuf; item.value_buf = buf; item.value_buf_size = bufsiz; if ((iss = X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert)) == NULL) { tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", "get_issuer_name err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } return !tqsl_get_name_entry(iss, "organizationalUnitName", &item); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotBeforeDate(tQSL_Cert cert, tQSL_Date *date) { char datebuf[40]; int len = (sizeof datebuf) -1; tqslTrace("tqsl_getCertificateQSONotBeforeDate", NULL); if (tqsl_init()) return 1; if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateQSONotBeforeDate", "arg err cert=0x%lx date=0x%lx", cert, date); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) { // Handle the key-only case *date = TQSL_API_TO_CERT(cert)->crq->qsoNotBefore; return 0; } if (tqsl_get_cert_ext(TQSL_API_TO_CERT(cert)->cert, "QSONotBeforeDate", (unsigned char *)datebuf, &len, NULL)) return 1; datebuf[len] = 0; return tqsl_initDate(date, const_cast(datebuf)); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotAfterDate(tQSL_Cert cert, tQSL_Date *date) { char datebuf[40]; int len = (sizeof datebuf) -1; tqslTrace("tqsl_getCertificateQSONotAfterDate", NULL); if (tqsl_init()) return 1; if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateQSONotAfterDate", "arg err cert=0x%lx date=0x%lx", cert, date); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) { // Handle the key-only case *date = TQSL_API_TO_CERT(cert)->crq->qsoNotAfter; return 0; } if (tqsl_get_cert_ext(TQSL_API_TO_CERT(cert)->cert, "QSONotAfterDate", (unsigned char *)datebuf, &len, NULL)) return 1; datebuf[len] = 0; return tqsl_initDate(date, const_cast(datebuf)); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotBeforeDate(tQSL_Cert cert, tQSL_Date *date) { const ASN1_TIME *tm; tqslTrace("tqsl_getCertificateNotBeforeDate", NULL); if (tqsl_init()) return 1; if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateNotBeforeDate", "arg err cert=0x%lx date=0x%lx", cert, date); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly) { tqslTrace("tqsl_getCertificateNotBeforeDate", "Err:cert is keyonly"); tQSL_Error = TQSL_CERT_KEY_ONLY; return 1; } if ((tm = X509_get_notBefore(TQSL_API_TO_CERT(cert)->cert)) == NULL) { tqslTrace("tqsl_getCertificateNotBeforeDate", "get_notBefore err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } return tqsl_get_asn1_date(tm, date); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotAfterDate(tQSL_Cert cert, tQSL_Date *date) { const ASN1_TIME *tm; if (tqsl_init()) return 1; if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getCertificateNotAfterDate", "arg err cert=0x%lx date=0x%lx", cert, date); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly) { tqslTrace("tqsl_getCertificateNotAfterDate", "Err:cert is keyonly"); tQSL_Error = TQSL_CERT_KEY_ONLY; return 1; } if ((tm = X509_get_notAfter(TQSL_API_TO_CERT(cert)->cert)) == NULL) { tqslTrace("tqsl_getCertificateNotAfterDate", "get_notAfter err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } return tqsl_get_asn1_date(tm, date); } DLLEXPORT int CALLCONVENTION tqsl_getCertificateDXCCEntity(tQSL_Cert cert, int *dxcc) { char buf[40]; int len = sizeof buf; tqslTrace("tqsl_getCertificateDXCCEntity", NULL); if (tqsl_init()) return 1; if (cert == NULL || dxcc == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificateDXCCEntity", "arg err cert=0x%lx dxcc=0x%lx", cert, dxcc); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) { // Handle the key-only case *dxcc = TQSL_API_TO_CERT(cert)->crq->dxccEntity; return 0; } if (tqsl_get_cert_ext(TQSL_API_TO_CERT(cert)->cert, "dxccEntity", (unsigned char *)buf, &len, NULL)) { tqslTrace("tqsl_getCertificateDXCCEntity", "Cert does not have dxcc extension"); return 1; } *dxcc = strtol(buf, NULL, 10); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificatePrivateKeyType(tQSL_Cert cert) { tqslTrace("tqsl_getCertificatePrivateKeyType", NULL); if (tqsl_init()) return 1; if (!tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_getCertificatePrivateKeyType", "arg err, bad cert"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (tqsl_beginSigning(cert, const_cast (""), 0, 0)) { // Try to unlock the key using no password if (tQSL_Error == TQSL_PASSWORD_ERROR) { tqsl_getErrorString(); // Clear the error tqslTrace("tqsl_getCertificatePrivateKeyType", "password error - encrypted"); return TQSL_PK_TYPE_ENC; } tqslTrace("tqsl_getCertificatePrivateKeyType", "other error"); return TQSL_PK_TYPE_ERR; } tqslTrace("tqsl_getCertificatePrivateKeyType", "unencrypted"); return TQSL_PK_TYPE_UNENC; } DLLEXPORT void CALLCONVENTION tqsl_freeCertificate(tQSL_Cert cert) { if (cert == NULL) return; tqsl_cert_free(TQSL_API_TO_CERT(cert)); } DLLEXPORT void CALLCONVENTION tqsl_freeCertificateList(tQSL_Cert* list, int ncerts) { for (int i = 0; i < ncerts; i++) if (list[i]) tqsl_cert_free(TQSL_API_TO_CERT(list[i])); if (list) free(list); } DLLEXPORT int CALLCONVENTION tqsl_beginSigning(tQSL_Cert cert, char *password, int(*pwcb)(char *, int, void *), void *userdata) { tqslTrace("tqsl_beginSigning", NULL); if (tqsl_init()) return 1; if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_beginSigning", "arg err cert=0x%lx", cert); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->key != NULL) return 0; if (TQSL_API_TO_CERT(cert)->keyonly) { if (TQSL_API_TO_CERT(cert)->privkey == 0) { tqslTrace("tqsl_beginSigning", "can't sign, keyonly"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } return tqsl_unlock_key(TQSL_API_TO_CERT(cert)->privkey, &(TQSL_API_TO_CERT(cert)->key), password, pwcb, userdata); } return tqsl_find_matching_key(TQSL_API_TO_CERT(cert)->cert, &(TQSL_API_TO_CERT(cert)->key), &(TQSL_API_TO_CERT(cert)->crq), password, pwcb, userdata); } DLLEXPORT int CALLCONVENTION tqsl_getMaxSignatureSize(tQSL_Cert cert, int *sigsize) { tqslTrace("tqsl_getMaxSignatureSize", NULL); if (tqsl_init()) return 1; if (cert == NULL || sigsize == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_getMaxSignatureSize", "arg err cert=0x%lx, sigsize=0x%lx", cert, sigsize); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->key == NULL) { tqslTrace("tqsl_getMaxSignatureSize", "arg err key=null"); tQSL_Error = TQSL_SIGNINIT_ERROR; return 1; } *sigsize = EVP_PKEY_size(TQSL_API_TO_CERT(cert)->key); return 0; } DLLEXPORT int CALLCONVENTION tqsl_checkSigningStatus(tQSL_Cert cert) { tqslTrace("tqsl_checkSigningStatus", NULL); if (tqsl_init()) return 1; if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_checkSigningStatus", "arg err cert=0x%lx", cert); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->key == NULL) { tqslTrace("tqsl_checkSigningStatus", "arg err no key"); tQSL_Error = TQSL_SIGNINIT_ERROR; return 1; } return 0; } DLLEXPORT int CALLCONVENTION tqsl_signDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen) { tqslTrace("tqsl_signDataBlock", NULL); if (tqsl_init()) return 1; if (cert == NULL || data == NULL || sig == NULL || siglen == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_signDataBlock", "arg error cert=0x%lx data=0x%lx sig=0x%lx siglen=0x%lx", cert, data, sig, siglen); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } EVP_MD_CTX *ctx = EVP_MD_CTX_create(); if (ctx == NULL) return 1; unsigned int slen = *siglen; if (TQSL_API_TO_CERT(cert)->key == NULL) { tqslTrace("tqsl_signDataBlock", "can't sign, no key"); tQSL_Error = TQSL_SIGNINIT_ERROR; if (ctx) EVP_MD_CTX_destroy(ctx); return 1; } EVP_SignInit(ctx, EVP_sha1()); EVP_SignUpdate(ctx, data, datalen); if (!EVP_SignFinal(ctx, sig, &slen, TQSL_API_TO_CERT(cert)->key)) { tqslTrace("tqsl_signDataBlock", "signing failed %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; if (ctx) EVP_MD_CTX_destroy(ctx); return 1; } *siglen = slen; if (ctx) EVP_MD_CTX_destroy(ctx); return 0; } DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); unsigned int slen = siglen; tqslTrace("tqsl_verifyDataBlock", NULL); if (ctx == NULL) return 1; if (tqsl_init()) return 1; if (cert == NULL || data == NULL || sig == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_verifyDataBlock", "arg error cert=0x%lx data=0x%lx sig=0x%lx", cert, data, sig); tQSL_Error = TQSL_ARGUMENT_ERROR; if (ctx) EVP_MD_CTX_destroy(ctx); return 1; } if (TQSL_API_TO_CERT(cert)->key == NULL) { tqslTrace("tqsl_verifyDataBlock", "no key"); tQSL_Error = TQSL_SIGNINIT_ERROR; if (ctx) EVP_MD_CTX_destroy(ctx); return 1; } EVP_VerifyInit(ctx, EVP_sha1()); EVP_VerifyUpdate(ctx, data, datalen); if (EVP_VerifyFinal(ctx, sig, slen, TQSL_API_TO_CERT(cert)->key) <= 0) { tqslTrace("tqsl_verifyDataBlock", "verify fail %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; if (ctx) EVP_MD_CTX_destroy(ctx); return 1; } if (ctx) EVP_MD_CTX_destroy(ctx); return 0; } DLLEXPORT int CALLCONVENTION tqsl_endSigning(tQSL_Cert cert) { tqslTrace("tqsl_endSigning", NULL); if (tqsl_init()) return 1; if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_endSigning", "arg err cert=0x%lx", cert); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->key != NULL) { EVP_PKEY_free(TQSL_API_TO_CERT(cert)->key); TQSL_API_TO_CERT(cert)->key = NULL; } if (TQSL_API_TO_CERT(cert)->crq != NULL) { tqsl_free(TQSL_API_TO_CERT(cert)->crq); TQSL_API_TO_CERT(cert)->crq = NULL; } return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress1(tQSL_Cert cert, char *buf, int bufsiz) { tqslTrace("tqsl_getCertificateRequestAddress1", NULL); if (tqsl_check_crq_field(cert, buf, bufsiz)) { tqslTrace("tqsl_getCertificateRequestAddress1", "check fail"); return 1; } strncpy(buf, (TQSL_API_TO_CERT(cert)->crq)->address1, bufsiz); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress2(tQSL_Cert cert, char *buf, int bufsiz) { tqslTrace("tqsl_getCertificateRequestAddress2", NULL); if (tqsl_check_crq_field(cert, buf, bufsiz)) { tqslTrace("tqsl_getCertificateRequestAddress2", "check fail"); return 1; } strncpy(buf, (TQSL_API_TO_CERT(cert)->crq)->address2, bufsiz); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCity(tQSL_Cert cert, char *buf, int bufsiz) { tqslTrace("tqsl_getCertificateRequestCity", NULL); if (tqsl_check_crq_field(cert, buf, bufsiz)) { tqslTrace("tqsl_getCertificateRequestCity", "check fail"); return 1; } strncpy(buf, (TQSL_API_TO_CERT(cert)->crq)->city, bufsiz); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestState(tQSL_Cert cert, char *buf, int bufsiz) { tqslTrace("tqsl_getCertificateRequestState", NULL); if (tqsl_check_crq_field(cert, buf, bufsiz)) { tqslTrace("tqsl_getCertificateRequestState", "check fail"); return 1; } strncpy(buf, (TQSL_API_TO_CERT(cert)->crq)->state, bufsiz); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestPostalCode(tQSL_Cert cert, char *buf, int bufsiz) { tqslTrace("tqsl_getCertificateRequestPostalCode", NULL); if (tqsl_check_crq_field(cert, buf, bufsiz)) { tqslTrace("tqsl_getCertificateRequestPostalCode", "check fail"); return 1; } strncpy(buf, (TQSL_API_TO_CERT(cert)->crq)->postalCode, bufsiz); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCountry(tQSL_Cert cert, char *buf, int bufsiz) { tqslTrace("tqsl_getCertificateRequestCountry", NULL); if (tqsl_check_crq_field(cert, buf, bufsiz)) { tqslTrace("tqsl_getCertificateRequestCountry", "check fail"); return 1; } strncpy(buf, (TQSL_API_TO_CERT(cert)->crq)->country, bufsiz); return 0; } static int tqsl_add_bag_attribute(PKCS12_SAFEBAG *bag, const char *oidname, const string& value) { int nid; nid = OBJ_txt2nid(const_cast(oidname)); if (nid == NID_undef) { tqslTrace("tqsl_add_bag_attribute", "OBJ_txt2nid err %s", tqsl_openssl_error()); return 1; } unsigned char *uni; int unilen; if (asc2uni(value.c_str(), value.length(), &uni, &unilen)) { ASN1_TYPE *val; X509_ATTRIBUTE *attrib; if (!uni[unilen - 1] && !uni[unilen - 2]) unilen -= 2; if ((val = ASN1_TYPE_new()) != 0) { ASN1_TYPE_set(val, V_ASN1_BMPSTRING, uni); if ((attrib = X509_ATTRIBUTE_new()) != 0) { X509_ATTRIBUTE_set1_object(attrib, OBJ_nid2obj(nid)); if ((X509_ATTRIBUTE_set1_data(attrib, V_ASN1_BMPSTRING, uni, unilen)) != 0) { #if (OPENSSL_VERSION_NUMBER & 0xfffff000) == 0x00906000 attrib->set = 1; #else #if OPENSSL_VERSION_NUMBER < 0x10100000L #if (OPENSSL_VERSION_NUMBER & 0xfffff000) >= 0x00907000 attrib->single = 0; #else #error "Unexpected OpenSSL version; check X509_ATTRIBUTE struct compatibility" #endif #endif #endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) STACK_OF(X509_ATTRIBUTE) *sk; sk = (STACK_OF(X509_ATTRIBUTE)*)PKCS12_SAFEBAG_get0_attrs(bag); if (sk) { sk_X509_ATTRIBUTE_push(sk, attrib); #else if (bag->attrib) { sk_X509_ATTRIBUTE_push(bag->attrib, attrib); #endif //cerr << "Added " << oidname << endl; } else { tqslTrace("tqsl_add_bag_attribute", "no attrib"); return 1; } } else { tqslTrace("tqsl_add_bag_attribute", "no value set"); return 1; } } else { tqslTrace("tqsl_add_bag_attribute", "attrib create err %s", tqsl_openssl_error()); return 1; } } else { tqslTrace("tqsl_add_bag_attribute", "bmp->data empty"); return 1; } } else { // asc2uni ok tqslTrace("tqsl_add_bag_attribute", "asc2uni err %s", tqsl_openssl_error()); return 1; } return 0; } static int tqsl_exportPKCS12(tQSL_Cert cert, bool returnB64, const char *filename, char *base64, int b64len, const char *p12password, bool weakCrypto) { STACK_OF(X509) *root_sk = 0, *ca_sk = 0, *chain = 0; const char *cp; char rootpath[TQSL_MAX_PATH_LEN], capath[TQSL_MAX_PATH_LEN]; char buf[256]; unsigned char keyid[EVP_MAX_MD_SIZE]; unsigned int keyidlen = 0; STACK_OF(PKCS12_SAFEBAG) *bags = 0; PKCS12_SAFEBAG *bag = 0; STACK_OF(PKCS7) *safes = 0; PKCS7 *authsafe = 0; int cert_pbe = NID_aes_256_cbc; int key_pbe = NID_aes_256_cbc; PKCS8_PRIV_KEY_INFO *p8 = 0; PKCS12 *p12 = 0; const EVP_MD *md = 0; BIO *out = 0, *b64 = 0; string callSign, issuerOrganization, issuerOrganizationalUnit; tQSL_Date date; string QSONotBeforeDate, QSONotAfterDate, dxccEntity, Email, Address1, Address2, City, State, Postal, Country; int dxcc = 0; int rval = 1; tqslTrace("tqsl_exportPKCS12", NULL); if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_exportPKCS12", "arg error cert=0x%lx", cert); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if ((returnB64 && base64 == NULL) || (!returnB64 && filename == NULL)) { tqslTrace("tqsl_exportPKCS12", "arg error returnB64=%d base64=0x%lx filename=0x%lx", returnB64, base64, filename); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tqslTrace("tqsl_exportPKCS12", "weak crypto flag %d", weakCrypto); // For compatibility with Apple Keychain for Mac // They don't support anything but deprecated P12 crypto // SHA1, 3DES, RC2. if (weakCrypto) { cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; md = reinterpret_cast (EVP_get_digestbyname("sha1")); } /* Get parameters for key bag attributes */ if (tqsl_getCertificateCallSign(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get callsign err %d", tQSL_Error); return 1; } callSign = buf; if (tqsl_getCertificateIssuerOrganization(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get org err %d", tQSL_Error); return 1; } issuerOrganization = buf; if (tqsl_getCertificateIssuerOrganizationalUnit(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get ou err %d", tQSL_Error); return 1; } issuerOrganizationalUnit = buf; if (!TQSL_API_TO_CERT(cert)->keyonly) { if (tqsl_getCertificateEmailAddress(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get email err %d", tQSL_Error); return 1; } Email = buf; if (tqsl_getCertificateRequestAddress1(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get addr1 err %d", tQSL_Error); return 1; } Address1 = buf; if (tqsl_getCertificateRequestAddress2(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get addr2 err %d", tQSL_Error); return 1; } Address2 = buf; if (tqsl_getCertificateRequestCity(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get city err %d", tQSL_Error); return 1; } City = buf; if (tqsl_getCertificateRequestState(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get state err %d", tQSL_Error); return 1; } State = buf; if (tqsl_getCertificateRequestPostalCode(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get postal err %d", tQSL_Error); return 1; } Postal = buf; if (tqsl_getCertificateRequestCountry(cert, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "get country err %d", tQSL_Error); return 1; } Country = buf; } if (tqsl_getCertificateQSONotBeforeDate(cert, &date)) { tqslTrace("tqsl_exportPKCS12", "get qso not before err %d", tQSL_Error); return 1; } if (!tqsl_convertDateToText(&date, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "qso not before err %d", tQSL_Error); return 1; } QSONotBeforeDate = buf; if (tqsl_getCertificateQSONotAfterDate(cert, &date)) { tqslTrace("tqsl_exportPKCS12", "get qso not after err %d", tQSL_Error); return 1; } if (!tqsl_isDateNull(&date)) { if (!tqsl_convertDateToText(&date, buf, sizeof buf)) { tqslTrace("tqsl_exportPKCS12", "qso not before err %d", tQSL_Error); return 1; } QSONotAfterDate = buf; } if (tqsl_getCertificateDXCCEntity(cert, &dxcc)) { tqslTrace("tqsl_exportPKCS12", "get entity err %d", tQSL_Error); return 1; } snprintf(buf, sizeof buf, "%d", dxcc); dxccEntity = buf; if (TQSL_API_TO_CERT(cert)->key == NULL) { tqslTrace("tqsl_exportPKCS12", "key is null"); tQSL_Error = TQSL_SIGNINIT_ERROR; return 1; } if (!TQSL_API_TO_CERT(cert)->keyonly) { tqslTrace("tqsl_exportPKCS12", "keyonly cert"); /* Generate local key ID to tie key to cert */ X509_digest(TQSL_API_TO_CERT(cert)->cert, EVP_sha1(), keyid, &keyidlen); /* Check the chain of authority back to a trusted root */ tqsl_make_cert_path("root", rootpath, sizeof rootpath); if ((root_sk = tqsl_ssl_load_certs_from_file(rootpath)) == NULL) { if (!tqsl_ssl_error_is_nofile()) { tqslTrace("tqsl_exportPKCS12", "can't find certs"); goto p12_end; } } tqsl_make_cert_path("authorities", capath, sizeof capath); if ((ca_sk = tqsl_ssl_load_certs_from_file(capath)) == NULL) { if (!tqsl_ssl_error_is_nofile()) { tqslTrace("tqsl_exportPKCS12", "can't find certs"); goto p12_end; } } /* tqsl_ssl_verify_cert will collect the certificates in the chain, back to the * root certificate, verify them and return a stack containing copies of just * those certificates (including the user certificate). */ cp = tqsl_ssl_verify_cert(TQSL_API_TO_CERT(cert)->cert, ca_sk, root_sk, 0, &tqsl_expired_is_ok, &chain); if (cp) { if (chain) sk_X509_free(chain); tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError); tqslTrace("tqsl_exportPKCS12", "verify fail: %s", cp); return 1; } } // !keyonly tQSL_Error = TQSL_OPENSSL_ERROR; // Assume error /* Open the output file */ if (!returnB64) { out = BIO_new_file(filename, "wb"); } else { b64 = BIO_new(BIO_f_base64()); out = BIO_new(BIO_s_mem()); out = BIO_push(b64, out); } if (!out) { tqslTrace("tqsl_exportPKCS12", "BIO_new err %s", tqsl_openssl_error()); goto p12_end; } safes = sk_PKCS7_new_null(); if (!TQSL_API_TO_CERT(cert)->keyonly) { /* Create a safebag stack and fill it with the needed certs */ bags = sk_PKCS12_SAFEBAG_new_null(); for (int i = 0; i < sk_X509_num(chain); i++) { X509 *x = sk_X509_value(chain, i); #if (OPENSSL_VERSION_NUMBER & 0xfffff000) == 0x00906000 bag = PKCS12_pack_safebag(reinterpret_cast(x), (int (*)())i2d_X509, NID_x509Certificate, NID_certBag); #else bag = PKCS12_x5092certbag(x); #endif if (!bag) { tqslTrace("tqsl_exportPKCS12", "Error creating bag: %s", tqsl_openssl_error()); goto p12_end; } if (x == TQSL_API_TO_CERT(cert)->cert) { PKCS12_add_friendlyname(bag, "TrustedQSL user certificate", -1); PKCS12_add_localkeyid(bag, keyid, keyidlen); } sk_PKCS12_SAFEBAG_push(bags, bag); } /* Convert stack of safebags into an authsafe */ unsigned char p12salt[9]; memcpy(p12salt, "lamesalt", 8); authsafe = PKCS12_pack_p7encdata(cert_pbe, p12password, -1, p12salt, 8, PKCS12_DEFAULT_ITER, bags); if (!authsafe) { tqslTrace("tqsl_exportPKCS12", "Error creating authsafe: %s", tqsl_openssl_error()); goto p12_end; } sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); bags = 0; /* Add to stack of authsafes */ sk_PKCS7_push(safes, authsafe); } // !keyonly /* Make a shrouded key bag */ p8 = EVP_PKEY2PKCS8(TQSL_API_TO_CERT(cert)->key); if (!p8) { tqslTrace("tqsl_exportPKCS12", "Error creating p8 container: %s", tqsl_openssl_error()); goto p12_end; } bag = PKCS12_MAKE_SHKEYBAG(key_pbe, p12password, -1, 0, 0, PKCS12_DEFAULT_ITER, p8); if (!bag) { tqslTrace("tqsl_exportPKCS12", "Error creating p8 keybag: %s", tqsl_openssl_error()); goto p12_end; } PKCS8_PRIV_KEY_INFO_free(p8); p8 = NULL; PKCS12_add_friendlyname(bag, "TrustedQSL user certificate", -1); if (!TQSL_API_TO_CERT(cert)->keyonly) PKCS12_add_localkeyid(bag, keyid, keyidlen); /* Add the attributes to the private key bag */ tqsl_add_bag_attribute(bag, "AROcallsign", callSign); tqsl_add_bag_attribute(bag, "QSONotBeforeDate", QSONotBeforeDate); if (QSONotAfterDate != "") tqsl_add_bag_attribute(bag, "QSONotAfterDate", QSONotAfterDate); tqsl_add_bag_attribute(bag, "tqslCRQIssuerOrganization", issuerOrganization); tqsl_add_bag_attribute(bag, "tqslCRQIssuerOrganizationalUnit", issuerOrganizationalUnit); tqsl_add_bag_attribute(bag, "dxccEntity", dxccEntity); tqsl_add_bag_attribute(bag, "tqslCRQEmail", Email); tqsl_add_bag_attribute(bag, "tqslCRQAddress1", Address1); tqsl_add_bag_attribute(bag, "tqslCRQAddress2", Address2); tqsl_add_bag_attribute(bag, "tqslCRQCity", City); tqsl_add_bag_attribute(bag, "tqslCRQState", State); tqsl_add_bag_attribute(bag, "tqslCRQPostal", Postal); tqsl_add_bag_attribute(bag, "tqslCRQCountry", Country); bags = sk_PKCS12_SAFEBAG_new_null(); if (!bags) { tqslTrace("tqsl_exportPKCS12", "Error creating safebag: %s", tqsl_openssl_error()); goto p12_end; } sk_PKCS12_SAFEBAG_push(bags, bag); /* Turn shrouded key bag into unencrypted safe bag and add to safes stack */ authsafe = PKCS12_pack_p7data(bags); sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); bags = NULL; sk_PKCS7_push(safes, authsafe); /* Form into PKCS12 data */ p12 = PKCS12_init(NID_pkcs7_data); M_PKCS12_pack_authsafes(p12, safes); sk_PKCS7_pop_free(safes, PKCS7_free); safes = NULL; PKCS12_set_mac(p12, p12password, -1, 0, 0, PKCS12_DEFAULT_ITER, md); /* Write the PKCS12 data */ i2d_PKCS12_bio(out, p12); if (BIO_flush(out) != 1) { rval = 1; tqslTrace("tqsl_exportPKCS12", "Error writing pkcs12: %s", tqsl_openssl_error()); goto p12_end; } if (returnB64) { char *encoded; int len; len = BIO_get_mem_data(out, &encoded); encoded[len - 1] = '\0'; strncpy(base64, encoded, b64len); } rval = 0; tQSL_Error = TQSL_NO_ERROR; p12_end: if (out) { BIO_free(out); if (rval && !returnB64) { #ifdef _WIN32 wchar_t* wfilename = utf8_to_wchar(filename); _wunlink(wfilename); free_wchar(wfilename); #else unlink(filename); #endif } } if (chain) sk_X509_free(chain); if (root_sk) sk_X509_free(root_sk); if (ca_sk) sk_X509_free(ca_sk); if (bags) sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); if (safes) sk_PKCS7_pop_free(safes, PKCS7_free); if (p8) PKCS8_PRIV_KEY_INFO_free(p8); return rval; } DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File(tQSL_Cert cert, const char *filename, const char *p12password) { tqslTrace("tqsl_exportPKCS12File", NULL); return tqsl_exportPKCS12(cert, false, filename, NULL, 0, p12password, false); } DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto(tQSL_Cert cert, const char *filename, const char *p12password) { tqslTrace("tqsl_exportPKCS12File", NULL); return tqsl_exportPKCS12(cert, false, filename, NULL, 0, p12password, true); } DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64(tQSL_Cert cert, char *base64, int b64len, const char *p12password) { tqslTrace("tqsl_exportPKCS12Base64", NULL); return tqsl_exportPKCS12(cert, true, NULL, base64, b64len, p12password, false); } static string tqsl_asn1_octet_string_to_hex(ASN1_OCTET_STRING *os) { string str; for (int k = 0; k < os->length; k++) { char hex[3] = " "; hex[0] = ((os->data[k] >> 4) & 0xf) + '0'; if (hex[0] > '9') hex[0] += 'A' - '9' - 1; hex[1] = (os->data[k] & 0xf) + '0'; if (hex[1] > '9') hex[1] += 'A' - '9' - 1; if (str.size()) str += " "; str += hex; } return str; } struct tqsl_imported_cert { string pem; string keyid; string callsign; }; static int tqsl_get_bag_attribute(PKCS12_SAFEBAG *bag, const char *oidname, string& str) { const ASN1_TYPE *attr; str = ""; if ((attr = PKCS12_get_attr(bag, OBJ_txt2nid(const_cast(oidname)))) != 0) { if (attr->type != V_ASN1_BMPSTRING) { tQSL_Error = TQSL_CERT_TYPE_ERROR; tqslTrace("tqsl_get_bag_attribute", "cert type error oid %s", oidname); return 1; } char *c = uni2asc(attr->value.bmpstring->data, attr->value.bmpstring->length); str = c; OPENSSL_free(c); } return 0; } static int tqsl_importPKCS12(bool importB64, const char *filename, const char *base64, const char *p12password, const char *password, int (*pwcb)(char *, int, void *), int(*cb)(int, const char *, void *), void *userdata) { PKCS12 *p12 = 0; PKCS12_SAFEBAG *bag; PKCS8_PRIV_KEY_INFO *p8 = 0; EVP_PKEY *pkey = 0; BIO *in = 0, *bio = 0 , *b64 = 0; STACK_OF(PKCS7) *safes = 0; STACK_OF(PKCS12_SAFEBAG) *bags = 0; PKCS7 *p7; X509 *x; BASIC_CONSTRAINTS *bs = 0; ASN1_OBJECT *callobj = 0, *obj = 0; const ASN1_TYPE *attr = 0; const EVP_CIPHER *cipher; unsigned char *cp; int i, j, bagnid, len; vector rootcerts; vector cacerts; vector usercerts; vector *certlist; vector::iterator it; bool is_cacert; string public_key, private_key, private_keyid, key_callsign, str; map key_attr; map newrecord; map::iterator mit; char path[TQSL_MAX_PATH_LEN], pw[256]; int rval = 1; tqslTrace("tqsl_importPKCS12", NULL); if (tqsl_init()) return 1; if ((!importB64 && filename == NULL) || (importB64 && base64 == NULL)) { tqslTrace("tqsl_importPKCS12", "arg error importB64=%d filename=0x%lx base64=0x%lx", importB64, filename, base64); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tQSL_ImportCall[0] = '\0'; tQSL_ImportSerial = 0; ImportCall[0] = '\0'; tQSL_Error = TQSL_OPENSSL_ERROR; /* Read in the PKCS#12 file */ if (importB64) { b64 = BIO_new(BIO_f_base64()); in = BIO_new_mem_buf(const_cast(base64), strlen(base64)); in = BIO_push(b64, in); } else { in = BIO_new_file(filename, "rb"); } if (in == 0) { tqslTrace("tqsl_importPKCS12", "Couldn't create bio: %s", tqsl_openssl_error()); goto imp_end; } if ((p12 = d2i_PKCS12_bio(in, 0)) == 0) { tqslTrace("tqsl_importPKCS12", "Couldn't read pkcs12: %s", tqsl_openssl_error()); goto imp_end; } BIO_free(in); in = 0; /* Verify MAC */ if (!PKCS12_verify_mac(p12, p12password, -1)) { tqslTrace("tqsl_importPKCS12", "Mac doesn't verify"); tQSL_Error = TQSL_PASSWORD_ERROR; goto imp_end; } /* Loop through the authsafes */ if ((safes = M_PKCS12_unpack_authsafes(p12)) == 0) { tqslTrace("tqsl_importPKCS12", "Can't unpack authsafe: %s", tqsl_openssl_error()); goto imp_end; } callobj = OBJ_txt2obj("AROcallsign", 0); for (i = 0; i < sk_PKCS7_num(safes); i++) { tqsl_imported_cert imported_cert; p7 = sk_PKCS7_value(safes, i); bagnid = OBJ_obj2nid(p7->type); if (bagnid == NID_pkcs7_data) { bags = PKCS12_unpack_p7data(p7); } else if (bagnid == NID_pkcs7_encrypted) { bags = PKCS12_unpack_p7encdata(p7, p12password, strlen(p12password)); } else { continue; // Not something we understand } if (!bags) { tQSL_Error = TQSL_PKCS12_ERROR; tqslTrace("tqsl_importPKCS12", "bags empty: %s", tqsl_openssl_error()); goto imp_end; } /* Loop through safebags */ for (j = 0; j < sk_PKCS12_SAFEBAG_num(bags); j++) { tqsl_imported_cert imported_cert; bag = sk_PKCS12_SAFEBAG_value(bags, j); switch (M_PKCS12_bag_type(bag)) { case NID_certBag: if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) break; // Can't handle anything else if ((x = M_PKCS12_certbag2x509(bag)) == 0) { tqslTrace("tqsl_importPKCS12", "bag2x509: %s", tqsl_openssl_error()); goto imp_end; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_importPKCS12", "bio_new: %s", tqsl_openssl_error()); goto imp_end; } if (!PEM_write_bio_X509(bio, x)) { tqslTrace("tqsl_importPKCS12", "write_bio: %s", tqsl_openssl_error()); goto imp_end; } len = static_cast(BIO_get_mem_data(bio, &cp)); imported_cert.pem = string((const char *)cp, len); if ((attr = PKCS12_get_attr(bag, NID_localKeyID)) != 0) { if (attr->type != V_ASN1_OCTET_STRING) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch"); tQSL_Error = TQSL_CERT_TYPE_ERROR; goto imp_end; } imported_cert.keyid = tqsl_asn1_octet_string_to_hex(attr->value.octet_string); } BIO_free(bio); bio = 0; is_cacert = false; if ((bs = reinterpret_cast(X509_get_ext_d2i(x, NID_basic_constraints, 0, 0))) != 0) { if (bs->ca) is_cacert = true; BASIC_CONSTRAINTS_free(bs); bs = 0; } certlist = &usercerts; if (is_cacert) { if (X509_check_issued(x, x) == X509_V_OK) // Self signed must be trusted certlist = &rootcerts; else certlist = &cacerts; } else { /* Make sure the cert is TQSL compatible */ TQSL_X509_NAME_ITEM item; char nbuf[40]; char callbuf[256]; item.name_buf = nbuf; item.name_buf_size = sizeof nbuf; item.value_buf = callbuf; item.value_buf_size = sizeof callbuf; if (!tqsl_cert_get_subject_name_entry(x, "AROcallsign", &item)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch"); tQSL_Error = TQSL_CERT_TYPE_ERROR; goto imp_end; } imported_cert.callsign = callbuf; } (*certlist).push_back(imported_cert); break; case NID_pkcs8ShroudedKeyBag: if ((attr = PKCS12_get_attr(bag, NID_localKeyID)) != 0) { if (attr->type != V_ASN1_OCTET_STRING) { tQSL_Error = TQSL_CERT_TYPE_ERROR; tqslTrace("tqsl_importPKCS12", "Cert type mismatch"); goto imp_end; } private_keyid = tqsl_asn1_octet_string_to_hex(attr->value.octet_string); } if (tqsl_get_bag_attribute(bag, "AROcallsign", key_callsign)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no callsign"); goto imp_end; } if (tqsl_get_bag_attribute(bag, "dxccEntity", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no dxcc"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_DXCC_ENTITY"] = str; if (tqsl_get_bag_attribute(bag, "QSONotBeforeDate", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no qsonotbefore"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_QSO_NOT_BEFORE"] = str; if (tqsl_get_bag_attribute(bag, "QSONotAfterDate", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no qsonotafter"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_QSO_NOT_AFTER"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQIssuerOrganization", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no org"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_PROVIDER"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQIssuerOrganizationalUnit", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no ou"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_PROVIDER_UNIT"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQEmail", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no email"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_EMAIL"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQAddress1", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no addr1"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_ADDRESS1"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQAddress2", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no addr2"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_ADDRESS2"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQCity", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no city"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_CITY"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQState", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no state"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_STATE"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQPostal", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no postal"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_POSTAL"] = str; if (tqsl_get_bag_attribute(bag, "tqslCRQCountry", str)) { tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no country"); goto imp_end; } if (str != "") key_attr["TQSL_CRQ_COUNTRY"] = str; if ((p8 = M_PKCS12_decrypt_skey(bag, p12password, strlen(p12password))) == 0) { tqslTrace("tqsl_importPKCS12", "password error"); goto imp_end; } if ((pkey = EVP_PKCS82PKEY(p8)) == 0) { tqslTrace("tqsl_importPKCS12", "pkey error"); goto imp_end; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_importPKCS12", "bio_new error %s", tqsl_openssl_error()); goto imp_end; } if (password == 0) { if (pwcb) { if ((*pwcb)(pw, sizeof pw -1, userdata)) { tqslTrace("tqsl_importPKCS12", "operator aborted at password prompt"); tQSL_Error = TQSL_OPERATOR_ABORT; goto imp_end; } password = pw; } else { password = NULL; } } if (password && *password != '\0') { cipher = EVP_des_ede3_cbc(); len = strlen(password); } else { cipher = 0; len = 0; } if (!PEM_write_bio_PrivateKey(bio, pkey, cipher, (unsigned char *)password, len, 0, 0)) { tqslTrace("tqsl_importPKCS12", "writing bio err: %s", tqsl_openssl_error()); goto imp_end; } len = static_cast(BIO_get_mem_data(bio, &cp)); private_key = string((const char *)cp, len); BIO_free(bio); if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_importPKCS12", "new bio err: %s", tqsl_openssl_error()); goto imp_end; } if (!PEM_write_bio_PUBKEY(bio, pkey)) { tqslTrace("tqsl_importPKCS12", "write pubkey bio err: %s", tqsl_openssl_error()); goto imp_end; } len = static_cast(BIO_get_mem_data(bio, &cp)); public_key = string((const char *)cp, len); BIO_free(bio); bio = 0; EVP_PKEY_free(pkey); pkey = 0; PKCS8_PRIV_KEY_INFO_free(p8); p8 = 0; break; case NID_keyBag: tqslTrace("tqsl_importPKCS12", "cert type err: NID_keyBag"); tQSL_Error = TQSL_CERT_TYPE_ERROR; goto imp_end; } // bag type switch } // safebags loop sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); bags = 0; } sk_PKCS7_pop_free(safes, PKCS7_free); safes = 0; /* Now we have the certificates and key pair, so add them to the local store */ tqslTrace("tqsl_importPKCS12", "have keys"); if (key_callsign == "") { /* Need to get call sign from cert. The tQSL_exportKeys function puts the * call sign in a safebag attribute that should have been read already, * but if some other software created the PKCS#12 file that may not have * happened. There should, however, be a localKeyID attribute that matches * the key to the certificate. If not, it's an error. */ if (private_keyid == "") { // No key ID, can't find cert tqslTrace("tqsl_importPKCS12", "no callsign attribute"); tQSL_Error = TQSL_CERT_TYPE_ERROR; goto imp_end; } for (it = usercerts.begin(); it != usercerts.end(); it++) { if ((*it).keyid == private_keyid) { key_callsign = (*it).callsign; break; } } if (key_callsign == "") { // Can't find cert or callsign tqslTrace("tqsl_importPKCS12", "can't find cert or callsign"); tQSL_Error = TQSL_CERT_TYPE_ERROR; goto imp_end; } } if (!tqsl_make_key_path(key_callsign.c_str(), path, sizeof path)) { tqslTrace("tqsl_importPKCS12", "keypath error %d", tQSL_Error); goto imp_end; } newrecord["PUBLIC_KEY"] = public_key; newrecord["PRIVATE_KEY"] = private_key; newrecord["CALLSIGN"] = key_callsign; for (mit = key_attr.begin(); mit != key_attr.end(); mit++) newrecord[mit->first] = mit->second; if (tqsl_replace_key(key_callsign.c_str(), path, newrecord, cb, userdata)) { tqslTrace("tqsl_importPKCS12", "replace key error %d", tQSL_Error); goto imp_end; } for (it = rootcerts.begin(); it != rootcerts.end(); it++) { if (tqsl_import_cert(it->pem.c_str(), tqsllib::ROOTCERT, cb, userdata) && tQSL_Error != TQSL_CERT_ERROR) { tqslTrace("tqsl_importPKCS12", "import root cert error %d", tQSL_Error); goto imp_end; } } for (it = cacerts.begin(); it != cacerts.end(); it++) { if (tqsl_import_cert(it->pem.c_str(), tqsllib::CACERT, cb, userdata) && tQSL_Error != TQSL_CERT_ERROR) { tqslTrace("tqsl_importPKCS12", "import ca cert error %d", tQSL_Error); goto imp_end; } } rval = 0; // Assume no errors for (it = usercerts.begin(); it != usercerts.end(); it++) { if (tqsl_import_cert(it->pem.c_str(), tqsllib::USERCERT, cb, userdata)) { if (tQSL_Error == TQSL_CERT_ERROR) { rval = 1; // Remember failure to import continue; } char savepath[TQSL_MAX_PATH_LEN], badpath[TQSL_MAX_PATH_LEN]; strncpy(badpath, path, sizeof(badpath)); strncat(badpath, ".bad", sizeof(badpath)-strlen(badpath)-1); badpath[sizeof(badpath)-1] = '\0'; #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); wchar_t* wbadpath = utf8_to_wchar(badpath); wchar_t* wsavepath = NULL; if (!_wrename(wpath, wbadpath)) { #else if (!rename(path, badpath)) { #endif strncpy(savepath, path, sizeof(savepath)); strncat(savepath, ".save", sizeof(savepath)-strlen(savepath)-1); savepath[sizeof(savepath)-1] = '\0'; #ifdef _WIN32 wsavepath = utf8_to_wchar(savepath); if (_wrename(wsavepath, wpath)) // didn't work _wrename(wbadpath, wpath); #else if (rename(savepath, path)) // didn't work rename(badpath, path); #endif else #ifdef _WIN32 { _wunlink(wbadpath); free_wchar(wpath); free_wchar(wbadpath); if (wsavepath) free_wchar(wsavepath); } #else unlink(badpath); #endif } goto imp_end; } } if (rval == 0) { tQSL_Error = TQSL_NO_ERROR; strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall); } else { if (tQSL_Error == 0) { tQSL_Error = TQSL_CERT_ERROR; } } imp_end: if (p12) PKCS12_free(p12); if (in) BIO_free(in); if (bags) sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); if (safes) sk_PKCS7_pop_free(safes, PKCS7_free); if (obj) ASN1_OBJECT_free(obj); if (callobj) ASN1_OBJECT_free(callobj); if (bs) BASIC_CONSTRAINTS_free(bs); if (p8) PKCS8_PRIV_KEY_INFO_free(p8); if (pkey) EVP_PKEY_free(pkey); return rval; } DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File(const char *filename, const char *p12password, const char *password, int (*pwcb)(char *, int, void *), int(*cb)(int, const char *, void *), void *userdata) { tqslTrace("tqsl_importPKCS12File", NULL); return tqsl_importPKCS12(false, filename, NULL, p12password, password, pwcb, cb, userdata); } DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64(const char *base64, const char *p12password, const char *password, int (*pwcb)(char *, int, void *), int(*cb)(int, const char *, void *), void *userdata) { tqslTrace("tqsl_importPKCS12Base64", NULL); return tqsl_importPKCS12(true, NULL, base64, p12password, password, pwcb, cb, userdata); } static int tqsl_backup_cert(tQSL_Cert cert) { char callsign[64]; long serial = 0; int dxcc = 0; int keyonly; tqsl_getCertificateKeyOnly(cert, &keyonly); tqsl_getCertificateCallSign(cert, callsign, sizeof callsign); if (!keyonly) tqsl_getCertificateSerial(cert, &serial); tqsl_getCertificateDXCCEntity(cert, &dxcc); char backupPath[TQSL_MAX_PATH_LEN]; tqsl_make_backup_path(callsign, backupPath, sizeof backupPath); FILE* out = NULL; #ifdef _WIN31 wchar_t* wpath = utf8_to_wchar(backupPath); _wunlink(wpath); fd = _wfopen(lfn, L"wb"); free_wchar(wpath); #else unlink(backupPath); out = fopen(backupPath, "wb"); #endif if (!out) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; strncpy(tQSL_ErrorFile, backupPath, sizeof tQSL_ErrorFile); tQSL_ErrorFile[sizeof tQSL_ErrorFile-1] = 0; tqslTrace("tqsl_backup_cert", "Error %d errno %d file %s", tQSL_Error, tQSL_Errno, backupPath); return 1; } char buf[8192]; fprintf(out, "\n", callsign, dxcc, serial); if (!keyonly) { fprintf(out, "\n"); tqsl_getCertificateEncoded(cert, buf, sizeof buf); fprintf(out, "%s", buf); fprintf(out, "\n"); } fprintf(out, "\n"); tqsl_getKeyEncoded(cert, buf, sizeof buf); fprintf(out, "%s", buf); fprintf(out, "\n\n"); fclose(out); return 0; } static int tqsl_make_backup_list(const char* filter, vector& keys) { keys.clear(); string path = tQSL_BaseDir; #ifdef _WIN32 path += "\\certtrash"; wchar_t* wpath = utf8_to_wchar(path.c_str()); MKDIR(wpath, 0700); #else path += "/certtrash"; MKDIR(path.c_str(), 0700); #endif #ifdef _WIN32 WDIR *dir = wopendir(wpath); free_wchar(wpath); #else DIR *dir = opendir(path.c_str()); #endif if (dir == NULL) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_make_backup_list", "Opendir %s error %s", path.c_str(), strerror(errno)); return 1; } #ifdef _WIN32 struct wdirent *ent; #else struct dirent *ent; #endif int rval = 0; int savedError = 0; int savedErrno = 0; char *savedFile = NULL; #ifdef _WIN32 while ((ent = wreaddir(dir)) != NULL) { if (ent->d_name[0] == '.') continue; char dname[TQSL_MAX_PATH_LEN]; wcstombs(dname, ent->d_name, TQSL_MAX_PATH_LEN); string filename = path + "\\" + dname; struct _stat32 s; wchar_t* wfilename = utf8_to_wchar(filename.c_str()); if (_wstat32(wfilename, &s) == 0) { if (S_ISDIR(s.st_mode)) { free_wchar(wfilename); continue; // If it's a directory, skip it. } } free_wchar(wfilename); #else while ((ent = readdir(dir)) != NULL) { if (ent->d_name[0] == '.') continue; string filename = path + "/" + ent->d_name; struct stat s; if (stat(filename.c_str(), &s) == 0) { if (S_ISDIR(s.st_mode)) continue; // If it's a directory, skip it. } #endif XMLElement *xel = new XMLElement; if (!xel) { tqslTrace("tqsl_make_backup_list", "Out of memory!"); return 1; } int status = xel->parseFile(filename.c_str()); if (status) continue; // Can't be parsed XMLElement cert; xel->getFirstElement(cert); pair atrval = cert.getAttribute("CallSign"); if (atrval.second) { // If the callsign matches, or if the filter is empty, add it. if (filter == NULL || atrval.first == filter) { keys.push_back(atrval.first); } } delete xel; } #ifdef _WIN32 _wclosedir(dir); #else closedir(dir); #endif if (rval) { tQSL_Error = savedError; tQSL_Errno = savedErrno; if (savedFile) { strncpy(tQSL_ErrorFile, savedFile, sizeof tQSL_ErrorFile); free(savedFile); } tqslTrace("tqsl_make_backup_list", "error %s %s", tQSL_ErrorFile, strerror(tQSL_Errno)); } return rval; } DLLEXPORT int CALLCONVENTION tqsl_deleteCertificate(tQSL_Cert cert) { tqslTrace("tqsl_deleteCertificate", NULL); if (tqsl_init()) return 1; if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) { tqslTrace("tqsl_deleteCertificate", "arg err cert=0x%lx", cert); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tqsl_backup_cert(cert); char callsign[256], path[TQSL_MAX_PATH_LEN], newpath[TQSL_MAX_PATH_LEN]; if (tqsl_getCertificateCallSign(cert, callsign, sizeof callsign)) { tqslTrace("tqsl_deleteCertificate", "no callsign %d", tQSL_Error); return 1; } int rval = 1; EVP_PKEY *key = 0; BIO *bio = 0; tQSL_Error = TQSL_OPENSSL_ERROR; // Delete private key map rec; if (TQSL_API_TO_CERT(cert)->pubkey) { rec["PUBLIC_KEY"] = TQSL_API_TO_CERT(cert)->pubkey; } else { // Get public key from cert if ((key = X509_get_pubkey(TQSL_API_TO_CERT(cert)->cert)) == 0) { tqslTrace("tqsl_deleteCertificate", "no public key %s", tqsl_openssl_error()); goto dc_end; } if ((bio = BIO_new(BIO_s_mem())) == NULL) { tqslTrace("tqsl_deleteCertificate", "bio err %s", tqsl_openssl_error()); goto dc_end; } if (!PEM_write_bio_PUBKEY(bio, key)) { tqslTrace("tqsl_deleteCertificate", "bio write err %s", tqsl_openssl_error()); goto dc_end; } char *cp; int len = static_cast(BIO_get_mem_data(bio, &cp)); rec["PUBLIC_KEY"] = string(cp, len); BIO_free(bio); bio = 0; EVP_PKEY_free(key); key = 0; } rec["CALLSIGN"] = callsign; if (!tqsl_make_key_path(callsign, path, sizeof path)) { tqslTrace("tqsl_deleteCertificate", "key path err %s", tQSL_Error); goto dc_end; } // Since there is no private key in "rec," tqsl_replace_key will just remove the // existing private key. tqsl_replace_key(callsign, path, rec, 0, 0); if (TQSL_API_TO_CERT(cert)->keyonly) { tqslTrace("tqsl_deleteCertificate", "key only"); goto dc_ok; } // Now the certificate tqsl_make_cert_path("user", path, sizeof path); tqsl_make_cert_path("user.new", newpath, sizeof newpath); if (xcerts == NULL) { if ((xcerts = tqsl_ssl_load_certs_from_file(path)) == 0) { tqslTrace("tqsl_deleteCertificate", "error reading certs %d", tQSL_Error); goto dc_end; } } if ((bio = BIO_new_file(newpath, "wb")) == 0) { tqslTrace("tqsl_deleteCertificate", "bio_new_file %s", tqsl_openssl_error()); goto dc_end; } X509 *x; while ((x = sk_X509_shift(xcerts)) != 0) { if (X509_issuer_and_serial_cmp(x, TQSL_API_TO_CERT(cert)->cert)) { if (!PEM_write_bio_X509(bio, x)) { // No match -- keep this one tqslTrace("tqsl_deleteCertificate", "pem_write_bio %s", tqsl_openssl_error()); goto dc_end; } } } BIO_free(bio); bio = 0; // Looks like the new file is okay, commit it #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); if (_wunlink(wpath) && errno != ENOENT) { free_wchar(wpath); #else if (unlink(path) && errno != ENOENT) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_deleteCertificate", "unlink err %d", errno); goto dc_end; } #ifdef _WIN32 wchar_t* wnewpath = utf8_to_wchar(newpath); if (_wrename(wnewpath, wpath)) { free_wchar(wpath); free_wchar(wnewpath); #else if (rename(newpath, path)) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_deleteCertificate", "rename err %d", errno); goto dc_end; } #ifdef _WIN32 free_wchar(wpath); free_wchar(wnewpath); #endif dc_ok: rval = 0; tQSL_Error = TQSL_NO_ERROR; dc_end: if (xcerts) { sk_X509_free(xcerts); xcerts = NULL; } if (key) EVP_PKEY_free(key); if (bio) BIO_free(bio); return rval; } /** Get the list of restorable callsign certificates. */ DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates(char ***calls, int *ncall, const char *filter) { vector callsigns; if (tqsl_make_backup_list(filter, callsigns)) { return 1; } *ncall = callsigns.size(); if (*ncall == 0) { if (calls) { *calls = NULL; } return 0; } if (calls == NULL) { return 0; } *calls = reinterpret_cast(calloc(*ncall, sizeof(**calls))); vector::iterator it; char **p = *calls; for (it = callsigns.begin(); it != callsigns.end(); it++) { *p++ = strdup((*it).c_str()); } return 0; } DLLEXPORT void CALLCONVENTION tqsl_freeDeletedCertificateList(char **list, int nloc) { if (!list) return; for (int i = 0; i < nloc; i++) if (list[i]) free(list[i]); if (list) free(list); } /** Restore a deleted callsign certificate by callsign. */ DLLEXPORT int CALLCONVENTION tqsl_restoreCallsignCertificate(const char *callsign) { tqslTrace("tqsl_restoreCallsignCertificate", "callsign = %s", callsign); char backupPath[TQSL_MAX_PATH_LEN]; tqsl_make_backup_path(callsign, backupPath, sizeof backupPath); XMLElement xel; int status = xel.parseFile(backupPath); if (status) { if (errno == ENOENT) { // No file is OK tqslTrace("tqsl_restoreCallsignCertificate", "FNF"); return 0; } strncpy(tQSL_ErrorFile, backupPath, sizeof tQSL_ErrorFile); if (status == XML_PARSE_SYSTEM_ERROR) { tQSL_Error = TQSL_FILE_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_restoreCallsignCertificate", "open error %s: %s", backupPath, strerror(tQSL_Errno)); } else { tqslTrace("tqsl_restoreCallsignCertificate", "syntax error %s", backupPath); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; } return 1; } XMLElement cert; string call; int dxcc = 0; long serial = 0; string privateKey; string publicKey; XMLElementList& ellist = xel.getElementList(); XMLElementList::iterator ep; for (ep = ellist.find("UserCert"); ep != ellist.end(); ep++) { if (ep->first != "UserCert") break; pair rval = ep->second->getAttribute("CallSign"); if (rval.second) call = rval.first; rval = ep->second->getAttribute("serial"); if (rval.second) serial = strtol(rval.first.c_str(), NULL, 10); rval = ep->second->getAttribute("dxcc"); if (rval.second) dxcc = strtol(rval.first.c_str(), NULL, 10); XMLElement el; if (ep->second->getFirstElement("SignedCert", el)) { publicKey = el.getText(); } if (ep->second->getFirstElement("PrivateKey", el)) { privateKey = el.getText(); } } // See if this certificate exists tQSL_Cert *certlist; int ncerts; tqsl_selectCertificates(&certlist, &ncerts, call.c_str(), dxcc, 0, 0, TQSL_SELECT_CERT_EXPIRED|TQSL_SELECT_CERT_SUPERCEDED|TQSL_SELECT_CERT_WITHKEYS); for (int i = 0; i < ncerts; i++) { long s = 0; int keyonly = false; tqsl_getCertificateKeyOnly(certlist[i], &keyonly); if (keyonly) { if (serial != 0) { // A full cert for this was imported continue; } } if (tqsl_getCertificateSerial(certlist[i], &s)) { continue; } if (s == serial) { // Already imported tqsl_freeCertificateList(certlist, ncerts); tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "This callsign certificate is already active and cannot be restored.", sizeof tQSL_CustomError); tqslTrace("tqsl_restoreCallsignCertificate", "certificate already exists"); return 1; } } tqsl_freeCertificateList(certlist, ncerts); int stat = tqsl_importKeyPairEncoded(call.c_str(), "user", privateKey.c_str(), publicKey.c_str()); if (!stat) { // Remove the backup file #ifdef _WIN32 wchar_t* wbpath = utf8_to_wchar(backupPath); _wunlink(wbpath); free_wchar(wbpath); #else unlink(backupPath); #endif } xel.clear(); return stat; } /********** END OF PUBLIC API FUNCTIONS **********/ /* Utility functions to manage private data structures */ static int tqsl_check_crq_field(tQSL_Cert cert, char *buf, int bufsiz) { if (tqsl_init()) return 1; if (cert == NULL || buf == NULL || bufsiz < 0 || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) { tqslTrace("tqsl_check_crq_field", "arg err cert=0x%lx buf=0x%lx bufsiz=%d", cert, buf, bufsiz); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (TQSL_API_TO_CERT(cert)->crq == NULL) { if (tqsl_find_matching_key(TQSL_API_TO_CERT(cert)->cert, NULL, &(TQSL_API_TO_CERT(cert)->crq), "", NULL, NULL) && tQSL_Error != TQSL_PASSWORD_ERROR) { tqslTrace("tqsl_check_crq_field", "can't find matching key err %d", tQSL_Error); return 1; } } return 0; } static int tqsl_cert_check(tqsl_cert *p, bool needcert) { if (p != NULL && p->id == 0xCE && (!needcert || p->cert != NULL)) return 1; tQSL_Error = TQSL_ARGUMENT_ERROR; return 0; } static tqsl_cert * tqsl_cert_new() { tqsl_cert *p; p = reinterpret_cast(tqsl_calloc(1, sizeof(tqsl_cert))); if (p != NULL) p->id = 0xCE; return p; } static void tqsl_cert_free(tqsl_cert *p) { if (p == NULL || p->id != 0xCE) return; p->id = 0; if (p->cert != NULL) X509_free(p->cert); if (p->key != NULL) EVP_PKEY_free(p->key); if (p->crq != NULL) tqsl_free_cert_req(p->crq, 0); if (p->pubkey != NULL) delete[] p->pubkey; if (p->privkey != NULL) delete[] p->privkey; tqsl_free(p); } static TQSL_CERT_REQ * tqsl_free_cert_req(TQSL_CERT_REQ *req, int seterr) { if (req == NULL) return NULL; tqsl_free(req); if (seterr) tQSL_Error = seterr; return NULL; } static TQSL_CERT_REQ * tqsl_copy_cert_req(TQSL_CERT_REQ *userreq) { TQSL_CERT_REQ *req; if ((req = reinterpret_cast(tqsl_calloc(1, sizeof(TQSL_CERT_REQ)))) == NULL) { tqslTrace("tqsl_copy_cert_req", "ENOMEM"); errno = ENOMEM; return NULL; } *req = *userreq; return req; } static int tqsl_check_parm(const char *p, const char *parmName) { if (strlen(p) == 0) { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Missing parameter: %s", parmName); tqslTrace("tqsl_check_parm", "error %s", tQSL_CustomError); return 1; } return 0; } static char * tqsl_trim(char *buf) { char lastc; char *cp, *op; /* Trim white space off end of string */ cp = buf + strlen(buf); while (cp != buf) { cp--; if (!isspace(*cp)) break; *cp = 0; } /* Skip past leading whitespace */ for (cp = buf; isspace(*cp); cp++) {} /* Fold runs of white space into single space */ lastc = 0; op = buf; for (; *cp != '\0'; cp++) { if (isspace(*cp)) *cp = ' '; if (*cp != ' ' || lastc != ' ') *op++ = *cp; lastc = *cp; } *op = '\0'; return cp; } /* Filter a list (stack) of X509 certs based on call sign, QSO date and/or * issuer. * * Returns a new stack of matching certs without altering the original stack. * * Note that you don't have to supply any of the criteria. If you supply * none, you;ll just get back an exact copy of the stack. */ CLIENT_STATIC STACK_OF(X509) * tqsl_filter_cert_list(STACK_OF(X509) *sk, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flags) { set superceded_certs; char buf[256], name_buf[256]; TQSL_X509_NAME_ITEM item; X509 *x = NULL; STACK_OF(X509) *newsk; int i, ok, len; tQSL_Date qso_date; tqslTrace("tqsl_filter_cert_list", NULL); if (tqsl_init()) return NULL; if ((newsk = sk_X509_new_null()) == NULL) { tqslTrace("tqsl_filter_cert_list", "sk_X509_new_null err %s", tqsl_openssl_error()); return NULL; } tqsl_cert* cp = tqsl_cert_new(); /* Loop through the list of certs */ for (i = 0; i < sk_X509_num(sk); i++) { ok = 1; /* Certificate is selected unless some check says otherwise */ x = sk_X509_value(sk, i); cp->cert = x; /* Check for expired unless asked not to */ if (ok && !(flags & TQSL_SELECT_CERT_EXPIRED)) { int exp = false; if (!tqsl_isCertificateExpired(TQSL_OBJ_TO_API(cp), &exp)) { if (exp) { ok = 0; } } } /* Check for superceded unless asked not to */ if (ok && !(flags & TQSL_SELECT_CERT_SUPERCEDED)) { int sup = false; if (!tqsl_isCertificateSuperceded(TQSL_OBJ_TO_API(cp), &sup)) { if (sup) { ok = 0; } } } /* Compare issuer if asked to */ if (ok && issuer != NULL) { X509_NAME *iss; if ((iss = X509_get_issuer_name(x)) == NULL) ok = 0; if (ok) { item.name_buf = name_buf; item.name_buf_size = sizeof name_buf; item.value_buf = buf; item.value_buf_size = sizeof buf; tqsl_get_name_entry(iss, "organizationName", &item); ok = !strcmp(issuer->organizationName, item.value_buf); } if (ok) { item.name_buf = name_buf; item.name_buf_size = sizeof name_buf; item.value_buf = buf; item.value_buf_size = sizeof buf; tqsl_get_name_entry(iss, "organizationalUnitName", &item); ok = !strcmp(issuer->organizationalUnitName, item.value_buf); } } /* Check call sign if asked */ if (ok && callsign != NULL) { item.name_buf = name_buf; item.name_buf_size = sizeof name_buf; item.value_buf = buf; item.value_buf_size = sizeof buf; if (!tqsl_cert_get_subject_name_entry(x, "AROcallsign", &item)) ok = 0; else ok = !strcmp(callsign, item.value_buf); } /* Check DXCC entity if asked */ if (ok && dxcc > 0) { len = sizeof buf-1; if (tqsl_get_cert_ext(x, "dxccEntity", (unsigned char *)buf, &len, NULL)) { ok = 0; } else { buf[len] = 0; if (dxcc != strtol(buf, NULL, 10)) ok = 0; } } /* Check QSO date if asked */ if (ok && date != NULL && !tqsl_isDateNull(date)) { len = sizeof buf-1; if (tqsl_get_cert_ext(x, "QSONotBeforeDate", (unsigned char *)buf, &len, NULL)) ok = 0; else if (tqsl_initDate(&qso_date, buf)) ok = 0; else if (tqsl_compareDates(date, &qso_date) < 0) ok = 0; } if (ok && date != NULL && !tqsl_isDateNull(date)) { len = sizeof buf-1; if (tqsl_get_cert_ext(x, "QSONotAfterDate", (unsigned char *)buf, &len, NULL)) ok = 0; else if (tqsl_initDate(&qso_date, buf)) ok = 0; else if (tqsl_compareDates(date, &qso_date) > 0) ok = 0; } /* If no check failed, copy this cert onto the new stack */ if (ok) { X509_up_ref(x); sk_X509_push(newsk, x); } } tqsl_free(cp); return newsk; } /* Set up a read-only BIO from the given file and pass to * tqsl_ssl_load_certs_from_BIO. */ CLIENT_STATIC STACK_OF(X509) * tqsl_ssl_load_certs_from_file(const char *filename) { BIO *in; STACK_OF(X509) *sk; FILE *cfile; tqslTrace("tqsl_ssl_load_certs_from_file", "filename=%s", filename); #ifdef _WIN32 wchar_t* wfilename = utf8_to_wchar(filename); if ((cfile = _wfopen(wfilename, L"r")) == NULL) { free_wchar(wfilename); #else if ((cfile = fopen(filename, "r")) == NULL) { #endif strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_ssl_load_certs_from_file", "File open error %s", strerror(errno)); return NULL; } #ifdef _WIN32 free(wfilename); #endif if ((in = BIO_new_fp(cfile, 0)) == NULL) { tQSL_Error = TQSL_OPENSSL_ERROR; tqslTrace("tqsl_ssl_load_certs_from_file", "bio_new_fp err %s", tqsl_openssl_error()); return NULL; } sk = tqsl_ssl_load_certs_from_BIO(in); BIO_free(in); fclose(cfile); return sk; } /* Load a set of certs from a file into a stack. The file may contain * other X509 objects (e.g., CRLs), but we'll ignore those. * * Return NULL if there are no certs in the file or on error. */ CLIENT_STATIC STACK_OF(X509) * tqsl_ssl_load_certs_from_BIO(BIO *in) { STACK_OF(X509_INFO) *sk = NULL; STACK_OF(X509) *stack = NULL; X509_INFO *xi; if (tqsl_init()) return NULL; if (!(stack = sk_X509_new_null())) { tqslTrace("tqsl_ssl_load_certs_from_BIO", "bio_new_fp err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } if (!(sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) { sk_X509_free(stack); tqslTrace("tqsl_ssl_load_certs_from_BIO", "PEM_X509_INFO_read_bio err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } /* Extract the certs from the X509_INFO objects and put them on a stack */ while (sk_X509_INFO_num(sk)) { xi = sk_X509_INFO_shift(sk); if (xi->x509 != NULL) { sk_X509_push(stack, xi->x509); xi->x509 = NULL; } X509_INFO_free(xi); } /* Empty file isn't really an error, is it? if(!sk_X509_num(stack)) { sk_X509_free(stack); stack = NULL; strcpy(tQSL_CustomError, "No certificates found"); tQSL_Error = TQSL_CUSTOM_ERROR; } */ sk_X509_INFO_free(sk); return stack; } /* Chain-verify a cert against a set of CA and a set of trusted root certs. * * Returns NULL if cert verifies, an error message if it does not. */ CLIENT_STATIC const char * tqsl_ssl_verify_cert(X509 *cert, STACK_OF(X509) *cacerts, STACK_OF(X509) *rootcerts, int purpose, int (*cb)(int ok, X509_STORE_CTX *ctx), STACK_OF(X509) **chain) { X509_STORE *store; X509_STORE_CTX *ctx; int rval; const char *errm; if (cert == NULL) { tqslTrace("tqsl_ssl_verify_cert", "No certificate to verify"); return "No certificate to verify"; } if (tqsl_init()) return NULL; store = X509_STORE_new(); if (store == NULL) { tqslTrace("tqsl_ssl_verify_cert", "out of memory"); return "Out of memory"; } if (cb != NULL) X509_STORE_set_verify_cb(store, cb); ctx = X509_STORE_CTX_new(); if (ctx == NULL) { X509_STORE_free(store); tqslTrace("tqsl_ssl_verify_cert", "store_ctx_new out of memory"); return "Out of memory"; } X509_STORE_CTX_init(ctx, store, cert, cacerts); if (cb != NULL) X509_STORE_CTX_set_verify_cb(ctx, cb); if (rootcerts) X509_STORE_CTX_trusted_stack(ctx, rootcerts); if (purpose >= 0) X509_STORE_CTX_set_purpose(ctx, purpose); X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CB_ISSUER_CHECK); rval = X509_verify_cert(ctx); errm = X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)); if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_NOT_YET_VALID) { errm = "This Callsign Certificate cannot be installed as the first date where it is valid is in the future.\nCheck if your computer is set to the proper date.\n\n"; } else if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED) { errm = "This Callsign Certificate cannot be installed as it has expired.\nCheck if your computer is set to the proper date.\n\n"; } else if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { if (cacerts != NULL) { errm = "This Callsign Certificate cannot be installed.\nThe certificate authority certificate cannot be found.\nPlease request a replacement Callsign Certificate.\n\n"; } else { errm = "This Callsign Certificate cannot be installed.\nThe trusted root certificate cannot be found.\nPlease request a replacement Callsign Certificate.\n\n"; } } #if OPENSSL_VERSION_NUMBER < 0x10100000L #define X509_STORE_CTX_get0_chain(o) ((o)->chain) #endif if (chain) { if (rval && X509_STORE_CTX_get0_chain(ctx)) *chain = sk_X509_dup(X509_STORE_CTX_get0_chain(ctx)); else *chain = 0; } X509_STORE_CTX_free(ctx); if (rval) return NULL; if (errm != NULL) { tqslTrace("tqsl_ssl_verify_cert", "err %s", errm); return errm; } return "Verification failed"; } /* [static] - Grab the data from an X509_NAME_ENTRY and put it into * a TQSL_X509_NAME_ITEM object, checking buffer sizes. * * Returns 0 on error, 1 if okay. * * It's okay for the name_buf or value_buf item of the object to * be NULL; it'll just be skipped. */ static int tqsl_get_name_stuff(X509_NAME_ENTRY *entry, TQSL_X509_NAME_ITEM *name_item) { ASN1_OBJECT *obj; ASN1_STRING *value; const char *val; unsigned int len; if (entry == NULL) { tqslTrace("tqsl_get_name_stuff", "entry=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 0; } obj = X509_NAME_ENTRY_get_object(entry); if (obj == NULL) { tqslTrace("tqsl_get_name_stuff", "get_object err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 0; } if (name_item->name_buf != NULL) { len = i2t_ASN1_OBJECT(name_item->name_buf, name_item->name_buf_size, obj); if (len <= 0 || len > strlen(name_item->name_buf)) { tqslTrace("tqsl_get_name_stuff", "len error len= %d need=%d", len, strlen(name_item->name_buf)); tQSL_Error = TQSL_OPENSSL_ERROR; return 0; } } if (name_item->value_buf != NULL) { value = X509_NAME_ENTRY_get_data(entry); val = (const char *)ASN1_STRING_get0_data(value); strncpy(name_item->value_buf, val, name_item->value_buf_size); name_item->value_buf[name_item->value_buf_size-1] = '\0'; if (strlen(val) > strlen(name_item->value_buf)) { tqslTrace("tqsl_get_name_stuff", "len error len= %d need=%d", strlen(val), strlen(name_item->value_buf)); tQSL_Error = TQSL_OPENSSL_ERROR; return 0; } } return 1; } /* Get a name entry from an X509_NAME by its name. */ CLIENT_STATIC int tqsl_get_name_entry(X509_NAME *name, const char *obj_name, TQSL_X509_NAME_ITEM *name_item) { X509_NAME_ENTRY *entry; int num_entries, i; if (tqsl_init()) return 0; num_entries = X509_NAME_entry_count(name); if (num_entries <= 0) return 0; /* Loop through the name entries */ for (i = 0; i < num_entries; i++) { entry = X509_NAME_get_entry(name, i); if (!tqsl_get_name_stuff(entry, name_item)) continue; if (name_item->name_buf != NULL && !strcmp(name_item->name_buf, obj_name)) { /* Found the wanted entry */ return 1; } } return 0; } /* Get a name entry from a cert's subject name by its name. */ CLIENT_STATIC int tqsl_cert_get_subject_name_entry(X509 *cert, const char *obj_name, TQSL_X509_NAME_ITEM *name_item) { X509_NAME *name; if (cert == NULL) return 0; if (tqsl_init()) return 0; if ((name = X509_get_subject_name(cert)) == NULL) return 0; return tqsl_get_name_entry(name, obj_name, name_item); } /* Initialize the tQSL (really OpenSSL) random number generator * Return 0 on error. */ CLIENT_STATIC int tqsl_init_random() { char fname[TQSL_MAX_PATH_LEN]; static int initialized = 0; if (initialized) return 1; if (RAND_file_name(fname, sizeof fname) != NULL) RAND_load_file(fname, -1); initialized = RAND_status(); if (!initialized) { tqslTrace("tqsl_init_random", "init error %s", tqsl_openssl_error()); tQSL_Error = TQSL_RANDOM_ERROR; } return initialized; } /* Generate an RSA key of at least 1024 bits length */ CLIENT_STATIC EVP_PKEY * tqsl_new_rsa_key(int nbits) { EVP_PKEY *pkey; if (nbits < 1024) { tqslTrace("tqsl_new_rsa_key", "nbits too small %d", nbits); tQSL_Error = TQSL_ARGUMENT_ERROR; return NULL; } if ((pkey = EVP_PKEY_new()) == NULL) { tqslTrace("tqsl_new_rsa_key", "EVP_PKEY_new err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } if (!tqsl_init_random()) /* Unable to init RN generator */ return NULL; RSA *rsa = RSA_new(); if (rsa == NULL) { EVP_PKEY_free(pkey); tqslTrace("tqsl_new_rsa_key", "RSA_new err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } BIGNUM *pubexp = BN_new(); if (pubexp == NULL) { EVP_PKEY_free(pkey); RSA_free(rsa); tqslTrace("tqsl_new_rsa_key", "BN_new err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } if (BN_set_word(pubexp, 0x10001) != 1) { EVP_PKEY_free(pkey); RSA_free(rsa); BN_free(pubexp); tqslTrace("tqsl_new_rsa_key", "BN_set_word err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } if (RSA_generate_key_ex(rsa, nbits, pubexp, NULL) != 1) { EVP_PKEY_free(pkey); RSA_free(rsa); BN_free(pubexp); tqslTrace("tqsl_new_rsa_key", "RSA_generate_key err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } if (!EVP_PKEY_assign_RSA(pkey, rsa)) { EVP_PKEY_free(pkey); RSA_free(rsa); BN_free(pubexp); tqslTrace("tqsl_new_rsa_key", "EVP_PKEY_assign_RSA err %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return NULL; } BN_free(pubexp); return pkey; } /* Output an ADIF field to a file descriptor. */ CLIENT_STATIC int tqsl_write_adif_field(FILE *fp, const char *fieldname, char type, const unsigned char *value, int len) { if (fieldname == NULL) /* Silly caller */ return 0; if (fputc('<', fp) == EOF) return 1; if (fputs(fieldname, fp) == EOF) return 1; if (type && type != ' ' && type != '\0') { if (fputc(':', fp) == EOF) return 1; if (fputc(type, fp) == EOF) return 1; } if (value != NULL && len != 0) { if (len < 0) len = strlen((const char *)value); if (fputc(':', fp) == EOF) return 1; fprintf(fp, "%d>", len); if (fwrite(value, 1, len, fp) != (unsigned int) len) return 1; } else if (fputc('>', fp) == EOF) { return 1; } if (fputs("\n\n", fp) == EOF) return 1; return 0; } /* Output an ADIF field to a BIO */ CLIENT_STATIC int tqsl_bio_write_adif_field(BIO *bio, const char *fieldname, char type, const unsigned char *value, int len) { int bret; if (fieldname == NULL) /* Silly caller */ return 0; if ((bret = BIO_write(bio, "<", 1)) <= 0) return 1; if ((bret = BIO_write(bio, fieldname, strlen(fieldname))) <= 0) return 1; if (type && type != ' ' && type != '\0') { if ((bret = BIO_write(bio, ":", 1)) <= 0) return 1; if ((bret = BIO_write(bio, &type, 1)) <= 0) return 1; } if (value != NULL && len != 0) { if (len < 0) len = strlen((const char *)value); if ((bret = BIO_write(bio, ":", 1)) <= 0) return 1; char numbuf[20]; snprintf(numbuf, sizeof numbuf, "%d>", len); if ((bret = BIO_write(bio, numbuf, strlen(numbuf))) <= 0) return 1; if ((bret = BIO_write(bio, value, len)) != len) return 1; } else if ((bret = BIO_write(bio, ">", 1)) <= 0) { return 1; } if ((bret = BIO_write(bio, "\n\n", 2)) <= 0) return 1; return 0; } static int tqsl_self_signed_is_ok(int ok, X509_STORE_CTX *ctx) { if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) return 1; if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_UNTRUSTED) return 1; // OK if root cert has expired if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED || X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_UNTRUSTED) return 1; return ok; } static int tqsl_expired_is_ok(int ok, X509_STORE_CTX *ctx) { if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED || X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_UNTRUSTED) return 1; return ok; } static char * tqsl_make_cert_path(const char *filename, char *path, int size) { strncpy(path, tQSL_BaseDir, size); #ifdef _WIN32 strncat(path, "\\certs", size - strlen(path)); wchar_t* wpath = utf8_to_wchar(path); if (MKDIR(wpath, 0700) && errno != EEXIST) { free_wchar(wpath); #else strncat(path, "/certs", size - strlen(path)); if (MKDIR(path, 0700) && errno != EEXIST) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_make_cert_path", "Making path %s failed with %s", path, strerror(errno)); return NULL; } #ifdef _WIN32 free_wchar(wpath); strncat(path, "\\", size - strlen(path)); #else strncat(path, "/", size - strlen(path)); #endif strncat(path, filename, size - strlen(path)); return path; } static int tqsl_clean_call(const char *callsign, char *buf, int size) { if ((static_cast(strlen(callsign))) > size-1) { tQSL_Error = TQSL_BUFFER_ERROR; return 1; } const char *cp; for (cp = callsign; *cp; cp++) { if (!isdigit(*cp) && !isalpha(*cp)) *buf = '_'; else *buf = *cp; ++buf; } *buf = 0; return 0; } static char * tqsl_make_key_path(const char *callsign, char *path, int size) { char fixcall[256]; tqsl_clean_call(callsign, fixcall, sizeof fixcall); strncpy(path, tQSL_BaseDir, size); #ifdef _WIN32 strncat(path, "\\keys", size - strlen(path)); wchar_t* wpath = utf8_to_wchar(path); if (MKDIR(wpath, 0700) && errno != EEXIST) { free_wchar(wpath); #else strncat(path, "/keys", size - strlen(path)); if (MKDIR(path, 0700) && errno != EEXIST) { #endif strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_make_key_path", "Making path %s failed with %s", path, strerror(errno)); return 0; } #ifdef _WIN32 free_wchar(wpath); strncat(path, "\\", size - strlen(path)); #else strncat(path, "/", size - strlen(path)); #endif strncat(path, fixcall, size - strlen(path)); return path; } static char * tqsl_make_backup_path(const char *callsign, char *path, int size) { char fixcall[256]; tqsl_clean_call(callsign, fixcall, sizeof fixcall); strncpy(path, tQSL_BaseDir, size); #ifdef _WIN32 strncat(path, "\\certtrash", size - strlen(path)); wchar_t* wpath = utf8_to_wchar(path); if (MKDIR(wpath, 0700) && errno != EEXIST) { free_wchar(wpath); #else strncat(path, "/certtrash", size - strlen(path)); if (MKDIR(path, 0700) && errno != EEXIST) { #endif strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_make_backup_path", "Making path %s failed with %s", path, strerror(errno)); return 0; } #ifdef _WIN32 free_wchar(wpath); strncat(path, "\\", size - strlen(path)); #else strncat(path, "/", size - strlen(path)); #endif strncat(path, fixcall, size - strlen(path)); return path; } static int tqsl_handle_root_cert(const char *pem, X509 *x, int (*cb)(int, const char *, void *), void *userdata) { const char *cp; /* Verify self-signature on the root certificate */ if ((cp = tqsl_ssl_verify_cert(x, NULL, NULL, 0, &tqsl_self_signed_is_ok)) != NULL) { strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; tqslTrace("tqsl_handle_root_cert", "sig verify err %s", tQSL_CustomError); return 1; } return tqsl_store_cert(pem, x, "root", TQSL_CERT_CB_ROOT, false, cb, userdata); } static int tqsl_ssl_error_is_nofile() { if (tQSL_Error == TQSL_SYSTEM_ERROR && tQSL_Errno == ENOENT) return 1; return 0; } static int tqsl_handle_ca_cert(const char *pem, X509 *x, int (*cb)(int, const char *, void *), void *userdata) { STACK_OF(X509) *root_sk; char rootpath[TQSL_MAX_PATH_LEN]; const char *cp; tqsl_make_cert_path("root", rootpath, sizeof rootpath); if ((root_sk = tqsl_ssl_load_certs_from_file(rootpath)) == NULL) { if (!tqsl_ssl_error_is_nofile()) { tqslTrace("tqsl_handle_ca_cert", "error not nofile - %d", errno); return 1; } } cp = tqsl_ssl_verify_cert(x, NULL, root_sk, 0, &tqsl_expired_is_ok); sk_X509_free(root_sk); if (cp) { strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; tqslTrace("tqsl_handle_ca_cert", "verify error %s", tQSL_CustomError); return 1; } return tqsl_store_cert(pem, x, "authorities", TQSL_CERT_CB_CA, false, cb, userdata); } static int tqsl_handle_user_cert(const char *cpem, X509 *x, int (*cb)(int, const char *, void *), void *userdata) { STACK_OF(X509) *root_sk, *ca_sk; char rootpath[TQSL_MAX_PATH_LEN], capath[TQSL_MAX_PATH_LEN]; char pem[sizeof tqsl_static_buf]; const char *cp; strncpy(pem, cpem, sizeof pem); /* Match the public key in the supplied certificate with a * private key in the key store. */ tQSL_ImportSerial = ASN1_INTEGER_get(X509_get_serialNumber(x)); if (cb != NULL) { // Update the "CRL" for this serial number (*cb)(TQSL_CERT_CB_MILESTONE | TQSL_CERT_CB_SERIAL, NULL, userdata); } if (tqsl_find_matching_key(x, NULL, NULL, "", NULL, NULL)) { if (tQSL_Error != TQSL_PASSWORD_ERROR) { tqslTrace("tqsl_handle_user_cert", "match error %s", tqsl_openssl_error()); return 1; } tQSL_Error = TQSL_NO_ERROR; /* clear error */ } /* Check the chain of authority back to a trusted root */ tqsl_make_cert_path("root", rootpath, sizeof rootpath); if ((root_sk = tqsl_ssl_load_certs_from_file(rootpath)) == NULL) { if (!tqsl_ssl_error_is_nofile()) { tqslTrace("tqsl_handle_user_cert", "Error loading certs %s", tqsl_openssl_error()); return 1; } } tqsl_make_cert_path("authorities", capath, sizeof capath); if ((ca_sk = tqsl_ssl_load_certs_from_file(capath)) == NULL) { if (!tqsl_ssl_error_is_nofile()) { sk_X509_free(root_sk); tqslTrace("tqsl_handle_user_cert", "Error loading authorities %s", tqsl_openssl_error()); return 1; } } cp = tqsl_ssl_verify_cert(x, ca_sk, root_sk, 0, &tqsl_expired_is_ok); sk_X509_free(ca_sk); sk_X509_free(root_sk); if (cp) { strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError); tQSL_Error = TQSL_CUSTOM_ERROR; tqslTrace("tqsl_handle_user_cert", "verify error %s", cp); return 1; } return tqsl_store_cert(pem, x, "user", TQSL_CERT_CB_USER, false, cb, userdata); } CLIENT_STATIC int tqsl_store_cert(const char *pem, X509 *cert, const char *certfile, int type, bool force, int (*cb)(int, const char *, void *), void *userdata) { STACK_OF(X509) *sk; char path[TQSL_MAX_PATH_LEN]; char issuer[256]; char name[256]; char value[256]; FILE *out; BIGNUM *bserial, *oldserial; string subjid, msg, callsign; TQSL_X509_NAME_ITEM item; int len, rval; tQSL_Date newExpires; string stype = "Unknown"; const ASN1_TIME *tm; if (type == TQSL_CERT_CB_ROOT) { stype = "Trusted Root Authority"; } else if (type == TQSL_CERT_CB_CA) { stype = "Certificate Authority"; } else if (type == TQSL_CERT_CB_USER) { stype = "Callsign"; // Invalidate the cached user certs if (xcerts != NULL) { sk_X509_free(xcerts); xcerts = NULL; } } tqsl_make_cert_path(certfile, path, sizeof path); item.name_buf = name; item.name_buf_size = sizeof name; item.value_buf = value; item.value_buf_size = sizeof value; if (tqsl_cert_get_subject_name_entry(cert, "AROcallsign", &item)) { // Subject contains a call sign (probably a user cert) callsign = value; strncpy(ImportCall, callsign.c_str(), sizeof(tQSL_ImportCall)); tQSL_ImportSerial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); subjid = string(" ") + value; tm = X509_get_notAfter(cert); if (tm) { tqsl_get_asn1_date(tm, &newExpires); } else { newExpires.year = 9999; newExpires.month = 1; newExpires.day = 1; } if (tqsl_cert_get_subject_name_entry(cert, "commonName", &item)) subjid += string(" (") + value + ")"; len = sizeof value-1; if (!tqsl_get_cert_ext(cert, "dxccEntity", (unsigned char *)value, &len, NULL)) { value[len] = 0; subjid += string(" DXCC = ") + value; } } else if (tqsl_cert_get_subject_name_entry(cert, "organizationName", &item)) { // Subject contains an organization (probably a CA or root CA cert) subjid = string(" ") + value; if (tqsl_cert_get_subject_name_entry(cert, "organizationalUnitName", &item)) subjid += string(" ") + value; } if (subjid == "") { // If haven't found a displayable subject name we understand, use the raw DN X509_NAME_oneline(X509_get_subject_name(cert), issuer, sizeof issuer); subjid = string(" ") + issuer; } X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof issuer); /* Check for dupes */ if ((sk = tqsl_ssl_load_certs_from_file(path)) == NULL) { if (!tqsl_ssl_error_is_nofile()) { tqslTrace("tqsl_store_cert", "unexpected openssl err %s", tqsl_openssl_error()); return 1; /* Unexpected OpenSSL error */ } } /* Check each certificate */ if (sk != NULL) { int i, n; tQSL_Date expires; bserial = BN_new(); ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bserial); n = sk_X509_num(sk); for (i = 0; i < n; i++) { char buf[256]; X509 *x; const char *cp; x = sk_X509_value(sk, i); cp = X509_NAME_oneline(X509_get_issuer_name(x), buf, sizeof buf); if (cp != NULL && !strcmp(cp, issuer)) { oldserial = BN_new(); ASN1_INTEGER_to_BN(X509_get_serialNumber(x), oldserial); int result = BN_ucmp(bserial, oldserial); BN_free(oldserial); if (result == 0) break; /* We have a match */ } if (!force && type == TQSL_CERT_CB_USER) { // Don't check for newer certs on restore item.name_buf = name; item.name_buf_size = sizeof name; item.value_buf = value; item.value_buf_size = sizeof value; if (tqsl_cert_get_subject_name_entry(x, "AROcallsign", &item)) { if (value == callsign) { /* * If it's another cert for * this call, is it older? */ tm = X509_get_notAfter(x); if (tm) { tqsl_get_asn1_date(tm, &expires); } else { expires.year = 0; expires.month = 0; expires.day = 0; } if (tqsl_compareDates(&newExpires, &expires) < 0) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "A newer certificate for this callsign is already installed", sizeof tQSL_CustomError); tqslTrace("tqsl_load_cert", tQSL_CustomError); BN_free(bserial); sk_X509_free(sk); return 1; } } } } } BN_free(bserial); sk_X509_free(sk); if (i < n) { /* Have a match -- cert is already in the file */ if (cb != NULL) { int rval; string msg = "Duplicate " + stype + " certificate: " + subjid; rval = (*cb)(TQSL_CERT_CB_RESULT | type | TQSL_CERT_CB_DUPLICATE, msg.c_str(), userdata); if (rval) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "Duplicate Callsign certificate", sizeof tQSL_CustomError); tqslTrace("tqsl_load_cert", tQSL_CustomError); return 1; } } if (tQSL_Error == 0) { tQSL_Error = TQSL_CERT_ERROR; } return 1; } } /* Cert is not a duplicate. Append it to the certificate file */ if (cb != NULL) { msg = "Adding " + stype + " Certificate for: " + subjid; tqslTrace("tqsl_load_cert", msg.c_str()); rval = (*cb)(TQSL_CERT_CB_MILESTONE | type | TQSL_CERT_CB_PROMPT, msg.c_str(), userdata); if (rval) { tqslTrace("tqsl_load_cert", "operator aborted"); tQSL_Error = TQSL_OPERATOR_ABORT; return 1; } } #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); if ((out = _wfopen(wpath, L"a")) == NULL) { free_wchar(wpath); #else if ((out = fopen(path, "a")) == NULL) { #endif strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_load_cert", "opening file err %s", strerror(errno)); return 1; } #ifdef _WIN32 free_wchar(wpath); #endif // Make sure there's always a newline between certs size_t pemlen = strlen(pem); if (fwrite("\n", 1, 1, out) != 1 || fwrite(pem, 1, pemlen, out) != pemlen) { strncpy(tQSL_ErrorFile, certfile, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_load_cert", "writing file err %s", strerror(errno)); return 1; } if (fclose(out) == EOF) { strncpy(tQSL_ErrorFile, certfile, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_load_cert", "writing file err %s", strerror(errno)); return 1; } msg = "Loaded: " + subjid; if (cb) rval = (*cb)(TQSL_CERT_CB_RESULT | type | TQSL_CERT_CB_LOADED, msg.c_str(), userdata); else rval = 0; if (rval) { tQSL_Error = TQSL_OPERATOR_ABORT; return 1; } strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall); return 0; } static int pw_aborted; static int fixed_password_callback(char *buf, int bufsiz, int verify, void *userdata) { pw_aborted = 0; if (userdata != NULL) strncpy(buf, reinterpret_cast(userdata), bufsiz); else buf[0] = 0; return strlen(buf); } static void *prompt_userdata; static int prompted_password_callback(char *buf, int bufsiz, int verify, void *userfunc) { pw_aborted = 0; if (userfunc != NULL) { int (*cb)(char *, int, void *) = (int (*)(char *, int, void *))userfunc; if ((*cb)(buf, bufsiz, prompt_userdata)) { pw_aborted = 1; return 0; } } else { buf[0] = 0; } return strlen(buf); } static tQSL_ADIF keyf_adif = 0; static int tqsl_open_key_file(const char *path) { if (keyf_adif) tqsl_endADIF(&keyf_adif); return tqsl_beginADIF(&keyf_adif, path); } static int tqsl_read_key(map& fields) { TQSL_ADIF_GET_FIELD_ERROR adif_status; tqsl_adifFieldResults field; static tqsl_adifFieldDefinitions adif_fields[] = { { "PUBLIC_KEY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "PRIVATE_KEY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "CALLSIGN", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_PROVIDER", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_PROVIDER_UNIT", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_ADDRESS1", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_ADDRESS2", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_CITY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_STATE", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_POSTAL", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_COUNTRY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_DXCC_ENTITY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_QSO_NOT_BEFORE", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "TQSL_CRQ_QSO_NOT_AFTER", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL }, { "DELETED", "", TQSL_ADIF_RANGE_TYPE_NONE, 200, 0, 0, NULL, NULL }, { "eor", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL, NULL }, { "", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL, NULL }, }; fields.clear(); do { if (tqsl_getADIFField(keyf_adif, &field, &adif_status, adif_fields, notypes, &tqsl_static_alloc)) return 1; if (adif_status == TQSL_ADIF_GET_FIELD_EOF) return 1; if (!strcasecmp(field.name, "eor")) return 0; if (adif_status == TQSL_ADIF_GET_FIELD_SUCCESS) { char *cp; for (cp = field.name; *cp; cp++) *cp = toupper(*cp); fields[field.name] = reinterpret_cast(field.data); } } while (adif_status == TQSL_ADIF_GET_FIELD_SUCCESS || adif_status == TQSL_ADIF_GET_FIELD_NO_NAME_MATCH); tQSL_Error = TQSL_ADIF_ERROR; return 1; } static void tqsl_close_key_file(void) { tqsl_endADIF(&keyf_adif); } static int tqsl_replace_key(const char *callsign, const char *path, map& newfields, int (*cb)(int, const char *, void *), void *userdata) { char newpath[TQSL_MAX_PATH_LEN]; char savepath[TQSL_MAX_PATH_LEN]; #ifdef _WIN32 wchar_t* wnewpath = NULL; #endif map fields; vector< map > records; vector< map >::iterator it; EVP_PKEY *new_key = NULL, *key = NULL; BIO *bio = 0; FILE *out = 0; int rval = 1; if ((bio = BIO_new_mem_buf(reinterpret_cast(const_cast(newfields["PUBLIC_KEY"].c_str())), newfields["PUBLIC_KEY"].length())) == NULL) { tqslTrace("tqsl_replace_key", "BIO_new_mem_buf err %s", tqsl_openssl_error()); goto trk_end; } if ((new_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { tqslTrace("tqsl_replace_key", "PEM_read_bio_PUBKEY err %s", tqsl_openssl_error()); goto trk_end; } BIO_free(bio); bio = 0; if (tqsl_open_key_file(path)) { if (tQSL_Error != TQSL_SYSTEM_ERROR || tQSL_Errno != ENOENT) { tqslTrace("tqsl_replace_key", "error opening key file %s: %s", path, strerror(tQSL_Errno)); return 1; } tQSL_Error = TQSL_NO_ERROR; } while (tqsl_read_key(fields) == 0) { vectorseen; bool match = false; for (size_t i = 0; i < seen.size(); i++) { if (seen[i] == fields["PUBLIC_KEY"]) { match = true; break; } } if (match) continue; // Drop dupes seen.push_back(fields["PUBLIC_KEY"]); if ((bio = BIO_new_mem_buf(reinterpret_cast(const_cast(fields["PUBLIC_KEY"].c_str())), fields["PUBLIC_KEY"].length())) == NULL) { tqslTrace("tqsl_replace_key", "BIO_new_mem_buf error %s", tqsl_openssl_error()); goto trk_end; } if ((key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { tqslTrace("tqsl_replace_key", "Pem_read_bio_rsa_pubkey error %s", tqsl_openssl_error()); goto trk_end; } BIO_free(bio); bio = NULL; if (EVP_PKEY_cmp(key, new_key) == 1) { fields["DELETED"] = "True"; // Mark as deleted } records.push_back(fields); } tqsl_close_key_file(); if (newfields["PRIVATE_KEY"] != "") records.push_back(newfields); strncpy(newpath, path, sizeof newpath); strncat(newpath, ".new", sizeof newpath - strlen(newpath)-1); strncpy(savepath, path, sizeof savepath); strncat(savepath, ".save", sizeof savepath - strlen(savepath)-1); #ifdef _WIN32 wnewpath = utf8_to_wchar(newpath); if ((out = _wfopen(wnewpath, TQSL_OPEN_WRITE)) == NULL) { free_wchar(wnewpath); #else if ((out = fopen(newpath, TQSL_OPEN_WRITE)) == NULL) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_replace_key", "open file %s: %s", newpath, strerror(tQSL_Errno)); goto trk_end; } for (it = records.begin(); it != records.end(); it++) { map::iterator mit; for (mit = it->begin(); mit != it->end(); mit++) { if (tqsl_write_adif_field(out, mit->first.c_str(), 0, (const unsigned char *)mit->second.c_str(), -1)) { tqslTrace("tqsl_replace_key", "error writing %s", strerror(tQSL_Errno)); #ifdef _WIN32 free_wchar(wnewpath); #endif goto trk_end; } } tqsl_write_adif_field(out, "eor", 0, NULL, 0); } if (fclose(out) == EOF) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_replace_key", "error closing %s", strerror(tQSL_Errno)); #ifdef _WIN32 free_wchar(wnewpath); #endif goto trk_end; } out = 0; /* Output file looks okay. Replace the old file with the new one. */ #ifdef _WIN32 wchar_t* wsavepath = utf8_to_wchar(savepath); if (_wunlink(wsavepath) && errno != ENOENT) { free_wchar(wsavepath); free_wchar(wnewpath); #else if (unlink(savepath) && errno != ENOENT) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_replace_key", "unlink file %s: %s", savepath, strerror(tQSL_Errno)); goto trk_end; } #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); if (_wrename(wpath, wsavepath) && errno != ENOENT) { free_wchar(wpath); free_wchar(wsavepath); free_wchar(wnewpath); #else if (rename(path, savepath) && errno != ENOENT) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_replace_key", "rename file %s->%s: %s", path, savepath, strerror(tQSL_Errno)); goto trk_end; } #ifdef _WIN32 if (_wrename(wnewpath, wpath)) { free_wchar(wnewpath); free_wchar(wpath); free_wchar(wsavepath); #else if (rename(newpath, path)) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_replace_key", "rename file %s->%s: %s", newpath, path, strerror(tQSL_Errno)); goto trk_end; } #ifdef _WIN32 free_wchar(wnewpath); free_wchar(wpath); free_wchar(wsavepath); #endif tqslTrace("tqsl_replace_key", "loaded private key for: %s", callsign); if (cb) { string msg = string("Loaded private key for: ") + callsign; (*cb)(TQSL_CERT_CB_RESULT + TQSL_CERT_CB_PKEY + TQSL_CERT_CB_LOADED, msg.c_str(), userdata); } rval = 0; trk_end: tqsl_close_key_file(); if (out) fclose(out); if (new_key) EVP_PKEY_free(new_key); if (key) EVP_PKEY_free(key); if (bio) BIO_free(bio); return rval; } static int tqsl_unlock_key(const char *pem, EVP_PKEY **keyp, const char *password, int (*cb)(char *, int, void *), void *userdata) { RSA *prsa = NULL; BIO *bio; int (*ssl_cb)(char *, int, int, void *) = NULL; void *cb_user = NULL; long e; int rval = 1; if ((bio = BIO_new_mem_buf(reinterpret_cast(const_cast(pem)), strlen(pem))) == NULL) { tqslTrace("tqsl_unlock_key", "BIO_new_mem_buf err %s", tqsl_openssl_error()); goto err; } if (password != NULL) { ssl_cb = &fixed_password_callback; cb_user = reinterpret_cast(const_cast(password)); } else if (cb != NULL) { prompt_userdata = userdata; ssl_cb = &prompted_password_callback; cb_user = reinterpret_cast(cb); } /* * This used to call PEM_read_bio_RSAPrivateKey() but * that has a memory leak. Leaving the original code * if ((prsa = PEM_read_bio_RSAPrivateKey(bio, NULL, ssl_cb, cb_user)) == NULL) { tqslTrace("tqsl_unlock_key", "PEM_read_bio_RSAPrivateKey err %s", tqsl_openssl_error()); goto err; } */ EVP_PKEY *pktmp; if ((pktmp = PEM_read_bio_PrivateKey(bio, NULL, ssl_cb, cb_user)) == NULL) { tqslTrace("tqsl_unlock_key", "PEM_read_bio_RSAPrivateKey err %s", tqsl_openssl_error()); goto err; } if ((prsa = EVP_PKEY_get1_RSA(pktmp)) == NULL) { tqslTrace("tqsl_unlock_key", "PEM_read_bio_RSAPrivateKey err %s", tqsl_openssl_error()); EVP_PKEY_free(pktmp); goto err; } EVP_PKEY_free(pktmp); if (keyp != NULL) { if ((*keyp = EVP_PKEY_new()) == NULL) goto err; EVP_PKEY_assign_RSA(*keyp, prsa); prsa = NULL; } rval = 0; goto end; err: e = ERR_peek_error(); if ((ERR_GET_LIB(e) == ERR_LIB_EVP && ERR_GET_REASON(e) == EVP_R_BAD_DECRYPT) #if OPENSSL_VERSION_MAJOR >= 3 || (ERR_GET_LIB(e) == ERR_LIB_PROV && ERR_GET_REASON(e) == PROV_R_BAD_DECRYPT) #endif || (ERR_GET_LIB(e) == ERR_LIB_PEM && ERR_GET_REASON(e) == PEM_R_BAD_PASSWORD_READ) || (ERR_GET_LIB(e) == ERR_LIB_PKCS12 && ERR_GET_REASON(e) == PKCS12_R_PKCS12_CIPHERFINAL_ERROR)) { tqsl_getErrorString(); /* clear error */ tQSL_Error = pw_aborted ? TQSL_OPERATOR_ABORT : TQSL_PASSWORD_ERROR; ERR_clear_error(); #if OPENSSL_VERSION_MAJOR >= 3 // Handle corrupted key } else if (ERR_GET_LIB(e) == ERR_LIB_OSSL_DECODER && ERR_GET_REASON(e) == ERR_R_UNSUPPORTED) { ERR_clear_error(); strncpy(tQSL_ErrorFile, "Private key file is corrupt or the passphrase is incorrect", sizeof tQSL_ErrorFile); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; #endif } else { tQSL_Error = TQSL_OPENSSL_ERROR; } tqslTrace("tqsl_unlock_key", "Key read error %d", tQSL_Error); end: if (prsa != NULL) RSA_free(prsa); if (bio != NULL) BIO_free(bio); return rval; } static int tqsl_find_matching_key(X509 *cert, EVP_PKEY **keyp, TQSL_CERT_REQ **crq, const char *password, int (*cb)(char *, int, void *), void *userdata) { char path[TQSL_MAX_PATH_LEN]; char aro[256]; TQSL_X509_NAME_ITEM item = { path, sizeof path, aro, sizeof aro }; EVP_PKEY *cert_key = NULL; EVP_PKEY *curkey = NULL; int rval = 0; int match = 0; int deleted = 0; BIO *bio = NULL; map fields; bool finddeleted = false; if (keyp != NULL) *keyp = NULL; if (!tqsl_cert_get_subject_name_entry(cert, "AROcallsign", &item)) { tqslTrace("tqsl_find_matching_key", "get subj name err %d", tQSL_Error); return 1; } tQSL_ImportSerial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); if (!tqsl_make_key_path(aro, path, sizeof path)) { tqslTrace("tqsl_find_matching_key", "key path err %d", tQSL_Error); rval = 1; goto end_nokey; } strncpy(ImportCall, aro, sizeof ImportCall); again: if (tqsl_open_key_file(path)) { /* Friendly error for file not found */ if (tQSL_Error == TQSL_SYSTEM_ERROR) { if (tQSL_Errno == ENOENT) { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "You can only open this callsign certificate by running TQSL on the computer where you created the certificate request for %s.", aro); } else { snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Can't open %s: %s\nThis file is needed to open this callsign certificate.", aro, strerror(tQSL_Errno)); } tQSL_Error = TQSL_CUSTOM_ERROR; tqslTrace("tqsl_find_matching_key", "opening file path err %s", tQSL_CustomError); } return 1; } if ((cert_key = X509_get_pubkey(cert)) == NULL) { tqslTrace("tqsl_find_matching_key", "error getting public key %s", tqsl_openssl_error()); goto err; } if (crq != NULL) { if (*crq != NULL) tqsl_free_cert_req(*crq, 0); *crq = reinterpret_cast(tqsl_calloc(1, sizeof(TQSL_CERT_REQ))); } while (!tqsl_read_key(fields)) { /* Compare the keys */ if ((bio = BIO_new_mem_buf(reinterpret_cast(const_cast(fields["PUBLIC_KEY"].c_str())), fields["PUBLIC_KEY"].length())) == NULL) { tqslTrace("tqsl_find_matching_key", "BIO_new_mem_buf err %s", tqsl_openssl_error()); goto err; } if ((curkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { tqslTrace("tqsl_find_matching_key", "PEM_read_bio_RSA_PUBKEY err %s", tqsl_openssl_error()); goto err; } BIO_free(bio); bio = NULL; if (EVP_PKEY_cmp(curkey, cert_key) == 1) { if (fields["DELETED"] == "True") { if (finddeleted) { match = 1; deleted = 1; } } else { match = 1; } } if (match) { /* We have a winner */ if (tqsl_unlock_key(fields["PRIVATE_KEY"].c_str(), keyp, password, cb, userdata)) { tqslTrace("tqsl_find_matching_key", "tqsl_unlock_key err %d", tQSL_Error); rval = 1; goto end; } if (crq != NULL) { tQSL_Error = TQSL_BUFFER_ERROR; if (!safe_strncpy((*crq)->providerName, fields["TQSL_CRQ_PROVIDER"].c_str(), sizeof (*crq)->providerName)) goto end; if (!safe_strncpy((*crq)->providerUnit, fields["TQSL_CRQ_PROVIDER_UNIT"].c_str(), sizeof (*crq)->providerUnit)) goto end; if (!safe_strncpy((*crq)->address1, fields["TQSL_CRQ_ADDRESS1"].c_str(), sizeof (*crq)->address1)) goto end; if (!safe_strncpy((*crq)->address2, fields["TQSL_CRQ_ADDRESS2"].c_str(), sizeof (*crq)->address2)) goto end; if (!safe_strncpy((*crq)->city, fields["TQSL_CRQ_CITY"].c_str(), sizeof (*crq)->city)) goto end; if (!safe_strncpy((*crq)->state, fields["TQSL_CRQ_STATE"].c_str(), sizeof (*crq)->state)) goto end; if (!safe_strncpy((*crq)->postalCode, fields["TQSL_CRQ_POSTAL"].c_str(), sizeof (*crq)->postalCode)) goto end; if (!safe_strncpy((*crq)->country, fields["TQSL_CRQ_COUNTRY"].c_str(), sizeof (*crq)->country)) goto end; tQSL_Error = 0; } rval = 0; break; } } if (match) goto end; if (!finddeleted) { finddeleted = true; tqsl_close_key_file(); goto again; } tqslTrace("tqsl_find_matching_key", "No matching private key found"); rval = 1; tQSL_Error = TQSL_CERT_NOT_FOUND; int sts; sts = tqsl_getCertificateStatus(tQSL_ImportSerial); switch (sts) { case TQSL_CERT_STATUS_INV: tQSL_Error |= TQSL_CERT_NOT_FOUND_INVALID; break; case TQSL_CERT_STATUS_SUP: tQSL_Error |= TQSL_CERT_NOT_FOUND_SUPERCEDED; break; case TQSL_CERT_STATUS_EXP: tQSL_Error |= TQSL_CERT_NOT_FOUND_EXPIRED; break; } /* Check for expired */ struct tm *tm; #ifdef _WIN32 __time32_t t = _time32(0); tm = _gmtime32(&t); #else time_t t; t = time(0); struct tm tmr; tm = &tmr; tm = gmtime_r(&t, tm); #endif tQSL_Date d; d.year = tm->tm_year + 1900; d.month = tm->tm_mon + 1; d.day = tm->tm_mday; const ASN1_TIME *ctm; if ((ctm = X509_get_notAfter(cert)) != NULL) { tQSL_Date cert_na; tqsl_get_asn1_date(ctm, &cert_na); if (tqsl_compareDates(&cert_na, &d) < 0) { tQSL_Error |= TQSL_CERT_NOT_FOUND_EXPIRED; } } strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall); goto end; err: rval = 1; tQSL_Error = TQSL_OPENSSL_ERROR; end: tqsl_close_key_file(); if (deleted) { int savedErr = tQSL_Error; tqsl_clear_deleted(aro, path, cert_key); tQSL_Error = savedErr; } end_nokey: if (curkey != NULL) EVP_PKEY_free(curkey); if (bio != NULL) BIO_free(bio); if (cert_key != NULL) EVP_PKEY_free(cert_key); // if (in != NULL) // fclose(in); if (rval == 0) { strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall); } return rval; } static int tqsl_make_key_list(vector< map > & keys) { keys.clear(); string path = tQSL_BaseDir; #ifdef _WIN32 path += "\\keys"; wchar_t* wpath = utf8_to_wchar(path.c_str()); MKDIR(wpath, 0700); #else path += "/keys"; MKDIR(path.c_str(), 0700); #endif #ifdef _WIN32 WDIR *dir = wopendir(wpath); free_wchar(wpath); #else DIR *dir = opendir(path.c_str()); #endif if (dir == NULL) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_make_key_list", "Opendir %s error %s", path.c_str(), strerror(errno)); return 1; } #ifdef _WIN32 struct wdirent *ent; #else struct dirent *ent; #endif int rval = 0; int savedError = 0; int savedErrno = 0; char *savedFile = NULL; #ifdef _WIN32 while ((ent = wreaddir(dir)) != NULL) { if (ent->d_name[0] == '.') continue; if (wcsstr(ent->d_name, L".save") || wcsstr(ent->d_name, L".new")) continue; char dname[TQSL_MAX_PATH_LEN]; wcstombs(dname, ent->d_name, TQSL_MAX_PATH_LEN); string filename = path + "\\" + dname; #else while ((ent = readdir(dir)) != NULL) { if (ent->d_name[0] == '.') continue; if (strstr(ent->d_name, ".save") || strstr(ent->d_name, ".new")) continue; string filename = path + "/" + ent->d_name; #endif char fixcall[256]; #ifdef _WIN32 struct _stat32 s; wchar_t* wfilename = utf8_to_wchar(filename.c_str()); if (_wstat32(wfilename, &s) == 0) { if (S_ISDIR(s.st_mode)) { free_wchar(wfilename); continue; // If it's a directory, skip it. } } free_wchar(wfilename); #else struct stat s; if (stat(filename.c_str(), &s) == 0) { if (S_ISDIR(s.st_mode)) continue; // If it's a directory, skip it. } #endif if (!tqsl_open_key_file(filename.c_str())) { vectorseen; map fields; while (!tqsl_read_key(fields)) { if (fields["DELETED"] == "True") continue; // Skip this one bool match = false; for (size_t i = 0; i < seen.size(); i++) { if (seen[i] == fields["PUBLIC_KEY"]) { match = true; break; } } if (match) continue; seen.push_back(fields["PUBLIC_KEY"]); if (tqsl_clean_call(fields["CALLSIGN"].c_str(), fixcall, sizeof fixcall)) { rval = 1; savedError = tQSL_Error; savedErrno = tQSL_Errno; if (savedFile) free(savedFile); savedFile = strdup(tQSL_ErrorFile); continue; // Keep looking for keys } #ifdef _WIN32 wchar_t* wfixcall = utf8_to_wchar(fixcall); if (wcscmp(wfixcall, ent->d_name)) { free_wchar(wfixcall); #else if (strcasecmp(fixcall, ent->d_name)) { #endif continue; } #ifdef _WIN32 free_wchar(wfixcall); #endif keys.push_back(fields); } tqsl_close_key_file(); } else { rval = 1; // Unable to open - remember that savedErrno = tQSL_Errno; savedError = tQSL_Error; if (savedFile) free(savedFile); savedFile = strdup(tQSL_ErrorFile); } } #ifdef _WIN32 _wclosedir(dir); #else closedir(dir); #endif if (rval) { tQSL_Error = savedError; tQSL_Errno = savedErrno; if (savedFile) { strncpy(tQSL_ErrorFile, savedFile, sizeof tQSL_ErrorFile); free(savedFile); } tqslTrace("tqsl_make_key_list", "error %s %s", tQSL_ErrorFile, strerror(tQSL_Errno)); } return rval; } static int tqsl_get_cert_ext(X509 *cert, const char *ext, unsigned char *userbuf, int *buflen, int *crit) { int i, n, datasiz; X509_EXTENSION *xe; char buf[256]; ASN1_OBJECT *obj; ASN1_OCTET_STRING *data; if (tqsl_init()) return 1; if (cert == NULL || ext == NULL || userbuf == NULL || buflen == NULL) { tqslTrace("tqsl_get_cert_ext", "arg error cert=0x%lx, ext=0x%lx userbuf=0x%lx, buflen=0x%lx crit=0x%lx", cert, ext, userbuf, buflen, crit); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } n = X509_get_ext_count(cert); for (i = 0; i < n; i++) { xe = X509_get_ext(cert, i); if (xe == NULL) { tqslTrace("tqsl_get_cert_ext", "X509_get_ext error %s", tqsl_openssl_error()); tQSL_Error = TQSL_OPENSSL_ERROR; return 1; } buf[0] = '\0'; obj = X509_EXTENSION_get_object(xe); if (obj) OBJ_obj2txt(buf, sizeof buf, obj, 0); if (strcmp(buf, ext)) continue; /* This is the desired extension */ data = X509_EXTENSION_get_data(xe); if (data != NULL) { datasiz = ASN1_STRING_length(data); if (datasiz > *buflen-1) { tqslTrace("tqsl_get_cert_ext", "buffer len %d needed %d", *buflen, datasiz); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } *buflen = datasiz; if (datasiz) memcpy(userbuf, ASN1_STRING_get0_data(data), datasiz); userbuf[datasiz] = '\0'; } if (crit != NULL) *crit = X509_EXTENSION_get_critical(xe); return 0; } snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Certificate Extension not found: %s", ext); tQSL_Error = TQSL_CUSTOM_ERROR; if (strcmp(ext, "supercededCertificate")) tqslTrace("tqsl_get_cert_ext", "Err %s", tQSL_CustomError); return 1; } CLIENT_STATIC int tqsl_get_asn1_date(const ASN1_TIME *tm, tQSL_Date *date) { char *v; int i; i = tm->length; v = reinterpret_cast(tm->data); if (i >= 14) { for (i = 0; i < 12; i++) if ((v[i] > '9') || (v[i] < '0')) goto err; date->year = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0'); date->month = (v[4]-'0')*10+(v[5]-'0'); if ((date->month > 12) || (date->month < 1)) goto err; date->day = (v[6]-'0')*10+(v[7]-'0'); } else if (i < 12) { goto err; } else { for (i = 0; i < 10; i++) if ((v[i] > '9') || (v[i] < '0')) goto err; date->year = (v[0]-'0')*10+(v[1]-'0'); if (date->year < 50) date->year+=100; date->year += 1900; date->month = (v[2]-'0')*10+(v[3]-'0'); if ((date->month > 12) || (date->month < 1)) goto err; date->day = (v[4]-'0')*10+(v[5]-'0'); } return 0; err: tqslTrace("tqsl_get_asn1_date", "invalid date"); tQSL_Error = TQSL_INVALID_DATE; return 1; } static char * tqsl_sign_base64_data(tQSL_Cert cert, char *b64data) { int len; static unsigned char sig[256]; int siglen = sizeof sig; if (b64data && !strncmp(b64data, "-----", 5)) { b64data = strchr(b64data, '\n'); if (b64data == NULL) return NULL; b64data++; } len = sizeof tqsl_static_buf; if (tqsl_decodeBase64(b64data, tqsl_static_buf, &len)) return NULL; if (tqsl_signDataBlock(cert, tqsl_static_buf, len, sig, &siglen)) return NULL; if (tqsl_encodeBase64(sig, siglen, reinterpret_cast(tqsl_static_buf), sizeof tqsl_static_buf)) return NULL; return reinterpret_cast(tqsl_static_buf); } static bool safe_strncpy(char *dest, const char *src, int size) { strncpy(dest, src, size); dest[size-1] = 0; return ((static_cast((strlen(src))) < size)); } static string tqsl_cert_status_filename(const char *f = "cert_status.xml") { string s = tQSL_BaseDir; #ifdef _WIN32 s += "\\"; #else s += "/"; #endif s += f; return s; } static XMLElement* certStatusData = NULL; static int tqsl_load_cert_status_data(void) { if (certStatusData) { return 0; } certStatusData = new XMLElement; if (!certStatusData) { tqslTrace("tqsl_load_cert_status_data", "Out of memory!"); return 1; } int status = certStatusData->parseFile(tqsl_cert_status_filename().c_str()); if (status) { if (errno == ENOENT) { // No file is OK tqslTrace("tqsl_load_cert_status_data", "FNF"); return 0; } strncpy(tQSL_ErrorFile, tqsl_cert_status_filename().c_str(), sizeof tQSL_ErrorFile); if (status == XML_PARSE_SYSTEM_ERROR) { tQSL_Error = TQSL_FILE_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_load_cert_status_data", "open error %s: %s", tqsl_cert_status_filename().c_str(), strerror(tQSL_Errno)); } else { tqslTrace("tqsl_load_cert_status_data", "syntax error %s", tqsl_cert_status_filename().c_str()); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; } return 1; } return status; } static int tqsl_dump_cert_status_data(XMLElement &xel) { ofstream out; string fn = tqsl_cert_status_filename(); out.exceptions(std::ios::failbit | std::ios::eofbit | std::ios::badbit); try { #ifdef _WIN32 wchar_t* wfn = utf8_to_wchar(fn.c_str()); out.open(wfn); free_wchar(wfn); #else out.open(fn.c_str()); #endif out << xel << endl; out.close(); } catch(exception& x) { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Error writing certificate status file (%s): %s/%s", fn.c_str(), x.what(), strerror(errno)); tqslTrace("tqsl_dump_cert_status_data", "write error %s", tQSL_CustomError); return 1; } delete certStatusData; certStatusData = NULL; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCertificateStatus(long serial) { if (tqsl_load_cert_status_data()) return TQSL_CERT_STATUS_UNK; XMLElement sfile; if (certStatusData->getFirstElement(sfile)) { XMLElement cd; bool ok = sfile.getFirstElement("Cert", cd); while (ok && cd.getElementName() == "Cert") { pair s = cd.getAttribute("serial"); if (s.second && strtol(s.first.c_str(), NULL, 10) == serial) { XMLElement xs; if (cd.getFirstElement("status", xs)) { if (!strcasecmp(xs.getText().c_str(), "Bad serial")) return TQSL_CERT_STATUS_INV; else if (!strcasecmp(xs.getText().c_str(), "Superceded")) return TQSL_CERT_STATUS_SUP; else if (!strcasecmp(xs.getText().c_str(), "Expired")) return TQSL_CERT_STATUS_EXP; else if (!strcasecmp(xs.getText().c_str(), "Unrevoked")) return TQSL_CERT_STATUS_OK; else return TQSL_CERT_STATUS_UNK; } } ok = sfile.getNextElement(cd); } } return TQSL_CERT_STATUS_UNK; } DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus(long serial, const char *status) { if (status == NULL) { tqslTrace("tqsl_setCertificateStatus", "status=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } char sstr[32]; snprintf(sstr, sizeof sstr, "%ld", serial); int stat = tqsl_load_cert_status_data(); if (stat == TQSL_FILE_SYSTEM_ERROR) { tqslTrace("tqsl_setCertificateStatus", "error %d", tQSL_Error); return 1; } XMLElement sfile; if (!certStatusData->getFirstElement(sfile)) sfile.setElementName("CertStatus"); XMLElementList& ellist = sfile.getElementList(); bool exists = false; XMLElementList::iterator ep; for (ep = ellist.find("Cert"); ep != ellist.end(); ep++) { if (ep->first != "Cert") break; pair rval = ep->second->getAttribute("serial"); if (rval.second && strtol(rval.first.c_str(), NULL, 10) == serial) { exists = true; break; } } XMLElement *cs = new XMLElement("Cert"); cs->setPretext("\n "); XMLElement *se = new XMLElement; se->setPretext(cs->getPretext() + " "); se->setElementName("status"); se->setText(status); cs->addElement(se); cs->setAttribute("serial", sstr); cs->setText("\n "); if (exists) ellist.erase(ep); sfile.addElement(cs); sfile.setText("\n"); return tqsl_dump_cert_status_data(sfile); } static int tqsl_clear_deleted(const char *callsign, const char *path, EVP_PKEY *cert_key) { char newpath[TQSL_MAX_PATH_LEN]; char savepath[TQSL_MAX_PATH_LEN]; #ifdef _WIN32 wchar_t* wnewpath = NULL; #endif map fields; vector< map > records; vector< map >::iterator it; EVP_PKEY *new_key = NULL, *key = NULL; BIO *bio = 0; FILE *out = 0; int rval = 1; if (tqsl_open_key_file(path)) { if (tQSL_Error != TQSL_SYSTEM_ERROR || tQSL_Errno != ENOENT) { tqslTrace("tqsl_clear_deleted", "error opening key file %s: %s", path, strerror(tQSL_Errno)); return 1; } tQSL_Error = TQSL_NO_ERROR; } while (tqsl_read_key(fields) == 0) { if ((bio = BIO_new_mem_buf(reinterpret_cast(const_cast(fields["PUBLIC_KEY"].c_str())), fields["PUBLIC_KEY"].length())) == NULL) { tqslTrace("tqsl_clear_deleted", "BIO_new_mem_buf error %s", tqsl_openssl_error()); goto trk_end; } if ((key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { tqslTrace("tqsl_clear_deleted", "Pem_read_bio_rsa_pubkey error %s", tqsl_openssl_error()); goto trk_end; } BIO_free(bio); bio = NULL; if (EVP_PKEY_cmp(key, cert_key) == 1) { fields["DELETED"] = "False"; } records.push_back(fields); } tqsl_close_key_file(); strncpy(newpath, path, sizeof newpath); strncat(newpath, ".new", sizeof newpath - strlen(newpath)-1); strncpy(savepath, path, sizeof savepath); strncat(savepath, ".save", sizeof savepath - strlen(savepath)-1); #ifdef _WIN32 wnewpath = utf8_to_wchar(newpath); if ((out = _wfopen(wnewpath, TQSL_OPEN_WRITE)) == NULL) { free_wchar(wnewpath); #else if ((out = fopen(newpath, TQSL_OPEN_WRITE)) == NULL) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_clear_deleted", "open file %s: %s", newpath, strerror(tQSL_Errno)); goto trk_end; } for (it = records.begin(); it != records.end(); it++) { map::iterator mit; for (mit = it->begin(); mit != it->end(); mit++) { if (tqsl_write_adif_field(out, mit->first.c_str(), 0, (const unsigned char *)mit->second.c_str(), -1)) { tqslTrace("tqsl_clear_deleted", "error writing %s", strerror(tQSL_Errno)); #ifdef _WIN32 free_wchar(wnewpath); #endif goto trk_end; } } tqsl_write_adif_field(out, "eor", 0, NULL, 0); } if (fclose(out) == EOF) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_clear_deleted", "error closing %s", strerror(tQSL_Errno)); #ifdef _WIN32 free_wchar(wnewpath); #endif goto trk_end; } out = 0; /* Output file looks okay. Replace the old file with the new one. */ #ifdef _WIN32 wchar_t* wsavepath = utf8_to_wchar(savepath); if (_wunlink(wsavepath) && errno != ENOENT) { free_wchar(wsavepath); free_wchar(wnewpath); #else if (unlink(savepath) && errno != ENOENT) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_clear_deleted", "unlink file %s: %s", savepath, strerror(tQSL_Errno)); goto trk_end; } #ifdef _WIN32 wchar_t* wpath = utf8_to_wchar(path); if (_wrename(wpath, wsavepath) && errno != ENOENT) { free_wchar(wpath); free_wchar(wsavepath); free_wchar(wnewpath); #else if (rename(path, savepath) && errno != ENOENT) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_clear_deleted", "rename file %s->%s: %s", path, savepath, strerror(tQSL_Errno)); goto trk_end; } #ifdef _WIN32 if (_wrename(wnewpath, wpath)) { free_wchar(wnewpath); free_wchar(wpath); free_wchar(wsavepath); #else if (rename(newpath, path)) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_clear_deleted", "rename file %s->%s: %s", newpath, path, strerror(tQSL_Errno)); goto trk_end; } #ifdef _WIN32 free_wchar(wnewpath); free_wchar(wpath); free_wchar(wsavepath); #endif rval = 0; trk_end: tqsl_close_key_file(); if (out) fclose(out); if (new_key) EVP_PKEY_free(new_key); if (key) EVP_PKEY_free(key); if (bio) BIO_free(bio); return rval; } static int tqsl_key_exists(const char *callsign, EVP_PKEY *cert_key) { map fields; vector< map >::iterator it; EVP_PKEY *key = NULL; BIO *bio = 0; int rval = 0; char path[TQSL_MAX_PATH_LEN]; if (!tqsl_make_key_path(callsign, path, sizeof path)) { tqslTrace("tqsl_createCertRequest", "make_key_path error %d", errno); return 0; } if (tqsl_open_key_file(path)) { return 0; } while (tqsl_read_key(fields) == 0) { if ((bio = BIO_new_mem_buf(reinterpret_cast(const_cast(fields["PUBLIC_KEY"].c_str())), fields["PUBLIC_KEY"].length())) == NULL) { tqslTrace("tqsl_clear_deleted", "BIO_new_mem_buf error %s", tqsl_openssl_error()); goto trk_end; } if ((key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { tqslTrace("tqsl_clear_deleted", "Pem_read_bio_rsa_pubkey error %s", tqsl_openssl_error()); goto trk_end; } BIO_free(bio); bio = NULL; if (EVP_PKEY_cmp(key, cert_key) == 1) { rval = 1; } } trk_end: tqsl_close_key_file(); if (key) EVP_PKEY_free(key); if (bio) BIO_free(bio); return rval; } /** Save the json results for a given callsign location Detail. */ DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo(const char *callsign, const char *json) { FILE *out; if (callsign == NULL) { tqslTrace("tqsl_saveCallsinLocationInfo", "arg error callsign=0x%lx, json=0x%lx", callsign, json); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } char fixcall[256]; char path[TQSL_MAX_PATH_LEN]; size_t size = sizeof path; #ifdef _WIN32 wchar_t* wfilename; #endif tqsl_clean_call(callsign, fixcall, sizeof fixcall); strncpy(path, tQSL_BaseDir, size); #ifdef _WIN32 strncat(path, "\\", size - strlen(path)); #else strncat(path, "/", size - strlen(path)); #endif strncat(path, fixcall, size - strlen(path)); strncat(path, ".json", size - strlen(path)); if (json == NULL) { // Delete the file #ifdef _WIN32 wfilename = utf8_to_wchar(path); _wunlink(wfilename); free_wchar(wfilename); #else unlink(path); #endif return 0; } /* Try opening the output stream */ #ifdef _WIN32 wfilename = utf8_to_wchar(path); if ((out = _wfopen(wfilename, TQSL_OPEN_WRITE)) == NULL) { free_wchar(wfilename); #else if ((out = fopen(path, TQSL_OPEN_WRITE)) == NULL) { #endif strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tqslTrace("tqsl_saveCallsignLocationInfo", "Open file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; return 1; } #ifdef _WIN32 free_wchar(wfilename); #endif if (fputs(json, out) == EOF) { strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tqslTrace("tqsl_createCertRequest", "Write request file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; return 1; } if (fclose(out) == EOF) { strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_saveCallsignLocationInfo", "write error %d", errno); return 1; } return 0; } /** Retrieve the json results for a given callsign location Detail. */ DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo(const char *callsign, char **buf) { FILE *in; static void* mybuf = NULL; static size_t bufsize = 0; if (bufsize == 0) { bufsize = 4096; mybuf = tqsl_malloc(bufsize); } if (callsign == NULL || buf == NULL) { tqslTrace("tqsl_getCallsinLocationInfo", "arg error callsign=0x%lx, buf=0x%lx", callsign, buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } char fixcall[256]; char path[TQSL_MAX_PATH_LEN]; size_t size = sizeof path; tqsl_clean_call(callsign, fixcall, sizeof fixcall); strncpy(path, tQSL_BaseDir, size); #ifdef _WIN32 strncat(path, "\\", size - strlen(path)); #else strncat(path, "/", size - strlen(path)); #endif strncat(path, fixcall, size - strlen(path)); strncat(path, ".json", size - strlen(path)); size_t buflen = bufsize; #ifdef _WIN32 struct _stat32 s; wchar_t* wfilename = utf8_to_wchar(path); if (_wstat32(wfilename, &s) == 0) { buflen = s.st_size + 512; } if ((in = _wfopen(wfilename, TQSL_OPEN_READ)) == NULL) { free_wchar(wfilename); #else struct stat s; if (stat(path, &s) == 0) { buflen = s.st_size + 512; } if ((in = fopen(path, TQSL_OPEN_READ)) == NULL) { #endif strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tqslTrace("tqsl_getCallsignLocationInfo", "Open file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; return 1; } #ifdef _WIN32 free_wchar(wfilename); #endif if (buflen > bufsize) { bufsize = buflen + 512; mybuf = tqsl_realloc(mybuf, bufsize); } *buf = reinterpret_cast(mybuf); size_t len; if ((len = fread(mybuf, 1, buflen, in)) == 0) { strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tqslTrace("tqsl_getCallsignLocationInformation", "Read file - system error %s", strerror(errno)); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; return 1; } if (fclose(in) == EOF) { strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_getCallsignLocationInformation", "read error %d", errno); return 1; } if (len < buflen) { char *t = reinterpret_cast(mybuf); t[len] = '\0'; } return 0; } tqsl-2.8.2/src/location.h0000644000175000017500000000213415061653721015262 0ustar rmurphyrmurphy/*************************************************************************** location.h - description ------------------- begin : Fri Nov 15 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef __location_h #define __location_h // TQSL_LOCATION_FIELD flag bits #define TQSL_LOCATION_FIELD_UPPER 1 #define TQSL_LOCATION_FIELD_MUSTSEL 2 #define TQSL_LOCATION_FIELD_SELNXT 4 #include #include #include "winstrdefs.h" using std::vector; class VUCCgrid { public: VUCCgrid(int ent, const char * pas, const char * grid) { _ent = ent; if (pas) _pas = strdup(pas); else _pas = NULL; _grid = strdup(grid); } int ent() { return _ent; } char* pas() { return _pas; } char* grid() { return _grid; } private: int _ent; char* _pas; char* _grid; }; typedef vector VUCCGridList; #endif // __location_h tqsl-2.8.2/src/location.cpp0000755000175000017500000042575615061653721015643 0ustar rmurphyrmurphy/*************************************************************************** location.cpp - description ------------------- begin : Wed Nov 6 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id: location.cpp,v 1.14 2013/03/01 13:20:30 k1mu Exp $ ***************************************************************************/ // #define DXCC_TEST #define TQSLLIB_DEF #include "location.h" #include #include #include #ifdef _WIN32 #include #endif #ifdef __APPLE__ #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "tqsllib.h" #include "tqslerrno.h" #include "xml.h" #include "openssl_cert.h" #ifdef _WIN32 #include "windows.h" #endif using std::string; using std::vector; using std::map; using std::pair; using std::make_pair; using std::ofstream; using std::ios; using std::endl; using std::exception; static int init_adif_map(void); #ifdef _WIN32 #define strtok_r strtok_s #endif namespace tqsllib { class TQSL_LOCATION_ITEM { public: TQSL_LOCATION_ITEM() : ivalue(0) {} string text; string label; string zonemap; int ivalue; }; class TQSL_LOCATION_FIELD { public: TQSL_LOCATION_FIELD() {} TQSL_LOCATION_FIELD(string i_gabbi_name, const char *i_label, int i_data_type, int i_data_len, int i_input_type, int i_flags = 0); string label; string gabbi_name; int data_type; int data_len; string cdata; vector items; int idx; int idata; int input_type; int flags; bool changed; string dependency; }; TQSL_LOCATION_FIELD::TQSL_LOCATION_FIELD(string i_gabbi_name, const char *i_label, int i_data_type, int i_data_len, int i_input_type, int i_flags) : data_type(i_data_type), data_len(i_data_len), cdata(""), input_type(i_input_type), flags(i_flags) { if (!i_gabbi_name.empty()) gabbi_name = i_gabbi_name; if (i_label) label = i_label; idx = idata = 0; } typedef vector TQSL_LOCATION_FIELDLIST; class TQSL_LOCATION_PAGE { public: TQSL_LOCATION_PAGE() : complete(false), prev(0), next(0) {} bool complete; int prev, next; string dependentOn, dependency; map > hash; TQSL_LOCATION_FIELDLIST fieldlist; }; typedef vector TQSL_LOCATION_PAGELIST; class TQSL_NAME { public: explicit TQSL_NAME(string n = "", string c = "") : name(n), call(c) {} string name; string call; }; class TQSL_LOCATION { public: TQSL_LOCATION() : sentinel(0x5445), page(0), cansave(false), sign_clean(false), cert_flags(TQSL_SELECT_CERT_WITHKEYS | TQSL_SELECT_CERT_EXPIRED), newflags(false), newDXCC(-1) {} ~TQSL_LOCATION() { sentinel = 0; } int sentinel; int page; bool cansave; string name; TQSL_LOCATION_PAGELIST pagelist; vector names; string signdata; string loc_details; string qso_details; bool sign_clean; string tSTATION; string tCONTACT; string sigspec; char data_errors[512]; int cert_flags; bool newflags; int newDXCC; }; class Band { public: string name, spectrum; int low, high; }; class Mode { public: string mode, group; }; class PropMode { public: string descrip, name; }; class Satellite { public: Satellite() { start.year = start.month = start.day = 0; end.year = end.month = end.day = 0; } string descrip, name; tQSL_Date start, end; }; bool operator< (const Band& o1, const Band& o2) { static const char *suffixes[] = { "M", "CM", "MM"}; static const char *prefix_chars = "0123456789."; // get suffixes string b1_suf = o1.name.substr(o1.name.find_first_not_of(prefix_chars)); string b2_suf = o2.name.substr(o2.name.find_first_not_of(prefix_chars)); if (b1_suf != b2_suf) { // Suffixes differ -- compare suffixes int b1_idx = (sizeof suffixes / sizeof suffixes[0]); int b2_idx = b1_idx; for (int i = 0; i < static_cast(sizeof suffixes / sizeof suffixes[0]); i++) { if (b1_suf == suffixes[i]) b1_idx = i; if (b2_suf == suffixes[i]) b2_idx = i; } return b1_idx < b2_idx; } return atof(o1.name.c_str()) > atof(o2.name.c_str()); } bool operator< (const PropMode& o1, const PropMode& o2) { if (o1.descrip < o2.descrip) return true; if (o1.descrip == o2.descrip) return (o1.name < o2.name); return false; } bool operator< (const Satellite& o1, const Satellite& o2) { if (o1.descrip < o2.descrip) return true; if (o1.descrip == o2.descrip) return (o1.name < o2.name); return false; } bool operator< (const Mode& o1, const Mode& o2) { static const char *groups[] = { "CW", "PHONE", "IMAGE", "DATA" }; // m1 < m2 if m1 is a modegroup and m2 is not if (o1.mode == o1.group) { if (o2.mode != o2.group) return true; } else if (o2.mode == o2.group) { return false; } // If groups are same, compare modes if (o1.group == o2.group) return o1.mode < o2.mode; int m1_g = (sizeof groups / sizeof groups[0]); int m2_g = m1_g; for (int i = 0; i < static_cast(sizeof groups / sizeof groups[0]); i++) { if (o1.group == groups[i]) m1_g = i; if (o2.group == groups[i]) m2_g = i; } return m1_g < m2_g; } } // namespace tqsllib using tqsllib::XMLElement; using tqsllib::XMLElementList; using tqsllib::Band; using tqsllib::Mode; using tqsllib::PropMode; using tqsllib::Satellite; using tqsllib::TQSL_LOCATION; using tqsllib::TQSL_LOCATION_PAGE; using tqsllib::TQSL_LOCATION_PAGELIST; using tqsllib::TQSL_LOCATION_FIELD; using tqsllib::TQSL_LOCATION_FIELDLIST; using tqsllib::TQSL_LOCATION_ITEM; using tqsllib::TQSL_NAME; using tqsllib::ROOTCERT; using tqsllib::CACERT; using tqsllib::USERCERT; using tqsllib::tqsl_get_pem_serial; #define CAST_TQSL_LOCATION(x) (reinterpret_cast((x))) typedef map IntMap; typedef map BoolMap; typedef map DateMap; static int num_entities = 0; static bool _ent_init = false; static struct _dxcc_entity { int number; const char* name; const char *zonemap; tQSL_Date start, end; bool deleted; } *entity_list = 0; template struct triplet { T1 first; T2 middle; T3 last; }; template triplet make_triplet(const T1 &f, const T2 &m, const T3 &l) { triplet trip; trip.first = f; trip.middle = m; trip.last = l; return trip; } // config data static XMLElement tqsl_xml_config; static int tqsl_xml_config_major = -1; static int tqsl_xml_config_minor = 0; static IntMap DXCCMap; static BoolMap DeletedMap; static IntMap DXCCZoneMap; static DateMap DXCCStartMap; static DateMap DXCCEndMap; static vector< pair > DXCCList; static vector BandList; static vector ModeList; static vector PropModeList; static vector SatelliteList; static map tqsl_page_map; static map tqsl_field_map; static map tqsl_adif_map; static vector tqsl_adif_mode_map; static map tqsl_adif_submode_map; static map > tqsl_cabrillo_map; static map > tqsl_cabrillo_user_map; static const char* cacertpem = {"-----BEGIN CERTIFICATE-----\n" "MIIGeDCCBGCgAwIBAgIUV31ApzN0aZACaQt7FGB26Mu5t4kwDQYJKoZIhvcNAQEL\n" "BQAwgdIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDVDESMBAGA1UEBwwJTmV3aW5n\n" "dG9uMSQwIgYDVQQKDBtBbWVyaWNhbiBSYWRpbyBSZWxheSBMZWFndWUxHTAbBgNV\n" "BAsMFExvZ2Jvb2sgb2YgdGhlIFdvcmxkMSUwIwYDVQQDDBxMb2dib29rIG9mIHRo\n" "ZSBXb3JsZCBSb290IENBMRgwFgYKCZImiZPyLGQBGRYIYXJybC5vcmcxHDAaBgkq\n" "hkiG9w0BCQEWDWxvdHdAYXJybC5vcmcwHhcNMTkwNjE5MTQxNzU4WhcNMjMwNjE5\n" "MTQxNzU4WjCB2DELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNUMRIwEAYDVQQHDAlO\n" "ZXdpbmd0b24xJDAiBgNVBAoMG0FtZXJpY2FuIFJhZGlvIFJlbGF5IExlYWd1ZTEd\n" "MBsGA1UECwwUTG9nYm9vayBvZiB0aGUgV29ybGQxKzApBgNVBAMMIkxvZ2Jvb2sg\n" "b2YgdGhlIFdvcmxkIFByb2R1Y3Rpb24gQ0ExGDAWBgoJkiaJk/IsZAEZFghhcnJs\n" "Lm9yZzEcMBoGCSqGSIb3DQEJARYNbG90d0BhcnJsLm9yZzCCASIwDQYJKoZIhvcN\n" "AQEBBQADggEPADCCAQoCggEBAM9Hf0icYR0we4cyYu/bD0mJTskM5InNxSim5Ql0\n" "OHJ2vfEY1aVZctsiW+Wj/4useYOdaO8e3NOWo80JEWpVXgQfBd1bbocHNQ1qyna7\n" "y0pVtMkvKK4ruDRCw6ZS1F5MCqVMwqR1OILukK5jlULkj+Zi1AoTD5PB1fZBlrKD\n" "xgE3XK0mGa+7bkgq694sOxR/TcCB1zfNRZBYy5g6mBVTztEJdvQvDw5rXxV4saJp\n" "MWagoknoc0sIQDsvOtP7/IWeov4Cnng+EwvKhHr2oHQ1U/DXo+ESOKt11UHqckQI\n" "cN0aFZZVLtdVoRMAkj+4AHS0nfrs9noLgwryZbaMcv1WQxUCAwEAAaOCATwwggE4\n" "MB0GA1UdDgQWBBSon29qgLN1wj/t5xz8TzNwqOwuvzCCAQcGA1UdIwSB/zCB/IAU\n" "x/zKwnPFr8tb9TpgfZqcGu/AjZOhgdikgdUwgdIxCzAJBgNVBAYTAlVTMQswCQYD\n" "VQQIDAJDVDESMBAGA1UEBwwJTmV3aW5ndG9uMSQwIgYDVQQKDBtBbWVyaWNhbiBS\n" "YWRpbyBSZWxheSBMZWFndWUxHTAbBgNVBAsMFExvZ2Jvb2sgb2YgdGhlIFdvcmxk\n" "MSUwIwYDVQQDDBxMb2dib29rIG9mIHRoZSBXb3JsZCBSb290IENBMRgwFgYKCZIm\n" "iZPyLGQBGRYIYXJybC5vcmcxHDAaBgkqhkiG9w0BCQEWDWxvdHdAYXJybC5vcmeC\n" "CQCD/w1L7eDLQzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCsar6K\n" "cW8QoKWmse7jBkEIG144eNc8+lzZY9h0rkDA473vS063Vh8SU08/e8LSreVfpJ1r\n" "fhcQBnk5kuvYI5TiCgoYL395DMP8r5OelD5ooS0r+OXRfMheJlW8L2nRvL2GYaZ8\n" "LO6laC3uZ5VpJrnA05rsL766BQByywWSLRH5EgFZ8SuVsnvKbHiM8fHAggaMZkFs\n" "f6bWg2QOETCufWhMKmkmMqJHQP4T4wtUjy4fay8kPMOYBHjealmK8lFrdEONPBh5\n" "Iviql+NzHPJmyB82Zv2WwlVUhoWnmUf1Lu7jcYTOmz9vNRpFls3DXoANv3l47l0W\n" "LXAiyDt/stS4MiAq9HS3IObGibFxYrDDa8F1IbyJXQsPUHEF7xuxI/Nj1TYZhOBW\n" "sGUyk+f/beRyMmx1y8cczmTqO+NqeWBhCqEqe9uLmEmpn1Fg1CdMW7aRchTwkcJh\n" "xc7Uh8smiW+DNSjH0HmLVHajyHHJOsCsSCy47xWSFvthCEHd3HMIMC+qmpOC2Ejj\n" "9dpGICTLFUD0fCvRq0bv9hwAKfnQqIbFEEmk2bT5Zi6lctPR04RUL4ICiFwkl5v0\n" "KWTBQFpTc/1KZcXHwWRgieaZ/epozvkjg51vkYlRHIPHiLIucbzwmz0qtkOjzfIK\n" "euRFuHg4j85bSZ3Nd+cvb09Fdr5xeJtHsCIn4g==\n" "-----END CERTIFICATE-----"}; static const char* rootcertpem = {"-----BEGIN CERTIFICATE-----\n" "MIIHZzCCBU+gAwIBAgIJAIP/DUvt4MtDMA0GCSqGSIb3DQEBDQUAMIHSMQswCQYD\n" "VQQGEwJVUzELMAkGA1UECAwCQ1QxEjAQBgNVBAcMCU5ld2luZ3RvbjEkMCIGA1UE\n" "CgwbQW1lcmljYW4gUmFkaW8gUmVsYXkgTGVhZ3VlMR0wGwYDVQQLDBRMb2dib29r\n" "IG9mIHRoZSBXb3JsZDElMCMGA1UEAwwcTG9nYm9vayBvZiB0aGUgV29ybGQgUm9v\n" "dCBDQTEYMBYGCgmSJomT8ixkARkWCGFycmwub3JnMRwwGgYJKoZIhvcNAQkBFg1s\n" "b3R3QGFycmwub3JnMB4XDTE1MDYwOTE1MzQyOFoXDTI1MDYwNjE1MzQyOFowgdIx\n" "CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDVDESMBAGA1UEBwwJTmV3aW5ndG9uMSQw\n" "IgYDVQQKDBtBbWVyaWNhbiBSYWRpbyBSZWxheSBMZWFndWUxHTAbBgNVBAsMFExv\n" "Z2Jvb2sgb2YgdGhlIFdvcmxkMSUwIwYDVQQDDBxMb2dib29rIG9mIHRoZSBXb3Js\n" "ZCBSb290IENBMRgwFgYKCZImiZPyLGQBGRYIYXJybC5vcmcxHDAaBgkqhkiG9w0B\n" "CQEWDWxvdHdAYXJybC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n" "AQDSV3CQz8/crg7uxPj/i3R8qs8vFqGOl3gWk4/BcKnJaYSf3I59cY3SlNxJhQmc\n" "zfAwOErOGW9C5gGInJJvpCLIkKZnHAeFhaNNn09/PaAPM0YrhTZMjUsHedhz9ObR\n" "UcZl7LEMhih9ctd3iPBf8FckG8MvgBJcMdMB1TrJfu8PekgRZtGKIG61tJc1tGYc\n" "RimmSaG3i4R0ZdiToj+tOifjbElDaLKTVnIn4YALSmA0RsB+UmPRZ/qMhI9663TM\n" "NsJfurcQL6TXg+EIHNnGlGa62y4cjNIPJdTI7Pk4rsL+WT4n7bZR+AWUVMXT6IYa\n" "ZvisOxmUM1qX9pYrcXf8OsWITE2GRRNMQZP+jVHQ3d4tl7JDNrNPziY1Oz9PLtud\n" "56ajJLf7smebsyza6e6NhZNgOhsSfbwu25fSc3b5xynI0TSwkz//J4szr8sfwkVJ\n" "whWoNG9GSONSHqnTQEaGVVarVpQUO9ZeuzOo3nZkSp7HH/aaf2akNGlwEqkqytn7\n" "HiYQKwbA54Vs+VRIX71TktF9KEdy6p03hVSfs9zqWuBLKdAX2een0IDTK9e8mdNF\n" "/9s4A5Q0mxASBrY9fe+FV347MLNctxDbaqeMcUsMBiyaihtTWmtZzC4zhBuccVW1\n" "u+YO26uodyGJ2ID7SQSyZDhiopWZLug//mhpTvvu8OZeewIDAQABo4IBPDCCATgw\n" "HQYDVR0OBBYEFMf8ysJzxa/LW/U6YH2anBrvwI2TMIIBBwYDVR0jBIH/MIH8gBTH\n" "/MrCc8Wvy1v1OmB9mpwa78CNk6GB2KSB1TCB0jELMAkGA1UEBhMCVVMxCzAJBgNV\n" "BAgMAkNUMRIwEAYDVQQHDAlOZXdpbmd0b24xJDAiBgNVBAoMG0FtZXJpY2FuIFJh\n" "ZGlvIFJlbGF5IExlYWd1ZTEdMBsGA1UECwwUTG9nYm9vayBvZiB0aGUgV29ybGQx\n" "JTAjBgNVBAMMHExvZ2Jvb2sgb2YgdGhlIFdvcmxkIFJvb3QgQ0ExGDAWBgoJkiaJ\n" "k/IsZAEZFghhcnJsLm9yZzEcMBoGCSqGSIb3DQEJARYNbG90d0BhcnJsLm9yZ4IJ\n" "AIP/DUvt4MtDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQENBQADggIBACtCtzn8\n" "41EpI7W55nNMIBcqBrzs2fil61aOt7b6BHk+KpFWonsKMcCsnT4W6yye+lG7aKf9\n" "eGjrxaSd8vHDKiYwr5fp2ahqmDyROtYyJgSJpurQUA+pB5lrIip2IuVNu3g92x7o\n" "CeGgGNU99/2WK0JXPVIAmTY4MO8B6wZ/ZVgB+QLfFEvMBWSiosnwfgT2cGynqCpz\n" "n5Q9SOFDAd83IjaOuuEssfLaRB1o3/UAS/wXgVLm5h+VjWLQ3176YPx/j6Ik+XAg\n" "QAQKLSyGhlZzVeRwPzCXKsAdPqIG7EUSLgqv2I9XyPS6zsI+UVw3WvJO3D6pEN77\n" "l6bqqvPWLjnZV4jV9PF3lenA0kChe+y+gTTejXNWyew8y0TTl4NOJPWjXsvKTQox\n" "oLY+0MhsyGzVSb2/HFs/B8/G9Fp+fiPOE8iv7sHs1ONhiAy4E2UgbPBG6OSXKP0Q\n" "hYyOMmcrBVAtTkq6DXugr0e2VBhs2wHlX3hVhlwNIGBA3Xrlji1Hx3gQjS0JZa1D\n" "ZCnX6/oGCbS6pio5/TyI0b1vArTMY1Sk/LFF7KjgfXGcxGO0i55HBqQhM3O68q/c\n" "vbT46W7TQ5zZUgFBeMltaxc2z3UsTiM02nF4K4hmsfD8Equh2fA5msc+p5PuaOJR\n" "4vVAjEWroIfchuU2z2ynrs3ZxrkZjJ+x72jD\n" "-----END CERTIFICATE-----" }; static char char_toupper(char c) { return toupper(c); } static string string_toupper(const string& in) { string out = in; transform(out.begin(), out.end(), out.begin(), char_toupper); return out; } // isspace() called on extended chars in UTF-8 raises asserts in // the windows C++ libs. Don't call isspace() if out of range. // static inline int isspc(int c) { if (c < 0 || c > 255) return 0; return isspace(c); } // trim from start static inline std::string <rim(std::string &s) { #if __cplusplus > 199711L s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) {return !std::isspace(c);})); #else s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(isspc)))); #endif return s; } // trim from end static inline std::string &rtrim(std::string &s) { #if __cplusplus > 199711L s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch);}).base(), s.end()); #else s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(isspc))).base(), s.end()); #endif return s; } // trim from both ends static inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } #define TQSL_NPAGES 4 static TQSL_LOCATION * check_loc(tQSL_Location loc, bool unclean = true) { if (tqsl_init()) return 0; if (loc == 0) return 0; if (unclean) CAST_TQSL_LOCATION(loc)->sign_clean = false; return CAST_TQSL_LOCATION(loc); } static int tqsl_load_xml_config() { if (tqsl_xml_config.getElementList().size() > 0) // Already init'd return 0; XMLElement default_config; XMLElement user_config; tqslTrace("tqsl_load_xml_config", NULL); #ifdef _WIN32 string default_path = string(tQSL_RsrcDir) + "\\config.xml"; string user_path = string(tQSL_BaseDir) + "\\config.xml"; #else string default_path = string(tQSL_RsrcDir) + "/config.xml"; string user_path = string(tQSL_BaseDir) + "/config.xml"; #endif tqslTrace("tqsl_load_xml_config", "user_path=%s", user_path.c_str()); int default_status = default_config.parseFile(default_path.c_str()); int user_status = user_config.parseFile(user_path.c_str()); tqslTrace("tqsl_load_xml_config", "default_status=%d, user_status=%d", default_status, user_status); if (default_status != XML_PARSE_NO_ERROR && user_status != XML_PARSE_NO_ERROR) { if (user_status == XML_PARSE_SYSTEM_ERROR) tQSL_Error = TQSL_CONFIG_ERROR; else tQSL_Error = TQSL_CONFIG_SYNTAX_ERROR; return 1; } int default_major = -1; int default_minor = 0; int user_major = -1; int user_minor = 0; XMLElement top; if (default_config.getFirstElement("tqslconfig", top)) { default_major = strtol(top.getAttribute("majorversion").first.c_str(), NULL, 10); default_minor = strtol(top.getAttribute("minorversion").first.c_str(), NULL, 10); } if (user_config.getFirstElement("tqslconfig", top)) { user_major = strtol(top.getAttribute("majorversion").first.c_str(), NULL, 10); user_minor = strtol(top.getAttribute("minorversion").first.c_str(), NULL, 10); } if (default_major > user_major || (default_major == user_major && default_minor > user_minor)) { tqsl_xml_config = default_config; tqsl_xml_config_major = default_major; tqsl_xml_config_minor = default_minor; user_config.clear(); return 0; } if (user_major < 0) { tQSL_Error = TQSL_CONFIG_SYNTAX_ERROR; tqslTrace("tqsl_load_xml_config", "Syntax error"); return 1; } tqsl_xml_config = user_config; tqsl_xml_config_major = user_major; tqsl_xml_config_minor = user_minor; default_config.clear(); return 0; } static VUCCGridList VUCC; static bool initVUCC(void) { static bool failed = false; if (failed) return failed; if (VUCC.size() != 0) return failed; XMLElement vucc_config; #ifdef _WIN32 string path = string(tQSL_RsrcDir) + "\\vuccgrids.dat"; #else string path = string(tQSL_RsrcDir) + "/vuccgrids.dat"; #endif tqslTrace("initVUCC", "path=%s", path.c_str()); int stat = vucc_config.parseFile(path.c_str()); if (stat != XML_PARSE_NO_ERROR) { failed = true; return failed; } XMLElement top; XMLElement v; int ent; char thispas[20]; char thisgrid[20]; if (vucc_config.getFirstElement("vuccgrids", top)) { if (top.getFirstElement("vucc", v)) { bool ok; do { string dx = v.getAttribute("entity").first; const char *dxcc = dx.c_str(); ent = strtol(dxcc, NULL, 10); if (ent == 0 && errno == EINVAL) { // Bad input tqslTrace("initVUCC", "invalid input - not an entity number %s", dxcc); failed = true; return failed; } if (!v.getAttribute("pas").second) { tqslTrace("initVUCC", "invalid input - no PAS"); failed = true; return failed; } strncpy(thispas, v.getAttribute("pas").first.c_str(), sizeof thispas); if (!v.getAttribute("grid").second) { tqslTrace("initVUCC", "invalid input - no grid"); failed = true; return failed; } strncpy(thisgrid, v.getAttribute("grid").first.c_str(), sizeof thisgrid); #ifdef DEBUG std::cout << ent << " " << thispas << " " << thisgrid << endl; #endif VUCC.push_back(VUCCgrid(ent, thispas, thisgrid)); ok = top.getNextElement(v); } while (ok); } else { failed = true; return failed; } } else { failed = true; return failed; } vucc_config.clear(); return failed; } DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid(int entity, const char *pas, const char *grid, int *result) { *result = 0; if (initVUCC()) { // fnf or corrupt *result = TQSL_VALID_VUCC_PAS|TQSL_VALID_VUCC_ENT; return 0; } for (size_t i = 0; i < VUCC.size(); i++) { if (VUCC[i].ent() < entity) continue; if (VUCC[i].ent() > entity) break; if (!strcmp(grid, VUCC[i].grid())) { // Valid grid for this entity tqslTrace("tqsl_validateVUCCGrid", "matches entity"); *result |= TQSL_VALID_VUCC_ENT; if (pas == NULL || strlen(pas) == 0) { // and empty PAS *result |= TQSL_VALID_VUCC_PAS; break; } if (VUCC[i].pas() == NULL || strlen(VUCC[i].pas()) == 0) {// No PAS for this grid/ent *result |= TQSL_VALID_VUCC_PAS; break; } if (pas && VUCC[i].pas() && (!strcmp(pas, VUCC[i].pas()))) { // Plus valid grid for this PAS tqslTrace("tqsl_validateVUCCGrid", "matches PAS and entity"); *result |= TQSL_VALID_VUCC_PAS; break; } } } if (*result == 0) { tqslTrace("tqsl_validateVUCCGrid", "Grid not found"); } return 0; } DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat(const char *grid, int twelve, char* newGrid, int newlen) { if (grid == NULL) { return 1; } string gtest = string(grid); // Uppercase and remove whitespace gtest = string_toupper(gtest); trim(gtest); // Truncate to size limit gtest = gtest.substr(0, twelve? 12 : 6); switch (gtest.size()) { case 2: case 4: case 6: break; case 8: case 10: case 12: if (twelve) break; default: // Not long enough yet or too long. return GRID_ERROR_INVALID_FORMAT; } // Field - range A-R if (gtest[0] < 'A' || gtest[0] > 'R') return GRID_ERROR_INVALID_FIELD; if (gtest[1] < 'A' || gtest[1] > 'R') return GRID_ERROR_INVALID_FIELD; if (gtest.size() > 2) { if (gtest[2] < '0' || gtest[2] > '9') return GRID_ERROR_INVALID_SQUARE; if (gtest[3] < '0' || gtest[3] > '9') return GRID_ERROR_INVALID_SUBSQUARE; } if (gtest.size() > 4) { if (gtest[4] < 'A' || gtest[4] > 'X') return GRID_ERROR_INVALID_SUBSQUARE; if (gtest[5] < 'A' || gtest[5] > 'X') return GRID_ERROR_INVALID_SUBSQUARE; } if (gtest.size() > 6) { if (gtest[6] < '0' || gtest[6] > '9') return GRID_ERROR_INVALID_SUBSUBSQUARE; if (gtest[7] < '0' || gtest[7] > '9') return GRID_ERROR_INVALID_SUBSUBSQUARE; } if (gtest.size() > 8) { if (gtest[8] < 'A' || gtest[8] > 'X') return GRID_ERROR_INVALID_SUBSUBSQUARE; if (gtest[9] < 'A' || gtest[9] > 'X') return GRID_ERROR_INVALID_SUBSUBSQUARE; } if (gtest.size() > 10) { if (gtest[10] < '0' || gtest[10] > '9') return GRID_ERROR_INVALID_SUBSUBSQUARE; if (gtest[11] < '0' || gtest[11] > '9') return GRID_ERROR_INVALID_SUBSUBSQUARE; } strncpy(newGrid, gtest.c_str(), newlen); newGrid[newlen - 1] = '\0'; return 0; } static int tqsl_get_xml_config_section(const string& section, XMLElement& el) { if (tqsl_load_xml_config()) return 1; XMLElement top; if (!tqsl_xml_config.getFirstElement("tqslconfig", top)) { tqsl_xml_config.clear(); tQSL_Error = TQSL_CONFIG_SYNTAX_ERROR; return 1; } if (!top.getFirstElement(section, el)) { tQSL_Error = TQSL_CONFIG_SYNTAX_ERROR; return 1; } return 0; } static int tqsl_load_provider_list(vector &plist) { plist.clear(); XMLElement providers; if (tqsl_get_xml_config_section("providers", providers)) return 1; tqslTrace("tqsl_load_provider_list", NULL); XMLElement provider; bool gotit = providers.getFirstElement("provider", provider); while (gotit) { TQSL_PROVIDER pdata; memset(&pdata, 0, sizeof pdata); pair rval = provider.getAttribute("organizationName"); if (!rval.second) { tQSL_Error = TQSL_PROVIDER_NOT_FOUND; tqslTrace("tqsl_load_provider_list", "Providers not found"); return 1; } strncpy(pdata.organizationName, rval.first.c_str(), sizeof pdata.organizationName); XMLElement item; if (provider.getFirstElement("organizationalUnitName", item)) strncpy(pdata.organizationalUnitName, item.getText().c_str(), sizeof pdata.organizationalUnitName); if (provider.getFirstElement("emailAddress", item)) strncpy(pdata.emailAddress, item.getText().c_str(), sizeof pdata.emailAddress); if (provider.getFirstElement("url", item)) strncpy(pdata.url, item.getText().c_str(), sizeof pdata.url); plist.push_back(pdata); gotit = providers.getNextElement(provider); if (gotit && provider.getElementName() != "provider") break; } return 0; } static XMLElement tCONTACT_sign; static int make_sign_data(TQSL_LOCATION *loc) { map field_data; // Loop through the location pages, getting field data // int old_page = loc->page; tqsl_setStationLocationCapturePage(loc, 1); do { TQSL_LOCATION_PAGE& p = loc->pagelist[loc->page-1]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD& f = p.fieldlist[i]; string s; if (f.input_type == TQSL_LOCATION_FIELD_DDLIST || f.input_type == TQSL_LOCATION_FIELD_LIST) { if (f.idx < 0 || f.idx >= static_cast(f.items.size())) s = ""; else s = f.items[f.idx].text; } else if (f.data_type == TQSL_LOCATION_FIELD_INT) { char buf[20]; snprintf(buf, sizeof buf, "%d", f.idata); s = buf; } else { s = f.cdata; } field_data[f.gabbi_name] = s; } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; tqsl_nextStationLocationCapture(loc); } while (1); tqsl_setStationLocationCapturePage(loc, old_page); loc->signdata = ""; loc->loc_details = ""; loc->sign_clean = false; XMLElement sigspecs; if (tqsl_get_xml_config_section("sigspecs", sigspecs)) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - it does not have a sigspecs section", sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } XMLElement sigspec; XMLElement ss; if (!sigspecs.getFirstElement("sigspec", sigspec)) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - it does not have a sigspec section", sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } ss = sigspec; bool ok; do { if (sigspec.getAttribute("status").first == "deprecated") { ok = sigspecs.getNextElement(sigspec); continue; } double ssver = atof(ss.getAttribute("version").first.c_str()); double newver = atof(sigspec.getAttribute("version").first.c_str()); if (newver > ssver) ss = sigspec; ok = sigspecs.getNextElement(sigspec); } while (ok); sigspec = ss; loc->sigspec = "SIGN_"; loc->sigspec += sigspec.getAttribute("name").first; loc->sigspec += "_V"; loc->sigspec += sigspec.getAttribute("version").first; tCONTACT_sign.clear(); if (!sigspec.getFirstElement("tCONTACT", tCONTACT_sign)) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - missing sigspec.tCONTACT", sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } if (tCONTACT_sign.getElementList().size() == 0) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - empty sigspec.tCONTACT", sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } XMLElement tSTATION; if (!sigspec.getFirstElement("tSTATION", tSTATION)) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - missing sigspec.tSTATION", sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } XMLElement specfield; if (!(ok = tSTATION.getFirstElement(specfield))) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - missing tSTATION.specfield", sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } do { string value = field_data[specfield.getElementName()]; value = trim(value); if (value == "") { pair attr = specfield.getAttribute("required"); if (attr.second && strtol(attr.first.c_str(), NULL, 10)) { string err = specfield.getElementName() + " field required by "; attr = sigspec.getAttribute("name"); if (attr.second) err += attr.first + " "; attr = sigspec.getAttribute("version"); if (attr.second) err += "V" + attr.first + " "; err += "signature specification not found"; tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, err.c_str(), sizeof tQSL_CustomError); tqslTrace("make_sign_data", "Error %s", tQSL_CustomError); return 1; } } else { loc->signdata += value; if (loc->loc_details != "") { loc->loc_details += ", "; } loc->loc_details += specfield.getElementName() + ": " + value; } ok = tSTATION.getNextElement(specfield); } while (ok); loc->sign_clean = true; return 0; } static int init_dxcc() { if (DXCCMap.size() > 0) return 0; tqslTrace("init_dxcc", NULL); XMLElement dxcc; if (tqsl_get_xml_config_section("dxcc", dxcc)) { tqslTrace("init_dxcc", "Error %d getting dxcc config section", tQSL_Error); return 1; } XMLElement dxcc_entity; bool ok = dxcc.getFirstElement("entity", dxcc_entity); while (ok) { pair rval = dxcc_entity.getAttribute("arrlId"); pair zval = dxcc_entity.getAttribute("zonemap"); pair strdate = dxcc_entity.getAttribute("valid"); pair enddate = dxcc_entity.getAttribute("invalid"); pair deleted = dxcc_entity.getAttribute("deleted"); if (rval.second) { int num = strtol(rval.first.c_str(), NULL, 10); DXCCMap[num] = dxcc_entity.getText(); DeletedMap[num] = false; if (deleted.second) { DeletedMap[num] = (deleted.first == "1"); } if (zval.second) { DXCCZoneMap[num] = zval.first; } tQSL_Date d; d.year = 1945; d.month = 11; d.day = 15; DXCCStartMap[num] = d; if (strdate.second) { if (!tqsl_initDate(&d, strdate.first.c_str())) { DXCCStartMap[num] = d; } } d.year = 0; d.month = 0; d.day = 0; DXCCEndMap[num] = d; if (enddate.second) { if (!tqsl_initDate(&d, enddate.first.c_str())) { DXCCEndMap[num] = d; } } DXCCList.push_back(make_pair(num, dxcc_entity.getText())); } ok = dxcc.getNextElement(dxcc_entity); } return 0; } static int init_band() { if (BandList.size() > 0) return 0; tqslTrace("init_band", NULL); XMLElement bands; if (tqsl_get_xml_config_section("bands", bands)) { tqslTrace("init_band", "Error %d getting bands", tQSL_Error); return 1; } XMLElement config_band; bool ok = bands.getFirstElement("band", config_band); while (ok) { Band b; b.name = config_band.getText(); b.spectrum = config_band.getAttribute("spectrum").first; b.low = strtol(config_band.getAttribute("low").first.c_str(), NULL, 10); b.high = strtol(config_band.getAttribute("high").first.c_str(), NULL, 10); BandList.push_back(b); ok = bands.getNextElement(config_band); } sort(BandList.begin(), BandList.end()); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getConfigVersion(int *major, int *minor) { if (tqsl_init()) return 1; if (tqsl_load_xml_config()) { tqslTrace("tqsl_getConfigVersion", "Error %d from tqsl_load_xml_config", tQSL_Error); return 1; } tqslTrace("tqsl_getConfigVersion", "major=%d, minor=%d", tqsl_xml_config_major, tqsl_xml_config_minor); if (major) *major = tqsl_xml_config_major; if (minor) *minor = tqsl_xml_config_minor; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumBand(int *number) { if (number == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tqslTrace("tqsl_getNumBand", NULL); if (init_band()) { tqslTrace("tqsl_getNumBand", "init_band error=%d", tQSL_Error); return 1; } *number = BandList.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getBand(int index, const char **name, const char **spectrum, int *low, int *high) { if (index < 0 || name == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_band()) { tqslTrace("tqsl_getBand", "init_band error=%d", tQSL_Error); return 1; } if (index >= static_cast(BandList.size())) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_getBand", "init_band arg error - index %d", index); return 1; } *name = BandList[index].name.c_str(); if (spectrum) *spectrum = BandList[index].spectrum.c_str(); if (low) *low = BandList[index].low; if (high) *high = BandList[index].high; return 0; } static int init_mode() { if (ModeList.size() > 0) return 0; XMLElement modes; if (tqsl_get_xml_config_section("modes", modes)) { tqslTrace("init_mode", "Error from tqsl_get_xml_config_section %d", tQSL_Error); return 1; } XMLElement config_mode; bool ok = modes.getFirstElement("mode", config_mode); while (ok) { Mode m; m.mode = config_mode.getText(); m.group = config_mode.getAttribute("group").first; ModeList.push_back(m); ok = modes.getNextElement(config_mode); } sort(ModeList.begin(), ModeList.end()); return 0; } static int init_propmode() { if (PropModeList.size() > 0) return 0; XMLElement propmodes; if (tqsl_get_xml_config_section("propmodes", propmodes)) { tqslTrace("init_propmode", "Error getting config section %d", tQSL_Error); return 1; } XMLElement config_mode; bool ok = propmodes.getFirstElement("propmode", config_mode); while (ok) { PropMode p; p.descrip = config_mode.getText(); p.name = config_mode.getAttribute("name").first; PropModeList.push_back(p); ok = propmodes.getNextElement(config_mode); } sort(PropModeList.begin(), PropModeList.end()); return 0; } static int init_satellite() { if (SatelliteList.size() > 0) return 0; XMLElement satellites; if (tqsl_get_xml_config_section("satellites", satellites)) { tqslTrace("init_satellite", "Error getting config section %d", tQSL_Error); return 1; } XMLElement config_sat; bool ok = satellites.getFirstElement("satellite", config_sat); while (ok) { Satellite s; s.descrip = config_sat.getText(); s.name = config_sat.getAttribute("name").first; tQSL_Date d; if (!tqsl_initDate(&d, config_sat.getAttribute("startDate").first.c_str())) s.start = d; if (!tqsl_initDate(&d, config_sat.getAttribute("endDate").first.c_str())) s.end = d; SatelliteList.push_back(s); ok = satellites.getNextElement(config_sat); } sort(SatelliteList.begin(), SatelliteList.end()); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumMode(int *number) { if (tqsl_init()) return 1; if (number == NULL) { tqslTrace("tqsl_getNumMode", "Argument error, number = 0x%lx", number); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_mode()) { tqslTrace("tqsl_getNumMode", "init_mode error %d", tQSL_Error); return 1; } *number = ModeList.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getMode(int index, const char **mode, const char **group) { if (index < 0 || mode == NULL) { tqslTrace("tqsl_getMode", "Arg error index=%d, mode=0x%lx, group=0x%lx", index, mode, group); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_mode()) { tqslTrace("tqsl_getMode", "init_mode error %d", tQSL_Error); return 1; } if (index >= static_cast(ModeList.size())) { tqslTrace("tqsl_getMode", "Argument error: %d", index); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *mode = ModeList[index].mode.c_str(); if (group) *group = ModeList[index].group.c_str(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumADIFMode(int *number) { if (tqsl_init()) return 1; if (number == NULL) { tqslTrace("tqsl_getNumADIFMode", "Argument error, number = 0x%lx", number); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_adif_map()) { tqslTrace("tqsl_getNumADIFMode", "init_mode error %d", tQSL_Error); return 1; } *number = tqsl_adif_mode_map.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry(int index, const char **mode) { if (tqsl_init()) return 1; if (mode == NULL) { tqslTrace("tqsl_getADIFMode", "Argument error, mode = 0x%lx", mode); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_adif_map()) { tqslTrace("tqsl_getADIFMode", "init_mode error %d", tQSL_Error); return 1; } if (index < 0 || index > static_cast (tqsl_adif_mode_map.size())) { tqslTrace("tqsl_getADIFMode", "Argument error, index = %d", index); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *mode = tqsl_adif_mode_map[index].c_str(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumDXCCEntity(int *number) { if (number == NULL) { tqslTrace("tqsl_getNumDXCCEntity", "Arg error - number=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getNumDXCCEntity", "init_dxcc error %d", tQSL_Error); return 1; } *number = DXCCList.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity(int index, int *number, const char **name) { if (index < 0 || name == NULL || number == NULL) { tqslTrace("tqsl_getDXCCEntity", "arg error index=%d, number = 0x%lx, name=0x%lx", index, number, name); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getDXCCEntity", "init_dxcc error %d", tQSL_Error); return 1; } if (index >= static_cast(DXCCList.size())) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_getDXCCEntity", "index range %d", index); return 1; } *number = DXCCList[index].first; *name = DXCCList[index].second.c_str(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName(int number, const char **name) { if (name == NULL) { tqslTrace("tqsl_getDXCCEntityName", "Name=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getDXCCEntityName", "init_dxcc error %d", tQSL_Error); return 1; } IntMap::const_iterator it; it = DXCCMap.find(number); if (it == DXCCMap.end()) { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } *name = it->second.c_str(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap(int number, const char **zonemap) { if (zonemap == NULL) { tqslTrace("tqsl_getDXCCZoneMap", "zonemap ptr null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getDXCCZoneMap", "init_dxcc error %d", tQSL_Error); return 1; } IntMap::const_iterator it; it = DXCCZoneMap.find(number); if (it == DXCCZoneMap.end()) { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } const char *map = it->second.c_str(); if (!map || map[0] == '\0') { *zonemap = NULL; } else { *zonemap = map; } return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDXCCStartDate(int number, tQSL_Date *d) { if (d == NULL) { tqslTrace("tqsl_getDXCCStartDate", "date ptr null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getDXCCStartDate", "init_dxcc error %d", tQSL_Error); return 1; } DateMap::const_iterator it; it = DXCCStartMap.find(number); if (it == DXCCStartMap.end()) { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } tQSL_Date newdate = it->second; *d = newdate; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDXCCEndDate(int number, tQSL_Date *d) { if (d == NULL) { tqslTrace("tqsl_getDXCCEndDate", "date ptr null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getDXCCEndDate", "init_dxcc error %d", tQSL_Error); return 1; } DateMap::const_iterator it; it = DXCCEndMap.find(number); if (it == DXCCEndMap.end()) { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } tQSL_Date newdate = it->second; *d = newdate; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted(int number, int *deleted) { if (deleted == NULL) { tqslTrace("tqsl_getDXCCDeleted", "Name=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_dxcc()) { tqslTrace("tqsl_getDXCCDeleted", "init_dxcc error %d", tQSL_Error); return 1; } *deleted = 0; BoolMap::const_iterator it; it = DeletedMap.find(number); if (it == DeletedMap.end()) { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } *deleted = it->second; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumPropagationMode(int *number) { if (tqsl_init()) return 1; if (number == NULL) { tqslTrace("tqsl_getNumPropagationMode", "number=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_propmode()) { tqslTrace("tqsl_getNumPropagationMode", "init_propmode error %d", tQSL_Error); return 1; } *number = PropModeList.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode(int index, const char **name, const char **descrip) { if (index < 0 || name == NULL) { tqslTrace("tqsl_getPropagationMode", "arg error index=%d name=0x%lx descrip=0x%lx", index, name, descrip); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_propmode()) { tqslTrace("tqsl_getPropagationMode", "init_propmode error %d", tQSL_Error); return 1; } if (index >= static_cast(PropModeList.size())) { tqslTrace("tqsl_getPropagationMode", "index out of range: %d", index); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *name = PropModeList[index].name.c_str(); if (descrip) *descrip = PropModeList[index].descrip.c_str(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumSatellite(int *number) { if (tqsl_init()) return 1; if (number == NULL) { tqslTrace("tqsl_getNumSatellite", "arg error number = null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_satellite()) { tqslTrace("tqsl_getNumSatellite", "init_satellite error %d", tQSL_Error); return 1; } *number = SatelliteList.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getSatellite(int index, const char **name, const char **descrip, tQSL_Date *start, tQSL_Date *end) { if (index < 0 || name == NULL) { tqslTrace("tqsl_getSatellite", "arg error index=%d name=0x%lx", index, name); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_satellite()) { tqslTrace("tqsl_getSatellite", "init_satellite error %d", tQSL_Error); return 1; } if (index >= static_cast(SatelliteList.size())) { tqslTrace("tqsl_getSatellite", "index error %d", index); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *name = SatelliteList[index].name.c_str(); if (descrip) *descrip = SatelliteList[index].descrip.c_str(); if (start) *start = SatelliteList[index].start; if (end) *end = SatelliteList[index].end; return 0; } static int init_cabrillo_map() { if (tqsl_cabrillo_map.size() > 0) return 0; XMLElement cabrillo_map; if (tqsl_get_xml_config_section("cabrillomap", cabrillo_map)) { tqslTrace("init_cabrillo_map", "get_xml_config_section error %d", tQSL_Error); return 1; } XMLElement cabrillo_item; bool ok = cabrillo_map.getFirstElement("cabrillocontest", cabrillo_item); int call_field = 0; int grid_field = 0; while (ok) { if (cabrillo_item.getText() != "") { call_field = strtol(cabrillo_item.getAttribute("field").first.c_str(), NULL, 10); grid_field = strtol(cabrillo_item.getAttribute("gridsquare").first.c_str(), NULL, 10); if (call_field > TQSL_MIN_CABRILLO_MAP_FIELD) { tqsl_cabrillo_map[cabrillo_item.getText()] = make_triplet(call_field - 1, grid_field - 1, (cabrillo_item.getAttribute("type").first == "VHF") ? TQSL_CABRILLO_VHF : TQSL_CABRILLO_HF); } } ok = cabrillo_map.getNextElement(cabrillo_item); } return 0; } DLLEXPORT int CALLCONVENTION tqsl_clearCabrilloMap() { tqslTrace("tqsl_clearCabrilloMap", NULL); tqsl_cabrillo_user_map.clear(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry(const char *contest, int field, int contest_type) { if (contest == NULL || field <= TQSL_MIN_CABRILLO_MAP_FIELD || (contest_type != TQSL_CABRILLO_HF && contest_type != TQSL_CABRILLO_VHF)) { tqslTrace("tqsl_setCabrilloMapEntry", "arg error contest=0x%lx field = %d", contest, field); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } tqsl_cabrillo_user_map[string_toupper(contest)] = make_pair(field-1, contest_type); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry(const char *contest, int *fieldnum, int *contest_type) { if (contest == NULL || fieldnum == NULL) { tqslTrace("tqsl_getCabrilloMapEntry", "arg error contest=0x%lx fieldnum = 0x%lx", contest, fieldnum); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_cabrillo_map()) { tqslTrace("tqsl_getCabrilloMapEntry", "init_cabrillo_map error %d", tQSL_Error); return 1; } map >::iterator it; map >::iterator uit; if ((uit = tqsl_cabrillo_user_map.find(string_toupper(contest))) == tqsl_cabrillo_user_map.end()) { if ((it = tqsl_cabrillo_map.find(string_toupper(contest))) == tqsl_cabrillo_map.end()) { *fieldnum = 0; return 0; } else { *fieldnum = it->second.first + 1 + ((it->second.middle + 1) * 1000); } if (contest_type) *contest_type = it->second.last; } else { *fieldnum = uit->second.first + 1; if (contest_type) *contest_type = uit->second.second; } return 0; } static int init_adif_map() { if (tqsl_adif_map.size() > 0) return 0; XMLElement adif_map; if (tqsl_get_xml_config_section("adifmap", adif_map)) { tqslTrace("init_adif_map", "tqsl_get_xml_config_section error %d", tQSL_Error); return 1; } XMLElement adif_item; bool ok = adif_map.getFirstElement("adifmode", adif_item); while (ok) { string adifmode = adif_item.getAttribute("adif-mode").first; string submode = adif_item.getAttribute("adif-submode").first; // Prefer the "mode=" attribute of the mode definition, else get the item value. string gabbi = adif_item.getAttribute("mode").first; string melem = adif_item.getText(); if (adifmode != "" && submode != "") { tqsl_adif_submode_map[melem] = adifmode + "%" + submode; } if (adifmode == "") { // Handle entries with just a mode element adifmode = melem; } bool found = false; for (unsigned int i = 0; i < tqsl_adif_mode_map.size(); i++) { if (tqsl_adif_mode_map[i] == melem) { found = true; } } if (!found) { tqsl_adif_mode_map.push_back(melem); } if (gabbi != "") { // There should always be one if (adifmode != "") { tqsl_adif_map[adifmode] = gabbi; } // Map this gabbi mode from submode if (submode != "" && submode != adifmode) { tqsl_adif_map[submode] = gabbi; } if (melem != "" && melem != adifmode) { tqsl_adif_map[melem] = gabbi; } // Add a mode%submode lookup too if (adifmode != "" && submode != "") { tqsl_adif_map[adifmode + "%" + submode] = gabbi; } } ok = adif_map.getNextElement(adif_item); } sort(tqsl_adif_mode_map.begin(), tqsl_adif_mode_map.end()); return 0; } DLLEXPORT int CALLCONVENTION tqsl_clearADIFModes() { tqsl_adif_map.clear(); tqsl_adif_mode_map.clear(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setADIFMode(const char *adif_item, const char *mode) { if (adif_item == NULL || mode == NULL) { tqslTrace("tqsl_setADIFMode", "arg error adif_item=0x%lx mode=0x%lx", adif_item, mode); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_adif_map()) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - ADIF map invalid", sizeof tQSL_CustomError); tqslTrace("tqslSetADIFMode", "Error %s", tQSL_CustomError); return 1; } string umode = string_toupper(mode); tqsl_adif_map[string_toupper(adif_item)] = umode; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getADIFMode(const char *adif_item, char *mode, int nmode) { if (adif_item == NULL || mode == NULL) { tqslTrace("tqsl_getADIFMode", "arg error adif_item=0x%lx, mode=0x%lx", adif_item, mode); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_adif_map()) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - ADIF map invalid", sizeof tQSL_CustomError); tqslTrace("tqsl_getADIFMode", "init_adif error %s", tQSL_CustomError); return 1; } string orig = adif_item; orig = string_toupper(orig); string amode; if (tqsl_adif_map.find(orig) != tqsl_adif_map.end()) { amode = tqsl_adif_map[orig]; } else { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } if (nmode < static_cast(amode.length())+1) { tqslTrace("tqsl_getAdifMode", "buffer error %s %s", nmode, amode.length()); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(mode, amode.c_str(), nmode); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode(const char *adif_item, char *mode, char *submode, int nmode) { if (adif_item == NULL || mode == NULL) { tqslTrace("tqsl_getADIFSubMode", "arg error adif_item=0x%lx, mode=0x%lx", adif_item, mode); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (init_adif_map()) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - ADIF map invalid", sizeof tQSL_CustomError); tqslTrace("tqsl_getADIFSubMode", "init_adif error %s", tQSL_CustomError); return 1; } string orig = adif_item; orig = string_toupper(orig); string amode; if (tqsl_adif_submode_map.find(orig) != tqsl_adif_submode_map.end()) { amode = tqsl_adif_submode_map[orig]; } else { tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } string adifmode = amode.substr(0, amode.find("%")); string adifsubmode = amode.substr(amode.find("%")+1); if (nmode < static_cast(amode.length())+1) { tqslTrace("tqsl_getAdifSubMode", "buffer error %s %s", nmode, amode.length()); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(mode, adifmode.c_str(), nmode); strncpy(submode, adifsubmode.c_str(), nmode); return 0; } static int init_loc_maps() { if (tqsl_field_map.size() > 0) return 0; XMLElement config_pages; if (tqsl_get_xml_config_section("locpages", config_pages)) { tqslTrace("init_loc_maps", "get_xml_config_section error %d", tQSL_Error); return 1; } XMLElement config_page; tqsl_page_map.clear(); bool ok; for (ok = config_pages.getFirstElement("page", config_page); ok; ok = config_pages.getNextElement(config_page)) { pair Id = config_page.getAttribute("Id"); int page_num = strtol(Id.first.c_str(), NULL, 10); if (!Id.second || page_num < 1) { // Must have the Id! tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - page missing ID", sizeof tQSL_CustomError); tqslTrace("init_loc_maps", "error %s", tQSL_CustomError); return 1; } tqsl_page_map[page_num] = config_page; } XMLElement config_fields; if (tqsl_get_xml_config_section("locfields", config_fields)) { tqslTrace("init_loc_maps", "get_xml_config_section locfields error %d", tQSL_Error); return 1; } XMLElement config_field; for (ok = config_fields.getFirstElement("field", config_field); ok; ok = config_fields.getNextElement(config_field)) { pair Id = config_field.getAttribute("Id"); if (!Id.second) { // Must have the Id! tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - field missing ID", sizeof tQSL_CustomError); tqslTrace("init_loc_maps", "config field error %s", tQSL_CustomError); return 1; } tqsl_field_map[Id.first] = config_field; } return 0; } static bool inMap(int cqvalue, int ituvalue, bool cqz, bool ituz, const char *map) { /* * Parse the zone map and return true if the value is a valid zone number * The maps are colon-separated number pairs, with a list of pairs comma separated. */ int cq, itu; bool result = false; // No map or empty string -> all match if (!map || map[0] == '\0') { return true; } char *mapcopy = strdup(map); char *state = NULL; char *mapPart = strtok_r(mapcopy, ",", &state); while (mapPart) { sscanf(mapPart, "%d:%d", &itu, &cq); if (cqz && ituz) { if ((cq == cqvalue || cqvalue == 0) && (itu == ituvalue || ituvalue == 0)) { result = true; break; } } else if (cqz && (cq == cqvalue || cqvalue == 0)) { result = true; break; } else if (ituz && (itu == ituvalue || ituvalue == 0)) { result = true; break; } mapPart = strtok_r(NULL, ",", &state); } free(mapcopy); return result; } static int _ent_cmp(const void *a, const void *b) { //was: //return strcasecmp(((struct _dxcc_entity *)a)->name, ((struct _dxcc_entity *)b)->name); char aname[128]; char bname[128]; struct _dxcc_entity* a1 = (struct _dxcc_entity *)a; struct _dxcc_entity* b1 = (struct _dxcc_entity *)b; /* * Terrible way to force the deleted entities to the * end of the list: add a 0x7f char to the front for * deleted and ^A for non-deleted. */ if (a1->deleted) { aname[0] = 0x7f; } else { aname[0] = 1; } if (b1->deleted) { bname[0] = 0x7f; } else { bname[0] = 1; } strncpy(aname + 1, a1->name, sizeof aname - 1); strncpy(bname + 1, b1->name, sizeof bname - 1); return strcasecmp(aname, bname); } static TQSL_LOCATION_FIELD * get_location_field_page(const string& gabbi, TQSL_LOCATION *loc, int* page = NULL) { for (int mypage = 1; mypage > 0; mypage = loc->pagelist[mypage-1].next) { TQSL_LOCATION_FIELDLIST& fl = loc->pagelist[mypage-1].fieldlist; for (int j = 0; j < static_cast(fl.size()); j++) { if (fl[j].gabbi_name == gabbi) { if (page) { *page = mypage; } return &(fl[j]); } } } return 0; } struct sasMap { const char *gabbi; const char *errstr; }; static struct sasMap sasMapping[] = { { "US_STATE", "Invalid zone selections for state" }, { "CA_PROVINCE", "Invalid zone selections for province" }, { "RU_OBLAST", "Invalid zone selections for oblast" }, { "CN_PROVINCE", "Invalid zone selections for province" }, { "AU_STATE", "Invalid zone selections for state" }, { "JA_PREFECTURE", "Invalid zone selections for prefecture" }, { "FI_KUNTA", "Invalid zone selections for kunta" }, { NULL, NULL } }; static TQSL_LOCATION_FIELD* get_primary_sub(TQSL_LOCATION* loc, string* errstr) { for (int i = 0; sasMapping[i].gabbi; i++) { TQSL_LOCATION_FIELD* temp = get_location_field_page(sasMapping[i].gabbi, loc); if (temp) { if (errstr) *errstr = sasMapping[i].errstr; return temp; } } return NULL; } static int find_next_page(TQSL_LOCATION *loc); static int update_page(int page, TQSL_LOCATION *loc) { TQSL_LOCATION_PAGE& p = loc->pagelist[page-1]; int dxcc; int current_entity = -1; int loaded_cqz = -1; int loaded_ituz = -1; TQSL_LOCATION_FIELD *cqz = get_location_field_page("CQZ", loc); TQSL_LOCATION_FIELD *ituz = get_location_field_page("ITUZ", loc); tqslTrace("update_page", "page=%d, loc=0x%lx", page, loc); for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD& field = p.fieldlist[i]; field.changed = false; if (field.gabbi_name == "CALL") { if (field.items.size() == 0 || loc->newflags) { // Build list of call signs from available certs field.changed = true; field.items.clear(); field.idx = 0; loc->newflags = false; field.flags = TQSL_LOCATION_FIELD_SELNXT; // Must be selected p.hash.clear(); tQSL_Cert *certlist; int ncerts; tqsl_selectCertificates(&certlist, &ncerts, 0, 0, 0, 0, loc->cert_flags); for (int i = 0; i < ncerts; i++) { char callsign[40]; tqsl_getCertificateCallSign(certlist[i], callsign, sizeof callsign); tqsl_getCertificateDXCCEntity(certlist[i], &dxcc); char ibuf[10]; snprintf(ibuf, sizeof ibuf, "%d", dxcc); bool found = false; // Only add a given DXCC entity to a call once. map >::iterator call_p; for (call_p = p.hash.begin(); call_p != p.hash.end(); call_p++) { if (call_p->first == callsign && call_p->second[0] == ibuf) { found = true; break; } } if (!found) p.hash[callsign].push_back(ibuf); } tqsl_freeCertificateList(certlist, ncerts); ncerts = 0; // Fill the call sign list map >::iterator call_p; field.idx = 0; TQSL_LOCATION_ITEM none; none.text = "[None]"; field.items.push_back(none); for (call_p = p.hash.begin(); call_p != p.hash.end(); call_p++) { TQSL_LOCATION_ITEM item; item.text = call_p->first; if (item.text == field.cdata) field.idx = static_cast(field.items.size()); field.items.push_back(item); } if (field.idx == 0 && field.items.size() == 2) { field.idx = 1; } if (field.idx >= 0) { field.cdata = field.items[field.idx].text; } } } else if (field.gabbi_name == "DXCC") { // Note: Expects CALL to be field 0 of this page. string call = p.fieldlist[0].cdata; if (field.items.size() == 0 || call != field.dependency) { // rebuild list field.changed = true; init_dxcc(); int olddxcc = strtol(field.cdata.c_str(), NULL, 10); if (loc->newDXCC != -1) { olddxcc = loc->newDXCC; loc->newDXCC = -1; } field.items.clear(); field.idx = 0; #ifdef DXCC_TEST const char *dxcc_test = getenv("TQSL_DXCC"); if (dxcc_test) { vector &entlist = p.hash[call]; char *parse_dxcc = strdup(dxcc_test); char *state = NULL; char *cp = strtok_r(parse_dxcc, ",", &state); while (cp) { if (find(entlist.begin(), entlist.end(), string(cp)) == entlist.end()) entlist.push_back(cp); cp = strtok_r(0, ",", &state); } free(parse_dxcc); } #endif if (call == "[None]") { int i; if (!_ent_init) { num_entities = DXCCMap.size(); entity_list = new struct _dxcc_entity[num_entities]; if (!entity_list) { tqslTrace("update_page", "Out of Memory for entity list!"); return 1; } IntMap::const_iterator it; for (it = DXCCMap.begin(), i = 0; it != DXCCMap.end(); it++, i++) { entity_list[i].number = it->first; entity_list[i].name = it->second.c_str(); entity_list[i].zonemap = DXCCZoneMap[it->first].c_str(); entity_list[i].start = DXCCStartMap[it->first]; entity_list[i].end = DXCCEndMap[it->first]; entity_list[i].deleted = DeletedMap[it->first]; } qsort(entity_list, num_entities, sizeof(struct _dxcc_entity), &_ent_cmp); _ent_init = true; } for (i = 0; i < num_entities; i++) { TQSL_LOCATION_ITEM item; item.ivalue = entity_list[i].number; char buf[10]; snprintf(buf, sizeof buf, "%d", item.ivalue); item.text = buf; item.label = entity_list[i].name; item.zonemap = entity_list[i].zonemap; if (item.ivalue == olddxcc) { field.idx = field.items.size(); } field.items.push_back(item); } field.idx = 0; } else { // This iterator walks the list of DXCC entities associated // with this callsign vector::iterator ip; TQSL_LOCATION_ITEM item; bool setIndex = false; for (ip = p.hash[call].begin(); ip != p.hash[call].end(); ip++) { item.text = *ip; item.ivalue = strtol(ip->c_str(), NULL, 10); IntMap::iterator dxcc_it = DXCCMap.find(item.ivalue); if (dxcc_it != DXCCMap.end()) { item.label = dxcc_it->second; item.zonemap = DXCCZoneMap[item.ivalue]; } if (item.ivalue == olddxcc) { field.idx = field.items.size(); setIndex = true; } field.items.push_back(item); } if (!setIndex) { field.idx = field.items.size()-1; } } if (field.items.size() > 0) { field.cdata = field.items[field.idx].text; } field.dependency = call; } // rebuild list } else { if (tqsl_field_map.find(field.gabbi_name) == tqsl_field_map.end()) { // Shouldn't happen! tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - field map mismatch.", sizeof tQSL_CustomError); tqslTrace("update_page", "field map error %s", field.gabbi_name.c_str()); return 1; } XMLElement config_field = tqsl_field_map.find(field.gabbi_name)->second; pair attr = config_field.getAttribute("dependsOn"); if (attr.first != "") { // Items list depends on other field TQSL_LOCATION_FIELD *fp = get_location_field_page(attr.first, loc); if (fp) { // Found the dependency field. Now find the enums to use string val = fp->cdata; if (fp->items.size() > 0) val = fp->items[fp->idx].text; if (val == field.dependency) continue; field.dependency = val; field.changed = true; field.items.clear(); string oldcdata = field.cdata; field.idx = 0; XMLElement enumlist; bool ok = config_field.getFirstElement("enums", enumlist); while (ok) { pair dependency = enumlist.getAttribute("dependency"); if (dependency.second && dependency.first == val) { if (!(field.flags & TQSL_LOCATION_FIELD_MUSTSEL)) { TQSL_LOCATION_ITEM item; item.label = "[None]"; field.items.push_back(item); } XMLElement enumitem; bool iok = enumlist.getFirstElement("enum", enumitem); while (iok) { TQSL_LOCATION_ITEM item; item.text = enumitem.getAttribute("value").first; item.label = enumitem.getText(); item.zonemap = enumitem.getAttribute("zonemap").first; field.items.push_back(item); if (item.text == oldcdata) { field.idx = field.items.size() - 1; } iok = enumlist.getNextElement(enumitem); } } ok = config_field.getNextElement(enumlist); } // enum loop } else { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - dependent field not found.", sizeof tQSL_CustomError); tqslTrace("update_page", "error %s", tQSL_CustomError); return 1; } } else { // No dependencies TQSL_LOCATION_FIELD *ent = get_location_field_page("DXCC", loc); current_entity = strtol(ent->cdata.c_str(), NULL, 10); bool isCQZ = field.gabbi_name == "CQZ"; bool isITUZ = field.gabbi_name == "ITUZ"; if (field.items.size() == 0 || (isCQZ && current_entity != loaded_cqz) || (isITUZ && current_entity != loaded_ituz)) { XMLElement enumlist; if (config_field.getFirstElement("enums", enumlist)) { field.items.clear(); field.idx = 0; string oldcdata = field.cdata; field.changed = true; if (!(field.flags & TQSL_LOCATION_FIELD_MUSTSEL)) { TQSL_LOCATION_ITEM item; item.label = "[None]"; field.items.push_back(item); } XMLElement enumitem; bool iok = enumlist.getFirstElement("enum", enumitem); while (iok) { TQSL_LOCATION_ITEM item; item.text = enumitem.getAttribute("value").first; item.label = enumitem.getText(); item.zonemap = enumitem.getAttribute("zonemap").first; field.items.push_back(item); if (item.text == oldcdata) { field.idx = field.items.size() - 1; } iok = enumlist.getNextElement(enumitem); } } else { // No enums supplied int ftype = strtol(config_field.getAttribute("intype").first.c_str(), NULL, 10); if (ftype == TQSL_LOCATION_FIELD_LIST || ftype == TQSL_LOCATION_FIELD_DDLIST) { // This a list field int lower = strtol(config_field.getAttribute("lower").first.c_str(), NULL, 10); int upper = strtol(config_field.getAttribute("upper").first.c_str(), NULL, 10); const char *zoneMap; /* Get the map */ if (tqsl_getDXCCZoneMap(current_entity, &zoneMap)) { zoneMap = NULL; } // Try for a zonemap from the primary subdivision TQSL_LOCATION_FIELD* pas = NULL; if (find_next_page(loc)) { pas = get_primary_sub(loc, NULL); } if (pas != NULL && pas->items.size() > 0 && (unsigned int) pas->idx < pas->items.size() && pas->items[pas->idx].zonemap != "") zoneMap = pas->items[pas->idx].zonemap.c_str(); if (upper < lower) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - field range order incorrect.", sizeof tQSL_CustomError); tqslTrace("update_page", "error %s", tQSL_CustomError); return 1; } field.items.clear(); field.idx = 0; string oldcdata = field.cdata; field.changed = true; int currentCQ = cqz->idata; int currentITU = ituz->idata; if (isCQZ) { loaded_cqz = current_entity; if (!inMap(0, currentITU, false, true, zoneMap)) { currentITU = 0; // Not valid here, ignore } } if (isITUZ) { loaded_ituz = current_entity; if (!inMap(currentCQ, 0, true, false, zoneMap)) { currentCQ = 0; // Not valid here, ignore } } if (!(field.flags & TQSL_LOCATION_FIELD_MUSTSEL)) { TQSL_LOCATION_ITEM item; item.label = "[None]"; field.items.push_back(item); } char buf[40]; for (int j = lower; j <= upper; j++) { bool zoneOK = true; if (zoneMap) { if (isCQZ) { zoneOK = inMap(j, currentITU, true, true, zoneMap); } if (isITUZ) { zoneOK = inMap(currentCQ, j, true, true, zoneMap); } } if (zoneOK) { snprintf(buf, sizeof buf, "%d", j); TQSL_LOCATION_ITEM item; item.text = buf; item.ivalue = j; field.items.push_back(item); if (item.text == oldcdata) { field.idx = field.items.size() - 1; } } } } // intype != TEXT } // enums supplied } // itemlist not empty and current entity } // no dependencies } // field name not CALL|DXCC } // field loop /* Sanity check zones */ bool zonesok = true; string zone_error = ""; int currentCQ = cqz->idata; int currentITU = ituz->idata; // Check each division, start from entity, then division TQSL_LOCATION_FIELD *entity = get_location_field_page("DXCC", loc); if (entity) { zone_error = "Invalid zone selections for DXCC entity"; if (entity && entity->idx >=0 && entity->items.size() > 0) { string dxzm = entity->items[entity->idx].zonemap; const char* dxccZoneMap = dxzm.c_str(); if (!inMap(currentCQ, currentITU, true, true, dxccZoneMap)) { zonesok = false; } } } // Entity is OK, try for the state/province/oblast TQSL_LOCATION_FIELD *state = get_primary_sub(loc, &zone_error); if (state && state->idx >=0 && state->items.size() > 0) { string szm = state->items[state->idx].zonemap; const char* stateZoneMap = szm.c_str(); if (!inMap(currentCQ, currentITU, true, true, stateZoneMap)) { zonesok = false; } } if (zonesok) { tQSL_CustomError[0] = '\0'; } else { strncpy(tQSL_CustomError, zone_error.c_str(), sizeof tQSL_CustomError); } p.complete = true; return 0; } static int make_page(TQSL_LOCATION_PAGELIST& pagelist, int page_num) { if (init_loc_maps()) { tqslTrace("make_page", "init_loc_maps error %d", tQSL_Error); return 1; } if (tqsl_page_map.find(page_num) == tqsl_page_map.end()) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - page reference could not be found.", sizeof tQSL_CustomError); tqslTrace("make_page", "Error %d %s", page_num, tQSL_CustomError); return 1; } TQSL_LOCATION_PAGE p; pagelist.push_back(p); XMLElement& config_page = tqsl_page_map[page_num]; pagelist.back().prev = strtol(config_page.getAttribute("follows").first.c_str(), NULL, 10); XMLElement config_pageField; bool field_ok = config_page.getFirstElement("pageField", config_pageField); while (field_ok) { string field_name = config_pageField.getText(); if (field_name == "" || tqsl_field_map.find(field_name) == tqsl_field_map.end()) { tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, "TQSL Configuration file invalid - page references undefined field.", sizeof tQSL_CustomError); tqslTrace("make_page", "Error %s", tQSL_CustomError); return 1; } XMLElement& config_field = tqsl_field_map[field_name]; TQSL_LOCATION_FIELD loc_field( field_name, config_field.getAttribute("label").first.c_str(), (config_field.getAttribute("type").first == "C") ? TQSL_LOCATION_FIELD_CHAR : TQSL_LOCATION_FIELD_INT, strtol(config_field.getAttribute("len").first.c_str(), NULL, 10), strtol(config_field.getAttribute("intype").first.c_str(), NULL, 10), strtol(config_field.getAttribute("flags").first.c_str(), NULL, 10) ); // NOLINT(whitespace/parens) pagelist.back().fieldlist.push_back(loc_field); field_ok = config_page.getNextElement(config_pageField); } return 0; } DLLEXPORT int CALLCONVENTION tqsl_initStationLocationCapture(tQSL_Location *locp) { if (tqsl_init()) return 1; if (locp == NULL) { tqslTrace("tqsl_initStationLocationCapture", "Arg error locp=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_LOCATION *loc = new TQSL_LOCATION; if (!loc) { tqslTrace("tqsl_initStataionLocationCapture", "Out of memory!"); return 1; } *locp = loc; if (init_loc_maps()) { tqslTrace("tqsl_initStationLocationCapture", "init_loc_maps error %d", tQSL_Error); return 1; } map::iterator pit; for (pit = tqsl_page_map.begin(); pit != tqsl_page_map.end(); pit++) { if (make_page(loc->pagelist, pit->first)) { tqslTrace("tqsl_initStationLocationCapture", "make_page error %d", tQSL_Error); return 1; } } loc->page = 1; if (update_page(1, loc)) { tqslTrace("tqsl_initStationLocationCapture", "updatePage error %d", tQSL_Error); return 1; } return 0; } DLLEXPORT int CALLCONVENTION tqsl_endStationLocationCapture(tQSL_Location *locp) { if (tqsl_init()) return 1; if (locp == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_endStationLocationCapture", "arg error locp=NULL"); return 1; } if (*locp == 0) return 0; if (CAST_TQSL_LOCATION(*locp)->sentinel == 0x5445) delete CAST_TQSL_LOCATION(*locp); *locp = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_updateStationLocationCapture(tQSL_Location locp) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_updateStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } // TQSL_LOCATION_PAGE &p = loc->pagelist[loc->page-1]; return update_page(loc->page, loc); } DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocationCapturePages(tQSL_Location locp, int *npages) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getNumStationLocationCapturePages", "check_loc error %d", tQSL_Error); return 1; } if (npages == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_getNumStationLocationCapturePages", "arg error npages=NULL"); return 1; } *npages = loc->pagelist.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCapturePage(tQSL_Location locp, int *page) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getStationLocationCapturePage", "check_loc error %d", tQSL_Error); return 1; } if (page == NULL) { tqslTrace("tqsl_getStationLocationCapturePage", "arg error page=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *page = loc->page; return 0; } DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCapturePage(tQSL_Location locp, int page) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_setStationLocationCapturePage", "check_loc error %d", tQSL_Error); return 1; } if (page < 1 || page > static_cast(loc->pagelist.size())) { tqslTrace("tqsl_setStationLocationCapturePage", "Page %d out of range", page); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } loc->page = page; return 0; } DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCertFlags(tQSL_Location locp, int flags) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_setStationLocationCertFlags", "check_loc error %d", tQSL_Error); return 1; } if (loc->cert_flags != flags) { loc->cert_flags = flags; loc->newflags = true; loc->page = 1; if (update_page(1, loc)) { tqslTrace("tqsl_setStationLocationCertFlags", "update_page error %d", tQSL_Error); return 1; } } return 0; } static int find_next_page(TQSL_LOCATION *loc) { // Set next page based on page dependencies TQSL_LOCATION_PAGE& p = loc->pagelist[loc->page-1]; map::iterator pit; p.next = 0; for (pit = tqsl_page_map.begin(); pit != tqsl_page_map.end(); pit++) { if (strtol(pit->second.getAttribute("follows").first.c_str(), NULL, 10) == loc->page) { string dependsOn = pit->second.getAttribute("dependsOn").first; string dependency = pit->second.getAttribute("dependency").first; if (dependsOn == "") { p.next = pit->first; return 1; // Found next page } TQSL_LOCATION_FIELD *fp = get_location_field_page(dependsOn, loc); if (static_cast(fp->items.size()) > fp->idx && fp->idx >= 0 && fp->items[fp->idx].text == dependency) { p.next = pit->first; return 1; // Found next page } } } return 0; } DLLEXPORT int CALLCONVENTION tqsl_nextStationLocationCapture(tQSL_Location locp) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_nextStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } if (!find_next_page(loc)) return 0; TQSL_LOCATION_PAGE &p = loc->pagelist[loc->page-1]; if (p.next > 0) loc->page = p.next; update_page(loc->page, loc); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNextStationLocationCapturePage(tQSL_Location locp, int *page) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp)) || page == NULL) { tqslTrace("tqsl_nextStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } if (!find_next_page(loc)) return 1; TQSL_LOCATION_PAGE &p = loc->pagelist[loc->page-1]; if (p.next > 0) { *page = p.next; return 0; } return 1; } DLLEXPORT int CALLCONVENTION tqsl_prevStationLocationCapture(tQSL_Location locp) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_prevStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_PAGE &p = loc->pagelist[loc->page-1]; if (p.prev > 0) loc->page = p.prev; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getPrevStationLocationCapturePage(tQSL_Location locp, int *page) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp)) || page == NULL) { tqslTrace("tqsl_getPrevStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_PAGE &p = loc->pagelist[loc->page-1]; if (p.prev > 0) { *page = p.prev; return 0; } return 1; } DLLEXPORT int CALLCONVENTION tqsl_getCurrentStationLocationCapturePage(tQSL_Location locp, int *page) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp)) || page == NULL) { tqslTrace("tqsl_getPrevStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } *page = loc->page; return 0; } DLLEXPORT int CALLCONVENTION tqsl_hasNextStationLocationCapture(tQSL_Location locp, int *rval) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_hasNextStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } if (rval == NULL) { tqslTrace("tqsl_hasNextStationLocationCapture", "Arg error rval=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (!find_next_page(loc)) { tqslTrace("tqsl_hasNextStationLocationCapture", "find_next_page error %d", tQSL_Error); return 1; } *rval = (loc->pagelist[loc->page-1].next > 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_hasPrevStationLocationCapture(tQSL_Location locp, int *rval) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_hasPrevStationLocationCapture", "check_loc error %d", tQSL_Error); return 1; } if (rval == NULL) { tqslTrace("tqsl_hasPrevStationLocationCapture", "arg error rval=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *rval = (loc->pagelist[loc->page-1].prev > 0); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField(tQSL_Location locp, int *numf) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getNumLocationField", "check_loc error %d", tQSL_Error); return 1; } if (numf == NULL) { tqslTrace("tqsl_getNumLocationField", "arg error numf=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; *numf = fl.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize(tQSL_Location locp, int field_num, int *rval) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldDataLabelSize", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (rval == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldDataLabelSize", "arg error rval=0x%lx, field_num=%d", rval, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *rval = fl[field_num].label.size()+1; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel(tQSL_Location locp, int field_num, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldDataLabel", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (buf == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldDataLabel", "arg error buf=0x%lx, field_num=%d", buf, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(buf, fl[field_num].label.c_str(), bufsiz); buf[bufsiz-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize(tQSL_Location locp, int field_num, int *rval) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldDataGABBISize", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (rval == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldDataGABBISize", "arg error rval=0x%lx, field_num=%d", rval, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *rval = fl[field_num].gabbi_name.size()+1; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI(tQSL_Location locp, int field_num, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldDataGABBI", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (buf == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldDataGABBI", "arg error buf=0x%lx, field_num=%d", buf, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(buf, fl[field_num].gabbi_name.c_str(), bufsiz); buf[bufsiz-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldInputType(tQSL_Location locp, int field_num, int *type) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldInputType", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (type == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldInputType", "arg error type=0x%lx, field_num=%d", type, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *type = fl[field_num].input_type; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldChanged(tQSL_Location locp, int field_num, int *changed) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldChanged", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (changed == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldChanged", "arg error changed=0x%lx, field_num=%d", changed, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *changed = fl[field_num].changed; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataType(tQSL_Location locp, int field_num, int *type) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldDataType", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (type == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldDataType", "arg error type=0x%lx, field_num=%d", type, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *type = fl[field_num].data_type; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldFlags(tQSL_Location locp, int field_num, int *flags) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldFlags", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (flags == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldFlags", "arg error flags=0x%lx, field_num=%d", flags, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *flags = fl[field_num].flags; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLength(tQSL_Location locp, int field_num, int *rval) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldDataLength", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (rval == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldDataLength", "arg error rval=0x%lx, field_num=%d", rval, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *rval = fl[field_num].data_len; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData(tQSL_Location locp, int field_num, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldCharData", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (buf == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldCharData", "arg error buf=0x%lx, field_num=%d", buf, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (fl[field_num].flags & TQSL_LOCATION_FIELD_UPPER) strncpy(buf, string_toupper(fl[field_num].cdata).c_str(), bufsiz); else strncpy(buf, fl[field_num].cdata.c_str(), bufsiz); buf[bufsiz-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIntData(tQSL_Location locp, int field_num, int *dat) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldIntData", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (dat == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldIntData", "arg error dat=0x%lx, field_num=%d", dat, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *dat = fl[field_num].idata; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIndex(tQSL_Location locp, int field_num, int *dat) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldIndex", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (dat == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_getLocationFieldIndex", "arg error dat=0x%lx, field_num=%d", dat, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (fl[field_num].input_type != TQSL_LOCATION_FIELD_DDLIST && fl[field_num].input_type != TQSL_LOCATION_FIELD_LIST) { tqslTrace("tqsl_getLocationFieldIndex", "arg error input type mismatch"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *dat = fl[field_num].idx; return 0; } DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldCharData(tQSL_Location locp, int field_num, const char *buf) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_setLocationFieldCharData", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (buf == NULL || field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_setLocationFieldCharData", "arg error buf=0x%lx, field_num=%d", buf, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } fl[field_num].cdata = string(buf).substr(0, fl[field_num].data_len); if (fl[field_num].flags & TQSL_LOCATION_FIELD_UPPER) fl[field_num].cdata = string_toupper(fl[field_num].cdata); if (fl[field_num].input_type == TQSL_LOCATION_FIELD_DDLIST || fl[field_num].input_type == TQSL_LOCATION_FIELD_LIST) { if (fl[field_num].cdata == "") { fl[field_num].idx = 0; fl[field_num].idata = fl[field_num].items[0].ivalue; } else { bool found = false; for (int i = 0; i < static_cast(fl[field_num].items.size()); i++) { if (fl[field_num].items[i].text == fl[field_num].cdata) { fl[field_num].idx = i; fl[field_num].idata = fl[field_num].items[i].ivalue; found = true; break; } } if (!found) { // There's no entry in the list that matches! fl[field_num].cdata = ""; fl[field_num].idx = 0; fl[field_num].idata = 0; } } } return 0; } /* Set the field's index. For pick lists, this is the index into * 'items'. In that case, also set the field's data to the picked value. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIndex(tQSL_Location locp, int field_num, int dat) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_setLocationFieldIndex", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_setLocationFieldIndex", "arg error index out of range page %d size %d - field_num=%d, dat=%d", loc->page, fl.size(), field_num, dat); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } fl[field_num].idx = dat; if (fl[field_num].input_type == TQSL_LOCATION_FIELD_DDLIST || fl[field_num].input_type == TQSL_LOCATION_FIELD_LIST) { if (dat >= 0 && dat < static_cast(fl[field_num].items.size())) { fl[field_num].idx = dat; fl[field_num].cdata = fl[field_num].items[dat].text; fl[field_num].idata = fl[field_num].items[dat].ivalue; } else { tqslTrace("tqsl_setLocationFieldIndex", "arg error page %d field_num=%d dat=%d", loc->page, field_num, dat); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } } return 0; } /* Set the field's integer data. */ DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIntData(tQSL_Location locp, int field_num, int dat) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_setLocationFieldIntData", "check_loc error %d", tQSL_Error); return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (field_num < 0 || field_num >= static_cast(fl.size())) { tqslTrace("tqsl_setLocationFieldIntData", "arg error field_num=%d, dat=%d", field_num, dat); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } fl[field_num].idata = dat; return 0; } /* For pick lists, this is the index into * 'items'. In that case, also set the field's char data to the picked value. */ DLLEXPORT int CALLCONVENTION tqsl_getNumLocationFieldListItems(tQSL_Location locp, int field_num, int *rval) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getNumLocationFieldListItems", "check_loc error %d", tQSL_Error); return 1; } if (rval == NULL) { tqslTrace("tqsl_getNumLocationFieldListItems", "arg error rval=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; *rval = fl[field_num].items.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem(tQSL_Location locp, int field_num, int item_idx, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getLocationFieldListItem", "check_loc error %d", tQSL_Error); return 1; } bool findKey = false; if (item_idx & 0x10000) { findKey = true; item_idx &= 0xffff; } TQSL_LOCATION_FIELDLIST &fl = loc->pagelist[loc->page-1].fieldlist; if (buf == NULL || field_num < 0 || field_num >= static_cast(fl.size()) || (fl[field_num].input_type != TQSL_LOCATION_FIELD_LIST && fl[field_num].input_type != TQSL_LOCATION_FIELD_DDLIST)) { tqslTrace("tqsl_getLocationFieldListItem", "arg error buf=0x%lx, field_num=%d", buf, field_num); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (item_idx < 0 || item_idx >= static_cast(fl[field_num].items.size())) { tqslTrace("tqsl_getLocationFieldListItem", "arg error item_idx=%d", item_idx); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (findKey) { strncpy(buf, fl[field_num].items[item_idx].text.c_str(), bufsiz); } else { string& str = (fl[field_num].items[item_idx].label == "") ? fl[field_num].items[item_idx].text : fl[field_num].items[item_idx].label; strncpy(buf, str.c_str(), bufsiz); } buf[bufsiz - 1] = '\0'; return 0; } static string tqsl_station_data_filename(bool deleted = false) { const char *f; if (deleted) f = "station_data_trash"; else f = "station_data"; string s = tQSL_BaseDir; #ifdef _WIN32 s += "\\"; #else s += "/"; #endif s += f; return s; } static int tqsl_load_station_data(XMLElement &xel, bool deleted = false) { int status = xel.parseFile(tqsl_station_data_filename(deleted).c_str()); tqslTrace("tqsl_load_station_data", "file %s parse status %d", tqsl_station_data_filename(deleted).c_str(), status); if (status) { if (errno == ENOENT) { // If there's no file, no error. tqslTrace("tqsl_load_station_data", "File does not exist"); return 0; } strncpy(tQSL_ErrorFile, tqsl_station_data_filename(deleted).c_str(), sizeof tQSL_ErrorFile); if (status == XML_PARSE_SYSTEM_ERROR) { tQSL_Error = TQSL_FILE_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_load_station_data", "parse error, errno=%d", tQSL_Errno); } else { tqslTrace("tqsl_load_station_data", "syntax error"); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; } return 1; } return status; } static int tqsl_dump_station_data(XMLElement &xel, bool deleted = false) { ofstream out; string fn = tqsl_station_data_filename(deleted); out.exceptions(ios::failbit | ios::eofbit | ios::badbit); try { #ifdef _WIN32 wchar_t* wfn = utf8_to_wchar(fn.c_str()); out.open(wfn); free_wchar(wfn); #else out.open(fn.c_str()); #endif out << xel << endl; out.close(); } catch(exception& x) { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Unable to save new station location file (%s): %s/%s", fn.c_str(), x.what(), strerror(errno)); tqslTrace("tqsl_dump_station_data", "file error %s %s", fn.c_str(), tQSL_CustomError); return 1; } return 0; } static int tqsl_load_loc(TQSL_LOCATION *loc, XMLElementList::iterator ep, bool ignoreZones) { bool exists; loc->page = 1; loc->data_errors[0] = '\0'; int bad_ituz = 0; int bad_cqz = 0; tqslTrace("tqsl_load_loc", NULL); while(1) { TQSL_LOCATION_PAGE& page = loc->pagelist[loc->page-1]; for (int fidx = 0; fidx < static_cast(page.fieldlist.size()); fidx++) { TQSL_LOCATION_FIELD& field = page.fieldlist[fidx]; if (field.gabbi_name != "") { // A field that may exist XMLElement el; if (ep->second->getFirstElement(field.gabbi_name, el)) { field.cdata = el.getText(); switch (field.input_type) { case TQSL_LOCATION_FIELD_DDLIST: case TQSL_LOCATION_FIELD_LIST: exists = false; for (int i = 0; i < static_cast(field.items.size()); i++) { string cp = field.items[i].text; int q = strcasecmp(field.cdata.c_str(), cp.c_str()); if (q == 0) { field.idx = i; field.cdata = cp; field.idata = field.items[i].ivalue; exists = true; break; } } if (!exists) { if (field.gabbi_name == "CQZ") bad_cqz = strtol(field.cdata.c_str(), NULL, 10); else if (field.gabbi_name == "ITUZ") bad_ituz = strtol(field.cdata.c_str(), NULL, 10); else if (field.gabbi_name == "CALL" || field.gabbi_name == "DXCC") field.idx = -1; } break; case TQSL_LOCATION_FIELD_TEXT: field.cdata = trim(field.cdata); if (field.data_type == TQSL_LOCATION_FIELD_INT) field.idata = strtol(field.cdata.c_str(), NULL, 10); break; } } } if (update_page(loc->page, loc)) return 1; } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; tqsl_nextStationLocationCapture(loc); } if (ignoreZones) return 0; if (bad_cqz && bad_ituz) { snprintf(loc->data_errors, sizeof(loc->data_errors), "This station location is configured with invalid CQ zone %d and invalid ITU zone %d.", bad_cqz, bad_ituz); } else if (bad_cqz) { snprintf(loc->data_errors, sizeof(loc->data_errors), "This station location is configured with invalid CQ zone %d.", bad_cqz); } else if (bad_ituz) { snprintf(loc->data_errors, sizeof(loc->data_errors), "This station location is configured with invalid ITU zone %d.", bad_ituz); } tqslTrace("tqsl_load_loc", "data_errors=%s", loc->data_errors); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getStationDataEnc(tQSL_StationDataEnc *sdata) { char *dbuf = NULL; size_t dlen = 0; gzFile in = NULL; #ifdef _WIN32 wchar_t *fn = utf8_to_wchar(tqsl_station_data_filename().c_str()); int fd = _wopen(fn, _O_RDONLY|_O_BINARY); free_wchar(fn); if (fd != -1) in = gzdopen(fd, "rb"); #else in = gzopen(tqsl_station_data_filename().c_str(), "rb"); #endif if (!in) { if (errno == ENOENT) { *sdata = NULL; tqslTrace("tqsl_getStationDataEnc", "File %s does not exist", tqsl_station_data_filename().c_str()); return 0; } tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; strncpy(tQSL_ErrorFile, tqsl_station_data_filename().c_str(), sizeof tQSL_ErrorFile); tqslTrace("tqsl_getStationDataEnc", "File %s open error %s", tqsl_station_data_filename().c_str(), strerror(tQSL_Error) ); return 1; } char buf[2048]; int rcount; while ((rcount = gzread(in, buf, sizeof buf)) > 0) { dlen += rcount; } dbuf = reinterpret_cast(malloc(dlen + 2)); if (!dbuf) { tqslTrace("tqsl_getStationDataEnc", "memory allocation error %d", dlen+2); return 1; } *sdata = dbuf; gzrewind(in); while ((rcount = gzread(in, dbuf, sizeof buf)) > 0) { dbuf += rcount; } *dbuf = '\0'; gzclose(in); return 0; } DLLEXPORT int CALLCONVENTION tqsl_freeStationDataEnc(tQSL_StationDataEnc sdata) { if (sdata) free(sdata); return 0; //can never fail } DLLEXPORT int CALLCONVENTION tqsl_mergeStationLocations(const char *locdata) { XMLElement new_data; XMLElement old_data; XMLElement new_top_el; XMLElement old_top_el; vector locnames; tqslTrace("tqsl_mergeStationLocations", NULL); // Load the current station data if (tqsl_load_station_data(old_top_el)) { tqslTrace("tqsl_mergeStationLocations", "error loading station data"); return 1; } // Parse the data to be merged new_top_el.parseString(locdata); if (!new_top_el.getFirstElement(new_data)) new_data.setElementName("StationDataFile"); if (!old_top_el.getFirstElement(old_data)) old_data.setElementName("StationDataFile"); // Build a list of existing station locations XMLElementList& namelist = old_data.getElementList(); XMLElementList::iterator nameiter; XMLElement locname; for (nameiter = namelist.find("StationData"); nameiter != namelist.end(); nameiter++) { if (nameiter->first != "StationData") break; pair rval = nameiter->second->getAttribute("name"); if (rval.second) { locnames.push_back(rval.first); } } // Iterate the new locations XMLElementList& ellist = new_data.getElementList(); XMLElementList::iterator ep; old_data.setPretext(old_data.getPretext() + " "); for (ep = ellist.find("StationData"); ep != ellist.end(); ep++) { if (ep->first != "StationData") break; pair rval = ep->second->getAttribute("name"); bool found = false; if (rval.second) { for (size_t j = 0; j < locnames.size(); j++) { if (locnames[j] == rval.first) { found = true; break; } } } if (!found) { // Add this one to the station data file XMLElement *newtop = new XMLElement("StationData"); if (!newtop) { tqslTrace("tqsl_mergeStationLocations", "Out of memory!"); return 1; } newtop->setPretext("\n "); newtop->setAttribute("name", rval.first); newtop->setText("\n "); XMLElement el; bool elok = ep->second->getFirstElement(el); while (elok) { XMLElement *sub = new XMLElement; if (!sub) { tqslTrace("tqsl_mergeStationLocations", "Out of memory!!"); return 1; } sub->setPretext(newtop->getPretext() + " "); sub->setElementName(el.getElementName()); sub->setText(el.getText()); newtop->addElement(sub); elok = ep->second->getNextElement(el); } old_data.addElement(newtop); old_data.setText("\n"); } } return tqsl_dump_station_data(old_data); } // Move a station location to or from the trash static int tqsl_move_station_location(const char *name, bool fromtrash) { tqslTrace("tqsl_move_station_location", "name=%s, fromtrash=%d", name, fromtrash); XMLElement from_top_el; XMLElement to_top_el; if (tqsl_load_station_data(from_top_el, fromtrash)) { tqslTrace("tqsl_move_station_location", "error %d loading data", tQSL_Error); return 1; } if (tqsl_load_station_data(to_top_el, !fromtrash)) { tqslTrace("tqsl_move_station_location", "error %d loading data", tQSL_Error); return 1; } XMLElement from_sfile; XMLElement to_sfile; if (!from_top_el.getFirstElement(from_sfile)) from_sfile.setElementName("StationDataFile"); if (!to_top_el.getFirstElement(to_sfile)) to_sfile.setElementName("StationDataFile"); XMLElementList& from_ellist = from_sfile.getElementList(); XMLElementList::iterator from_ep; for (from_ep = from_ellist.find("StationData"); from_ep != from_ellist.end(); from_ep++) { if (from_ep->first != "StationData") break; pair from_rval = from_ep->second->getAttribute("name"); if (from_rval.second && !strcasecmp(from_rval.first.c_str(), name)) { // Match, move it. // First, delete any old backup for this station location XMLElementList& to_ellist = to_sfile.getElementList(); XMLElementList::iterator to_ep; for (to_ep = to_ellist.find("StationData"); to_ep != to_ellist.end(); to_ep++) { if (to_ep->first != "StationData") break; pair to_rval = to_ep->second->getAttribute("name"); if (to_rval.second && !strcasecmp(to_rval.first.c_str(), name)) { to_ellist.erase(to_ep); break; } } // Now add it to the target XMLElement *newtop = new XMLElement("StationData"); if (!newtop) { tqslTrace("tqsl_moveStationLocation", "Out of memory!"); return 1; } newtop->setPretext("\n "); newtop->setAttribute("name", from_rval.first); newtop->setText("\n "); XMLElement el; bool elok = from_ep->second->getFirstElement(el); while (elok) { XMLElement *sub = new XMLElement; if (!sub) { tqslTrace("tqsl_moveStationLocation", "Out of memory!!"); return 1; } sub->setPretext(newtop->getPretext() + " "); sub->setElementName(el.getElementName()); sub->setText(el.getText()); newtop->addElement(sub); elok = from_ep->second->getNextElement(el); } to_sfile.addElement(newtop); to_sfile.setText("\n"); tqsl_dump_station_data(to_sfile, !fromtrash); from_ellist.erase(from_ep); return tqsl_dump_station_data(from_sfile, fromtrash); } } tqslTrace("tqsl_move_station_location", "location not found"); tQSL_Error = TQSL_LOCATION_NOT_FOUND; tQSL_CustomError[0] = '\0'; return 1; } DLLEXPORT int CALLCONVENTION tqsl_deleteStationLocation(const char *name) { tqslTrace("tqsl_deleteStationLocation", "name=%s", name); return tqsl_move_station_location(name, false); } DLLEXPORT int CALLCONVENTION tqsl_restoreStationLocation(const char *name) { tqslTrace("tqsl_restoreStationLocation", "name=%s", name); return tqsl_move_station_location(name, true); } DLLEXPORT int CALLCONVENTION tqsl_getStationLocation(tQSL_Location *locp, const char *name) { if (tqsl_initStationLocationCapture(locp)) { tqslTrace("tqsl_getStationLocation", "name=%s error=%d", name, tQSL_Error); return 1; } TQSL_LOCATION *loc; if (!(loc = check_loc(*locp))) { tqslTrace("tqsl_getStationLocation", "loc error %d", tQSL_Error); return 1; } loc->name = name; XMLElement top_el; if (tqsl_load_station_data(top_el)) { tqslTrace("tqsl_getStationLocation", "load station data error %d", tQSL_Error); return 1; } XMLElement sfile; if (!top_el.getFirstElement(sfile)) sfile.setElementName("StationDataFile"); XMLElementList& ellist = sfile.getElementList(); bool exists = false; XMLElementList::iterator ep; for (ep = ellist.find("StationData"); ep != ellist.end(); ep++) { if (ep->first != "StationData") break; pair rval = ep->second->getAttribute("name"); if (rval.second && !strcasecmp(trim(rval.first).c_str(), trim(loc->name).c_str())) { exists = true; break; } } if (!exists) { tQSL_Error = TQSL_LOCATION_NOT_FOUND; strncpy(tQSL_CustomError, name, sizeof tQSL_CustomError); tqslTrace("tqsl_getStationLocation", "location %s does not exist", name); return 1; } int rval = tqsl_load_loc(loc, ep, false); top_el.clear(); return rval; } DLLEXPORT int CALLCONVENTION tqsl_getStationLocationErrors(tQSL_Location locp, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getStationLocation", "loc error %d", tQSL_Error); return 1; } if (buf == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; tqslTrace("tqsl_getStationLocation", "buf = NULL"); return 1; } strncpy(buf, loc->data_errors, bufsiz); buf[bufsiz-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocations(tQSL_Location locp, int *nloc) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getNumStationLocations", "loc error %d", tQSL_Error); return 1; } if (nloc == NULL) { tqslTrace("tqsl_getNumStationLocations", "arg error nloc=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } loc->names.clear(); XMLElement top_el; if (tqsl_load_station_data(top_el)) { tqslTrace("tqsl_getNumStationLocations", "error %d loading station data", tQSL_Error); return 1; } XMLElement sfile; if (top_el.getFirstElement(sfile)) { XMLElement sd; bool ok = sfile.getFirstElement("StationData", sd); while (ok && sd.getElementName() == "StationData") { pair name = sd.getAttribute("name"); if (name.second) { XMLElement xc; string call; if (sd.getFirstElement("CALL", xc)) call = xc.getText(); loc->names.push_back(TQSL_NAME(name.first, call)); } ok = sfile.getNextElement(sd); } } *nloc = loc->names.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getStationLocationName(tQSL_Location locp, int idx, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getStationLocationName", "loc error %d", tQSL_Error); return 1; } if (buf == NULL || idx < 0 || idx >= static_cast(loc->names.size())) { tqslTrace("tqsl_getStationLocationName", "arg error buf=0x%lx, idx=%d", buf, idx); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(buf, loc->names[idx].name.c_str(), bufsiz); buf[bufsiz-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCallSign(tQSL_Location locp, int idx, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getStationLocationCallSign", "loc error %d", tQSL_Error); return 1; } if (buf == NULL || idx < 0 || idx >= static_cast(loc->names.size())) { tqslTrace("tqsl_getStationLocationCallSign", "arg error buf=0x%lx, idx=%d", buf, idx); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(buf, loc->names[idx].call.c_str(), bufsiz); buf[bufsiz-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField(tQSL_Location locp, const char *name, char *namebuf, int bufsize) { int old_page; TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getStationLocationField", "loc error %d", tQSL_Error); return 1; } if (name == NULL || namebuf == NULL) { tqslTrace("tqsl_getStationLocationField", "arg error name=0x%lx, namebuf=0x%lx", name, namebuf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (tqsl_getStationLocationCapturePage(loc, &old_page)) { tqslTrace("tqsl_getStationLocationField", "get cap page error %d", tQSL_Error); return 1; } string find = name; tqsl_setStationLocationCapturePage(loc, 1); do { int numf; if (tqsl_getNumLocationField(loc, &numf)) { tqslTrace("tqsl_getStationLocationField", "error getting num fields %d", tQSL_Error); return 1; } for (int i = 0; i < numf; i++) { TQSL_LOCATION_FIELD& field = loc->pagelist[loc->page-1].fieldlist[i]; if (find == field.gabbi_name) { // Found it switch (field.input_type) { case TQSL_LOCATION_FIELD_DDLIST: case TQSL_LOCATION_FIELD_LIST: if (field.data_type == TQSL_LOCATION_FIELD_INT) { char numbuf[20]; if (static_cast(field.items.size()) <= field.idx) { strncpy(namebuf, field.cdata.c_str(), bufsize); } else if (field.idx == 0 && field.items[field.idx].label == "[None]") { strncpy(namebuf, "", bufsize); } else { snprintf(numbuf, sizeof numbuf, "%d", field.items[field.idx].ivalue); strncpy(namebuf, numbuf, bufsize); } } else if (field.idx < 0 || field.idx >= static_cast(field.items.size())) { // Allow CALL to not be in the items list if (field.idx == -1 && i == 0) strncpy(namebuf, field.cdata.c_str(), bufsize); else strncpy(namebuf, "", bufsize); } else { if (field.items[field.idx].label == "") { strncpy(namebuf, field.items[field.idx].text.c_str(), bufsize); } else { strncpy(namebuf, field.items[field.idx].label.c_str(), bufsize); } } break; case TQSL_LOCATION_FIELD_TEXT: field.cdata = trim(field.cdata); if (field.flags & TQSL_LOCATION_FIELD_UPPER) field.cdata = string_toupper(field.cdata); strncpy(namebuf, field.cdata.c_str(), bufsize); break; } goto done; } } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; if (tqsl_nextStationLocationCapture(loc)) { tqslTrace("tqsl_getStationLocationField", "error in nextStationLocationCapture %d", tQSL_Error); return 1; } } while (1); strncpy(namebuf, "", bufsize); // Did not find it done: tqsl_setStationLocationCapturePage(loc, old_page); return 0; } static int tqsl_location_to_xml(TQSL_LOCATION *loc, XMLElement& sd) { int old_page; if (tqsl_getStationLocationCapturePage(loc, &old_page)) { tqslTrace("tqsl_location_to_xml", "get_sta_loc_cap_page error %d", tQSL_Error); return 1; } tqsl_setStationLocationCapturePage(loc, 1); do { int numf; if (tqsl_getNumLocationField(loc, &numf)) { tqslTrace("tqsl_location_to_xml", "get num loc field error %d", tQSL_Error); return 1; } for (int i = 0; i < numf; i++) { TQSL_LOCATION_FIELD& field = loc->pagelist[loc->page-1].fieldlist[i]; XMLElement *fd = new XMLElement; if (!fd) { tqslTrace("tqsl_location_to_xml", "Out of memory!"); return 1; } fd->setPretext(sd.getPretext() + " "); fd->setElementName(field.gabbi_name); switch (field.input_type) { case TQSL_LOCATION_FIELD_DDLIST: case TQSL_LOCATION_FIELD_LIST: if (field.idx < 0 || field.idx >= static_cast(field.items.size())) { fd->setText(""); if (field.gabbi_name == "CALL") { fd->setText("NONE"); } } else if (field.data_type == TQSL_LOCATION_FIELD_INT) { char numbuf[20]; snprintf(numbuf, sizeof numbuf, "%d", field.items[field.idx].ivalue); fd->setText(numbuf); } else { fd->setText(field.items[field.idx].text); } break; case TQSL_LOCATION_FIELD_TEXT: field.cdata = trim(field.cdata); if (field.flags & TQSL_LOCATION_FIELD_UPPER) field.cdata = string_toupper(field.cdata); fd->setText(field.cdata); break; } if (strcmp(fd->getText().c_str(), "")) sd.addElement(fd); } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; if (tqsl_nextStationLocationCapture(loc)) return 1; } while (1); tqsl_setStationLocationCapturePage(loc, old_page); return 0; } DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCaptureName(tQSL_Location locp, const char *name) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_setStationLocationCaptureName", "loc error %d", tQSL_Error); return 1; } if (name == NULL) { tqslTrace("tqsl_setStationLocationCaptureName", "arg error name=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } loc->name = name; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCaptureName(tQSL_Location locp, char *namebuf, int bufsize) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_getStationLocationCaptureName", "loc error %d", tQSL_Error); return 1; } if (namebuf == NULL) { tqslTrace("tqsl_getStationLocationCaptureName", "arg error namebuf=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(namebuf, loc->name.c_str(), bufsize); namebuf[bufsize-1] = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_saveStationLocationCapture(tQSL_Location locp, int overwrite) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp))) { tqslTrace("tqsl_saveStationLocationCaptureName", "loc error %d", tQSL_Error); return 1; } if (loc->name == "") { tqslTrace("tqsl_saveStationLocationCaptureName", "name empty"); tQSL_Error = TQSL_EXPECTED_NAME; return 1; } XMLElement top_el; if (tqsl_load_station_data(top_el)) { tqslTrace("tqsl_saveStationLocationCaptureName", "error %d loading station data", tQSL_Error); return 1; } XMLElement sfile; if (!top_el.getFirstElement(sfile)) sfile.setElementName("StationDataFile"); XMLElementList& ellist = sfile.getElementList(); bool exists = false; XMLElementList::iterator ep; for (ep = ellist.find("StationData"); ep != ellist.end(); ep++) { if (ep->first != "StationData") break; pair rval = ep->second->getAttribute("name"); if (rval.second && !strcasecmp(rval.first.c_str(), loc->name.c_str())) { exists = true; break; } } if (exists && !overwrite) { tqslTrace("tqsl_saveStationLocationCaptureName", "exists, no overwrite"); tQSL_Error = TQSL_NAME_EXISTS; return 1; } XMLElement *sd = new XMLElement("StationData"); if (!sd) { tqslTrace("tqsl_saveStationLocationCapture", "Out of memory!"); return 1; } sd->setPretext("\n "); if (tqsl_location_to_xml(loc, *sd)) { tqslTrace("tqsl_saveStationLocationCaptureName", "error in loc_to_xml %d", tQSL_Error); return 1; } sd->setAttribute("name", loc->name); sd->setText("\n "); // If 'exists', ep points to the existing station record if (exists) ellist.erase(ep); sfile.addElement(sd); sfile.setText("\n"); return tqsl_dump_station_data(sfile); } DLLEXPORT int CALLCONVENTION tqsl_signQSORecord(tQSL_Cert cert, tQSL_Location locp, TQSL_QSO_RECORD *rec, unsigned char *sig, int *siglen) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_signQSORecord", "loc error %d", tQSL_Error); return 1; } if (make_sign_data(loc)) { tqslTrace("tqsl_signQSORecord", "error %d making sign data", tQSL_Error); return 1; } XMLElement specfield; bool ok = tCONTACT_sign.getFirstElement(specfield); string rec_sign_data = loc->signdata; while (ok) { string eln = specfield.getElementName(); const char *elname = eln.c_str(); const char *value = 0; char buf[100]; if (!strcmp(elname, "CALL")) { value = rec->callsign; } else if (!strcmp(elname, "BAND")) { value = rec->band; } else if (!strcmp(elname, "BAND_RX")) { value = rec->rxband; } else if (!strcmp(elname, "MODE")) { value = rec->mode; } else if (!strcmp(elname, "FREQ")) { value = rec->freq; } else if (!strcmp(elname, "FREQ_RX")) { value = rec->rxfreq; } else if (!strcmp(elname, "PROP_MODE")) { value = rec->propmode; } else if (!strcmp(elname, "SAT_NAME")) { value = rec->satname; } else if (!strcmp(elname, "QSO_DATE")) { if (tqsl_isDateValid(&(rec->date))) value = tqsl_convertDateToText(&(rec->date), buf, sizeof buf); } else if (!strcmp(elname, "QSO_TIME")) { if (tqsl_isTimeValid(&(rec->time))) value = tqsl_convertTimeToText(&(rec->time), buf, sizeof buf); } else { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Unknown field in signing specification: %s", elname); tqslTrace("tqsl_signQSORecord", "field err %s", tQSL_CustomError); return 1; } if (value == 0 || value[0] == 0) { pair attr = specfield.getAttribute("required"); if (attr.second && strtol(attr.first.c_str(), NULL, 10)) { string err = specfield.getElementName() + " field required by signature specification not found"; tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, err.c_str(), sizeof tQSL_CustomError); tqslTrace("tqsl_signQSORecord", "val err %s", tQSL_CustomError); return 1; } } else { string v(value); rec_sign_data += trim(v); } ok = tCONTACT_sign.getNextElement(specfield); } return tqsl_signDataBlock(cert, (const unsigned char *)rec_sign_data.c_str(), rec_sign_data.size(), sig, siglen); } DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItCERT(tQSL_Cert cert, int uid) { static string s; s = ""; char buf[3000]; if (tqsl_getCertificateEncoded(cert, buf, sizeof buf)) return 0; char *cp = strstr(buf, "-----END CERTIFICATE-----"); if (cp) *cp = 0; if ((cp = strstr(buf, "\n"))) cp++; else cp = buf; s = "tCERT\n"; char sbuf[10], lbuf[40]; snprintf(sbuf, sizeof sbuf, "%d", uid); snprintf(lbuf, sizeof lbuf, "%s\n", static_cast(strlen(sbuf)), sbuf); s += lbuf; snprintf(lbuf, sizeof lbuf, "", static_cast(strlen(cp))); s += lbuf; s += cp; s += "\n"; return s.c_str(); //KC2YWE 1/26 - dangerous but might work since s is static } DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItSTATION(tQSL_Location locp, int uid, int certuid) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getGABBItSTATION", "loc error %d", tQSL_Error); return 0; } unsigned char *buf = 0; int bufsiz = 0; loc->tSTATION = "tSTATION\n"; char sbuf[10], lbuf[40]; snprintf(sbuf, sizeof sbuf, "%d", uid); snprintf(lbuf, sizeof lbuf, "%s\n", static_cast(strlen(sbuf)), sbuf); loc->tSTATION += lbuf; snprintf(sbuf, sizeof sbuf, "%d", certuid); snprintf(lbuf, sizeof lbuf, "%s\n", static_cast(strlen(sbuf)), sbuf); loc->tSTATION += lbuf; int old_page = loc->page; tqsl_setStationLocationCapturePage(loc, 1); do { TQSL_LOCATION_PAGE& p = loc->pagelist[loc->page-1]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD& f = p.fieldlist[i]; string s; if (f.input_type == TQSL_LOCATION_FIELD_BADZONE) // Don't output these to tSTATION continue; if (f.input_type == TQSL_LOCATION_FIELD_DDLIST || f.input_type == TQSL_LOCATION_FIELD_LIST) { if (f.idx < 0 || f.idx >= static_cast(f.items.size())) { s = ""; } else { s = f.items[f.idx].text; } } else if (f.data_type == TQSL_LOCATION_FIELD_INT) { char buf[20]; snprintf(buf, sizeof buf, "%d", f.idata); s = buf; } else { s = f.cdata; } if (s.size() == 0) continue; int wantsize = s.size() + f.gabbi_name.size() + 20; if (buf == 0 || bufsiz < wantsize) { if (buf != 0) delete[] buf; buf = new unsigned char[wantsize]; bufsiz = wantsize; } if (tqsl_adifMakeField(f.gabbi_name.c_str(), 0, (unsigned char *)s.c_str(), s.size(), buf, bufsiz)) { delete[] buf; return 0; } loc->tSTATION += (const char *)buf; loc->tSTATION += "\n"; } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; tqsl_nextStationLocationCapture(loc); } while (1); tqsl_setStationLocationCapturePage(loc, old_page); if (buf != 0) delete[] buf; loc->tSTATION += "\n"; return loc->tSTATION.c_str(); } DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItCONTACTData(tQSL_Cert cert, tQSL_Location locp, TQSL_QSO_RECORD *qso, int stationuid, char* signdata, int sdlen) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getGABBItCONTACTData", "loc error %d", tQSL_Error); return 0; } if (make_sign_data(loc)) { tqslTrace("tqsl_getGABBItCONTACTData", "make_sign_data error %d", tQSL_Error); return 0; } XMLElement specfield; bool ok = tCONTACT_sign.getFirstElement(specfield); string rec_sign_data = loc->signdata; loc->qso_details = ""; while(ok) { string en = specfield.getElementName(); const char *elname = en.c_str(); const char *value = 0; char buf[100]; if (!strcmp(elname, "CALL")) { value = qso->callsign; } else if (!strcmp(elname, "BAND")) { value = qso->band; } else if (!strcmp(elname, "BAND_RX")) { value = qso->rxband; } else if (!strcmp(elname, "MODE")) { value = qso->mode; } else if (!strcmp(elname, "FREQ")) { value = qso->freq; } else if (!strcmp(elname, "FREQ_RX")) { value = qso->rxfreq; } else if (!strcmp(elname, "PROP_MODE")) { value = qso->propmode; } else if (!strcmp(elname, "SAT_NAME")) { value = qso->satname; } else if (!strcmp(elname, "QSO_DATE")) { if (tqsl_isDateValid(&(qso->date))) value = tqsl_convertDateToText(&(qso->date), buf, sizeof buf); } else if (!strcmp(elname, "QSO_TIME")) { if (tqsl_isTimeValid(&(qso->time))) value = tqsl_convertTimeToText(&(qso->time), buf, sizeof buf); } else { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Unknown field in signing specification: %s", elname); tqslTrace("tqsl_getGABBItCONTACTData", "field err %s", tQSL_CustomError); return 0; } if (value == 0 || value[0] == 0) { pair attr = specfield.getAttribute("required"); if (attr.second && strtol(attr.first.c_str(), NULL, 10)) { string err = specfield.getElementName() + " field required by signature specification not found"; tQSL_Error = TQSL_CUSTOM_ERROR; strncpy(tQSL_CustomError, err.c_str(), sizeof tQSL_CustomError); tqslTrace("tqsl_getGABBItCONTACTData", "field err %s", tQSL_CustomError); return 0; } } else { string v(value); rec_sign_data += trim(v); loc->qso_details += trim(v); } ok = tCONTACT_sign.getNextElement(specfield); } unsigned char sig[129]; int siglen = sizeof sig; strncpy(reinterpret_cast(sig), "DUMMY", sizeof sig); rec_sign_data = string_toupper(rec_sign_data); if (!qso->do_not_sign) { if (tqsl_signDataBlock(cert, (const unsigned char *)rec_sign_data.c_str(), rec_sign_data.size(), sig, &siglen)) return 0; } char b64[512]; if (tqsl_encodeBase64(sig, siglen, b64, sizeof b64)) return 0; loc->tCONTACT = "tCONTACT\n"; char sbuf[10], lbuf[40]; snprintf(sbuf, sizeof sbuf, "%d", stationuid); snprintf(lbuf, sizeof lbuf, "%s\n", static_cast(strlen(sbuf)), sbuf); loc->tCONTACT += lbuf; char buf[256]; tqsl_adifMakeField("CALL", 0, (const unsigned char *)qso->callsign, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; tqsl_adifMakeField("BAND", 0, (const unsigned char *)qso->band, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; tqsl_adifMakeField("MODE", 0, (const unsigned char *)qso->mode, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; // Optional fields if (qso->freq[0] != 0) { tqsl_adifMakeField("FREQ", 0, (const unsigned char *)qso->freq, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; } if (qso->rxfreq[0] != 0) { tqsl_adifMakeField("FREQ_RX", 0, (const unsigned char *)qso->rxfreq, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; } if (qso->propmode[0] != 0) { tqsl_adifMakeField("PROP_MODE", 0, (const unsigned char *)qso->propmode, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; } if (qso->satname[0] != 0) { tqsl_adifMakeField("SAT_NAME", 0, (const unsigned char *)qso->satname, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; } if (qso->rxband[0] != 0) { tqsl_adifMakeField("BAND_RX", 0, (const unsigned char *)qso->rxband, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; } // Date and Time char date_buf[40] = ""; tqsl_convertDateToText(&(qso->date), date_buf, sizeof date_buf); tqsl_adifMakeField("QSO_DATE", 0, (const unsigned char *)date_buf, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; date_buf[0] = 0; tqsl_convertTimeToText(&(qso->time), date_buf, sizeof date_buf); tqsl_adifMakeField("QSO_TIME", 0, (const unsigned char *)date_buf, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; tqsl_adifMakeField(loc->sigspec.c_str(), '6', (const unsigned char *)b64, -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; // Signature tqsl_adifMakeField("SIGNDATA", 0, (const unsigned char *)rec_sign_data.c_str(), -1, (unsigned char *)buf, sizeof buf); loc->tCONTACT += buf; loc->tCONTACT += "\n"; loc->tCONTACT += "\n"; if (signdata) strncpy(signdata, rec_sign_data.c_str(), sdlen); return loc->tCONTACT.c_str(); } DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItCONTACT(tQSL_Cert cert, tQSL_Location locp, TQSL_QSO_RECORD *qso, int stationuid) { return tqsl_getGABBItCONTACTData(cert, locp, qso, stationuid, NULL, 0); } DLLEXPORT int CALLCONVENTION tqsl_getLocationCallSign(tQSL_Location locp, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getLocationCallSign", "loc error %d", tQSL_Error); return 1; } if (buf == NULL || bufsiz <= 0) { tqslTrace("tqsl_getLocationCallSign", "arg error buf=0x%lx, bufsiz=%d", buf, bufsiz); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_LOCATION_PAGE& p = loc->pagelist[0]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD f = p.fieldlist[i]; if (f.gabbi_name == "CALL") { strncpy(buf, f.cdata.c_str(), bufsiz); buf[bufsiz-1] = 0; if (static_cast(f.cdata.size()) >= bufsiz) { tqslTrace("tqsl_getLocationCallSign", "buf error req=%d avail=%d", static_cast(f.cdata.size()), bufsiz); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } return 0; } } tQSL_Error = TQSL_CALL_NOT_FOUND; return 1; } DLLEXPORT int CALLCONVENTION tqsl_setLocationCallSign(tQSL_Location locp, const char *buf, int dxcc) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_setLocationCallSign", "loc error %d", tQSL_Error); return 1; } if (buf == NULL) { tqslTrace("tqsl_setLocationCallSign", "arg error buf=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_LOCATION_PAGE& p = loc->pagelist[0]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD f = p.fieldlist[i]; if (f.gabbi_name == "CALL") { for (int j = 0; j < static_cast(f.items.size()); j++) { if (f.items[j].text == buf) { loc->pagelist[0].fieldlist[i].idx = j; loc->pagelist[0].fieldlist[i].cdata = buf; loc->newflags = true; loc->newDXCC = dxcc; break; } } return 0; } } tQSL_Error = TQSL_CALL_NOT_FOUND; return 1; } DLLEXPORT int CALLCONVENTION tqsl_getLocationField(tQSL_Location locp, const char *field, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getLocationField", "loc error %d", tQSL_Error); return 1; } if (buf == NULL || bufsiz <= 0) { tqslTrace("tqsl_getLocationField", "arg error buf=0x%lx, bufsiz=%d", buf, bufsiz); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *buf = '\0'; int old_page = loc->page; tqsl_setStationLocationCapturePage(loc, 1); do { TQSL_LOCATION_PAGE& p = loc->pagelist[loc->page-1]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD f = p.fieldlist[i]; if (f.gabbi_name == field) { if ((f.gabbi_name == "ITUZ" || f.gabbi_name == "CQZ") && f.cdata == "0") { buf[0] = '\0'; } else { strncpy(buf, f.cdata.c_str(), bufsiz); } buf[bufsiz-1] = 0; if (static_cast(f.cdata.size()) >= bufsiz) { tqslTrace("tqsl_getLocationField", "buf error req=%d avail=%d", static_cast(f.cdata.size()), bufsiz); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } tqsl_setStationLocationCapturePage(loc, old_page); return 0; } } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; tqsl_nextStationLocationCapture(loc); } while (1); tQSL_Error = TQSL_CALL_NOT_FOUND; return 1; } DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel(tQSL_Location locp, const char *field, char *buf, int bufsiz) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getLocationFieldLabel", "loc error %d", tQSL_Error); return 1; } if (buf == NULL || bufsiz <= 0) { tqslTrace("tqsl_getLocationFieldLabel", "arg error buf=0x%lx, bufsiz=%d", buf, bufsiz); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *buf = '\0'; int old_page = loc->page; tqsl_setStationLocationCapturePage(loc, 1); do { TQSL_LOCATION_PAGE& p = loc->pagelist[loc->page-1]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD f = p.fieldlist[i]; if (f.gabbi_name == field) { if ((f.gabbi_name == "ITUZ" || f.gabbi_name == "CQZ") && f.cdata == "0") { buf[0] = '\0'; } else { if (static_cast(f.items.size()) > f.idx) strncpy(buf, f.items[f.idx].label.c_str(), bufsiz); } buf[bufsiz-1] = 0; if (static_cast(f.label.size()) >= bufsiz) { tqslTrace("tqsl_getLocationFieldLabel", "buf error req=%d avail=%d", static_cast(f.cdata.size()), bufsiz); tQSL_Error = TQSL_BUFFER_ERROR; return 1; } tqsl_setStationLocationCapturePage(loc, old_page); return 0; } } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; tqsl_nextStationLocationCapture(loc); } while (1); tQSL_Error = TQSL_CALL_NOT_FOUND; return 1; } // Replaces all occurrences of 'from' with 'to' in string 'str' static void replaceAll(string& str, const string& from, const string& to) { if (from.empty()) { return; } size_t start_pos = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } static bool fuzzy_match(string userInput, string field) { // First upcase string left = string_toupper(userInput); string right = string_toupper(field); // Strip spaces replaceAll(left, " ", ""); replaceAll(right, " ", ""); // Strip apostraphes replaceAll(left, "'", ""); replaceAll(right, "'", ""); // Strip hyphens replaceAll(left, "-", ""); replaceAll(right, "-", ""); // Alaska fixes replaceAll(left, "CITYANDBOROUGH", ""); replaceAll(right, "CITYANDBOROUGH", ""); replaceAll(left, "BOROUGH", ""); replaceAll(right, "BOROUGH", ""); replaceAll(left, "CENSUSAREA", ""); replaceAll(right, "CENSUSAREA", ""); replaceAll(left, "MUNICIPALITY", ""); replaceAll(right, "MUNICIPALITY", ""); // Normalize saints replaceAll(left, "ST.", "SAINT"); replaceAll(right, "ST.", "SAINT"); replaceAll(left, "STE.", "SAINTE"); replaceAll(right, "STE.", "SAINTE"); // One-offs replaceAll(left, "DOÑAANA", "DONAANA"); replaceAll(right, "DOÑAANA", "DONAANA"); replaceAll(left, "BRISTOLCITY", "BRISTOL"); replaceAll(right, "BRISTOLCITY", "BRISTOL"); replaceAll(left, "SALEMCITY", "SALEM"); replaceAll(right, "SALEMCITY", "SALEM"); return (left == right); } DLLEXPORT int CALLCONVENTION tqsl_setLocationField(tQSL_Location locp, const char *field, const char *buf) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_setLocationField", "loc error %d", tQSL_Error); return 1; } if (buf == NULL) { tqslTrace("tqsl_setLocationField", "arg error buf=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } int old_page = loc->page; tqsl_setStationLocationCapturePage(loc, 1); do { TQSL_LOCATION_PAGE& p = loc->pagelist[loc->page-1]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD *pf = &p.fieldlist[i]; if (pf->gabbi_name == field) { bool found = false; bool adifVal = false; pf->cdata = string(buf); if (pf->flags & TQSL_LOCATION_FIELD_UPPER) pf->cdata = string_toupper(pf->cdata); if (pf->input_type == TQSL_LOCATION_FIELD_DDLIST || pf->input_type == TQSL_LOCATION_FIELD_LIST) { if (pf->cdata == "") { pf->idx = 0; pf->idata = pf->items[0].ivalue; } else { for (int i = 0; i < static_cast(pf->items.size()); i++) { if (string_toupper(pf->items[i].text) == string_toupper(pf->cdata)) { pf->cdata = pf->items[i].text; pf->idx = i; pf->idata = pf->items[i].ivalue; found = true; break; } if (fuzzy_match(pf->items[i].label, pf->cdata)) { strncpy(tQSL_CustomError, pf->items[i].text.c_str(), sizeof tQSL_CustomError); pf->cdata = pf->items[i].text; pf->idx = i; pf->idata = pf->items[i].ivalue; found = true; adifVal = true; break; } } // This was being used to force-add fields to enumerations, but that's wrong. // Keeping it around in case it's useful later. // if (!found) { // TQSL_LOCATION_ITEM item; // item.text = buf; // item.ivalue = strtol(buf, NULL, 10); // pf->items.push_back(item); // pf->idx = pf->items.size() - 1; // pf->idata = item.ivalue; // } } } else { found = true; } if (pf->data_type == TQSL_LOCATION_FIELD_INT) { pf->idata = strtol(buf, NULL, 10); } tqsl_setStationLocationCapturePage(loc, old_page); if (adifVal) return -2; if (!found) return -1; return 0; } } int rval; if (tqsl_hasNextStationLocationCapture(loc, &rval) || !rval) break; tqsl_nextStationLocationCapture(loc); } while (1); tqsl_setStationLocationCapturePage(loc, old_page); tQSL_Error = TQSL_CALL_NOT_FOUND; return 1; } DLLEXPORT int CALLCONVENTION tqsl_getLocationDXCCEntity(tQSL_Location locp, int *dxcc) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getLocationDXCCEntity", "loc error %d", tQSL_Error); return 1; } if (dxcc == NULL) { tqslTrace("tqsl_getLocationDXCCEntity", "arg err dxcc=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } TQSL_LOCATION_PAGE& p = loc->pagelist[0]; for (int i = 0; i < static_cast(p.fieldlist.size()); i++) { TQSL_LOCATION_FIELD f = p.fieldlist[i]; if (f.gabbi_name == "DXCC") { if (f.idx < 0 || f.idx >= static_cast(f.items.size())) break; // No matching DXCC entity *dxcc = f.items[f.idx].ivalue; return 0; } } tqslTrace("tqsl_getLocationDXCCEntity", "name not found"); tQSL_Error = TQSL_NAME_NOT_FOUND; return 1; } DLLEXPORT int CALLCONVENTION tqsl_getNumProviders(int *n) { if (n == NULL) { tqslTrace("tqsl_getNumProviders", "arg error n=null"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } vector plist; if (tqsl_load_provider_list(plist)) { tqslTrace("tqsl_getNumProviders", "error loading providers %d", tQSL_Error); return 1; } if (plist.size() == 0) { tqslTrace("tqsl_getNumProviders", "prov not found"); tQSL_Error = TQSL_PROVIDER_NOT_FOUND; return 1; } *n = plist.size(); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getProvider(int idx, TQSL_PROVIDER *provider) { if (provider == NULL || idx < 0) { tqslTrace("tqsl_getProvider", "arg error provider=0x%lx, idx=%d", provider, idx); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } vector plist; if (tqsl_load_provider_list(plist)) { tqslTrace("tqsl_getProvider", "err %d loading list", tQSL_Error); return 1; } if (idx >= static_cast(plist.size())) { tqslTrace("tqsl_getProvider", "prov not found"); tQSL_Error = TQSL_PROVIDER_NOT_FOUND; return 1; } *provider = plist[idx]; return 0; } DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile(const char *file, int(*cb)(int type, const char *, void *), void *userdata) { bool foundcerts = false; int rval = 0; if (file == NULL) { tqslTrace("tqsl_importTQSLFile", "file=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } // Import the "lost" Root and CA certs as trusted. tqsl_import_cert(rootcertpem, ROOTCERT, NULL, NULL); tqsl_import_cert(cacertpem, CACERT, NULL, NULL); tQSL_ImportCall[0] = '\0'; tQSL_ImportSerial = 0; XMLElement topel; int status = topel.parseFile(file); if (status) { strncpy(tQSL_ErrorFile, file, sizeof tQSL_ErrorFile); if (status == XML_PARSE_SYSTEM_ERROR) { tQSL_Error = TQSL_FILE_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_importTQSLFile", "system error file=%s err=%s", file, strerror(tQSL_Errno)); } else { tQSL_Error = TQSL_FILE_SYNTAX_ERROR; tqslTrace("tqsl_importTQSLFile", "file %s syntax error", file); } return 1; } XMLElement tqsldata; if (!topel.getFirstElement("tqsldata", tqsldata)) { strncpy(tQSL_ErrorFile, file, sizeof tQSL_ErrorFile); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; return 1; } XMLElement section; bool stat = tqsldata.getFirstElement("tqslcerts", section); if (stat) { XMLElement cert; bool cstat = section.getFirstElement("rootcert", cert); while (cstat) { foundcerts = true; if (tqsl_import_cert(cert.getText().c_str(), ROOTCERT, cb, userdata)) { tqslTrace("tqsl_importTQSLFile", "duplicate/expired root cert"); } cstat = section.getNextElement(cert); } cstat = section.getFirstElement("cacert", cert); while (cstat) { foundcerts = true; if (tqsl_import_cert(cert.getText().c_str(), CACERT, cb, userdata)) { tqslTrace("tqsl_importTQSLFile", "duplicate/expired ca cert"); } cstat = section.getNextElement(cert); } cstat = section.getFirstElement("usercert", cert); while (cstat) { foundcerts = true; if (tqsl_import_cert(cert.getText().c_str(), USERCERT, cb, userdata)) { tqslTrace("tqsl_importTQSLFile", "error importing user cert"); tQSL_Error = TQSL_CERT_ERROR; rval = 1; } cstat = section.getNextElement(cert); } } // If any of the user certificates failed import, return the error status. if (rval) { topel.clear(); return rval; } stat = tqsldata.getFirstElement("tqslconfig", section); if (stat) { // Check to make sure we aren't overwriting newer version int major = strtol(section.getAttribute("majorversion").first.c_str(), NULL, 10); int minor = strtol(section.getAttribute("minorversion").first.c_str(), NULL, 10); int curmajor, curminor; if (tqsl_getConfigVersion(&curmajor, &curminor)) { tqslTrace("tqsl_importTQSLFile", "Get config ver error %d", tQSL_Error); return 1; } if (major < curmajor) { if (foundcerts) { tqslTrace("tqsl_importTQSLFile", "Suppressing update from V%d.%d to V%d.%d", curmajor, curminor, major, minor); topel.clear(); return rval; } tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "This configuration file (V%d.%d) is older than the currently installed one (V%d.%d). It will not be installed.", major, minor, curmajor, curminor); tqslTrace("tqsl_importTQSLFile", "Config update error: %s", tQSL_CustomError); topel.clear(); return 1; } if (major == curmajor) { if (minor == curminor) { // Same rev as already installed tqslTrace("tqsl_importTQSLFile", "Suppressing update from V%d.%d to V%d.%d", curmajor, curminor, major, minor); topel.clear(); return rval; } if (minor < curminor) { if (foundcerts) { tqslTrace("tqsl_importTQSLFile", "Suppressing update from V%d.%d to V%d.%d", curmajor, curminor, major, minor); topel.clear(); return rval; } tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "This configuration file (V%d.%d) is older than the currently installed one (V%d.%d). It will not be installed.", major, minor, curmajor, curminor); tqslTrace("tqsl_importTQSLFile", "Config update error: %s", tQSL_CustomError); topel.clear(); return rval; } } // Save the configuration file ofstream out; #ifdef _WIN32 string fn = string(tQSL_BaseDir) + "\\config.xml"; #else string fn = string(tQSL_BaseDir) + "/config.xml"; #endif out.exceptions(ios::failbit | ios::eofbit | ios::badbit); try { #ifdef _WIN32 wchar_t *wfn = utf8_to_wchar(fn.c_str()); out.open(wfn); free_wchar(wfn); #else out.open(fn.c_str()); #endif out << section << endl; out.close(); } catch(exception& x) { tQSL_Error = TQSL_CUSTOM_ERROR; snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Error writing new configuration file (%s): %s/%s", fn.c_str(), x.what(), strerror(errno)); tqslTrace("tqsl_importTQSLFile", "I/O error: %s", tQSL_CustomError); if (cb) return (*cb)(TQSL_CERT_CB_RESULT | TQSL_CERT_CB_ERROR | TQSL_CERT_CB_CONFIG, fn.c_str(), userdata); if (tQSL_Error == 0) { tQSL_Error = TQSL_CERT_ERROR; } return 1; } // Clear stored config data to force re-reading new config DXCCMap.clear(); DXCCList.clear(); DeletedMap.clear(); DXCCZoneMap.clear(); DXCCStartMap.clear(); DXCCEndMap.clear(); BandList.clear(); ModeList.clear(); PropModeList.clear(); SatelliteList.clear(); tqsl_page_map.clear(); tqsl_field_map.clear(); tqsl_adif_map.clear(); tqsl_adif_mode_map.clear(); tqsl_adif_submode_map.clear(); tqsl_cabrillo_map.clear(); tqsl_cabrillo_user_map.clear(); tqsl_xml_config.clear(); topel.clear(); // Now reload it all tqsl_load_xml_config(); string version = "Configuration V" + section.getAttribute("majorversion").first + "." + section.getAttribute("minorversion").first + "\n" + fn; if (cb) { int cbret = (*cb)(TQSL_CERT_CB_RESULT | TQSL_CERT_CB_LOADED | TQSL_CERT_CB_CONFIG, version.c_str(), userdata); if (cbret || rval) { if (tQSL_Error == 0) { tQSL_Error = TQSL_CERT_ERROR; } return 1; } } } if (rval && tQSL_Error == 0) { tQSL_Error = TQSL_CERT_ERROR; } return rval; } /* * Get the first user certificate from a .tq6 file */ DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile(const char *file, long *serial) { XMLElement topel; if (file == NULL || serial == NULL) { tqslTrace("tqsl_getSerialFromTQSLFile", "Arg error file=0x%lx, serial=0x%lx", file, serial); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } int status = topel.parseFile(file); if (status) { strncpy(tQSL_ErrorFile, file, sizeof tQSL_ErrorFile); if (status == XML_PARSE_SYSTEM_ERROR) { tQSL_Error = TQSL_FILE_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_getSerialFromTQSLFile", "parse error %d, error %s", tQSL_Error, strerror(tQSL_Errno)); } else { tQSL_Error = TQSL_FILE_SYNTAX_ERROR; tqslTrace("tqsl_getSerialFromTQSLFile", "parse syntax error %d", tQSL_Error); } topel.clear(); return 1; } XMLElement tqsldata; if (!topel.getFirstElement("tqsldata", tqsldata)) { strncpy(tQSL_ErrorFile, file, sizeof tQSL_ErrorFile); tqslTrace("tqsl_getSerialFromTQSLFile", "parse syntax error %d", tQSL_Error); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; topel.clear(); return 1; } XMLElement section; bool stat = tqsldata.getFirstElement("tqslcerts", section); if (stat) { XMLElement cert; bool cstat = section.getFirstElement("usercert", cert); if (cstat) { if (tqsl_get_pem_serial(cert.getText().c_str(), serial)) { strncpy(tQSL_ErrorFile, file, sizeof tQSL_ErrorFile); tqslTrace("tqsl_getSerialFromTQSLFile", "parse syntax error %d", tQSL_Error); tQSL_Error = TQSL_FILE_SYNTAX_ERROR; return 1; } topel.clear(); return 0; } } tqslTrace("tqsl_getSerialFromTQSLFile", "no usercert in file %s", file); topel.clear(); return 1; } DLLEXPORT int CALLCONVENTION tqsl_getDeletedStationLocations(char ***locp, int *nloc) { if (locp == NULL) { tqslTrace("tqsl_getDeletedStationLocations", "arg error locp=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (nloc == NULL) { tqslTrace("tqsl_getDeletedStationLocations", "arg error nloc=NULL"); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *locp = NULL; *nloc = 0; vector namelist; XMLElement top_el; if (tqsl_load_station_data(top_el, true)) { tqslTrace("tqsl_getDeletedStationLocations", "error %d loading station data", tQSL_Error); return 1; } XMLElement sfile; if (top_el.getFirstElement(sfile)) { XMLElement sd; bool ok = sfile.getFirstElement("StationData", sd); while (ok && sd.getElementName() == "StationData") { pair name = sd.getAttribute("name"); if (name.second) { namelist.push_back(name.first); } ok = sfile.getNextElement(sd); } } *nloc = namelist.size(); if (*nloc == 0) { *locp = NULL; return 0; } *locp = reinterpret_cast(calloc(*nloc, sizeof(**locp))); vector::iterator it; char **p = *locp; for (it = namelist.begin(); it != namelist.end(); it++) { *p++ = strdup((*it).c_str()); } return 0; } DLLEXPORT void CALLCONVENTION tqsl_freeDeletedLocationList(char** list, int nloc) { if (!list) return; for (int i = 0; i < nloc; i++) if (list[i]) free(list[i]); if (list) free(list); } DLLEXPORT int CALLCONVENTION tqsl_getLocationQSODetails(tQSL_Location locp, char *buf, int buflen) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getLocationQSODetails", "loc error %d", tQSL_Error); return 1; } if (buf == NULL) { tqslTrace("tqsl_getLocationQSODetails", "Argument error, buf = 0x%lx", buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(buf, loc->qso_details.c_str(), buflen); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getLocationStationDetails(tQSL_Location locp, char *buf, int buflen) { TQSL_LOCATION *loc; if (!(loc = check_loc(locp, false))) { tqslTrace("tqsl_getLocationStationDetails", "loc error %d", tQSL_Error); return 1; } if (buf == NULL) { tqslTrace("tqsl_getLocationStationDetails", "Argument error, buf = 0x%lx", buf); tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } strncpy(buf, loc->loc_details.c_str(), buflen); return 0; } tqsl-2.8.2/src/load_cert.cpp0000644000175000017500000000203315061653721015737 0ustar rmurphyrmurphy/*************************************************************************** load_cert.cpp - description ------------------- begin : Sat Dec 14 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "sysconfig.h" #endif #include #include #include #include "tqsllib.h" using std::string; using std::ios; using std::cerr; using std::cout; using std::endl; int cb(int, const char *msg, void *) { cout << msg << endl; return 0; } int main(int argc, char *argv[]) { if (tqsl_init()) { cerr << tqsl_getErrorString() << endl; return EXIT_FAILURE; } for (int i = 1; i < argc; i++) { if (tqsl_importTQSLFile(argv[i], cb, 0)) { cerr << tqsl_getErrorString() << endl; return EXIT_FAILURE; } } return EXIT_SUCCESS; } tqsl-2.8.2/src/gen_crq.cpp0000644000175000017500000000727715061653721015440 0ustar rmurphyrmurphy/*************************************************************************** gen_crq.cpp - description ------------------- begin : Sat Dec 14 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ Generates a set of certificate-request files. ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "sysconfig.h" #endif #include #ifdef HAVE_GETOPT_H #include #endif #include #include #include #include #include #include #include #include "tqsllib.h" #include "tqslexc.h" using std::cerr; using std::endl; int usage() { std::cerr << "Usage: -e email -d dxcc [-c sign_call] [-x sign_dxcc] call1 [call2 ...]" << endl; exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { string sign_call, email_addr; int dxcc = 0, sign_dxcc = 0; tQSL_Cert sign_cert = 0; try { if (tqsl_init()) throw tqslexc(); int c; while ((c = getopt(argc, argv, "c:x:e:d:")) != -1) { switch (c) { case 'c': sign_call = optarg; break; case 'x': sign_dxcc = strtol(optarg, NULL, 10); break; case 'd': dxcc = strtol(optarg, NULL, 10); break; case 'e': email_addr = optarg; break; default: usage(); } } if (optind >= argc || email_addr == "" || dxcc == 0) usage(); if (sign_call != "") { // if (sign_dxcc == 0) // usage(); tQSL_Cert *list; int ncerts; if (tqsl_selectCertificates(&list, &ncerts, sign_call.c_str(), sign_dxcc, 0, 0, 1)) throw tqslexc(); if (ncerts < 1) { string erm = "No signing certificate found for " + sign_call; if (sign_dxcc) { const char *entity; tqsl_getDXCCEntityName(sign_dxcc, &entity); erm += " with DXCC Entity="; erm += entity; } throw myexc(erm); } sign_cert = *list; } else if (sign_dxcc != 0) { usage(); } if (sign_cert) { char buf[512]; long serial; int cdxcc; if (tqsl_getCertificateIssuer(sign_cert, buf, sizeof buf)) throw tqslexc(); if (tqsl_getCertificateSerial(sign_cert, &serial)) throw tqslexc(); if (tqsl_getCertificateDXCCEntity(sign_cert, &cdxcc)) throw tqslexc(); std::cout << "Signing certificate issuer: " << buf << endl; std::cout << "Signing certificate serial: " << serial << endl; std::cout << " Signing certificate DXCC: " << cdxcc << endl; if (tqsl_beginSigning(sign_cert, const_cast(""), 0, 0)) throw tqslexc(); } TQSL_CERT_REQ crq; memset(&crq, 0, sizeof crq); strncpy(crq.name, "Ish Kabibble", sizeof crq.name); strncpy(crq.address1, "1 No Place", sizeof crq.address1); strncpy(crq.city, "City", sizeof crq.city); strncpy(crq.state, "ST", sizeof crq.state); strncpy(crq.country, "USA", sizeof crq.country); strncpy(crq.emailAddress, email_addr.c_str(), sizeof crq.emailAddress); crq.dxccEntity = dxcc; tqsl_initDate(&crq.qsoNotBefore, "1945-11-15"); crq.signer = sign_cert; for (; optind < argc; optind++) { string call = argv[optind]; strncpy(crq.callSign, call.c_str(), sizeof crq.callSign); for (char *cp = argv[optind]; *cp; cp++) { if (*cp == '/') *cp = '_'; } string filename = string(argv[optind]) + ".tq5"; std::cout << "Creating CRQ for " << crq.callSign << " DXCC=" << crq.dxccEntity << endl; if (tqsl_createCertRequest(filename.c_str(), &crq, 0, 0)) throw tqslexc(); } return EXIT_SUCCESS; } catch(exception& x) { std::cerr << "Aborting: " << x.what() << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } tqsl-2.8.2/src/dumptqsldata.cpp0000644000175000017500000000411215061653721016506 0ustar rmurphyrmurphy/*************************************************************************** dumptqsldata.c - description ------------------- begin : Mon Mar 3 2003 copyright : (C) 2003 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ /* Dumps the config data from the TQSL library */ #include #include #include #include "tqsllib.h" void errchk(int stat) { if (stat) { printf("ERROR: %s\n", tqsl_getErrorString()); exit(1); } } int main() { int count, i; const char *cp1, *cp2; tQSL_Date start, end; int low, high; char buf1[20], buf2[20]; errchk(tqsl_init()); puts("===== MODES =====\n Mode Group"); errchk(tqsl_getNumMode(&count)); for (i = 0; i < count; i++) { errchk(tqsl_getMode(i, &cp1, &cp2)); printf(" %-10.10s %s\n", cp1, cp2); } puts("\n===== BANDS =====\n Band Spectrum Low High"); errchk(tqsl_getNumBand(&count)); for (i = 0; i < count; i++) { errchk(tqsl_getBand(i, &cp1, &cp2, &low, &high)); printf(" %-10.10s %-8.8s %-8d %d\n", cp1, cp2, low, high); } puts("\n===== DXCC =====\n Entity Name"); errchk(tqsl_getNumDXCCEntity(&count)); for (i = 0; i < count; i++) { errchk(tqsl_getDXCCEntity(i, &low, &cp1)); printf(" %-6d %s\n", low, cp1); } puts("\n===== PROP_MODES =====\n Mode Descrip"); errchk(tqsl_getNumPropagationMode(&count)); for (i = 0; i < count; i++) { errchk(tqsl_getPropagationMode(i, &cp1, &cp2)); printf(" %-6s %s\n", cp1, cp2); } puts("\n===== SATELLITES =====\n Sat Start Date End Date Descrip"); errchk(tqsl_getNumSatellite(&count)); for (i = 0; i < count; i++) { errchk(tqsl_getSatellite(i, &cp1, &cp2, &start, &end)); buf1[0] = buf2[0] = '\0'; tqsl_convertDateToText(&start, buf1, sizeof buf1); tqsl_convertDateToText(&end, buf2, sizeof buf2); printf(" %-6s %-10s %-10s %s\n", cp1, buf1, buf2, cp2); } return 0; } tqsl-2.8.2/src/doxygen/0000755000175000017500000000000015061653721014756 5ustar rmurphyrmurphytqsl-2.8.2/src/doxygen/html/0000755000175000017500000000000015061653721015722 5ustar rmurphyrmurphytqsl-2.8.2/src/doxygen/html/tqsllib_8h_source.html0000644000175000017500000106617515061653721022261 0ustar rmurphyrmurphy TrustedQSL Library API: tqsllib.h Source File
TrustedQSL Library API
tqsllib.h
Go to the documentation of this file.
1/***************************************************************************
2 tqsllib.h - description
3 -------------------
4 begin : Mon May 20 2002
5 copyright : (C) 2002 by ARRL
6 author : Jon Bloom
7 email : jbloom@arrl.org
8 revision : $Id: tqsllib.h,v 1.14 2013/03/01 13:26:44 k1mu Exp $
9 ***************************************************************************/
10
11#ifndef TQSLLIB_H
12#define TQSLLIB_H
13
14#if defined(_WIN32) && !defined(TQSL_NODLL)
15 #ifdef TQSLLIB_DEF
16 #define DLLEXPORT __declspec(dllexport)
17 #define DLLEXPORTDATA __declspec(dllexport)
18 #define CALLCONVENTION __stdcall
19 #else
20 #define DLLEXPORT __declspec(dllimport)
21 #define DLLEXPORTDATA __declspec(dllimport)
22 #define CALLCONVENTION __stdcall
23 #endif
24#else
25 #define DLLEXPORT
26 #define DLLEXPORTDATA
27 #define CALLCONVENTION
28 #include <limits.h>
29#endif
30
31#include <cstdio>
32
33#include "adif.h"
34#include "cabrillo.h"
35
39
40#ifndef PATH_MAX // Should be set by <limits.h>
41#define PATH_MAX 4096
42#endif
43
44/* Sizes */
45#define TQSL_MAX_PATH_LEN PATH_MAX
46#define TQSL_PASSWORD_MAX 80
47#define TQSL_NAME_ELEMENT_MAX 256
48#define TQSL_CALLSIGN_MAX 20
49#define TQSL_CRQ_NAME_MAX 60
50#define TQSL_CRQ_ADDR_MAX 80
51#define TQSL_CRQ_CITY_MAX 80
52#define TQSL_CRQ_STATE_MAX 80
53#define TQSL_CRQ_POSTAL_MAX 20
54#define TQSL_CRQ_COUNTRY_MAX 80
55#define TQSL_CRQ_EMAIL_MAX 180
56#define TQSL_BAND_MAX 6
57#define TQSL_MODE_MAX 16
58#define TQSL_FREQ_MAX 20
59#define TQSL_SATNAME_MAX 20
60#define TQSL_PROPMODE_MAX 20
61#define TQSL_STATE_MAX 30
62#define TQSL_GRID_MAX 30
63#define TQSL_CNTY_MAX 30
64#define TQSL_COUNTRY_MAX 60
65#define TQSL_ZONE_MAX 5
66#define TQSL_IOTA_MAX 10
67
68#define TQSL_CERT_CB_USER 0
69#define TQSL_CERT_CB_CA 1
70#define TQSL_CERT_CB_ROOT 2
71#define TQSL_CERT_CB_PKEY 3
72#define TQSL_CERT_CB_CONFIG 4
73#define TQSL_CERT_CB_CERT_TYPE(x) ((x) & 0xf)
74#define TQSL_CERT_CB_MILESTONE 0
75#define TQSL_CERT_CB_RESULT 0x10
76#define TQSL_CERT_CB_CALL_TYPE(x) ((x) & TQSL_CERT_CB_RESULT)
77#define TQSL_CERT_CB_PROMPT 0
78#define TQSL_CERT_CB_DUPLICATE 0x100
79#define TQSL_CERT_CB_ERROR 0x200
80#define TQSL_CERT_CB_LOADED 0x400
81#define TQSL_CERT_CB_SERIAL 0x800
82#define TQSL_CERT_CB_RESULT_TYPE(x) ((x) & 0x0f00)
83
84#define TQSL_MSG_FLAGGED 0x1000
85
86typedef void * tQSL_Cert;
87typedef void * tQSL_Location;
88typedef char * tQSL_StationDataEnc;
89
91typedef struct {
92 int year;
93 int month;
94 int day;
95} tQSL_Date;
96
98typedef struct {
99 int hour;
100 int minute;
101 int second;
102} tQSL_Time;
103
111
132
167
169DLLEXPORTDATA extern const char *tQSL_BaseDir;
171DLLEXPORTDATA extern const char *tQSL_RsrcDir;
172
173#ifdef __cplusplus
174extern "C" {
175#endif
176
180
182
184DLLEXPORTDATA extern int tQSL_Error;
192DLLEXPORTDATA extern char tQSL_CustomError[256];
194DLLEXPORTDATA extern int tQSL_Errno;
196DLLEXPORTDATA extern char tQSL_ImportCall[256];
200DLLEXPORTDATA extern FILE* tQSL_DiagFile;
201
207
218
223
229
237DLLEXPORT int CALLCONVENTION tqsl_encodeBase64(const unsigned char *data, int datalen, char *output, int outputlen);
238
247DLLEXPORT int CALLCONVENTION tqsl_decodeBase64(const char *input, unsigned char *data, int *datalen);
248
256
264
275
282
287DLLEXPORT char* CALLCONVENTION tqsl_convertDateToText(const tQSL_Date *date, char *buf, int bufsiz);
288
294
300
306
311DLLEXPORT char* CALLCONVENTION tqsl_convertTimeToText(const tQSL_Time *time, char *buf, int bufsiz);
312
315DLLEXPORT int CALLCONVENTION tqsl_getVersion(int *major, int *minor);
316
320
322
323
346
348
349#define TQSL_SELECT_CERT_WITHKEYS 1
350#define TQSL_SELECT_CERT_EXPIRED 2
351#define TQSL_SELECT_CERT_SUPERCEDED 4
352
381 const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flag);
382
394DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates(tQSL_Cert **certlist, int *ncerts, const char *type);
395
405 int idx);
406
410
414
418
422
426
429DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded(tQSL_Cert cert, char *buf, int bufsiz);
430
433DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded(const char *callsign, const char *type, const char *keybuf, const char *certbuf);
434
438
442DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt(tQSL_Cert cert, char *serial, int serialsiz);
443
448
459
500
511
521
531
541
551
561
573
585
597
609
621
633
634#define TQSL_PK_TYPE_ERR 0
635#define TQSL_PK_TYPE_NONE 1
636#define TQSL_PK_TYPE_UNENC 2
637#define TQSL_PK_TYPE_ENC 3
638
654
655
660
667
668#define TQSL_CERT_STATUS_UNK 0
669#define TQSL_CERT_STATUS_SUP 1
670#define TQSL_CERT_STATUS_EXP 2
671#define TQSL_CERT_STATUS_OK 3
672#define TQSL_CERT_STATUS_INV 4
673
689
694DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus(long serial, const char *status);
695
696/* int tqsl_checkCertificate(tQSL_Cert); */
697
715DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile(const char *file, int(*cb)(int type, const char *message, void *userdata), void *user);
716
725DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile(const char *file, long *serial);
726
730
736
750 int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user);
751
759DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File(tQSL_Cert cert, const char *filename, const char *p12password);
760
769DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto(tQSL_Cert cert, const char *filename, const char *p12password);
770
778
779DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64(tQSL_Cert cert, char *base64, int b64len, const char *p12password);
780
783DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File(const char *filename, const char *p12password, const char *password,
784 int (*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type , const char *message, void *userdata), void *user);
785
788DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64(const char *base64, const char *p12password, const char *password,
789 int (*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type , const char *message, void *userdata), void *user);
790
792DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates(char ***calls, int *ncall, const char *filter);
793
796
799
803
805
812
826DLLEXPORT int CALLCONVENTION tqsl_beginSigning(tQSL_Cert cert, char *password, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user);
827
833
839
845DLLEXPORT int CALLCONVENTION tqsl_signDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen);
846
851DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen);
852
860DLLEXPORT int CALLCONVENTION tqsl_signQSORecord(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *rec, unsigned char *sig, int *siglen);
861
867
869
969
971
972/* Location field input types */
973
974#define TQSL_LOCATION_FIELD_TEXT 1
975#define TQSL_LOCATION_FIELD_DDLIST 2
976#define TQSL_LOCATION_FIELD_LIST 3
977#define TQSL_LOCATION_FIELD_BADZONE 4
978
979/* Location field data types */
980#define TQSL_LOCATION_FIELD_CHAR 1
981#define TQSL_LOCATION_FIELD_INT 2
982
985
991
994
996
998
1001
1007
1012
1015
1018
1021
1024
1027
1030
1033
1041
1044
1047
1050
1053
1056
1058DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField(tQSL_Location locp, const char *name, char *namebuf, int bufsize);
1059
1065
1073
1078
1082
1085
1088
1091
1094
1097
1100
1103
1105DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel(tQSL_Location loc, int field_num, char *buf, int bufsiz);
1106
1109
1111DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI(tQSL_Location loc, int field_num, char *buf, int bufsiz);
1112
1120
1123
1125DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel(tQSL_Location loc, int field_num, char *buf, int bufsiz);
1126
1129
1131DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI(tQSL_Location loc, int field_num, char *buf, int bufsiz);
1132
1139
1145
1155
1158
1165DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData(tQSL_Location loc, int field_num, char *buf, int bufsiz);
1166
1173
1179
1182
1184DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem(tQSL_Location loc, int field_num, int item_idx, char *buf, int bufsiz);
1185
1188
1192
1198
1204
1207
1210
1212DLLEXPORT int CALLCONVENTION tqsl_getLocationField(tQSL_Location locp, const char *field, char *buf, int bufsiz);
1213
1215DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel(tQSL_Location locp, const char *field, char *buf, int bufsiz);
1216
1218DLLEXPORT int CALLCONVENTION tqsl_setLocationField(tQSL_Location locp, const char *field, const char *buf);
1219
1222
1225
1228
1230DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo(const char *callsign, const char *json);
1231
1233DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo(const char *callsign, char **buf);
1234
1235#define TQSL_VALID_VUCC_ENT 0x2000
1236#define TQSL_VALID_VUCC_PAS 0x4000
1237
1239DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid(int entity, const char *pas, const char *grid, int *result);
1240
1244
1247DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity(int index, int *number, const char **name);
1248
1251DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName(int number, const char **name);
1252
1255DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap(int number, const char **zonemap);
1256
1260
1264
1267DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted(int number, int *deleted);
1268
1271
1281DLLEXPORT int CALLCONVENTION tqsl_getBand(int index, const char **name, const char **spectrum, int *low, int *high);
1282
1285
1293DLLEXPORT int CALLCONVENTION tqsl_getMode(int index, const char **mode, const char **group);
1294
1297
1303DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry(int index, const char **mode);
1304
1307
1315DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode(int index, const char **name, const char **descrip);
1316
1319
1329DLLEXPORT int CALLCONVENTION tqsl_getSatellite(int index, const char **name, const char **descrip,
1330 tQSL_Date *start, tQSL_Date *end);
1331
1335
1346DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry(const char *contest, int field, int contest_type);
1347
1359DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry(const char *contest, int *fieldnum, int *contest_type);
1360
1364
1367DLLEXPORT int CALLCONVENTION tqsl_setADIFMode(const char *adif_item, const char *mode);
1368
1371DLLEXPORT int CALLCONVENTION tqsl_getADIFMode(const char *adif_item, char *mode, int nmode);
1372
1375DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode(const char *adif_item, char *mode, char *submode, int nmode);
1376
1387
1398DLLEXPORT const char* CALLCONVENTION tqsl_getGABBItSTATION(tQSL_Location loc, int uid, int certuid);
1399
1413 int stationuid);
1414
1429 int stationuid, char *signdata, int sdlen);
1430
1431#define GRID_ERROR_INVALID_FIELD 2
1432#define GRID_ERROR_INVALID_SQUARE 3
1433#define GRID_ERROR_INVALID_SUBSQUARE 4
1434#define GRID_ERROR_INVALID_SUBSUBSQUARE 5
1435#define GRID_ERROR_INVALID_FORMAT 6
1436
1442DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat(const char *grid, int twelve, char* newGrid, int newlen);
1443
1445
1450DLLEXPORT void CALLCONVENTION tqslTrace(const char *name, const char *format, ...);
1465
1466#ifdef _WIN32
1467DLLEXPORT wchar_t* CALLCONVENTION utf8_to_wchar(const char* str);
1468DLLEXPORT char* CALLCONVENTION wchar_to_utf8(const wchar_t* str, bool forceUTF8);
1469DLLEXPORT void CALLCONVENTION free_wchar(wchar_t* ptr);
1470#endif
1471
1472#ifdef __cplusplus
1473}
1474#endif
1475
1476/* Useful defines */
1477#define TQSL_MAX_PW_LENGTH 32
1478
1479#endif /* TQSLLIB_H */
TQSL_ADIF_GET_FIELD_ERROR
Response values returned from tqsl_getADIFField()
Definition adif.h:51
TQSL_CABRILLO_ERROR_TYPE
Cabrillo status values.
Definition cabrillo.h:38
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress1(tQSL_Cert cert, char *str, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateAROName(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File(const char *filename, const char *p12password, const char *password, int(*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type, const char *message, void *userdata), void *user)
DLLEXPORT int CALLCONVENTION tqsl_deleteCertificate(tQSL_Cert cert)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCity(tQSL_Cert cert, char *str, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File(tQSL_Cert cert, const char *filename, const char *p12password)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestState(tQSL_Cert cert, char *str, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getSelectedCertificate(tQSL_Cert *cert, const tQSL_Cert **certlist, int idx)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganizationalUnit(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_isCertificateSuperceded(tQSL_Cert cert, int *status)
DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto(tQSL_Cert cert, const char *filename, const char *p12password)
DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates(tQSL_Cert **certlist, int *ncerts, const char *type)
DLLEXPORT int CALLCONVENTION tqsl_getCertificatePrivateKeyType(tQSL_Cert cert)
DLLEXPORT int CALLCONVENTION tqsl_restoreCallsignCertificate(const char *callsign)
DLLEXPORT int CALLCONVENTION tqsl_createCertRequest(const char *filename, TQSL_CERT_REQ *req, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user)
DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded(const char *callsign, const char *type, const char *keybuf, const char *certbuf)
DLLEXPORT int CALLCONVENTION tqsl_selectCertificates(tQSL_Cert **certlist, int *ncerts, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flag)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialLength(tQSL_Cert cert)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotAfterDate(tQSL_Cert cert, tQSL_Date *date)
DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile(const char *file, long *serial)
DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64(const char *base64, const char *p12password, const char *password, int(*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type, const char *message, void *userdata), void *user)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerial(tQSL_Cert cert, long *serial)
DLLEXPORT int CALLCONVENTION tqsl_getNumProviders(int *n)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganization(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotBeforeDate(tQSL_Cert cert, tQSL_Date *date)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotAfterDate(tQSL_Cert cert, tQSL_Date *date)
DLLEXPORT int CALLCONVENTION tqsl_isCertificateRenewable(tQSL_Cert cert, int *status)
DLLEXPORT int CALLCONVENTION tqsl_isCertificateExpired(tQSL_Cert cert, int *status)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateEmailAddress(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotBeforeDate(tQSL_Cert cert, tQSL_Date *date)
DLLEXPORT int CALLCONVENTION tqsl_getProvider(int idx, TQSL_PROVIDER *provider)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestPostalCode(tQSL_Cert cert, char *str, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateCallSign(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT void CALLCONVENTION tqsl_freeCertificateList(tQSL_Cert *list, int ncerts)
DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateStatus(long serial)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateKeyOnly(tQSL_Cert cert, int *keyonly)
DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64(tQSL_Cert cert, char *base64, int b64len, const char *p12password)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress2(tQSL_Cert cert, char *str, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuer(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateEncoded(tQSL_Cert cert, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateDXCCEntity(tQSL_Cert cert, int *dxcc)
DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile(const char *file, int(*cb)(int type, const char *message, void *userdata), void *user)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCountry(tQSL_Cert cert, char *str, int bufsiz)
DLLEXPORT void CALLCONVENTION tqsl_freeCertificate(tQSL_Cert cert)
DLLEXPORT void CALLCONVENTION tqsl_freeDeletedCertificateList(char **list, int nloc)
DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus(long serial, const char *status)
DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt(tQSL_Cert cert, char *serial, int serialsiz)
DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates(char ***calls, int *ncall, const char *filter)
DLLEXPORT int CALLCONVENTION tqsl_getADIFMode(const char *adif_item, char *mode, int nmode)
DLLEXPORT int CALLCONVENTION tqsl_initStationLocationCapture(tQSL_Location *locp)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldFlags(tQSL_Location loc, int field_num, int *flags)
DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldCharData(tQSL_Location loc, int field_num, const char *buf)
DLLEXPORT int CALLCONVENTION tqsl_getNumSatellite(int *number)
DLLEXPORT int CALLCONVENTION tqsl_saveStationLocationCapture(tQSL_Location loc, int overwrite)
DLLEXPORT int CALLCONVENTION tqsl_getNumMode(int *number)
DLLEXPORT int CALLCONVENTION tqsl_getDXCCEndDate(int number, tQSL_Date *d)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocation(tQSL_Location *loc, const char *name)
DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIndex(tQSL_Location loc, int field_num, int dat)
DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocationCapturePages(tQSL_Location loc, int *npages)
DLLEXPORT int CALLCONVENTION tqsl_getStationDataEnc(tQSL_StationDataEnc *sdata)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize(tQSL_Location loc, int field_num, int *rval)
DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocations(tQSL_Location loc, int *nloc)
DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIntData(tQSL_Location loc, int field_num, int dat)
DLLEXPORT int CALLCONVENTION tqsl_setLocationField(tQSL_Location locp, const char *field, const char *buf)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataType(tQSL_Location loc, int field_num, int *type)
DLLEXPORT int CALLCONVENTION tqsl_freeStationDataEnc(tQSL_StationDataEnc sdata)
DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry(int index, const char **mode)
DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat(const char *grid, int twelve, char *newGrid, int newlen)
DLLEXPORT int CALLCONVENTION tqsl_endStationLocationCapture(tQSL_Location *locp)
DLLEXPORT int CALLCONVENTION tqsl_getPrevStationLocationCapturePage(tQSL_Location loc, int *page)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCapturePage(tQSL_Location loc, int *page)
DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCaptureName(tQSL_Location loc, const char *name)
DLLEXPORT int CALLCONVENTION tqsl_getNumADIFMode(int *number)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationErrors(tQSL_Location loc, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getDeletedStationLocations(char ***locp, int *nloc)
DLLEXPORT int CALLCONVENTION tqsl_getNextStationLocationCapturePage(tQSL_Location loc, int *page)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI(tQSL_Location loc, int field_num, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName(int number, const char **name)
DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCapturePage(tQSL_Location loc, int page)
DLLEXPORT int CALLCONVENTION tqsl_setLocationCallSign(tQSL_Location loc, const char *buf, int dxcc)
DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid(int entity, const char *pas, const char *grid, int *result)
DLLEXPORT int CALLCONVENTION tqsl_hasNextStationLocationCapture(tQSL_Location loc, int *rval)
DLLEXPORT int CALLCONVENTION tqsl_getLocationField(tQSL_Location locp, const char *field, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel(tQSL_Location loc, int field_num, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity(int index, int *number, const char **name)
DLLEXPORT int CALLCONVENTION tqsl_getDXCCStartDate(int number, tQSL_Date *d)
DLLEXPORT int CALLCONVENTION tqsl_getNumLocationFieldListItems(tQSL_Location loc, int field_num, int *rval)
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACTData(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid, char *signdata, int sdlen)
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACT(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIntData(tQSL_Location loc, int field_num, int *dat)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem(tQSL_Location loc, int field_num, int item_idx, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getCurrentStationLocationCapturePage(tQSL_Location loc, int *page)
DLLEXPORT int CALLCONVENTION tqsl_prevStationLocationCapture(tQSL_Location loc)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCallSign(tQSL_Location loc, int idx, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getLocationStationDetails(tQSL_Location locp, char *buf, int buflen)
DLLEXPORT int CALLCONVENTION tqsl_getMode(int index, const char **mode, const char **group)
DLLEXPORT int CALLCONVENTION tqsl_updateStationLocationCapture(tQSL_Location loc)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCaptureName(tQSL_Location loc, char *namebuf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getLocationQSODetails(tQSL_Location locp, char *buf, int buflen)
DLLEXPORT int CALLCONVENTION tqsl_getNumBand(int *number)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldInputType(tQSL_Location loc, int field_num, int *type)
DLLEXPORT int CALLCONVENTION tqsl_restoreStationLocation(const char *name)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData(tQSL_Location loc, int field_num, char *buf, int bufsiz)
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItSTATION(tQSL_Location loc, int uid, int certuid)
DLLEXPORT int CALLCONVENTION tqsl_nextStationLocationCapture(tQSL_Location loc)
DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCertFlags(tQSL_Location loc, int flags)
DLLEXPORT int CALLCONVENTION tqsl_getBand(int index, const char **name, const char **spectrum, int *low, int *high)
DLLEXPORT int CALLCONVENTION tqsl_deleteStationLocation(const char *name)
DLLEXPORT int CALLCONVENTION tqsl_setADIFMode(const char *adif_item, const char *mode)
DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo(const char *callsign, char **buf)
DLLEXPORT int CALLCONVENTION tqsl_clearADIFModes()
DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry(const char *contest, int field, int contest_type)
DLLEXPORT int CALLCONVENTION tqsl_clearCabrilloMap()
DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField(tQSL_Location loc, int *numf)
DLLEXPORT int CALLCONVENTION tqsl_getNumDXCCEntity(int *number)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize(tQSL_Location loc, int field_num, int *rval)
DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode(const char *adif_item, char *mode, char *submode, int nmode)
DLLEXPORT int CALLCONVENTION tqsl_getLocationCallSign(tQSL_Location loc, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel(tQSL_Location locp, const char *field, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldChanged(tQSL_Location loc, int field_num, int *changed)
DLLEXPORT int CALLCONVENTION tqsl_mergeStationLocations(const char *locdata)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField(tQSL_Location locp, const char *name, char *namebuf, int bufsize)
DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap(int number, const char **zonemap)
DLLEXPORT int CALLCONVENTION tqsl_getSatellite(int index, const char **name, const char **descrip, tQSL_Date *start, tQSL_Date *end)
DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry(const char *contest, int *fieldnum, int *contest_type)
DLLEXPORT int CALLCONVENTION tqsl_getNumPropagationMode(int *number)
DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo(const char *callsign, const char *json)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLength(tQSL_Location loc, int field_num, int *rval)
DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode(int index, const char **name, const char **descrip)
DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted(int number, int *deleted)
DLLEXPORT int CALLCONVENTION tqsl_hasPrevStationLocationCapture(tQSL_Location loc, int *rval)
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationName(tQSL_Location loc, int idx, char *buf, int bufsiz)
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCERT(tQSL_Cert cert, int uid)
DLLEXPORT void CALLCONVENTION tqsl_freeDeletedLocationList(char **list, int nloc)
DLLEXPORT int CALLCONVENTION tqsl_getLocationDXCCEntity(tQSL_Location loc, int *dxcc)
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIndex(tQSL_Location loc, int field_num, int *dat)
DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen)
DLLEXPORT int CALLCONVENTION tqsl_getMaxSignatureSize(tQSL_Cert cert, int *sigsize)
DLLEXPORT int CALLCONVENTION tqsl_signDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen)
DLLEXPORT int CALLCONVENTION tqsl_beginSigning(tQSL_Cert cert, char *password, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user)
DLLEXPORT int CALLCONVENTION tqsl_endSigning(tQSL_Cert cert)
DLLEXPORT int CALLCONVENTION tqsl_checkSigningStatus(tQSL_Cert cert)
DLLEXPORT int CALLCONVENTION tqsl_signQSORecord(tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *rec, unsigned char *sig, int *siglen)
DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString()
DLLEXPORTDATA TQSL_ADIF_GET_FIELD_ERROR tQSL_ADIF_Error
The ADIF error code.
DLLEXPORT char *CALLCONVENTION tqsl_convertDateToText(const tQSL_Date *date, char *buf, int bufsiz)
DLLEXPORTDATA FILE * tQSL_DiagFile
Diagnostic log file.
DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString_v(int err)
DLLEXPORT int CALLCONVENTION tqsl_decodeBase64(const char *input, unsigned char *data, int *datalen)
DLLEXPORT int CALLCONVENTION tqsl_getVersion(int *major, int *minor)
DLLEXPORT int CALLCONVENTION tqsl_compareDates(const tQSL_Date *a, const tQSL_Date *b)
DLLEXPORT int CALLCONVENTION tqsl_init()
DLLEXPORTDATA char tQSL_CustomError[256]
Custom error message string.
DLLEXPORT int CALLCONVENTION tqsl_isDateValid(const tQSL_Date *d)
DLLEXPORT int CALLCONVENTION tqsl_subtractDates(const tQSL_Date *a, const tQSL_Date *b, int *diff)
DLLEXPORT int CALLCONVENTION tqsl_isTimeValid(const tQSL_Time *t)
DLLEXPORT int CALLCONVENTION tqsl_isDateNull(const tQSL_Date *d)
DLLEXPORT int CALLCONVENTION tqsl_setDirectory(const char *dir)
DLLEXPORT int CALLCONVENTION tqsl_encodeBase64(const unsigned char *data, int datalen, char *output, int outputlen)
DLLEXPORT int CALLCONVENTION tqsl_initTime(tQSL_Time *time, const char *str)
DLLEXPORT char *CALLCONVENTION tqsl_convertTimeToText(const tQSL_Time *time, char *buf, int bufsiz)
DLLEXPORT int CALLCONVENTION tqsl_getConfigVersion(int *major, int *minor)
DLLEXPORTDATA long tQSL_ImportSerial
Serial number of recent certificate import.
DLLEXPORTDATA int tQSL_Error
Error code from most recent tQSL library call.
DLLEXPORTDATA TQSL_CABRILLO_ERROR_TYPE tQSL_Cabrillo_Error
The ADIF error code.
DLLEXPORT int CALLCONVENTION tqsl_initDate(tQSL_Date *date, const char *str)
DLLEXPORTDATA char tQSL_ErrorFile[TQSL_MAX_PATH_LEN]
File name of file giving error. (May be empty.)
DLLEXPORTDATA int tQSL_Errno
System errno - stored when tQSL_Error == TQSL_SYSTEM_ERROR.
DLLEXPORTDATA char tQSL_ImportCall[256]
Callsign used in import - used for missing public key error.
Definition tqsllib.h:134
bool time_set
QSO specifies a time.
Definition tqsllib.h:150
bool date_set
QSO specifies a date.
Definition tqsllib.h:149
char my_country[TQSL_COUNTRY_MAX+1]
QSO specifies MY_COUNTRY.
Definition tqsllib.h:156
bool mode_set
QSO specifies a mode.
Definition tqsllib.h:147
tQSL_Date date
QSO date.
Definition tqsllib.h:139
bool callsign_set
QSO specifies a call worked.
Definition tqsllib.h:146
bool band_set
QSO specifies a band or frequency.
Definition tqsllib.h:148
char propmode[TQSL_PROPMODE_MAX+1]
QSO prop mode.
Definition tqsllib.h:144
char my_vucc_grids[TQSL_GRID_MAX+1]
QSO specifies MY_VUCC_GRIDS.
Definition tqsllib.h:153
char my_cnty_state[TQSL_STATE_MAX+1]
QSO specifies a state with MY_CNTY.
Definition tqsllib.h:155
char my_itu_zone[TQSL_ZONE_MAX+1]
QSO specifies MY_ITU_ZONE.
Definition tqsllib.h:158
int my_dxcc
QSO specifies MY_DXCC.
Definition tqsllib.h:159
char rxfreq[TQSL_FREQ_MAX+1]
QSO receive frequency.
Definition tqsllib.h:142
char band[TQSL_BAND_MAX+1]
QSO band.
Definition tqsllib.h:136
char my_call[TQSL_CALLSIGN_MAX+1]
Station Callsign.
Definition tqsllib.h:160
tQSL_Time time
QSO time.
Definition tqsllib.h:140
char satname[TQSL_SATNAME_MAX+1]
QSO satellite name.
Definition tqsllib.h:145
char rxband[TQSL_BAND_MAX+1]
QSO RX band.
Definition tqsllib.h:143
char my_county[TQSL_CNTY_MAX+1]
QSO specifies MY_CNTY.
Definition tqsllib.h:154
char my_state[TQSL_STATE_MAX+1]
QSO specifies MY_STATE.
Definition tqsllib.h:151
char mode[TQSL_MODE_MAX+1]
QSO mode.
Definition tqsllib.h:137
char callsign[TQSL_CALLSIGN_MAX+1]
QSO callsign.
Definition tqsllib.h:135
char my_gridsquare[TQSL_GRID_MAX+1]
QSO specifies MY_GRIDSQUARE.
Definition tqsllib.h:152
char my_iota[TQSL_IOTA_MAX+1]
QSO specifies MY_IOTA_.
Definition tqsllib.h:165
char my_operator[TQSL_CALLSIGN_MAX+1]
Operator's callsign.
Definition tqsllib.h:164
char submode[TQSL_MODE_MAX+1]
QSO submode.
Definition tqsllib.h:138
char my_cq_zone[TQSL_ZONE_MAX+1]
QSO specifies MY_CQ_ZONE.
Definition tqsllib.h:157
char freq[TQSL_FREQ_MAX+1]
QSO frequency.
Definition tqsllib.h:141
Definition tqsllib.h:91
int month
Numeric month.
Definition tqsllib.h:93
int year
Numeric year.
Definition tqsllib.h:92
int day
Numeric day.
Definition tqsllib.h:94
Definition tqsllib.h:98
int second
Time seconds field.
Definition tqsllib.h:101
int hour
Time hour field.
Definition tqsllib.h:99
int minute
Time minute field.
Definition tqsllib.h:100
Definition tqsllib.h:113
char password[TQSL_PASSWORD_MAX+1]
Password.
Definition tqsllib.h:128
char renew
Rewewal reference.
Definition tqsllib.h:130
char address2[TQSL_CRQ_ADDR_MAX+1]
Address 2.
Definition tqsllib.h:119
tQSL_Date qsoNotAfter
QSOs not after date.
Definition tqsllib.h:127
tQSL_Cert signer
Signing cert.
Definition tqsllib.h:129
char callSign[TQSL_CALLSIGN_MAX+1]
Callsign.
Definition tqsllib.h:116
char state[TQSL_CRQ_STATE_MAX+1]
State.
Definition tqsllib.h:121
char postalCode[TQSL_CRQ_POSTAL_MAX+1]
Postal Code.
Definition tqsllib.h:122
char providerUnit[TQSL_NAME_ELEMENT_MAX+1]
Provider unit.
Definition tqsllib.h:115
tQSL_Date qsoNotBefore
QSOs not before date.
Definition tqsllib.h:126
char name[TQSL_CRQ_NAME_MAX+1]
Name.
Definition tqsllib.h:117
char address1[TQSL_CRQ_ADDR_MAX+1]
Address 1.
Definition tqsllib.h:118
int dxccEntity
DXCC Entity code.
Definition tqsllib.h:125
char city[TQSL_CRQ_CITY_MAX+1]
City.
Definition tqsllib.h:120
char country[TQSL_CRQ_COUNTRY_MAX+1]
Country.
Definition tqsllib.h:123
char emailAddress[TQSL_CRQ_EMAIL_MAX+1]
e-mail
Definition tqsllib.h:124
char providerName[TQSL_NAME_ELEMENT_MAX+1]
< Cert request data
Definition tqsllib.h:114
Definition tqsllib.h:105
char emailAddress[TQSL_NAME_ELEMENT_MAX+1]
Provider e-mail.
Definition tqsllib.h:108
char url[TQSL_NAME_ELEMENT_MAX+1]
Provider URL.
Definition tqsllib.h:109
char organizationName[TQSL_NAME_ELEMENT_MAX+1]
Provider name.
Definition tqsllib.h:106
char organizationalUnitName[TQSL_NAME_ELEMENT_MAX+1]
Provider unit.
Definition tqsllib.h:107
#define CALLCONVENTION
Symbol exports - Windows only.
Definition tqsllib.h:27
void * tQSL_Location
Opaque location type.
Definition tqsllib.h:87
#define TQSL_ZONE_MAX
Max length of a zone number.
Definition tqsllib.h:65
#define TQSL_MODE_MAX
Max length of a mode name.
Definition tqsllib.h:57
#define TQSL_GRID_MAX
Max length of a grid set.
Definition tqsllib.h:62
#define TQSL_CRQ_POSTAL_MAX
Max length of request zip.
Definition tqsllib.h:53
DLLEXPORT int CALLCONVENTION tqsl_openDiagFile(const char *file)
#define TQSL_COUNTRY_MAX
Max length of a country name.
Definition tqsllib.h:64
DLLEXPORT void CALLCONVENTION tqslTrace(const char *name, const char *format,...)
#define TQSL_CRQ_STATE_MAX
Max length of request state.
Definition tqsllib.h:52
#define TQSL_CRQ_COUNTRY_MAX
Max length of req entity.
Definition tqsllib.h:54
DLLEXPORT void CALLCONVENTION tqsl_closeDiagFile(void)
DLLEXPORT void CALLCONVENTION tqsl_removeUploadDatabase(void)
#define TQSL_IOTA_MAX
Max length of a IOTA identifier.
Definition tqsllib.h:66
#define TQSL_MAX_PATH_LEN
Max length of a FS path.
Definition tqsllib.h:45
#define DLLEXPORTDATA
Symbol exports - Windows only.
Definition tqsllib.h:26
#define TQSL_PASSWORD_MAX
Max password length.
Definition tqsllib.h:46
DLLEXPORTDATA const char * tQSL_BaseDir
Base directory for tQSL library working files.
#define DLLEXPORT
Symbol exports - Windows only.
Definition tqsllib.h:25
DLLEXPORT int CALLCONVENTION tqsl_diagFileOpen(void)
struct tqsl_provider_st TQSL_PROVIDER
#define TQSL_PROPMODE_MAX
Max length of a prop mode.
Definition tqsllib.h:60
char * tQSL_StationDataEnc
Opaque station data type.
Definition tqsllib.h:88
#define TQSL_NAME_ELEMENT_MAX
Max Org name length.
Definition tqsllib.h:47
void * tQSL_Cert
Opaque certificate type.
Definition tqsllib.h:86
#define TQSL_STATE_MAX
Max length of a state name.
Definition tqsllib.h:61
#define TQSL_CALLSIGN_MAX
Max callsign length.
Definition tqsllib.h:48
#define TQSL_CNTY_MAX
Max length of a county name.
Definition tqsllib.h:63
#define TQSL_CRQ_EMAIL_MAX
Max length of req email.
Definition tqsllib.h:55
#define TQSL_SATNAME_MAX
Max length of a sat name.
Definition tqsllib.h:59
DLLEXPORTDATA const char * tQSL_RsrcDir
Directory for resources bundled with tqsl executable.
struct tqsl_cert_req_st TQSL_CERT_REQ
#define TQSL_BAND_MAX
Max length of a band name.
Definition tqsllib.h:56
#define TQSL_FREQ_MAX
Max length of a frequency.
Definition tqsllib.h:58
#define TQSL_CRQ_NAME_MAX
Max length of request name.
Definition tqsllib.h:49
#define TQSL_CRQ_CITY_MAX
Max length of request city.
Definition tqsllib.h:51
#define TQSL_CRQ_ADDR_MAX
Max length of request addr.
Definition tqsllib.h:50
tqsl-2.8.2/src/doxygen/html/tqsllib_8h.html0000644000175000017500000052160015061653721020665 0ustar rmurphyrmurphy TrustedQSL Library API: tqsllib.h File Reference
TrustedQSL Library API
tqsllib.h File Reference
#include <limits.h>
#include <cstdio>
#include "adif.h"
#include "cabrillo.h"

Go to the source code of this file.

Classes

struct  tQSL_Date
 
struct  tQSL_Time
 
struct  tqsl_provider_st
 
struct  tqsl_cert_req_st
 
struct  TQSL_QSO_RECORD
 

Macros

#define DLLEXPORT
 Symbol exports - Windows only.
 
#define DLLEXPORTDATA
 Symbol exports - Windows only.
 
#define CALLCONVENTION
 Symbol exports - Windows only.
 
#define PATH_MAX   4096
 Override in case not defined in limits.h.
 
#define TQSL_MAX_PATH_LEN   PATH_MAX
 Max length of a FS path.
 
#define TQSL_PASSWORD_MAX   80
 Max password length.
 
#define TQSL_NAME_ELEMENT_MAX   256
 Max Org name length.
 
#define TQSL_CALLSIGN_MAX   20
 Max callsign length.
 
#define TQSL_CRQ_NAME_MAX   60
 Max length of request name.
 
#define TQSL_CRQ_ADDR_MAX   80
 Max length of request addr.
 
#define TQSL_CRQ_CITY_MAX   80
 Max length of request city.
 
#define TQSL_CRQ_STATE_MAX   80
 Max length of request state.
 
#define TQSL_CRQ_POSTAL_MAX   20
 Max length of request zip.
 
#define TQSL_CRQ_COUNTRY_MAX   80
 Max length of req entity.
 
#define TQSL_CRQ_EMAIL_MAX   180
 Max length of req email.
 
#define TQSL_BAND_MAX   6
 Max length of a band name.
 
#define TQSL_MODE_MAX   16
 Max length of a mode name.
 
#define TQSL_FREQ_MAX   20
 Max length of a frequency.
 
#define TQSL_SATNAME_MAX   20
 Max length of a sat name.
 
#define TQSL_PROPMODE_MAX   20
 Max length of a prop mode.
 
#define TQSL_STATE_MAX   30
 Max length of a state name.
 
#define TQSL_GRID_MAX   30
 Max length of a grid set.
 
#define TQSL_CNTY_MAX   30
 Max length of a county name.
 
#define TQSL_COUNTRY_MAX   60
 Max length of a country name.
 
#define TQSL_ZONE_MAX   5
 Max length of a zone number.
 
#define TQSL_IOTA_MAX   10
 Max length of a IOTA identifier.
 
#define TQSL_CERT_CB_USER   0
 Callback is for user cert.
 
#define TQSL_CERT_CB_CA   1
 Callback is for CA cert.
 
#define TQSL_CERT_CB_ROOT   2
 Callback is for root cert.
 
#define TQSL_CERT_CB_PKEY   3
 Callback is for private key.
 
#define TQSL_CERT_CB_CONFIG   4
 Callback for config file.
 
#define TQSL_CERT_CB_CERT_TYPE(x)
 Type of the cert.
 
#define TQSL_CERT_CB_MILESTONE   0
 New certificate.
 
#define TQSL_CERT_CB_RESULT   0x10
 Cert import result.
 
#define TQSL_CERT_CB_CALL_TYPE(x)
 Callback type.
 
#define TQSL_CERT_CB_PROMPT   0
 Callback prompt.
 
#define TQSL_CERT_CB_DUPLICATE   0x100
 Dupe cert callback.
 
#define TQSL_CERT_CB_ERROR   0x200
 Error import callback.
 
#define TQSL_CERT_CB_LOADED   0x400
 Cert loaded callback.
 
#define TQSL_CERT_CB_SERIAL   0x800
 User cert serial callback.
 
#define TQSL_CERT_CB_RESULT_TYPE(x)
 Result type mask.
 
#define TQSL_MSG_FLAGGED   0x1000
 Alt message handling flag.
 
#define TQSL_SELECT_CERT_WITHKEYS   1
 Private keys only (no cert)
 
#define TQSL_SELECT_CERT_EXPIRED   2
 Include expired certs.
 
#define TQSL_SELECT_CERT_SUPERCEDED   4
 Include superseded certs.
 
#define TQSL_PK_TYPE_ERR   0
 Error retrieving private key.
 
#define TQSL_PK_TYPE_NONE   1
 No private key.
 
#define TQSL_PK_TYPE_UNENC   2
 Private key is not encrypted.
 
#define TQSL_PK_TYPE_ENC   3
 Private key is encrypted.
 
#define TQSL_CERT_STATUS_UNK   0
 Status is unknown.
 
#define TQSL_CERT_STATUS_SUP   1
 Certificate is superceded.
 
#define TQSL_CERT_STATUS_EXP   2
 Certificate is expired.
 
#define TQSL_CERT_STATUS_OK   3
 Certificate is valid.
 
#define TQSL_CERT_STATUS_INV   4
 Invalid serial number.
 
#define TQSL_LOCATION_FIELD_TEXT   1
 Text type input field.
 
#define TQSL_LOCATION_FIELD_DDLIST   2
 Dropdown list input field.
 
#define TQSL_LOCATION_FIELD_LIST   3
 List type input field.
 
#define TQSL_LOCATION_FIELD_BADZONE   4
 Used to return zone selection errors.
 
#define TQSL_LOCATION_FIELD_CHAR   1
 Character field.
 
#define TQSL_LOCATION_FIELD_INT   2
 Integer field.
 
#define TQSL_VALID_VUCC_ENT   0x2000
 Grid is valid for DXCC Entity.
 
#define TQSL_VALID_VUCC_PAS   0x4000
 Grid is valid for Primary Administrative Subdivision (State, etc.)
 
#define GRID_ERROR_INVALID_FIELD   2
 Field - first two chars - is invalid.
 
#define GRID_ERROR_INVALID_SQUARE   3
 Square - second two chars - is invalid.
 
#define GRID_ERROR_INVALID_SUBSQUARE   4
 Subsquare - third pair - is invalid.
 
#define GRID_ERROR_INVALID_SUBSUBSQUARE   5
 Sub-subsquare - fourth pair etc. - is invalid.
 
#define GRID_ERROR_INVALID_FORMAT   6
 Format error.
 
#define TQSL_MAX_PW_LENGTH   32
 Password buffer length.
 

Typedefs

typedef void * tQSL_Cert
 Opaque certificate type.
 
typedef void * tQSL_Location
 Opaque location type.
 
typedef char * tQSL_StationDataEnc
 Opaque station data type.
 
typedef struct tqsl_provider_st TQSL_PROVIDER
 
typedef struct tqsl_cert_req_st TQSL_CERT_REQ
 

Functions

DLLEXPORT int CALLCONVENTION tqsl_init ()
 
DLLEXPORT int CALLCONVENTION tqsl_setDirectory (const char *dir)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString ()
 
DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString_v (int err)
 
DLLEXPORT int CALLCONVENTION tqsl_encodeBase64 (const unsigned char *data, int datalen, char *output, int outputlen)
 
DLLEXPORT int CALLCONVENTION tqsl_decodeBase64 (const char *input, unsigned char *data, int *datalen)
 
DLLEXPORT int CALLCONVENTION tqsl_initDate (tQSL_Date *date, const char *str)
 
DLLEXPORT int CALLCONVENTION tqsl_initTime (tQSL_Time *time, const char *str)
 
DLLEXPORT int CALLCONVENTION tqsl_compareDates (const tQSL_Date *a, const tQSL_Date *b)
 
DLLEXPORT int CALLCONVENTION tqsl_subtractDates (const tQSL_Date *a, const tQSL_Date *b, int *diff)
 
DLLEXPORT char *CALLCONVENTION tqsl_convertDateToText (const tQSL_Date *date, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_isDateValid (const tQSL_Date *d)
 
DLLEXPORT int CALLCONVENTION tqsl_isDateNull (const tQSL_Date *d)
 
DLLEXPORT int CALLCONVENTION tqsl_isTimeValid (const tQSL_Time *t)
 
DLLEXPORT char *CALLCONVENTION tqsl_convertTimeToText (const tQSL_Time *time, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getVersion (int *major, int *minor)
 
DLLEXPORT int CALLCONVENTION tqsl_getConfigVersion (int *major, int *minor)
 
DLLEXPORT int CALLCONVENTION tqsl_selectCertificates (tQSL_Cert **certlist, int *ncerts, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flag)
 
DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates (tQSL_Cert **certlist, int *ncerts, const char *type)
 
DLLEXPORT int CALLCONVENTION tqsl_getSelectedCertificate (tQSL_Cert *cert, const tQSL_Cert **certlist, int idx)
 
DLLEXPORT int CALLCONVENTION tqsl_isCertificateExpired (tQSL_Cert cert, int *status)
 
DLLEXPORT int CALLCONVENTION tqsl_isCertificateSuperceded (tQSL_Cert cert, int *status)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateKeyOnly (tQSL_Cert cert, int *keyonly)
 
DLLEXPORT int CALLCONVENTION tqsl_isCertificateRenewable (tQSL_Cert cert, int *status)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateEncoded (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded (const char *callsign, const char *type, const char *keybuf, const char *certbuf)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerial (tQSL_Cert cert, long *serial)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt (tQSL_Cert cert, char *serial, int serialsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialLength (tQSL_Cert cert)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuer (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganization (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganizationalUnit (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateCallSign (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateAROName (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateEmailAddress (tQSL_Cert cert, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotBeforeDate (tQSL_Cert cert, tQSL_Date *date)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotAfterDate (tQSL_Cert cert, tQSL_Date *date)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotBeforeDate (tQSL_Cert cert, tQSL_Date *date)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotAfterDate (tQSL_Cert cert, tQSL_Date *date)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateDXCCEntity (tQSL_Cert cert, int *dxcc)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress1 (tQSL_Cert cert, char *str, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress2 (tQSL_Cert cert, char *str, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCity (tQSL_Cert cert, char *str, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestState (tQSL_Cert cert, char *str, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestPostalCode (tQSL_Cert cert, char *str, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCountry (tQSL_Cert cert, char *str, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificatePrivateKeyType (tQSL_Cert cert)
 
DLLEXPORT void CALLCONVENTION tqsl_freeCertificate (tQSL_Cert cert)
 
DLLEXPORT void CALLCONVENTION tqsl_freeCertificateList (tQSL_Cert *list, int ncerts)
 
DLLEXPORT int CALLCONVENTION tqsl_getCertificateStatus (long serial)
 
DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus (long serial, const char *status)
 
DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile (const char *file, int(*cb)(int type, const char *message, void *userdata), void *user)
 
DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile (const char *file, long *serial)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumProviders (int *n)
 
DLLEXPORT int CALLCONVENTION tqsl_getProvider (int idx, TQSL_PROVIDER *provider)
 
DLLEXPORT int CALLCONVENTION tqsl_createCertRequest (const char *filename, TQSL_CERT_REQ *req, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user)
 
DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File (tQSL_Cert cert, const char *filename, const char *p12password)
 
DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto (tQSL_Cert cert, const char *filename, const char *p12password)
 
DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64 (tQSL_Cert cert, char *base64, int b64len, const char *p12password)
 
DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File (const char *filename, const char *p12password, const char *password, int(*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type, const char *message, void *userdata), void *user)
 
DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64 (const char *base64, const char *p12password, const char *password, int(*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type, const char *message, void *userdata), void *user)
 
DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates (char ***calls, int *ncall, const char *filter)
 
DLLEXPORT void CALLCONVENTION tqsl_freeDeletedCertificateList (char **list, int nloc)
 
DLLEXPORT int CALLCONVENTION tqsl_restoreCallsignCertificate (const char *callsign)
 
DLLEXPORT int CALLCONVENTION tqsl_deleteCertificate (tQSL_Cert cert)
 
DLLEXPORT int CALLCONVENTION tqsl_beginSigning (tQSL_Cert cert, char *password, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user)
 
DLLEXPORT int CALLCONVENTION tqsl_checkSigningStatus (tQSL_Cert cert)
 
DLLEXPORT int CALLCONVENTION tqsl_getMaxSignatureSize (tQSL_Cert cert, int *sigsize)
 
DLLEXPORT int CALLCONVENTION tqsl_signDataBlock (tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen)
 
DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock (tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen)
 
DLLEXPORT int CALLCONVENTION tqsl_signQSORecord (tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *rec, unsigned char *sig, int *siglen)
 
DLLEXPORT int CALLCONVENTION tqsl_endSigning (tQSL_Cert cert)
 
DLLEXPORT int CALLCONVENTION tqsl_initStationLocationCapture (tQSL_Location *locp)
 
DLLEXPORT int CALLCONVENTION tqsl_endStationLocationCapture (tQSL_Location *locp)
 
DLLEXPORT int CALLCONVENTION tqsl_updateStationLocationCapture (tQSL_Location loc)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocationCapturePages (tQSL_Location loc, int *npages)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCapturePage (tQSL_Location loc, int *page)
 
DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCapturePage (tQSL_Location loc, int page)
 
DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCertFlags (tQSL_Location loc, int flags)
 
DLLEXPORT int CALLCONVENTION tqsl_nextStationLocationCapture (tQSL_Location loc)
 
DLLEXPORT int CALLCONVENTION tqsl_getNextStationLocationCapturePage (tQSL_Location loc, int *page)
 
DLLEXPORT int CALLCONVENTION tqsl_prevStationLocationCapture (tQSL_Location loc)
 
DLLEXPORT int CALLCONVENTION tqsl_getPrevStationLocationCapturePage (tQSL_Location loc, int *page)
 
DLLEXPORT int CALLCONVENTION tqsl_getCurrentStationLocationCapturePage (tQSL_Location loc, int *page)
 
DLLEXPORT int CALLCONVENTION tqsl_hasNextStationLocationCapture (tQSL_Location loc, int *rval)
 
DLLEXPORT int CALLCONVENTION tqsl_hasPrevStationLocationCapture (tQSL_Location loc, int *rval)
 
DLLEXPORT int CALLCONVENTION tqsl_saveStationLocationCapture (tQSL_Location loc, int overwrite)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCaptureName (tQSL_Location loc, char *namebuf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCaptureName (tQSL_Location loc, const char *name)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocations (tQSL_Location loc, int *nloc)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationName (tQSL_Location loc, int idx, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCallSign (tQSL_Location loc, int idx, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField (tQSL_Location locp, const char *name, char *namebuf, int bufsize)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocation (tQSL_Location *loc, const char *name)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationLocationErrors (tQSL_Location loc, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getStationDataEnc (tQSL_StationDataEnc *sdata)
 
DLLEXPORT int CALLCONVENTION tqsl_freeStationDataEnc (tQSL_StationDataEnc sdata)
 
DLLEXPORT int CALLCONVENTION tqsl_mergeStationLocations (const char *locdata)
 
DLLEXPORT int CALLCONVENTION tqsl_deleteStationLocation (const char *name)
 
DLLEXPORT int CALLCONVENTION tqsl_restoreStationLocation (const char *name)
 
DLLEXPORT int CALLCONVENTION tqsl_getDeletedStationLocations (char ***locp, int *nloc)
 
DLLEXPORT void CALLCONVENTION tqsl_freeDeletedLocationList (char **list, int nloc)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField (tQSL_Location loc, int *numf)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize (tQSL_Location loc, int field_num, int *rval)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel (tQSL_Location loc, int field_num, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize (tQSL_Location loc, int field_num, int *rval)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI (tQSL_Location loc, int field_num, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldInputType (tQSL_Location loc, int field_num, int *type)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataType (tQSL_Location loc, int field_num, int *type)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldFlags (tQSL_Location loc, int field_num, int *flags)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLength (tQSL_Location loc, int field_num, int *rval)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData (tQSL_Location loc, int field_num, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIntData (tQSL_Location loc, int field_num, int *dat)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIndex (tQSL_Location loc, int field_num, int *dat)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumLocationFieldListItems (tQSL_Location loc, int field_num, int *rval)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem (tQSL_Location loc, int field_num, int item_idx, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldCharData (tQSL_Location loc, int field_num, const char *buf)
 
DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIntData (tQSL_Location loc, int field_num, int dat)
 
DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIndex (tQSL_Location loc, int field_num, int dat)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldChanged (tQSL_Location loc, int field_num, int *changed)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationCallSign (tQSL_Location loc, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_setLocationCallSign (tQSL_Location loc, const char *buf, int dxcc)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationField (tQSL_Location locp, const char *field, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel (tQSL_Location locp, const char *field, char *buf, int bufsiz)
 
DLLEXPORT int CALLCONVENTION tqsl_setLocationField (tQSL_Location locp, const char *field, const char *buf)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationDXCCEntity (tQSL_Location loc, int *dxcc)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationQSODetails (tQSL_Location locp, char *buf, int buflen)
 
DLLEXPORT int CALLCONVENTION tqsl_getLocationStationDetails (tQSL_Location locp, char *buf, int buflen)
 
DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo (const char *callsign, const char *json)
 
DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo (const char *callsign, char **buf)
 
DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid (int entity, const char *pas, const char *grid, int *result)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumDXCCEntity (int *number)
 
DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity (int index, int *number, const char **name)
 
DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName (int number, const char **name)
 
DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap (int number, const char **zonemap)
 
DLLEXPORT int CALLCONVENTION tqsl_getDXCCStartDate (int number, tQSL_Date *d)
 
DLLEXPORT int CALLCONVENTION tqsl_getDXCCEndDate (int number, tQSL_Date *d)
 
DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted (int number, int *deleted)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumBand (int *number)
 
DLLEXPORT int CALLCONVENTION tqsl_getBand (int index, const char **name, const char **spectrum, int *low, int *high)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumMode (int *number)
 
DLLEXPORT int CALLCONVENTION tqsl_getMode (int index, const char **mode, const char **group)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumADIFMode (int *number)
 
DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry (int index, const char **mode)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumPropagationMode (int *number)
 
DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode (int index, const char **name, const char **descrip)
 
DLLEXPORT int CALLCONVENTION tqsl_getNumSatellite (int *number)
 
DLLEXPORT int CALLCONVENTION tqsl_getSatellite (int index, const char **name, const char **descrip, tQSL_Date *start, tQSL_Date *end)
 
DLLEXPORT int CALLCONVENTION tqsl_clearCabrilloMap ()
 
DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry (const char *contest, int field, int contest_type)
 
DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry (const char *contest, int *fieldnum, int *contest_type)
 
DLLEXPORT int CALLCONVENTION tqsl_clearADIFModes ()
 
DLLEXPORT int CALLCONVENTION tqsl_setADIFMode (const char *adif_item, const char *mode)
 
DLLEXPORT int CALLCONVENTION tqsl_getADIFMode (const char *adif_item, char *mode, int nmode)
 
DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode (const char *adif_item, char *mode, char *submode, int nmode)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCERT (tQSL_Cert cert, int uid)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItSTATION (tQSL_Location loc, int uid, int certuid)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACT (tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACTData (tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid, char *signdata, int sdlen)
 
DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat (const char *grid, int twelve, char *newGrid, int newlen)
 
DLLEXPORT void CALLCONVENTION tqslTrace (const char *name, const char *format,...)
 
DLLEXPORT void CALLCONVENTION tqsl_closeDiagFile (void)
 
DLLEXPORT int CALLCONVENTION tqsl_diagFileOpen (void)
 
DLLEXPORT int CALLCONVENTION tqsl_openDiagFile (const char *file)
 
DLLEXPORT void CALLCONVENTION tqsl_removeUploadDatabase (void)
 

Variables

DLLEXPORTDATA const char * tQSL_BaseDir
 Base directory for tQSL library working files.
 
DLLEXPORTDATA const char * tQSL_RsrcDir
 Directory for resources bundled with tqsl executable.
 
DLLEXPORTDATA int tQSL_Error
 Error code from most recent tQSL library call.
 
DLLEXPORTDATA TQSL_ADIF_GET_FIELD_ERROR tQSL_ADIF_Error
 The ADIF error code.
 
DLLEXPORTDATA TQSL_CABRILLO_ERROR_TYPE tQSL_Cabrillo_Error
 The ADIF error code.
 
DLLEXPORTDATA char tQSL_ErrorFile [TQSL_MAX_PATH_LEN]
 File name of file giving error. (May be empty.)
 
DLLEXPORTDATA char tQSL_CustomError [256]
 Custom error message string.
 
DLLEXPORTDATA int tQSL_Errno
 System errno - stored when tQSL_Error == TQSL_SYSTEM_ERROR.
 
DLLEXPORTDATA char tQSL_ImportCall [256]
 Callsign used in import - used for missing public key error.
 
DLLEXPORTDATA long tQSL_ImportSerial
 Serial number of recent certificate import.
 
DLLEXPORTDATA FILE * tQSL_DiagFile
 Diagnostic log file.
 

Detailed Description

tQSL library functions.

Macro Definition Documentation

◆ TQSL_CERT_CB_CALL_TYPE

#define TQSL_CERT_CB_CALL_TYPE ( x)
Value:
#define TQSL_CERT_CB_RESULT
Cert import result.
Definition tqsllib.h:75

Callback type.

◆ TQSL_CERT_CB_CERT_TYPE

#define TQSL_CERT_CB_CERT_TYPE ( x)
Value:
((x) & 0xf)

Type of the cert.

◆ TQSL_CERT_CB_RESULT_TYPE

#define TQSL_CERT_CB_RESULT_TYPE ( x)
Value:
((x) & 0x0f00)

Result type mask.

Typedef Documentation

◆ TQSL_CERT_REQ

Certificate request data

◆ TQSL_PROVIDER

Certificate provider data

Function Documentation

◆ tqsl_closeDiagFile()

DLLEXPORT void CALLCONVENTION tqsl_closeDiagFile ( void )

Close the diagnostic trace file (if it is open)

◆ tqsl_diagFileOpen()

DLLEXPORT int CALLCONVENTION tqsl_diagFileOpen ( void )

Close the diagnostic trace file (if it is open)

◆ tqsl_openDiagFile()

DLLEXPORT int CALLCONVENTION tqsl_openDiagFile ( const char * file)

Returns true if the log file is open

◆ tqsl_removeUploadDatabase()

DLLEXPORT void CALLCONVENTION tqsl_removeUploadDatabase ( void )

Removes the upload database if it exists

◆ tqslTrace()

DLLEXPORT void CALLCONVENTION tqslTrace ( const char * name,
const char * format,
... )

Output to a diagnostic trace file (if one is opened.

  • name is the name of the function being executed
tqsl-2.8.2/src/doxygen/html/tqsllib.css0000644000175000017500000000211615061653721020106 0ustar rmurphyrmurphyBODY { font-family: Helvetica,Arial,sans-serif; font-size: small } H1 { text-align: center; font-size: x-large } H2 { font-size: large } CODE { font-size: medium } A.qindex {} A.qindexRef {} A.el { text-decoration: none; font-weight: bold; } A.elRef { font-weight: bold } A.code { text-decoration: none; font-weight: normal; color: #4444ee } A.codeRef { font-weight: normal; color: #4444ee } A:link { color: #0000ff } A:visited { color: #0066cc } DL.el { margin-left: -1cm } DIV.fragment { width: 100%; border: none; background-color: #eeeeee } DIV.ah { background-color: black; margin-bottom: 3; margin-top: 3 } TD.md { background-color: #f2f2ff } DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold } DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller } FONT.keyword { color: #008000 } FONT.keywordtype { color: #604020 } FONT.keywordflow { color: #e08000 } FONT.comment { color: #800000 } FONT.preprocessor { color: #806020 } FONT.stringliteral { color: #002080 } FONT.charliteral { color: #008080 } TD { font-size: small } tqsl-2.8.2/src/doxygen/html/tqsllib-doc_8h_source.html0000644000175000017500000001014715061653721023007 0ustar rmurphyrmurphy TrustedQSL Library API: tqsllib-doc.h Source File
TrustedQSL Library API
tqsllib-doc.h
1/***************************************************************************
2 tqsllib-doc.h - description
3 -------------------
4 begin : Tue Jun 4 2002
5 copyright : (C) 2002 by ARRL
6 author : Jon Bloom
7 email : jbloom@arrl.org
8 revision : $Id$
9 ***************************************************************************/
10
tqsl-2.8.2/src/doxygen/html/tqslerrno_8h_source.html0000644000175000017500000003705515061653721022632 0ustar rmurphyrmurphy TrustedQSL Library API: tqslerrno.h Source File
TrustedQSL Library API
tqslerrno.h
Go to the documentation of this file.
1/***************************************************************************
2 tqslerrno.h - description
3 -------------------
4 begin : Tue May 28 2002
5 copyright : (C) 2002 by ARRL
6 author : Jon Bloom
7 email : jbloom@arrl.org
8 revision : $Id$
9 ***************************************************************************/
10
11#ifndef __TQSLERRNO_H
12#define __TQSLERRNO_H
13
17
18#define TQSL_NO_ERROR 0
19#define TQSL_SYSTEM_ERROR 1
20#define TQSL_OPENSSL_ERROR 2
21#define TQSL_ADIF_ERROR 3
22#define TQSL_CUSTOM_ERROR 4
23#define TQSL_CABRILLO_ERROR 5
24#define TQSL_OPENSSL_VERSION_ERROR 6
25#define TQSL_ERROR_ENUM_BASE 16
26#define TQSL_ALLOC_ERROR 16
27#define TQSL_RANDOM_ERROR 17
28#define TQSL_ARGUMENT_ERROR 18
29#define TQSL_OPERATOR_ABORT 19
30#define TQSL_NOKEY_ERROR 20
31#define TQSL_BUFFER_ERROR 21
32#define TQSL_INVALID_DATE 22
33#define TQSL_SIGNINIT_ERROR 23
34#define TQSL_PASSWORD_ERROR 24
35#define TQSL_EXPECTED_NAME 25
36#define TQSL_NAME_EXISTS 26
37#define TQSL_NAME_NOT_FOUND 27
38#define TQSL_INVALID_TIME 28
39#define TQSL_CERT_DATE_MISMATCH 29
40#define TQSL_PROVIDER_NOT_FOUND 30
41#define TQSL_CERT_KEY_ONLY 31
42#define TQSL_CONFIG_ERROR 32
43#define TQSL_CERT_NOT_FOUND 33
44#define TQSL_PKCS12_ERROR 34
45#define TQSL_CERT_TYPE_ERROR 35
46#define TQSL_DATE_OUT_OF_RANGE 36
47#define TQSL_DUPLICATE_QSO 37
48#define TQSL_DB_ERROR 38
49#define TQSL_LOCATION_NOT_FOUND 39
50#define TQSL_CALL_NOT_FOUND 40
51#define TQSL_CONFIG_SYNTAX_ERROR 41
52#define TQSL_FILE_SYSTEM_ERROR 42
53#define TQSL_FILE_SYNTAX_ERROR 43
54#define TQSL_CERT_ERROR 44
55#define TQSL_CERT_MISMATCH 45
56#define TQSL_LOCATION_MISMATCH 46
57#define TQSL_NEW_UPLOAD_DB 47
58#define TQSL_INCONSISTENT_GRID 48
59#define TQSL_INVALID_ADIF 49
60
61#define TQSL_CERT_NOT_FOUND_INVALID 0x10000
62#define TQSL_CERT_NOT_FOUND_EXPIRED 0x20000
63#define TQSL_CERT_NOT_FOUND_SUPERCEDED 0x40000
64
65#endif /* __TQSLERRNO_H */
tqsl-2.8.2/src/doxygen/html/tqslerrno_8h.html0000644000175000017500000007440115061653721021246 0ustar rmurphyrmurphy TrustedQSL Library API: tqslerrno.h File Reference
TrustedQSL Library API
tqslerrno.h File Reference

Go to the source code of this file.

Macros

#define TQSL_NO_ERROR   0
 No error.
 
#define TQSL_SYSTEM_ERROR   1
 System Error.
 
#define TQSL_OPENSSL_ERROR   2
 Error in OpenSSL calls.
 
#define TQSL_ADIF_ERROR   3
 ADIF Errors.
 
#define TQSL_CUSTOM_ERROR   4
 Custom errors - output to tQSL_CustomError.
 
#define TQSL_CABRILLO_ERROR   5
 Cabrillo handler error.
 
#define TQSL_OPENSSL_VERSION_ERROR   6
 OpenSSL version obsolete.
 
#define TQSL_ERROR_ENUM_BASE   16
 Base for enumerated errors.
 
#define TQSL_ALLOC_ERROR   16
 Memory allocation error.
 
#define TQSL_RANDOM_ERROR   17
 Error initializing random number generator.
 
#define TQSL_ARGUMENT_ERROR   18
 Invalid arguments.
 
#define TQSL_OPERATOR_ABORT   19
 Aborted by operator.
 
#define TQSL_NOKEY_ERROR   20
 No key available.
 
#define TQSL_BUFFER_ERROR   21
 Insufficient buffer space.
 
#define TQSL_INVALID_DATE   22
 Date string invalid.
 
#define TQSL_SIGNINIT_ERROR   23
 Error initializing signing routine.
 
#define TQSL_PASSWORD_ERROR   24
 Invalid password.
 
#define TQSL_EXPECTED_NAME   25
 Name expected but not supplied.
 
#define TQSL_NAME_EXISTS   26
 Entity name exists already.
 
#define TQSL_NAME_NOT_FOUND   27
 Entity name does not exist.
 
#define TQSL_INVALID_TIME   28
 Time format is invalid.
 
#define TQSL_CERT_DATE_MISMATCH   29
 Certificate date mismatch.
 
#define TQSL_PROVIDER_NOT_FOUND   30
 Certificate provider unknown.
 
#define TQSL_CERT_KEY_ONLY   31
 No signed public key is installed.
 
#define TQSL_CONFIG_ERROR   32
 There is an error in the configuration file.
 
#define TQSL_CERT_NOT_FOUND   33
 The certificate could not be found.
 
#define TQSL_PKCS12_ERROR   34
 There is an error parsing the .p12 file.
 
#define TQSL_CERT_TYPE_ERROR   35
 The certificate type is invalid.
 
#define TQSL_DATE_OUT_OF_RANGE   36
 The date is out of the valid range.
 
#define TQSL_DUPLICATE_QSO   37
 This QSO is previously signed.
 
#define TQSL_DB_ERROR   38
 The dupe database could not be accessed.
 
#define TQSL_LOCATION_NOT_FOUND   39
 The station location is invalid.
 
#define TQSL_CALL_NOT_FOUND   40
 The callsign could not be located.
 
#define TQSL_CONFIG_SYNTAX_ERROR   41
 The config file has a syntax error.
 
#define TQSL_FILE_SYSTEM_ERROR   42
 There was a file system I/O error.
 
#define TQSL_FILE_SYNTAX_ERROR   43
 The file format is invalid.
 
#define TQSL_CERT_ERROR   44
 Callsign certificate could not be installed.
 
#define TQSL_CERT_MISMATCH   45
 Callsign Certificate does not match QSO details.
 
#define TQSL_LOCATION_MISMATCH   46
 Station Location does not match QSO details.
 
#define TQSL_NEW_UPLOAD_DB   47
 New upload database created, try to re-load it.
 
#define TQSL_INCONSISTENT_GRID   48
 Gridsquare inconsistent with location.
 
#define TQSL_INVALID_ADIF   49
 ADIF field value is invalid.
 
#define TQSL_CERT_NOT_FOUND_INVALID   0x10000
 Certificate is invalid.
 
#define TQSL_CERT_NOT_FOUND_EXPIRED   0x20000
 Certificate has expired.
 
#define TQSL_CERT_NOT_FOUND_SUPERCEDED   0x40000
 Certificate has been replaced with a newer one.
 

Detailed Description

tQSL_Error values

tqsl-2.8.2/src/doxygen/html/tqslconvert_8h_source.html0000644000175000017500000010363315061653721023161 0ustar rmurphyrmurphy TrustedQSL Library API: tqslconvert.h Source File
TrustedQSL Library API
tqslconvert.h
Go to the documentation of this file.
1/***************************************************************************
2 convert.h - description
3 -------------------
4 begin : Sun Nov 17 2002
5 copyright : (C) 2002 by ARRL
6 author : Jon Bloom
7 email : jbloom@arrl.org
8 revision : $Id$
9 ***************************************************************************/
10
11#ifndef __tqslconvert_h
12#define __tqslconvert_h
13
14#include "tqsllib.h"
15
19
26
27typedef void * tQSL_Converter;
30
31#ifdef __cplusplus
32extern "C" {
33#endif
34
39
42
53 tQSL_Cert *certs, int ncerts, tQSL_Location loc);
54
65 tQSL_Cert *certs, int ncerts, tQSL_Location loc);
66
69
79
80#define TQSL_LOC_IGNORE 0
81#define TQSL_LOC_REPORT 1
82#define TQSL_LOC_UPDATE 2
83
90
108
115
123
129
131
139
146
154tqsl_getDuplicateRecords(tQSL_Converter convp, char *key, char *data, int keylen);
155
164tqsl_getDuplicateRecordsV2(tQSL_Converter convp, char *key, char *data, int keylen);
165
173tqsl_putDuplicateRecord(tQSL_Converter convp, const char *key, const char *data, int keylen);
174
182
184 tQSL_Date *end);
185
212
215
219
225
227
228#ifdef __cplusplus
229}
230#endif
231
232#endif /* __tqslconvert_h */
233
DLLEXPORT int CALLCONVENTION tqsl_converterCommit(tQSL_Converter convp)
void * tQSL_Converter
Definition tqslconvert.h:27
DLLEXPORT int CALLCONVENTION tqsl_setConverterQTHDetails(tQSL_Converter conv, int logverify)
DLLEXPORT int CALLCONVENTION tqsl_converterRollBack(tQSL_Converter convp)
DLLEXPORT int CALLCONVENTION tqsl_endConverter(tQSL_Converter *conv)
DLLEXPORT int CALLCONVENTION tqsl_setConverterAppName(tQSL_Converter convp, const char *app)
DLLEXPORT int CALLCONVENTION tqsl_putDuplicateRecord(tQSL_Converter convp, const char *key, const char *data, int keylen)
DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowBadCall(tQSL_Converter conv, int allow)
DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecords(tQSL_Converter convp, char *key, char *data, int keylen)
DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecordsV2(tQSL_Converter convp, char *key, char *data, int keylen)
DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreSeconds(tQSL_Converter convp, int ignore)
DLLEXPORT int CALLCONVENTION tqsl_beginADIFConverter(tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc)
DLLEXPORT const char *CALLCONVENTION tqsl_getConverterRecordText(tQSL_Converter conv)
DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreCallsigns(tQSL_Converter convp, int ignore)
DLLEXPORT int CALLCONVENTION tqsl_beginConverter(tQSL_Converter *convp)
DLLEXPORT int CALLCONVENTION tqsl_setConverterDupesOnly(tQSL_Converter convp, int dupesOnly)
DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowDuplicates(tQSL_Converter convp, int ignore)
DLLEXPORT int CALLCONVENTION tqsl_beginCabrilloConverter(tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc)
DLLEXPORT int CALLCONVENTION tqsl_setADIFConverterDateFilter(tQSL_Converter conv, tQSL_Date *start, tQSL_Date *end)
DLLEXPORT const char *CALLCONVENTION tqsl_getConverterGABBI(tQSL_Converter conv)
DLLEXPORT int CALLCONVENTION tqsl_getConverterCert(tQSL_Converter conv, tQSL_Cert *certp)
DLLEXPORT int CALLCONVENTION tqsl_getConverterLine(tQSL_Converter conv, int *lineno)
Definition tqsllib.h:91
#define CALLCONVENTION
Symbol exports - Windows only.
Definition tqsllib.h:27
void * tQSL_Location
Opaque location type.
Definition tqsllib.h:87
#define DLLEXPORT
Symbol exports - Windows only.
Definition tqsllib.h:25
void * tQSL_Cert
Opaque certificate type.
Definition tqsllib.h:86
tqsl-2.8.2/src/doxygen/html/tqslconvert_8h.html0000644000175000017500000005162715061653721021606 0ustar rmurphyrmurphy TrustedQSL Library API: tqslconvert.h File Reference
TrustedQSL Library API
tqslconvert.h File Reference
#include "tqsllib.h"

Go to the source code of this file.

Macros

#define TQSL_LOC_IGNORE   0
 Ignore MY_ ADIF fields.
 
#define TQSL_LOC_REPORT   1
 Report on MY_ ADIF fields not matching cert/location.
 
#define TQSL_LOC_UPDATE   2
 Update Cert/Loc to track MY_ ADIF fields.
 

Typedefs

typedef void * tQSL_Converter
 

Functions

DLLEXPORT int CALLCONVENTION tqsl_beginConverter (tQSL_Converter *convp)
 
DLLEXPORT int CALLCONVENTION tqsl_beginADIFConverter (tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc)
 
DLLEXPORT int CALLCONVENTION tqsl_beginCabrilloConverter (tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc)
 
DLLEXPORT int CALLCONVENTION tqsl_endConverter (tQSL_Converter *conv)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowBadCall (tQSL_Converter conv, int allow)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterQTHDetails (tQSL_Converter conv, int logverify)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowDuplicates (tQSL_Converter convp, int ignore)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreSeconds (tQSL_Converter convp, int ignore)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreCallsigns (tQSL_Converter convp, int ignore)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterAppName (tQSL_Converter convp, const char *app)
 
DLLEXPORT int CALLCONVENTION tqsl_setConverterDupesOnly (tQSL_Converter convp, int dupesOnly)
 
DLLEXPORT int CALLCONVENTION tqsl_converterRollBack (tQSL_Converter convp)
 
DLLEXPORT int CALLCONVENTION tqsl_converterCommit (tQSL_Converter convp)
 
DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecords (tQSL_Converter convp, char *key, char *data, int keylen)
 
DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecordsV2 (tQSL_Converter convp, char *key, char *data, int keylen)
 
DLLEXPORT int CALLCONVENTION tqsl_putDuplicateRecord (tQSL_Converter convp, const char *key, const char *data, int keylen)
 
DLLEXPORT int CALLCONVENTION tqsl_setADIFConverterDateFilter (tQSL_Converter conv, tQSL_Date *start, tQSL_Date *end)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getConverterGABBI (tQSL_Converter conv)
 
DLLEXPORT int CALLCONVENTION tqsl_getConverterCert (tQSL_Converter conv, tQSL_Cert *certp)
 
DLLEXPORT int CALLCONVENTION tqsl_getConverterLine (tQSL_Converter conv, int *lineno)
 
DLLEXPORT const char *CALLCONVENTION tqsl_getConverterRecordText (tQSL_Converter conv)
 

Detailed Description

tQSL library converter functions.

tqsl-2.8.2/src/doxygen/html/topics.html0000644000175000017500000001006515061653721020113 0ustar rmurphyrmurphy TrustedQSL Library API: Topics
TrustedQSL Library API
Topics
Here is a list of all topics with brief descriptions:
tqsl-2.8.2/src/doxygen/html/tabs.css0000644000175000017500000002536315061653721017376 0ustar rmurphyrmurphy.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.main-menu-btn{position:relative;display:inline-block;width:36px;height:36px;text-indent:36px;margin-left:8px;white-space:nowrap;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}.main-menu-btn-icon,.main-menu-btn-icon:before,.main-menu-btn-icon:after{position:absolute;top:50%;left:2px;height:2px;width:24px;background:var(--nav-menu-button-color);-webkit-transition:all .25s;transition:all .25s}.main-menu-btn-icon:before{content:'';top:-7px;left:0}.main-menu-btn-icon:after{content:'';top:7px;left:0}#main-menu-state:checked ~ .main-menu-btn .main-menu-btn-icon{height:0}#main-menu-state:checked ~ .main-menu-btn .main-menu-btn-icon:before{top:0;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}#main-menu-state:checked ~ .main-menu-btn .main-menu-btn-icon:after{top:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}#main-menu-state{position:absolute;width:1px;height:1px;margin:-1px;border:0;padding:0;overflow:hidden;clip:rect(1px,1px,1px,1px)}#main-menu-state:not(:checked) ~ #main-menu{display:none}#main-menu-state:checked ~ #main-menu{display:block}@media(min-width:768px){.main-menu-btn{position:absolute;top:-99999px}#main-menu-state:not(:checked) ~ #main-menu{display:block}}.sm-dox{background-image:var(--nav-gradient-image)}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:var(--font-family-nav);font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:var(--nav-text-normal-shadow);color:var(--nav-text-normal-color);outline:0}.sm-dox a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:var(--nav-text-hover-shadow)}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace !important;text-align:center;text-shadow:none;background:var(--nav-menu-toggle-color);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a span.sub-arrow:before{display:block;content:'+'}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:var(--nav-menu-background-color)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:var(--nav-menu-background-color);background-image:none}.sm-dox ul a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:var(--nav-gradient-image);line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:var(--nav-text-normal-color) transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:var(--nav-separator-image);background-repeat:no-repeat;background-position:right;-moz-border-radius:0 !important;-webkit-border-radius:0;border-radius:0 !important}.sm-dox a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:var(--nav-text-hover-shadow)}.sm-dox a:hover span.sub-arrow{border-color:var(--nav-text-hover-color) transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent var(--nav-menu-background-color) transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:var(--nav-menu-background-color);-moz-border-radius:5px !important;-webkit-border-radius:5px;border-radius:5px !important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent var(--nav-menu-foreground-color);border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:var(--nav-menu-foreground-color);background-image:none;border:0 !important}.sm-dox ul a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:var(--nav-text-hover-shadow)}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent var(--nav-text-hover-color)}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:var(--nav-menu-background-color);height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent var(--nav-menu-foreground-color) transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:var(--nav-menu-foreground-color) transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px !important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:var(--nav-gradient-image)}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:var(--nav-menu-background-color)}} tqsl-2.8.2/src/doxygen/html/tab_sd.png0000644000175000017500000000027415061653721017667 0ustar rmurphyrmurphyPNG  IHDR$[IDATx{ 0/ir:'V3"t.3$?)P/LĴG_Nm2ڜQ>ٓ莤HYlKKH2C)rBM08?j HZ-IENDB`tqsl-2.8.2/src/doxygen/html/tab_s.png0000644000175000017500000000027015061653721017517 0ustar rmurphyrmurphyPNG  IHDR$[IDATx݁ @@ѣ?Q"%If6[HQ<]dr s?O=w'F -~rÍ[芭m֬ݯнF)Y% `n,9B!ь\<#IENDB`tqsl-2.8.2/src/doxygen/html/tab_hd.png0000644000175000017500000000026415061653721017653 0ustar rmurphyrmurphyPNG  IHDR$[{IDATxK @D̀""I w1E.gABntX\?,oۺ5:=}`V5!0݇CD*Dm#JI24eVKIENDB`tqsl-2.8.2/src/doxygen/html/tab_h.png0000644000175000017500000000026115061653721017504 0ustar rmurphyrmurphyPNG  IHDR$[xIDATxM@~ΒEv"!d*rGq={SݧH uO^[_Xvyұ=VCff{R%_rug(?gh\i>|sIENDB`tqsl-2.8.2/src/doxygen/html/tab_bd.png0000644000175000017500000000025515061653721017645 0ustar rmurphyrmurphyPNG  IHDR$[tIDATx[ 0Л66)IZ_%)(.(z* u97d:.Lqwg?8LWxʐOЧVql` 1+S^Z ~dA .YBIENDB`tqsl-2.8.2/src/doxygen/html/tab_b.png0000644000175000017500000000025115061653721017475 0ustar rmurphyrmurphyPNG  IHDR$[pIDATxM EǻԸu`V0}:t]Ds䮂u|x>1&m8SxLU޲iEOsnxKN~jIENDB`tqsl-2.8.2/src/doxygen/html/tab_ad.png0000644000175000017500000000020715061653721017641 0ustar rmurphyrmurphyPNG  IHDR$[NIDATxa P" ޟ.!L/nEX2i̝^ rV}r>=>bHa5IENDB`tqsl-2.8.2/src/doxygen/html/tab_a.png0000644000175000017500000000021615061653721017475 0ustar rmurphyrmurphyPNG  IHDR$[UIDATxK 0C'o([Ž%x#٩ We# 3t I 3+E~\D9wM}Y_A4Y}IENDB`tqsl-2.8.2/src/doxygen/html/sync_on.png0000644000175000017500000000151515061653721020102 0ustar rmurphyrmurphyPNG  IHDRw=IDATx_HTY8i4-g6&kQ)!0URKڅ/PE>K-+K.YdEPaAZSܝ;3wgfsWK.Da'q_k DQCg 0Y:qZ)~L0HV z-C%g68%wUϿ }? ?3 K@h aaUe s~2&&B*Alji*˨,oƣT,d[3-*> LɟfkҠw#*AEjKUy>&{8m5Ki jjD*Nigw7DmzK۾M!k?o_lX#~XӑR*EՂדE;6e"Q(=Ezæ5Kؼָ_ 1zBJ X96jL^7{J1i@%8'7M_\Q#Uy Wo x8sv|Sn q_m >b[JX,4[T{Ratjjzz'ȶiIws KC^Y%6ꈺ]vhiWvh'̂|[^YrD=ѝlU_?]Y(N8f1qn-etm 0}b%׌=0?1s08;_ W|%\Zð >舽lnp.a{ )t; b n652?>Oдunm`׭ZWjC~>־0+ {{fMŕټ` ݛ%uA6,]kWu]7ihu1 l Ҷ̺:\cxhRQt$ fd<4B[fd7=.M9//O a},j?.5ښm?X2#d p(?c!a1ޗةܾ7dK:)3],H+ku<|`LhC7e םt H$^2%l.aeÉ|s }D^hz~Rá]|#@חև[k<|(*ݹdtM:,]' X_n| /cfOIENDB`tqsl-2.8.2/src/doxygen/html/structtqsl__provider__st.html0000644000175000017500000001354515061653721023766 0ustar rmurphyrmurphy TrustedQSL Library API: tqsl_provider_st Struct Reference
TrustedQSL Library API
tqsl_provider_st Struct Reference

#include <tqsllib.h>

Public Attributes

char organizationName [TQSL_NAME_ELEMENT_MAX+1]
 Provider name.
 
char organizationalUnitName [TQSL_NAME_ELEMENT_MAX+1]
 Provider unit.
 
char emailAddress [TQSL_NAME_ELEMENT_MAX+1]
 Provider e-mail.
 
char url [TQSL_NAME_ELEMENT_MAX+1]
 Provider URL.
 

Detailed Description

Certificate provider data


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtqsl__provider__st-members.html0000644000175000017500000000731715061653721025416 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tqsl_provider_st Member List
tqsl-2.8.2/src/doxygen/html/structtqsl__cert__req__st.html0000644000175000017500000003507415061653721024100 0ustar rmurphyrmurphy TrustedQSL Library API: tqsl_cert_req_st Struct Reference
TrustedQSL Library API
tqsl_cert_req_st Struct Reference

#include <tqsllib.h>

Public Attributes

char providerName [TQSL_NAME_ELEMENT_MAX+1]
 < Cert request data
 
char providerUnit [TQSL_NAME_ELEMENT_MAX+1]
 Provider unit.
 
char callSign [TQSL_CALLSIGN_MAX+1]
 Callsign.
 
char name [TQSL_CRQ_NAME_MAX+1]
 Name.
 
char address1 [TQSL_CRQ_ADDR_MAX+1]
 Address 1.
 
char address2 [TQSL_CRQ_ADDR_MAX+1]
 Address 2.
 
char city [TQSL_CRQ_CITY_MAX+1]
 City.
 
char state [TQSL_CRQ_STATE_MAX+1]
 State.
 
char postalCode [TQSL_CRQ_POSTAL_MAX+1]
 Postal Code.
 
char country [TQSL_CRQ_COUNTRY_MAX+1]
 Country.
 
char emailAddress [TQSL_CRQ_EMAIL_MAX+1]
 e-mail
 
int dxccEntity
 DXCC Entity code.
 
tQSL_Date qsoNotBefore
 QSOs not before date.
 
tQSL_Date qsoNotAfter
 QSOs not after date.
 
char password [TQSL_PASSWORD_MAX+1]
 Password.
 
tQSL_Cert signer
 Signing cert.
 
char renew
 Rewewal reference.
 

Detailed Description

Certificate request data

Member Data Documentation

◆ providerName

char tqsl_cert_req_st::providerName[TQSL_NAME_ELEMENT_MAX+1]

< Cert request data

Provider name


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtqsl__cert__req__st-members.html0000644000175000017500000001605315061653721025524 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tqsl-2.8.2/src/doxygen/html/structtqsl__cabrilloField.html0000644000175000017500000001255315061653721024020 0ustar rmurphyrmurphy TrustedQSL Library API: tqsl_cabrilloField Struct Reference
TrustedQSL Library API
tqsl_cabrilloField Struct Reference

#include <cabrillo.h>

Public Attributes

char name [TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX+1]
 < Cabrillo field
 
char value [TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX+1]
 Field value.
 

Detailed Description

Cabrillo field data:

  • name - ADIF field name
  • value - Field content

Member Data Documentation

◆ name

char tqsl_cabrilloField::name[TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX+1]

< Cabrillo field

Field name


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtqsl__cabrilloField-members.html0000644000175000017500000000626515061653721025453 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tqsl_cabrilloField Member List

This is the complete list of members for tqsl_cabrilloField, including all inherited members.

nametqsl_cabrilloField
valuetqsl_cabrilloField
tqsl-2.8.2/src/doxygen/html/structtqsl__adifFieldResults.html0000644000175000017500000001700515061653721024513 0ustar rmurphyrmurphy TrustedQSL Library API: tqsl_adifFieldResults Struct Reference
TrustedQSL Library API
tqsl_adifFieldResults Struct Reference

#include <adif.h>

Public Attributes

char name [TQSL_ADIF_FIELD_NAME_LENGTH_MAX+1]
 Field name.
 
char size [TQSL_ADIF_FIELD_SIZE_LENGTH_MAX+1]
 Size.
 
char type [TQSL_ADIF_FIELD_TYPE_LENGTH_MAX+1]
 Type.
 
unsigned char * data
 data
 
unsigned int adifNameIndex
 Name index.
 
void * userPointer
 User pointer.
 
int line_no
 Input line where the tag was found.
 

Detailed Description

Field returned from parsing


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtqsl__adifFieldResults-members.html0000644000175000017500000001105315061653721026140 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tqsl-2.8.2/src/doxygen/html/structtqsl__adifFieldDefinitions.html0000644000175000017500000002010715061653721025322 0ustar rmurphyrmurphy TrustedQSL Library API: tqsl_adifFieldDefinitions Struct Reference
TrustedQSL Library API
tqsl_adifFieldDefinitions Struct Reference

#include <adif.h>

Public Attributes

char name [TQSL_ADIF_FIELD_NAME_LENGTH_MAX+1]
 Field name.
 
char type [TQSL_ADIF_FIELD_TYPE_LENGTH_MAX+1]
 Field type.
 
TQSL_ADIF_RANGE_TYPE rangeType
 Range type.
 
unsigned int max_length
 Max length.
 
long signed min_value
 Min value.
 
long signed max_value
 Max value.
 
const char ** enumStrings
 Enumerated values.
 
void * userPointer
 user pointer
 

Detailed Description

An ADIF field definition


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtqsl__adifFieldDefinitions-members.html0000644000175000017500000001166515061653721026763 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tqsl-2.8.2/src/doxygen/html/structtQSL__Time.html0000644000175000017500000001155315061653721022022 0ustar rmurphyrmurphy TrustedQSL Library API: tQSL_Time Struct Reference
TrustedQSL Library API
tQSL_Time Struct Reference

#include <tqsllib.h>

Public Attributes

int hour
 Time hour field.
 
int minute
 Time minute field.
 
int second
 Time seconds field.
 

Detailed Description

Struct that holds h-m-s


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtQSL__Time-members.html0000644000175000017500000000652215061653721023452 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tQSL_Time Member List

This is the complete list of members for tQSL_Time, including all inherited members.

hourtQSL_Time
minutetQSL_Time
secondtQSL_Time
tqsl-2.8.2/src/doxygen/html/structtQSL__Date.html0000644000175000017500000001153115061653721021775 0ustar rmurphyrmurphy TrustedQSL Library API: tQSL_Date Struct Reference
TrustedQSL Library API
tQSL_Date Struct Reference

#include <tqsllib.h>

Public Attributes

int year
 Numeric year.
 
int month
 Numeric month.
 
int day
 Numeric day.
 

Detailed Description

Struct that holds y-m-d


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structtQSL__Date-members.html0000644000175000017500000000651615061653721023434 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tQSL_Date Member List

This is the complete list of members for tQSL_Date, including all inherited members.

daytQSL_Date
monthtQSL_Date
yeartQSL_Date
tqsl-2.8.2/src/doxygen/html/structTQSL__QSO__RECORD.html0000644000175000017500000005152415061653721022725 0ustar rmurphyrmurphy TrustedQSL Library API: TQSL_QSO_RECORD Struct Reference
TrustedQSL Library API
TQSL_QSO_RECORD Struct Reference

#include <tqsllib.h>

Public Attributes

char callsign [TQSL_CALLSIGN_MAX+1]
 QSO callsign.
 
char band [TQSL_BAND_MAX+1]
 QSO band.
 
char mode [TQSL_MODE_MAX+1]
 QSO mode.
 
char submode [TQSL_MODE_MAX+1]
 QSO submode.
 
tQSL_Date date
 QSO date.
 
tQSL_Time time
 QSO time.
 
char freq [TQSL_FREQ_MAX+1]
 QSO frequency.
 
char rxfreq [TQSL_FREQ_MAX+1]
 QSO receive frequency.
 
char rxband [TQSL_BAND_MAX+1]
 QSO RX band.
 
char propmode [TQSL_PROPMODE_MAX+1]
 QSO prop mode.
 
char satname [TQSL_SATNAME_MAX+1]
 QSO satellite name.
 
bool callsign_set
 QSO specifies a call worked.
 
bool mode_set
 QSO specifies a mode.
 
bool band_set
 QSO specifies a band or frequency.
 
bool date_set
 QSO specifies a date.
 
bool time_set
 QSO specifies a time.
 
char my_state [TQSL_STATE_MAX+1]
 QSO specifies MY_STATE.
 
char my_gridsquare [TQSL_GRID_MAX+1]
 QSO specifies MY_GRIDSQUARE.
 
char my_vucc_grids [TQSL_GRID_MAX+1]
 QSO specifies MY_VUCC_GRIDS.
 
char my_county [TQSL_CNTY_MAX+1]
 QSO specifies MY_CNTY.
 
char my_cnty_state [TQSL_STATE_MAX+1]
 QSO specifies a state with MY_CNTY.
 
char my_country [TQSL_COUNTRY_MAX+1]
 QSO specifies MY_COUNTRY.
 
char my_cq_zone [TQSL_ZONE_MAX+1]
 QSO specifies MY_CQ_ZONE.
 
char my_itu_zone [TQSL_ZONE_MAX+1]
 QSO specifies MY_ITU_ZONE.
 
int my_dxcc
 QSO specifies MY_DXCC.
 
char my_call [TQSL_CALLSIGN_MAX+1]
 Station Callsign.
 
char my_operator [TQSL_CALLSIGN_MAX+1]
 Operator's callsign.
 
char my_iota [TQSL_IOTA_MAX+1]
 QSO specifies MY_IOTA_.
 

Detailed Description

QSO data


The documentation for this struct was generated from the following file:
tqsl-2.8.2/src/doxygen/html/structTQSL__QSO__RECORD-members.html0000644000175000017500000002335015061653721024351 0ustar rmurphyrmurphy TrustedQSL Library API: Member List
TrustedQSL Library API
tqsl-2.8.2/src/doxygen/html/splitbard.png0000644000175000017500000000043215061653721020413 0ustar rmurphyrmurphyPNG  IHDRMIDATx1jPFE$H3f B܀P܅ 6q_E=o^v'{/(ESa"LQ)0E(ESa"LQ)0E( r8޼~ׯ>_3gOp?/գ7W(ESa"LQ)0E(ESa"LQ)0E(E?'V+q.IENDB`tqsl-2.8.2/src/doxygen/html/splitbar.png0000644000175000017500000000047215061653721020253 0ustar rmurphyrmurphyPNG  IHDRMIDATxݡJCa( %4 bȘͶ3v^EL ,b;{Ï/aYկq:\IIIIIIIIIIIIIIIIII-l揊_t/ϻYQVYivk_ۣI@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$C[V=[fIENDB`tqsl-2.8.2/src/doxygen/html/resize.js0000644000175000017500000001313215061653721017561 0ustar rmurphyrmurphy/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ function initResizable(treeview) { let sidenav,navtree,content,header,footer,barWidth=6; const RESIZE_COOKIE_NAME = ''+'width'; function resizeWidth() { const sidenavWidth = $(sidenav).outerWidth(); content.css({marginLeft:parseInt(sidenavWidth)+"px"}); if (typeof page_layout!=='undefined' && page_layout==1) { footer.css({marginLeft:parseInt(sidenavWidth)+"px"}); } Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); } function restoreWidth(navWidth) { content.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); if (typeof page_layout!=='undefined' && page_layout==1) { footer.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); } sidenav.css({width:navWidth + "px"}); } function resizeHeight(treeview) { const headerHeight = header.outerHeight(); const windowHeight = $(window).height(); let contentHeight; if (treeview) { const footerHeight = footer.outerHeight(); let navtreeHeight,sideNavHeight; if (typeof page_layout==='undefined' || page_layout==0) { /* DISABLE_INDEX=NO */ contentHeight = windowHeight - headerHeight - footerHeight; navtreeHeight = contentHeight; sideNavHeight = contentHeight; } else if (page_layout==1) { /* DISABLE_INDEX=YES */ contentHeight = windowHeight - footerHeight; navtreeHeight = windowHeight - headerHeight; sideNavHeight = windowHeight; } navtree.css({height:navtreeHeight + "px"}); sidenav.css({height:sideNavHeight + "px"}); } else { contentHeight = windowHeight - headerHeight; } content.css({height:contentHeight + "px"}); if (location.hash.slice(1)) { (document.getElementById(location.hash.slice(1))||document.body).scrollIntoView(); } } function collapseExpand() { let newWidth; if (sidenav.width()>0) { newWidth=0; } else { const width = Cookie.readSetting(RESIZE_COOKIE_NAME,250); newWidth = (width>250 && width<$(window).width()) ? width : 250; } restoreWidth(newWidth); const sidenavWidth = $(sidenav).outerWidth(); Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); } header = $("#top"); content = $("#doc-content"); footer = $("#nav-path"); sidenav = $("#side-nav"); if (!treeview) { // title = $("#titlearea"); // titleH = $(title).height(); // let animating = false; // content.on("scroll", function() { // slideOpts = { duration: 200, // step: function() { // contentHeight = $(window).height() - header.outerHeight(); // content.css({ height : contentHeight + "px" }); // }, // done: function() { animating=false; } // }; // if (content.scrollTop()>titleH && title.css('display')!='none' && !animating) { // title.slideUp(slideOpts); // animating=true; // } else if (content.scrollTop()<=titleH && title.css('display')=='none' && !animating) { // title.slideDown(slideOpts); // animating=true; // } // }); } else { navtree = $("#nav-tree"); $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); $(sidenav).resizable({ minWidth: 0 }); } $(window).resize(function() { resizeHeight(treeview); }); if (treeview) { const device = navigator.userAgent.toLowerCase(); const touch_device = device.match(/(iphone|ipod|ipad|android)/); if (touch_device) { /* wider split bar for touch only devices */ $(sidenav).css({ paddingRight:'20px' }); $('.ui-resizable-e').css({ width:'20px' }); $('#nav-sync').css({ right:'34px' }); barWidth=20; } const width = Cookie.readSetting(RESIZE_COOKIE_NAME,250); if (width) { restoreWidth(width); } else { resizeWidth(); } } resizeHeight(treeview); const url = location.href; const i=url.indexOf("#"); if (i>=0) window.location.hash=url.substr(i); const _preventDefault = function(evt) { evt.preventDefault(); }; if (treeview) { $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); $(".ui-resizable-handle").dblclick(collapseExpand); // workaround for firefox $("body").css({overflow: "hidden"}); } $(window).on('load',function() { resizeHeight(treeview); }); } /* @license-end */ tqsl-2.8.2/src/doxygen/html/plusd.svg0000644000175000017500000000127015061653721017572 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/plus.svg0000644000175000017500000000127015061653721017426 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/open.png0000644000175000017500000000017315061653721017372 0ustar rmurphyrmurphyPNG  IHDR BIDATx 0 ׬ՙ\39b!9{|I>$#ߴ8/z/>2[giU,/~\ 9ٸIENDB`tqsl-2.8.2/src/doxygen/html/navtree.css0000644000175000017500000000416715061653721020110 0ustar rmurphyrmurphy#nav-tree .children_ul { margin:0; padding:4px; } #nav-tree ul { list-style:none outside none; margin:0px; padding:0px; } #nav-tree li { white-space:nowrap; margin:0px; padding:0px; } #nav-tree .plus { margin:0px; } #nav-tree .selected { background-image: url('tab_a.png'); background-repeat:repeat-x; color: var(--nav-text-active-color); text-shadow: var(--nav-text-active-shadow); } #nav-tree .selected .arrow { color: var(--nav-arrow-selected-color); text-shadow: none; } #nav-tree img { margin:0px; padding:0px; border:0px; vertical-align: middle; } #nav-tree a { text-decoration:none; padding:0px; margin:0px; } #nav-tree .label { margin:0px; padding:0px; font: 12px var(--font-family-nav); } #nav-tree .label a { padding:2px; } #nav-tree .selected a { text-decoration:none; color:var(--nav-text-active-color); } #nav-tree .children_ul { margin:0px; padding:0px; } #nav-tree .item { margin:0px; padding:0px; } #nav-tree { padding: 0px 0px; font-size:14px; overflow:auto; } #doc-content { overflow:auto; display:block; padding:0px; margin:0px; -webkit-overflow-scrolling : touch; /* iOS 5+ */ } #side-nav { padding:0 6px 0 0; margin: 0px; display:block; position: absolute; left: 0px; width: $width; overflow : hidden; } .ui-resizable .ui-resizable-handle { display:block; } .ui-resizable-e { background-image:var(--nav-splitbar-image); background-size:100%; background-repeat:repeat-y; background-attachment: scroll; cursor:ew-resize; height:100%; right:0; top:0; width:6px; } .ui-resizable-handle { display:none; font-size:0.1px; position:absolute; z-index:1; } #nav-tree-contents { margin: 6px 0px 0px 0px; } #nav-tree { background-repeat:repeat-x; background-color: var(--nav-background-color); -webkit-overflow-scrolling : touch; /* iOS 5+ */ } #nav-sync { position:absolute; top:5px; right:24px; z-index:0; } #nav-sync img { opacity:0.3; } #nav-sync img:hover { opacity:0.9; } @media print { #nav-tree { display: none; } div.ui-resizable-handle { display: none; position: relative; } } tqsl-2.8.2/src/doxygen/html/nav_hd.png0000644000175000017500000000016215061653721017666 0ustar rmurphyrmurphyPNG  IHDR ,@9IDATxݻ Q ;r5 W v?P_E27jA v #IENDB`tqsl-2.8.2/src/doxygen/html/nav_h.png0000644000175000017500000000014215061653721017520 0ustar rmurphyrmurphyPNG  IHDR ,@)IDATxA @BQۛТ) ) aܿoRlIENDB`tqsl-2.8.2/src/doxygen/html/nav_g.png0000644000175000017500000000013715061653721017523 0ustar rmurphyrmurphyPNG  IHDR1&IDATx1 OHf_ ->~M iMS<IENDB`tqsl-2.8.2/src/doxygen/html/nav_fd.png0000644000175000017500000000025115061653721017663 0ustar rmurphyrmurphyPNG  IHDR8pIDATxM F ((jMM[73o@s ´K̑ y=[>P\U/gdHȢ(zNC.??;y@AKIENDB`tqsl-2.8.2/src/doxygen/html/nav_f.png0000644000175000017500000000023115061653721017515 0ustar rmurphyrmurphyPNG  IHDR8`IDATxK Eі[BmkHprӼ.ꎤR6Z VIE5jliIJ0/u޿6sH yIENDB`tqsl-2.8.2/src/doxygen/html/modules.html0000644000175000017500000000665315061653721020272 0ustar rmurphyrmurphy TrustedQSL Library API: Modules
TrustedQSL Library API
Modules
tqsl-2.8.2/src/doxygen/html/minusd.svg0000644000175000017500000000110615061653721017740 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/minus.svg0000644000175000017500000000110615061653721017574 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/menudata.js0000644000175000017500000001012615061653721020056 0ustar rmurphyrmurphy/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ var menudata={children:[ {text:"Main Page",url:"index.html"}, {text:"Topics",url:"topics.html"}, {text:"Classes",url:"annotated.html",children:[ {text:"Class List",url:"annotated.html"}, {text:"Class Members",url:"functions.html",children:[ {text:"All",url:"functions.html",children:[ {text:"a",url:"functions.html#index_a"}, {text:"b",url:"functions.html#index_b"}, {text:"c",url:"functions.html#index_c"}, {text:"d",url:"functions.html#index_d"}, {text:"e",url:"functions.html#index_e"}, {text:"f",url:"functions.html#index_f"}, {text:"h",url:"functions.html#index_h"}, {text:"l",url:"functions.html#index_l"}, {text:"m",url:"functions.html#index_m"}, {text:"n",url:"functions.html#index_n"}, {text:"o",url:"functions.html#index_o"}, {text:"p",url:"functions.html#index_p"}, {text:"q",url:"functions.html#index_q"}, {text:"r",url:"functions.html#index_r"}, {text:"s",url:"functions.html#index_s"}, {text:"t",url:"functions.html#index_t"}, {text:"u",url:"functions.html#index_u"}, {text:"v",url:"functions.html#index_v"}, {text:"y",url:"functions.html#index_y"}]}, {text:"Variables",url:"functions_vars.html",children:[ {text:"a",url:"functions_vars.html#index_a"}, {text:"b",url:"functions_vars.html#index_b"}, {text:"c",url:"functions_vars.html#index_c"}, {text:"d",url:"functions_vars.html#index_d"}, {text:"e",url:"functions_vars.html#index_e"}, {text:"f",url:"functions_vars.html#index_f"}, {text:"h",url:"functions_vars.html#index_h"}, {text:"l",url:"functions_vars.html#index_l"}, {text:"m",url:"functions_vars.html#index_m"}, {text:"n",url:"functions_vars.html#index_n"}, {text:"o",url:"functions_vars.html#index_o"}, {text:"p",url:"functions_vars.html#index_p"}, {text:"q",url:"functions_vars.html#index_q"}, {text:"r",url:"functions_vars.html#index_r"}, {text:"s",url:"functions_vars.html#index_s"}, {text:"t",url:"functions_vars.html#index_t"}, {text:"u",url:"functions_vars.html#index_u"}, {text:"v",url:"functions_vars.html#index_v"}, {text:"y",url:"functions_vars.html#index_y"}]}]}]}, {text:"Files",url:"files.html",children:[ {text:"File List",url:"files.html"}, {text:"File Members",url:"globals.html",children:[ {text:"All",url:"globals.html",children:[ {text:"c",url:"globals.html#index_c"}, {text:"d",url:"globals_d.html#index_d"}, {text:"g",url:"globals_g.html#index_g"}, {text:"p",url:"globals_p.html#index_p"}, {text:"t",url:"globals_t.html#index_t"}]}, {text:"Functions",url:"globals_func.html",children:[ {text:"t",url:"globals_func.html#index_t"}]}, {text:"Variables",url:"globals_vars.html"}, {text:"Typedefs",url:"globals_type.html"}, {text:"Enumerations",url:"globals_enum.html"}, {text:"Macros",url:"globals_defs.html",children:[ {text:"c",url:"globals_defs.html#index_c"}, {text:"d",url:"globals_defs.html#index_d"}, {text:"g",url:"globals_defs.html#index_g"}, {text:"p",url:"globals_defs.html#index_p"}, {text:"t",url:"globals_defs.html#index_t"}]}]}]}]} tqsl-2.8.2/src/doxygen/html/menu.js0000644000175000017500000001337515061653721017235 0ustar rmurphyrmurphy/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ function initMenu(relPath,searchEnabled,serverSide,searchPage,search,treeview) { function makeTree(data,relPath) { let result=''; if ('children' in data) { result+='
    '; for (let i in data.children) { let url; const link = data.children[i].url; if (link.substring(0,1)=='^') { url = link.substring(1); } else { url = relPath+link; } result+='
  • '+ data.children[i].text+''+ makeTree(data.children[i],relPath)+'
  • '; } result+='
'; } return result; } let searchBoxHtml; if (searchEnabled) { if (serverSide) { searchBoxHtml='
'+ '
'+ '
 '+ ''+ '
'+ '
'+ '
'+ '
'; } else { searchBoxHtml='
'+ ''+ ' '+ ''+ ''+ ''+ ''+ ''+ '
'; } } $('#main-nav').before('
'+ ''+ ''+ '
'); $('#main-nav').append(makeTree(menudata,relPath)); $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu'); if (searchBoxHtml) { $('#main-menu').append('
  • '); } const $mainMenuState = $('#main-menu-state'); let prevWidth = 0; if ($mainMenuState.length) { const initResizableIfExists = function() { if (typeof initResizable==='function') initResizable(treeview); } // animate mobile menu $mainMenuState.change(function() { const $menu = $('#main-menu'); let options = { duration: 250, step: initResizableIfExists }; if (this.checked) { options['complete'] = () => $menu.css('display', 'block'); $menu.hide().slideDown(options); } else { options['complete'] = () => $menu.css('display', 'none'); $menu.show().slideUp(options); } }); // set default menu visibility const resetState = function() { const $menu = $('#main-menu'); const newWidth = $(window).outerWidth(); if (newWidth!=prevWidth) { if ($(window).outerWidth()<768) { $mainMenuState.prop('checked',false); $menu.hide(); $('#searchBoxPos1').html(searchBoxHtml); $('#searchBoxPos2').hide(); } else { $menu.show(); $('#searchBoxPos1').empty(); $('#searchBoxPos2').html(searchBoxHtml); $('#searchBoxPos2').show(); } if (typeof searchBox!=='undefined') { searchBox.CloseResultsWindow(); } prevWidth = newWidth; } } $(window).ready(function() { resetState(); initResizableIfExists(); }); $(window).resize(resetState); } $('#main-menu').smartmenus(); } /* @license-end */ tqsl-2.8.2/src/doxygen/html/jquery.js0000644000175000017500000053121615061653721017607 0ustar rmurphyrmurphy/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e} var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType }catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c )),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){ return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll( ":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id") )&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push( "\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test( a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null, null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne ).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for( var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n; return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0, r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r] ,C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each( function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r, "position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})} ),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each( "blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=y(e||this.defaultElement||this)[0],this.element=y(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=y(),this.hoverable=y(),this.focusable=y(),this.classesElementLookup={},e!==this&&(y.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t ){t.target===e&&this.destroy()}}),this.document=y(e.style?e.ownerDocument:e.document||e),this.window=y(this.document[0].defaultView||this.document[0].parentWindow)),this.options=y.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:y.noop,_create:y.noop,_init:y.noop,destroy:function(){var i=this;this._destroy(),y.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:y.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return y.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t ]=y.widget.extend({},this.options[t]),n=0;n
    "),i=e.children()[0];return y("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i}, getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(D(s),D(n))?o.important="horizontal":o.important="vertical",p.using.call(this,t,o)}),h.offset(y.extend(l,{using:t}))})},y.ui.position={fit:{left:function(t,e){var i=e.within, s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),y.ui.plugin={add:function(t,e,i){var s,n=y.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n").css({overflow:"hidden",position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})), this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&y(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy(),this._addedHandles.remove();function t(t){y(t ).removeData("resizable").removeData("ui-resizable").off(".resizable")}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;case"aspectRatio":this._aspectRatio=!!e}},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(y(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=y(),this._addedHandles=y(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split( ","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.children(this.handles[t]).length||(this.element.append(n),this._addedHandles=this._addedHandles.add(n));this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=y(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=y(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add( this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._addedHandles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=y(this.handles[e])[0])!==t.target&&!y.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=y(s.containment).scrollLeft()||0,i+=y(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{ width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=y(".ui-resizable-"+this.axis).css("cursor"),y("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(), !this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),y.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(y.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),y("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){ this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,r=this.originalPosition.top+this.originalSize.height ,l=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=a-e.minWidth),s&&l&&(t.left=a-e.maxWidth),h&&i&&(t.top=r-e.minHeight),n&&i&&(t.top=r-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e").css({overflow:"hidden"}),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e, i){return y.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){y.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),y.ui.plugin.add("resizable","animate",{stop:function(e){var i=y(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left )||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(y.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&y(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),y.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=y(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof y?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=y(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:y(document),left:0,top:0,width:y(document).width(),height:y(document).height()||document.body.parentNode.scrollHeight}):(i=y(h),s=[],y(["Top","Right","Left","Bottom"]).each(function(t,e ){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=y(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0), i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=y(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=y(t.helper),h=o.offset(),a=o.outerWidth( )-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),y.ui.plugin.add("resizable","alsoResize",{start:function(){var t=y(this).resizable("instance").options;y(t.alsoResize).each(function(){var t=y(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=y(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};y(s.alsoResize).each(function(){var t=y(this),s=y(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];y.each(e, function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){y(this).removeData("ui-resizable-alsoresize")}}),y.ui.plugin.add("resizable","ghost",{start:function(){var t=y(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==y.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=y(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=y(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),y.ui.plugin.add("resizable","grid",{resize:function(){var t,e=y(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,r=a[0 ]||1,l=a[1]||1,u=Math.round((s.width-n.width)/r)*r,p=Math.round((s.height-n.height)/l)*l,d=n.width+u,c=n.height+p,f=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>c;i.grid=a,m&&(d+=r),s&&(c+=l),f&&(d-=r),g&&(c-=l),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=c):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.top=o.top-p):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.left=o.left-u):((c-l<=0||d-r<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0=f[g]?0:Math.min(f[g],n));!a&&1-1){ targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se", "n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if( session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)} closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if( session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE, function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset); tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList, finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight())); return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")} function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(), elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight, viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b, "_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); /*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 * http://www.smartmenus.org/ * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)), mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend( $.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy( this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData( "smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id" ).indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
    ').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?( this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for( var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){ return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if(( !this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&( this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0 ]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass( "highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){ t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]" )||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){ t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"), a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i, downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2) )&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t )&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0), canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}}, rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})} return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1, bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); tqsl-2.8.2/src/doxygen/html/index.html0000644000175000017500000001105315061653721017717 0ustar rmurphyrmurphy TrustedQSL Library API: TrustedQSL Library API
    TrustedQSL Library API
    TrustedQSL Library API

    The TrustedQSL library API is divided into several groups:

    • Certificate Handling API - Request, load and retrieve digital certificates
    • Data API - Manage station-location data and produce signed data records
    • Converter API - Convert and sign ADIF and Cabrillo log files
    • Utility API - Functions to operate on objects, set system parameters, and report errors
    • Signing API - Low-level digital signing
    • ADIF API - Low-level parsing and creation of ADIF files
    • Cabrillo API - Low-level parsing of Cabrillo files.

    Most of the library functions return an integer value that is zero if there is no error and 1 if there is an error. The specific error can be determined by examining tQSL_Error and, possibly, tQSL_ADIF_Error, tQSL_Cabrillo_Error, tQSL_ErrorFile and tQSL_CustomError. The tqsl_getErrorString() and tqsl_getErrorString_v() functions can be used to get error text strings.

    tqsl-2.8.2/src/doxygen/html/group__Util.html0000644000175000017500000012235515061653721021110 0ustar rmurphyrmurphy TrustedQSL Library API: Utility API
    TrustedQSL Library API
    Utility API

    Functions

    DLLEXPORT int CALLCONVENTION tqsl_init ()
     
    DLLEXPORT int CALLCONVENTION tqsl_setDirectory (const char *dir)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString ()
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString_v (int err)
     
    DLLEXPORT int CALLCONVENTION tqsl_encodeBase64 (const unsigned char *data, int datalen, char *output, int outputlen)
     
    DLLEXPORT int CALLCONVENTION tqsl_decodeBase64 (const char *input, unsigned char *data, int *datalen)
     
    DLLEXPORT int CALLCONVENTION tqsl_initDate (tQSL_Date *date, const char *str)
     
    DLLEXPORT int CALLCONVENTION tqsl_initTime (tQSL_Time *time, const char *str)
     
    DLLEXPORT int CALLCONVENTION tqsl_compareDates (const tQSL_Date *a, const tQSL_Date *b)
     
    DLLEXPORT int CALLCONVENTION tqsl_subtractDates (const tQSL_Date *a, const tQSL_Date *b, int *diff)
     
    DLLEXPORT char *CALLCONVENTION tqsl_convertDateToText (const tQSL_Date *date, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_isDateValid (const tQSL_Date *d)
     
    DLLEXPORT int CALLCONVENTION tqsl_isDateNull (const tQSL_Date *d)
     
    DLLEXPORT int CALLCONVENTION tqsl_isTimeValid (const tQSL_Time *t)
     
    DLLEXPORT char *CALLCONVENTION tqsl_convertTimeToText (const tQSL_Time *time, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getVersion (int *major, int *minor)
     
    DLLEXPORT int CALLCONVENTION tqsl_getConfigVersion (int *major, int *minor)
     

    Variables

    DLLEXPORTDATA int tQSL_Error
     Error code from most recent tQSL library call.
     
    DLLEXPORTDATA TQSL_ADIF_GET_FIELD_ERROR tQSL_ADIF_Error
     The ADIF error code.
     
    DLLEXPORTDATA TQSL_CABRILLO_ERROR_TYPE tQSL_Cabrillo_Error
     The ADIF error code.
     
    DLLEXPORTDATA char tQSL_ErrorFile [TQSL_MAX_PATH_LEN]
     File name of file giving error. (May be empty.)
     
    DLLEXPORTDATA char tQSL_CustomError [256]
     Custom error message string.
     
    DLLEXPORTDATA int tQSL_Errno
     System errno - stored when tQSL_Error == TQSL_SYSTEM_ERROR.
     
    DLLEXPORTDATA char tQSL_ImportCall [256]
     Callsign used in import - used for missing public key error.
     
    DLLEXPORTDATA long tQSL_ImportSerial
     Serial number of recent certificate import.
     
    DLLEXPORTDATA FILE * tQSL_DiagFile
     Diagnostic log file.
     

    Detailed Description

    Function Documentation

    ◆ tqsl_compareDates()

    DLLEXPORT int CALLCONVENTION tqsl_compareDates ( const tQSL_Date * a,
    const tQSL_Date * b )

    Compare two tQSL_Date objects.

    Returns:

    • -1 if a < b
    • 0 if a == b
    • 1 if a > b

    ◆ tqsl_convertDateToText()

    DLLEXPORT char *CALLCONVENTION tqsl_convertDateToText ( const tQSL_Date * date,
    char * buf,
    int bufsiz )

    Converts a tQSL_Date object to a YYYY-MM-DD string.

    Returns a pointer to buf or NULL on error

    ◆ tqsl_convertTimeToText()

    DLLEXPORT char *CALLCONVENTION tqsl_convertTimeToText ( const tQSL_Time * time,
    char * buf,
    int bufsiz )

    Converts a tQSL_Time object to a HH:MM:SSZ string.

    Returns a pointer to buf or NULL on error

    ◆ tqsl_decodeBase64()

    DLLEXPORT int CALLCONVENTION tqsl_decodeBase64 ( const char * input,
    unsigned char * data,
    int * datalen )

    Decode Base64 text into binary data.

    • input = NUL-terminated text string of Base64-encoded data
    • data = pointer to output buffer
    • datalen = pointer to int containing the size of the output buffer in bytes

    Places the number of resulting data bytes into *datalen.

    ◆ tqsl_encodeBase64()

    DLLEXPORT int CALLCONVENTION tqsl_encodeBase64 ( const unsigned char * data,
    int datalen,
    char * output,
    int outputlen )

    Encode a block of data into Base64 text.

    • data = block of data to encode
    • datalen = length of data in bytes
    • output = pointer to output buffer
    • outputlen = size of output buffer in bytes

    ◆ tqsl_getConfigVersion()

    DLLEXPORT int CALLCONVENTION tqsl_getConfigVersion ( int * major,
    int * minor )

    Returns the configuration-file version. major and/or minor may be NULL.

    ◆ tqsl_getErrorString()

    DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString ( )

    Gets the error string for the current tQSL library error and resets the error status. See tqsl_getErrorString_v().

    ◆ tqsl_getErrorString_v()

    DLLEXPORT const char *CALLCONVENTION tqsl_getErrorString_v ( int err)

    Gets the error string corresponding to the given error number. The error string is available only until the next call to tqsl_getErrorString_v or tqsl_getErrorString.

    ◆ tqsl_getVersion()

    DLLEXPORT int CALLCONVENTION tqsl_getVersion ( int * major,
    int * minor )

    Returns the library version. major and/or minor may be NULL.

    ◆ tqsl_init()

    DLLEXPORT int CALLCONVENTION tqsl_init ( )

    Initialize the tQSL library

    This function should be called prior to calling any other library functions.

    ◆ tqsl_initDate()

    DLLEXPORT int CALLCONVENTION tqsl_initDate ( tQSL_Date * date,
    const char * str )

    Initialize a tQSL_Date object from a date string.

    The date string must be YYYY-MM-DD or YYYYMMDD format.

    Returns 0 on success, nonzero on failure

    ◆ tqsl_initTime()

    DLLEXPORT int CALLCONVENTION tqsl_initTime ( tQSL_Time * time,
    const char * str )

    Initialize a tQSL_Time object from a time string.

    The time string must be HH[:]MM[[:]SS] format.

    Returns 0 on success, nonzero on failure

    ◆ tqsl_isDateNull()

    DLLEXPORT int CALLCONVENTION tqsl_isDateNull ( const tQSL_Date * d)

    Test whether a tQSL_Date is empty (contains all zeroes)

    Returns 1 if the date is null

    ◆ tqsl_isDateValid()

    DLLEXPORT int CALLCONVENTION tqsl_isDateValid ( const tQSL_Date * d)

    Test whether a tQSL_Date contains a valid date value

    Returns 1 if the date is valid

    ◆ tqsl_isTimeValid()

    DLLEXPORT int CALLCONVENTION tqsl_isTimeValid ( const tQSL_Time * t)

    Test whether a tQSL_Time contains a valid time value

    Returns 1 if the time is valid

    ◆ tqsl_setDirectory()

    DLLEXPORT int CALLCONVENTION tqsl_setDirectory ( const char * dir)

    Set the directory where the TQSL files are kept. May be called either before of after tqsl_init(), but should be called before calling any other functions in the library.

    Note that this is purely optional. The library will figure out an appropriate directory if tqsl_setDirectory isn't called. Unless there is some particular need to set the directory explicitly, programs should refrain from doing so.

    ◆ tqsl_subtractDates()

    DLLEXPORT int CALLCONVENTION tqsl_subtractDates ( const tQSL_Date * a,
    const tQSL_Date * b,
    int * diff )

    Calculate the number of days between two tQSL_Date objects.

    Returns a positive result if the first date is earlier, otherwise negative.

    Variable Documentation

    ◆ tQSL_Error

    DLLEXPORTDATA int tQSL_Error
    extern

    Error code from most recent tQSL library call.

    The values for the error code are defined in tqslerrno.h

    tqsl-2.8.2/src/doxygen/html/group__Sign.html0000644000175000017500000005016515061653721021072 0ustar rmurphyrmurphy TrustedQSL Library API: Signing API
    TrustedQSL Library API
    Signing API

    Functions

    DLLEXPORT int CALLCONVENTION tqsl_beginSigning (tQSL_Cert cert, char *password, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user)
     
    DLLEXPORT int CALLCONVENTION tqsl_checkSigningStatus (tQSL_Cert cert)
     
    DLLEXPORT int CALLCONVENTION tqsl_getMaxSignatureSize (tQSL_Cert cert, int *sigsize)
     
    DLLEXPORT int CALLCONVENTION tqsl_signDataBlock (tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen)
     
    DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock (tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen)
     
    DLLEXPORT int CALLCONVENTION tqsl_signQSORecord (tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *rec, unsigned char *sig, int *siglen)
     
    DLLEXPORT int CALLCONVENTION tqsl_endSigning (tQSL_Cert cert)
     

    Detailed Description

    The Signing API uses a tQSL_Cert (see Certificate Handling API) to digitally sign a block of data.

    Function Documentation

    ◆ tqsl_beginSigning()

    DLLEXPORT int CALLCONVENTION tqsl_beginSigning ( tQSL_Cert cert,
    char * password,
    int(* pwcb )(char *pwbuf, int pwsize, void *userdata),
    void * user )

    Initialize the tQSL_Cert object for use in signing.

    This produces an unencrypted copy of the private key in memory.

    if password is not NULL, it must point to the password to use to decrypt the private key. If password is NULL and pwcb is not NULL, pwcb is called to get the password. If the private key is encrypted and both password and pwcb are NULL, or if the supplied password fails to decrypt the key, a TQSL_PASSWORD_ERROR error is returned.

    pwcb parameters: pwbuf is a pointer to a buffer of pwsize chars. The buffer should be NUL-terminated.

    ◆ tqsl_checkSigningStatus()

    DLLEXPORT int CALLCONVENTION tqsl_checkSigningStatus ( tQSL_Cert cert)

    Test whether the tQSL_Cert object is initialized for signing.

    Returns 0 if initialized. Sets tQSL_Error to TQSL_SIGNINIT_ERROR if not.

    ◆ tqsl_endSigning()

    DLLEXPORT int CALLCONVENTION tqsl_endSigning ( tQSL_Cert cert)

    Terminate signing operations for this tQSL_Cert object.

    This zero-fills the unencrypted private key in memory.

    ◆ tqsl_getMaxSignatureSize()

    DLLEXPORT int CALLCONVENTION tqsl_getMaxSignatureSize ( tQSL_Cert cert,
    int * sigsize )

    Get the maximum size of a signature block that will be produced when the tQSL_Cert is used to sign data. (Note that the size of the signature block is unaffected by the size of the data block being signed.)

    ◆ tqsl_signDataBlock()

    DLLEXPORT int CALLCONVENTION tqsl_signDataBlock ( tQSL_Cert cert,
    const unsigned char * data,
    int datalen,
    unsigned char * sig,
    int * siglen )

    Sign a data block.

    tqsl_beginSigning() must have been called for the tQSL_Cert object before calling this function.

    ◆ tqsl_signQSORecord()

    DLLEXPORT int CALLCONVENTION tqsl_signQSORecord ( tQSL_Cert cert,
    tQSL_Location loc,
    TQSL_QSO_RECORD * rec,
    unsigned char * sig,
    int * siglen )

    Sign a single QSO record

    tqsl_beginSigning() must have been called for the tQSL_Cert object before calling this function.

    loc must be a valid tQSL_Location object. See Data API.

    ◆ tqsl_verifyDataBlock()

    DLLEXPORT int CALLCONVENTION tqsl_verifyDataBlock ( tQSL_Cert cert,
    const unsigned char * data,
    int datalen,
    unsigned char * sig,
    int siglen )

    Verify a signed data block.

    tqsl_beginSigning() need not have been called.

    tqsl-2.8.2/src/doxygen/html/group__Data.html0000644000175000017500000057306515061653721021054 0ustar rmurphyrmurphy TrustedQSL Library API: Data API
    TrustedQSL Library API
    Data API

    Macros

    #define TQSL_LOCATION_FIELD_TEXT   1
     Text type input field.
     
    #define TQSL_LOCATION_FIELD_DDLIST   2
     Dropdown list input field.
     
    #define TQSL_LOCATION_FIELD_LIST   3
     List type input field.
     
    #define TQSL_LOCATION_FIELD_BADZONE   4
     Used to return zone selection errors.
     
    #define TQSL_LOCATION_FIELD_CHAR   1
     Character field.
     
    #define TQSL_LOCATION_FIELD_INT   2
     Integer field.
     
    #define TQSL_VALID_VUCC_ENT   0x2000
     Grid is valid for DXCC Entity.
     
    #define TQSL_VALID_VUCC_PAS   0x4000
     Grid is valid for Primary Administrative Subdivision (State, etc.)
     
    #define GRID_ERROR_INVALID_FIELD   2
     Field - first two chars - is invalid.
     
    #define GRID_ERROR_INVALID_SQUARE   3
     Square - second two chars - is invalid.
     
    #define GRID_ERROR_INVALID_SUBSQUARE   4
     Subsquare - third pair - is invalid.
     
    #define GRID_ERROR_INVALID_SUBSUBSQUARE   5
     Sub-subsquare - fourth pair etc. - is invalid.
     
    #define GRID_ERROR_INVALID_FORMAT   6
     Format error.
     

    Functions

    DLLEXPORT int CALLCONVENTION tqsl_initStationLocationCapture (tQSL_Location *locp)
     
    DLLEXPORT int CALLCONVENTION tqsl_endStationLocationCapture (tQSL_Location *locp)
     
    DLLEXPORT int CALLCONVENTION tqsl_updateStationLocationCapture (tQSL_Location loc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocationCapturePages (tQSL_Location loc, int *npages)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCapturePage (tQSL_Location loc, int *page)
     
    DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCapturePage (tQSL_Location loc, int page)
     
    DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCertFlags (tQSL_Location loc, int flags)
     
    DLLEXPORT int CALLCONVENTION tqsl_nextStationLocationCapture (tQSL_Location loc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNextStationLocationCapturePage (tQSL_Location loc, int *page)
     
    DLLEXPORT int CALLCONVENTION tqsl_prevStationLocationCapture (tQSL_Location loc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getPrevStationLocationCapturePage (tQSL_Location loc, int *page)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCurrentStationLocationCapturePage (tQSL_Location loc, int *page)
     
    DLLEXPORT int CALLCONVENTION tqsl_hasNextStationLocationCapture (tQSL_Location loc, int *rval)
     
    DLLEXPORT int CALLCONVENTION tqsl_hasPrevStationLocationCapture (tQSL_Location loc, int *rval)
     
    DLLEXPORT int CALLCONVENTION tqsl_saveStationLocationCapture (tQSL_Location loc, int overwrite)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCaptureName (tQSL_Location loc, char *namebuf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCaptureName (tQSL_Location loc, const char *name)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocations (tQSL_Location loc, int *nloc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationName (tQSL_Location loc, int idx, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCallSign (tQSL_Location loc, int idx, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField (tQSL_Location locp, const char *name, char *namebuf, int bufsize)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocation (tQSL_Location *loc, const char *name)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationErrors (tQSL_Location loc, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getStationDataEnc (tQSL_StationDataEnc *sdata)
     
    DLLEXPORT int CALLCONVENTION tqsl_freeStationDataEnc (tQSL_StationDataEnc sdata)
     
    DLLEXPORT int CALLCONVENTION tqsl_mergeStationLocations (const char *locdata)
     
    DLLEXPORT int CALLCONVENTION tqsl_deleteStationLocation (const char *name)
     
    DLLEXPORT int CALLCONVENTION tqsl_restoreStationLocation (const char *name)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDeletedStationLocations (char ***locp, int *nloc)
     
    DLLEXPORT void CALLCONVENTION tqsl_freeDeletedLocationList (char **list, int nloc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField (tQSL_Location loc, int *numf)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize (tQSL_Location loc, int field_num, int *rval)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel (tQSL_Location loc, int field_num, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize (tQSL_Location loc, int field_num, int *rval)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI (tQSL_Location loc, int field_num, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldInputType (tQSL_Location loc, int field_num, int *type)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataType (tQSL_Location loc, int field_num, int *type)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldFlags (tQSL_Location loc, int field_num, int *flags)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLength (tQSL_Location loc, int field_num, int *rval)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData (tQSL_Location loc, int field_num, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIntData (tQSL_Location loc, int field_num, int *dat)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIndex (tQSL_Location loc, int field_num, int *dat)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumLocationFieldListItems (tQSL_Location loc, int field_num, int *rval)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem (tQSL_Location loc, int field_num, int item_idx, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldCharData (tQSL_Location loc, int field_num, const char *buf)
     
    DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIntData (tQSL_Location loc, int field_num, int dat)
     
    DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIndex (tQSL_Location loc, int field_num, int dat)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldChanged (tQSL_Location loc, int field_num, int *changed)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationCallSign (tQSL_Location loc, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_setLocationCallSign (tQSL_Location loc, const char *buf, int dxcc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationField (tQSL_Location locp, const char *field, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel (tQSL_Location locp, const char *field, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_setLocationField (tQSL_Location locp, const char *field, const char *buf)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationDXCCEntity (tQSL_Location loc, int *dxcc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationQSODetails (tQSL_Location locp, char *buf, int buflen)
     
    DLLEXPORT int CALLCONVENTION tqsl_getLocationStationDetails (tQSL_Location locp, char *buf, int buflen)
     
    DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo (const char *callsign, const char *json)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo (const char *callsign, char **buf)
     
    DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid (int entity, const char *pas, const char *grid, int *result)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumDXCCEntity (int *number)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity (int index, int *number, const char **name)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName (int number, const char **name)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap (int number, const char **zonemap)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDXCCStartDate (int number, tQSL_Date *d)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDXCCEndDate (int number, tQSL_Date *d)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted (int number, int *deleted)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumBand (int *number)
     
    DLLEXPORT int CALLCONVENTION tqsl_getBand (int index, const char **name, const char **spectrum, int *low, int *high)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumMode (int *number)
     
    DLLEXPORT int CALLCONVENTION tqsl_getMode (int index, const char **mode, const char **group)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumADIFMode (int *number)
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry (int index, const char **mode)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumPropagationMode (int *number)
     
    DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode (int index, const char **name, const char **descrip)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumSatellite (int *number)
     
    DLLEXPORT int CALLCONVENTION tqsl_getSatellite (int index, const char **name, const char **descrip, tQSL_Date *start, tQSL_Date *end)
     
    DLLEXPORT int CALLCONVENTION tqsl_clearCabrilloMap ()
     
    DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry (const char *contest, int field, int contest_type)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry (const char *contest, int *fieldnum, int *contest_type)
     
    DLLEXPORT int CALLCONVENTION tqsl_clearADIFModes ()
     
    DLLEXPORT int CALLCONVENTION tqsl_setADIFMode (const char *adif_item, const char *mode)
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFMode (const char *adif_item, char *mode, int nmode)
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode (const char *adif_item, char *mode, char *submode, int nmode)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCERT (tQSL_Cert cert, int uid)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItSTATION (tQSL_Location loc, int uid, int certuid)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACT (tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACTData (tQSL_Cert cert, tQSL_Location loc, TQSL_QSO_RECORD *qso, int stationuid, char *signdata, int sdlen)
     
    DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat (const char *grid, int twelve, char *newGrid, int newlen)
     

    Detailed Description

    The Data API is used to form data into TrustedQSL records. A TrustedQSL record consists of a station record and a QSO record. Together, the two records fully describe one station's end of the QSO – just as a paper QSL card does.

    The station record contains the callsign and geographic location of the station submitting the QSO record. The library manages the station records. The tqsl_xxxStationLocationCapture functions are used to generate and save a station record. The intent is to provide an interface that makes a step-by-step system (such as a GUI "wizard") easily implemented.

    The tqsl_getStationLocation() function is used to retrieve station records.

    With the necessary station location available, a signed GABBI output file can be generated using the tqsl_getGABBIxxxxx functions:

    The GABBI format requires that the tCERT record contain an integer identifier that is unique within the GABBI file. Similarly, each tSTATION record must contain a unique identifier. Additionally, the tSTATION record must reference the identifier of a preceding tCERT record. Finally, each tCONTACT record must reference a preceding tSTATION record. (A GABBI processor uses these identifiers and references to tie the station and contact records together and to verify their signature via the certificate.) It is the responsibility of the caller to supply these identifiers and to ensure that the supplied references match the tQSL_Cert and tQSL_Location used to create the referenced GABBI records.

    Station Location Generation

    The station-location generation process involves determining the values for a number of station-location parameters. Normally this will be done by prompting the user for the values. The responses given by the user may determine which later fields are required. For example, if the user indicates that the DXCC entity is UNITED STATES, a later field would ask for the US state. This field would not be required if the DXCC entity were not in the US.

    To accommodate the dynamic nature of the field requirements, the fields are ordered such that dependent fields are queried after the field(s) on which they depend. To make this process acceptable in a GUI system, the fields are grouped into pages, where multiple fields may be displayed on the same page. The grouping is such that which fields are within the page is not dependent on any of the values of the fields within the page. That is, a page of fields contains the same fields no matter what value any of the fields contains. (However, the values of fields within the page can depend on the values of fields that precede them in the page.)

    Here is a brief overview of the sequence of events involved in generating a station location interactively, one field at a time:

    1) Call tqsl_initStationLocationCapture() (new location) or tqsl_getStationLocation() (existing location).

    2) For field from 0 to tqsl_getNumLocationField():

    3) If tqsl_hasNextStationLocationCapture() returns 1, call tqsl_nextStationLocationCapture() and go back to step 2.

    In the case of a GUI system, you'll probably want to display the fields in pages. The sequence of events is a bit different:

    1) Call tqsl_initStationLocationCapture() (new location) or tqsl_getStationLocation() (existing location).

    2) For field from 0 to tqsl_getNumLocationField(),

    3) Each time the user changes a field, call tqsl_updateStationLocationCapture(). This may change the allowable selection for fields that follow the field the user changed, so the control for each of those fields should be updated as in step 2.

    4) Once the user has completed entries for the page, if tqsl_hasNextStationLocationCapture() returns 1, call tqsl_nextStationLocationCapture() and go back to step 2.

    N.B. The first two fields in the station-location capture process are always call sign and DXCC entity, in that order. As a practical matter, these two fields must match the corresponding fields in the available certificates. The library will therefore constrain the values of these fields to match what's available in the certificate store. See Certificate Handling API.

    Function Documentation

    ◆ tqsl_clearADIFModes()

    DLLEXPORT int CALLCONVENTION tqsl_clearADIFModes ( )

    Clear the map of ADIF modes

    ◆ tqsl_clearCabrilloMap()

    DLLEXPORT int CALLCONVENTION tqsl_clearCabrilloMap ( )

    Clear the map of Cabrillo contests.

    ◆ tqsl_deleteStationLocation()

    DLLEXPORT int CALLCONVENTION tqsl_deleteStationLocation ( const char * name)

    Remove the stored station location by name.

    ◆ tqsl_endStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_endStationLocationCapture ( tQSL_Location * locp)

    Release the station-location resources. This should be called for any tQSL_Location that was initialized via tqsl_initStationLocationCapture() or tqsl_getStationLocation()

    ◆ tqsl_freeDeletedLocationList()

    DLLEXPORT void CALLCONVENTION tqsl_freeDeletedLocationList ( char ** list,
    int nloc )

    Free the list of restorable station locations.

    ◆ tqsl_freeStationDataEnc()

    DLLEXPORT int CALLCONVENTION tqsl_freeStationDataEnc ( tQSL_StationDataEnc sdata)

    Free the pointer returned by tqsl_getStationDataEnc(tQSL_StationDataEnc*)

    ◆ tqsl_getADIFMode()

    DLLEXPORT int CALLCONVENTION tqsl_getADIFMode ( const char * adif_item,
    char * mode,
    int nmode )

    Map an ADIF mode to its TQSL equivalent.

    ◆ tqsl_getADIFModeEntry()

    DLLEXPORT int CALLCONVENTION tqsl_getADIFModeEntry ( int index,
    const char ** mode )

    Get an ADIF mode by its index.

    mode - The ADIF mode name

    ◆ tqsl_getADIFSubMode()

    DLLEXPORT int CALLCONVENTION tqsl_getADIFSubMode ( const char * adif_item,
    char * mode,
    char * submode,
    int nmode )

    Map a GABBI mode to its mode/submode pair.

    ◆ tqsl_getBand()

    DLLEXPORT int CALLCONVENTION tqsl_getBand ( int index,
    const char ** name,
    const char ** spectrum,
    int * low,
    int * high )

    Get a band by its index.

    name - The GAABI name of the band. spectrum - HF | VHF | UHF low - The low end of the band in kHz (HF) or MHz (VHF/UHF) high - The low high of the band in kHz (HF) or MHz (VHF/UHF)

    Note: spectrum, low and/or high may be NULL.

    ◆ tqsl_getCabrilloMapEntry()

    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloMapEntry ( const char * contest,
    int * fieldnum,
    int * contest_type )

    Get the mapping of a Cabrillo contest name (as found in the CONTEST line of a Cabrillo file) to a call-worked field number and the contest type.

    fieldnum will be set to 0 if the contest name isn't in the Cabrillo map. Otherwise it is set to the QSO line field number of the call-worked field, with field counting starting at 1.

    contest_type may be NULL. If not, it is set to the Cabrillo contest type (TQSL_CABRILLO_HF or TQSL_CABRILLO_VHF), defined in cabrillo.h.

    ◆ tqsl_getCallsignLocationInfo()

    DLLEXPORT int CALLCONVENTION tqsl_getCallsignLocationInfo ( const char * callsign,
    char ** buf )

    Retrieve the json results for a given callsign location Detail.

    ◆ tqsl_getCurrentStationLocationCapturePage()

    DLLEXPORT int CALLCONVENTION tqsl_getCurrentStationLocationCapturePage ( tQSL_Location loc,
    int * page )

    Return the current page in the page sequence.

    ◆ tqsl_getDeletedStationLocations()

    DLLEXPORT int CALLCONVENTION tqsl_getDeletedStationLocations ( char *** locp,
    int * nloc )

    Get the list of restorable station locations.

    ◆ tqsl_getDXCCDeleted()

    DLLEXPORT int CALLCONVENTION tqsl_getDXCCDeleted ( int number,
    int * deleted )

    Get the deleted status of a DXCC Entity by its DXCC number.

    ◆ tqsl_getDXCCEndDate()

    DLLEXPORT int CALLCONVENTION tqsl_getDXCCEndDate ( int number,
    tQSL_Date * d )

    Get the end date of a DXCC Entity by its DXCC number.

    ◆ tqsl_getDXCCEntity()

    DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntity ( int index,
    int * number,
    const char ** name )

    Get a DXCC entity from the list of DXCC entities by its index.

    ◆ tqsl_getDXCCEntityName()

    DLLEXPORT int CALLCONVENTION tqsl_getDXCCEntityName ( int number,
    const char ** name )

    Get the name of a DXCC Entity by its DXCC number.

    ◆ tqsl_getDXCCStartDate()

    DLLEXPORT int CALLCONVENTION tqsl_getDXCCStartDate ( int number,
    tQSL_Date * d )

    Get the start date of a DXCC Entity by its DXCC number.

    ◆ tqsl_getDXCCZoneMap()

    DLLEXPORT int CALLCONVENTION tqsl_getDXCCZoneMap ( int number,
    const char ** zonemap )

    Get the zonemap of a DXCC Entity by its DXCC number.

    ◆ tqsl_getGABBItCERT()

    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCERT ( tQSL_Cert cert,
    int uid )

    Get a GABBI record that contains the certificate.

    uid is the value for the CERT_UID field

    Returns the NULL pointer on error.

    N.B. On systems that distinguish text-mode files from binary-mode files, notably Windows, the GABBI records should be written in binary mode.

    ◆ tqsl_getGABBItCONTACT()

    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACT ( tQSL_Cert cert,
    tQSL_Location loc,
    TQSL_QSO_RECORD * qso,
    int stationuid )

    Get a GABBI record that contains the QSO data.

    • stationuid is the value of the associated STATION_UID field.

    N.B.: If cert is not initialized for signing (see tqsl_beginSigning()) the function will return with a TQSL_SIGNINIT_ERROR error.

    Returns the NULL pointer on error.

    N.B. On systems that distinguish text-mode files from binary-mode files, notably Windows, the GABBI records should be written in binary mode.

    ◆ tqsl_getGABBItCONTACTData()

    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItCONTACTData ( tQSL_Cert cert,
    tQSL_Location loc,
    TQSL_QSO_RECORD * qso,
    int stationuid,
    char * signdata,
    int sdlen )

    Get a GABBI record that contains the QSO data along with the associated signdata (QSO data signed to validate the QSO).

    • stationuid is the value of the associated STATION_UID field.

    N.B.: If cert is not initialized for signing (see tqsl_beginSigning()) the function will return with a TQSL_SIGNINIT_ERROR error.

    Returns the NULL pointer on error.

    N.B. On systems that distinguish text-mode files from binary-mode files, notably Windows, the GABBI records should be written in binary mode.

    ◆ tqsl_getGABBItSTATION()

    DLLEXPORT const char *CALLCONVENTION tqsl_getGABBItSTATION ( tQSL_Location loc,
    int uid,
    int certuid )

    Get a GABBI record that contains the Station Location data.

    • uid is the value for the STATION_UID field.
    • certuid is the value of the associated CERT_UID field.

    Returns the NULL pointer on error.

    N.B. On systems that distinguish text-mode files from binary-mode files, notably Windows, the GABBI records should be written in binary mode.

    ◆ tqsl_getLocationCallSign()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationCallSign ( tQSL_Location loc,
    char * buf,
    int bufsiz )

    Get the call sign from the station location.

    ◆ tqsl_getLocationDXCCEntity()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationDXCCEntity ( tQSL_Location loc,
    int * dxcc )

    Get the DXCC entity from the station location.

    ◆ tqsl_getLocationField()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationField ( tQSL_Location locp,
    const char * field,
    char * buf,
    int bufsiz )

    Get a field from the station location.

    ◆ tqsl_getLocationFieldChanged()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldChanged ( tQSL_Location loc,
    int field_num,
    int * changed )

    Get the changed status of a field. The changed flag is set to 1 if the field's pick list was changed during the last call to tqsl_updateStationLocationCapture or zero if the list was not changed.

    ◆ tqsl_getLocationFieldCharData()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldCharData ( tQSL_Location loc,
    int field_num,
    char * buf,
    int bufsiz )

    Get the character data from the specified field.

    If the field input type (see tqsl_getLocationFieldInputType()) is TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST, this will return the text of the selected item.

    ◆ tqsl_getLocationFieldDataGABBI()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBI ( tQSL_Location loc,
    int field_num,
    char * buf,
    int bufsiz )

    Get the GABBI name of the specified field

    ◆ tqsl_getLocationFieldDataGABBISize()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataGABBISize ( tQSL_Location loc,
    int field_num,
    int * rval )

    Get the size of the GABBI name of the specified field

    ◆ tqsl_getLocationFieldDataLabel()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabel ( tQSL_Location loc,
    int field_num,
    char * buf,
    int bufsiz )

    Get the label for the specified field

    ◆ tqsl_getLocationFieldDataLabelSize()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLabelSize ( tQSL_Location loc,
    int field_num,
    int * rval )

    Get the number of characters in the label for the specified field

    ◆ tqsl_getLocationFieldDataLength()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataLength ( tQSL_Location loc,
    int field_num,
    int * rval )

    Get the length of the input field data.

    ◆ tqsl_getLocationFieldDataType()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldDataType ( tQSL_Location loc,
    int field_num,
    int * type )

    Get the data type of the input field.

    type will be either TQSL_LOCATION_FIELD_CHAR or TQSL_LOCATION_FIELD_INT

    ◆ tqsl_getLocationFieldFlags()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldFlags ( tQSL_Location loc,
    int field_num,
    int * flags )

    Get the flags for the input field.

    flags will be either TQSL_LOCATION_FIELD_UPPER Field is to be uppercased on input TQSL_LOCATION_FIELD_MUSTSEL Value must be selected TQSL_LOCATION_FIELD_SELNXT Value must be selected to allow Next/Finish

    ◆ tqsl_getLocationFieldIndex()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIndex ( tQSL_Location loc,
    int field_num,
    int * dat )

    If the field input type (see tqsl_getLocationFieldInputType()) is TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST, gets the index of the selected list item.

    ◆ tqsl_getLocationFieldInputType()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldInputType ( tQSL_Location loc,
    int field_num,
    int * type )

    Get the input type of the input field.

    type will be one of TQSL_LOCATION_FIELD_TEXT, TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST

    ◆ tqsl_getLocationFieldIntData()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldIntData ( tQSL_Location loc,
    int field_num,
    int * dat )

    Get the integer data from the specified field.

    This is only meaningful if the field data type (see tqsl_getLocationFieldDataType()) is TQSL_LOCATION_FIELD_INT.

    ◆ tqsl_getLocationFieldLabel()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldLabel ( tQSL_Location locp,
    const char * field,
    char * buf,
    int bufsiz )

    Get a field label from the station location.

    ◆ tqsl_getLocationFieldListItem()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationFieldListItem ( tQSL_Location loc,
    int field_num,
    int item_idx,
    char * buf,
    int bufsiz )

    Get the text of a specified item of a specified field

    ◆ tqsl_getLocationQSODetails()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationQSODetails ( tQSL_Location locp,
    char * buf,
    int buflen )

    Get the QSO details in canonical form.

    ◆ tqsl_getLocationStationDetails()

    DLLEXPORT int CALLCONVENTION tqsl_getLocationStationDetails ( tQSL_Location locp,
    char * buf,
    int buflen )

    Get the station location details in canonical form.

    ◆ tqsl_getMode()

    DLLEXPORT int CALLCONVENTION tqsl_getMode ( int index,
    const char ** mode,
    const char ** group )

    Get a mode by its index.

    mode - The GAABI mode name group - CW | PHONE | IMAGE | DATA

    Note: group may be NULL.

    ◆ tqsl_getNextStationLocationCapturePage()

    DLLEXPORT int CALLCONVENTION tqsl_getNextStationLocationCapturePage ( tQSL_Location loc,
    int * page )

    Return the next page to in the page sequence

    ◆ tqsl_getNumADIFMode()

    DLLEXPORT int CALLCONVENTION tqsl_getNumADIFMode ( int * number)

    Get the number of ADIF Mode entries in the Mode list

    ◆ tqsl_getNumBand()

    DLLEXPORT int CALLCONVENTION tqsl_getNumBand ( int * number)

    Get the number of Band entries in the Band list

    ◆ tqsl_getNumDXCCEntity()

    DLLEXPORT int CALLCONVENTION tqsl_getNumDXCCEntity ( int * number)

    Get the number of DXCC entities in the primary DXCC list.

    ◆ tqsl_getNumLocationField()

    DLLEXPORT int CALLCONVENTION tqsl_getNumLocationField ( tQSL_Location loc,
    int * numf )

    Get the number of fields on the current station location page

    Get the input type of the input field.

    type will be one of TQSL_LOCATION_FIELD_TEXT, TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST Get the number of fields on the current station location page

    ◆ tqsl_getNumLocationFieldListItems()

    DLLEXPORT int CALLCONVENTION tqsl_getNumLocationFieldListItems ( tQSL_Location loc,
    int field_num,
    int * rval )

    Get the number of items in the specified field's pick list.

    ◆ tqsl_getNumMode()

    DLLEXPORT int CALLCONVENTION tqsl_getNumMode ( int * number)

    Get the number of Mode entries in the Mode list

    ◆ tqsl_getNumPropagationMode()

    DLLEXPORT int CALLCONVENTION tqsl_getNumPropagationMode ( int * number)

    Get the number of Propagation Mode entries in the Propagation Mode list

    ◆ tqsl_getNumSatellite()

    DLLEXPORT int CALLCONVENTION tqsl_getNumSatellite ( int * number)

    Get the number of Satellite entries in the Satellite list

    ◆ tqsl_getNumStationLocationCapturePages()

    DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocationCapturePages ( tQSL_Location loc,
    int * npages )

    Return the number of station location capture pages.

    ◆ tqsl_getNumStationLocations()

    DLLEXPORT int CALLCONVENTION tqsl_getNumStationLocations ( tQSL_Location loc,
    int * nloc )

    Get the number of saved station locations

    ◆ tqsl_getPrevStationLocationCapturePage()

    DLLEXPORT int CALLCONVENTION tqsl_getPrevStationLocationCapturePage ( tQSL_Location loc,
    int * page )

    Return the previous page in the page sequence.

    ◆ tqsl_getPropagationMode()

    DLLEXPORT int CALLCONVENTION tqsl_getPropagationMode ( int index,
    const char ** name,
    const char ** descrip )

    Get a propagation mode by its index.

    name - The GAABI propagation mode name descrip - Text description of the propagation mode

    Note: descrip may be NULL.

    ◆ tqsl_getSatellite()

    DLLEXPORT int CALLCONVENTION tqsl_getSatellite ( int index,
    const char ** name,
    const char ** descrip,
    tQSL_Date * start,
    tQSL_Date * end )

    Get a satellite by its index.

    name - The GAABI satellite name descrip - Text description of the satellite start - The date the satellite entered service end - The last date the satellite was in service

    Note: descrip, start and/or end may be NULL.

    ◆ tqsl_getStationDataEnc()

    DLLEXPORT int CALLCONVENTION tqsl_getStationDataEnc ( tQSL_StationDataEnc * sdata)

    Return the contents of the station data file as a byte stream. The caller is required to tqsl_freeStationDataEnc() this pointer when done with it.

    ◆ tqsl_getStationLocation()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocation ( tQSL_Location * loc,
    const char * name )

    Retrieve a saved station location. Once finished with the station location, tqsl_endStationLocationCapture() should be called to release resources.

    ◆ tqsl_getStationLocationCallSign()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCallSign ( tQSL_Location loc,
    int idx,
    char * buf,
    int bufsiz )

    Get the call sign from the station location

    ◆ tqsl_getStationLocationCaptureName()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCaptureName ( tQSL_Location loc,
    char * namebuf,
    int bufsiz )

    Get the name of the station location

    ◆ tqsl_getStationLocationCapturePage()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationCapturePage ( tQSL_Location loc,
    int * page )

    Get the current page number

    ◆ tqsl_getStationLocationErrors()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationErrors ( tQSL_Location loc,
    char * buf,
    int bufsiz )

    Get any errors returned from parsing the selected station location. This should be called after tqsl_getStationLocation to determine if any of the existing fields failed validation. Currently only zone data is validated here, but future validations for things like properly formatted grid squares is likely.

    ◆ tqsl_getStationLocationField()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationField ( tQSL_Location locp,
    const char * name,
    char * namebuf,
    int bufsize )

    Get a named field from the station location

    ◆ tqsl_getStationLocationName()

    DLLEXPORT int CALLCONVENTION tqsl_getStationLocationName ( tQSL_Location loc,
    int idx,
    char * buf,
    int bufsiz )

    Get the name of the specified (by idx) saved station location

    ◆ tqsl_hasNextStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_hasNextStationLocationCapture ( tQSL_Location loc,
    int * rval )

    Returns 1 (in rval) if there is a next page

    ◆ tqsl_hasPrevStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_hasPrevStationLocationCapture ( tQSL_Location loc,
    int * rval )

    Returns 1 (in rval) if there is a previous page

    ◆ tqsl_initStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_initStationLocationCapture ( tQSL_Location * locp)

    Begin the process of generating a station record

    ◆ tqsl_mergeStationLocations()

    DLLEXPORT int CALLCONVENTION tqsl_mergeStationLocations ( const char * locdata)

    Merge saved location data with existing

    ◆ tqsl_nextStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_nextStationLocationCapture ( tQSL_Location loc)

    Advance the page to the next one in the page sequence

    ◆ tqsl_prevStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_prevStationLocationCapture ( tQSL_Location loc)

    Return the page to the previous one in the page sequence.

    ◆ tqsl_restoreStationLocation()

    DLLEXPORT int CALLCONVENTION tqsl_restoreStationLocation ( const char * name)

    Restore the deleted station location by name.

    ◆ tqsl_saveCallsignLocationInfo()

    DLLEXPORT int CALLCONVENTION tqsl_saveCallsignLocationInfo ( const char * callsign,
    const char * json )

    Save the json results for a given callsign location Detail.

    ◆ tqsl_saveStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_saveStationLocationCapture ( tQSL_Location loc,
    int overwrite )

    Save the station location data. Note that the name must have been set via tqsl_setStationLocationCaptureName if this is a new station location. If the overwrite parameter is zero and a station location of that name is already in existence, an error occurs with tQSL_Error set to TQSL_NAME_EXISTS.

    ◆ tqsl_setADIFMode()

    DLLEXPORT int CALLCONVENTION tqsl_setADIFMode ( const char * adif_item,
    const char * mode )

    Set the mapping of an ADIF mode to a TQSL mode.

    ◆ tqsl_setCabrilloMapEntry()

    DLLEXPORT int CALLCONVENTION tqsl_setCabrilloMapEntry ( const char * contest,
    int field,
    int contest_type )

    Set the mapping of a Cabrillo contest name (as found in the CONTEST line of a Cabrillo file) to the QSO line call-worked field number and the contest type.

    field can have a value of TQSL_MIN_CABRILLO_MAP_FIELD (cabrillo.h) or greater. Field number starts at 1.

    contest_type must be TQSL_CABRILLO_HF or TQSL_CABRILLO_VHF, defined in cabrillo.h

    ◆ tqsl_setLocationCallSign()

    DLLEXPORT int CALLCONVENTION tqsl_setLocationCallSign ( tQSL_Location loc,
    const char * buf,
    int dxcc )

    Set the call sign for the station location.

    ◆ tqsl_setLocationField()

    DLLEXPORT int CALLCONVENTION tqsl_setLocationField ( tQSL_Location locp,
    const char * field,
    const char * buf )

    Set a field in a station location.

    ◆ tqsl_setLocationFieldCharData()

    DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldCharData ( tQSL_Location loc,
    int field_num,
    const char * buf )

    Set the text data of a specified field.

    ◆ tqsl_setLocationFieldIndex()

    DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIndex ( tQSL_Location loc,
    int field_num,
    int dat )

    If the field input type (see tqsl_getLocationFieldInputType()) is TQSL_LOCATION_FIELD_DDLIST or TQSL_LOCATION_FIELD_LIST, sets the index of the selected list item.

    ◆ tqsl_setLocationFieldIntData()

    DLLEXPORT int CALLCONVENTION tqsl_setLocationFieldIntData ( tQSL_Location loc,
    int field_num,
    int dat )

    Set the integer data of a specified field.

    ◆ tqsl_setStationLocationCaptureName()

    DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCaptureName ( tQSL_Location loc,
    const char * name )

    Set the name of the station location

    ◆ tqsl_setStationLocationCapturePage()

    DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCapturePage ( tQSL_Location loc,
    int page )

    Set the current page number. Typically, the page number will be 1 (the starting page) or a value obtained from tqsl_getStationLocationCapturePage().

    ◆ tqsl_setStationLocationCertFlags()

    DLLEXPORT int CALLCONVENTION tqsl_setStationLocationCertFlags ( tQSL_Location loc,
    int flags )

    Set the certificate flags used in a location page. This is used to enable expired certs (or disable).

    ◆ tqsl_updateStationLocationCapture()

    DLLEXPORT int CALLCONVENTION tqsl_updateStationLocationCapture ( tQSL_Location loc)

    Update the pages based on the currently selected settings.

    ◆ tqsl_validateVUCCGrid()

    DLLEXPORT int CALLCONVENTION tqsl_validateVUCCGrid ( int entity,
    const char * pas,
    const char * grid,
    int * result )

    Validate that a given four-character gridsquare is acceptable for entity and primary administrative subdivision

    ◆ tqsl_verifyGridFormat()

    DLLEXPORT int CALLCONVENTION tqsl_verifyGridFormat ( const char * grid,
    int twelve,
    char * newGrid,
    int newlen )

    Check and normalize a Maidenhead Gridsquare

    • grid is the input string
    • twelve is true if 12 character grids are allowed
    • newGrid gets the resulting edited grid
    tqsl-2.8.2/src/doxygen/html/group__Convert.html0000644000175000017500000014540115061653721021610 0ustar rmurphyrmurphy TrustedQSL Library API: Converter API
    TrustedQSL Library API
    Converter API

    Macros

    #define TQSL_LOC_IGNORE   0
     Ignore MY_ ADIF fields.
     
    #define TQSL_LOC_REPORT   1
     Report on MY_ ADIF fields not matching cert/location.
     
    #define TQSL_LOC_UPDATE   2
     Update Cert/Loc to track MY_ ADIF fields.
     

    Typedefs

    typedef void * tQSL_Converter
     

    Functions

    DLLEXPORT int CALLCONVENTION tqsl_beginConverter (tQSL_Converter *convp)
     
    DLLEXPORT int CALLCONVENTION tqsl_beginADIFConverter (tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc)
     
    DLLEXPORT int CALLCONVENTION tqsl_beginCabrilloConverter (tQSL_Converter *conv, const char *filename, tQSL_Cert *certs, int ncerts, tQSL_Location loc)
     
    DLLEXPORT int CALLCONVENTION tqsl_endConverter (tQSL_Converter *conv)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowBadCall (tQSL_Converter conv, int allow)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterQTHDetails (tQSL_Converter conv, int logverify)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowDuplicates (tQSL_Converter convp, int ignore)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreSeconds (tQSL_Converter convp, int ignore)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreCallsigns (tQSL_Converter convp, int ignore)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterAppName (tQSL_Converter convp, const char *app)
     
    DLLEXPORT int CALLCONVENTION tqsl_setConverterDupesOnly (tQSL_Converter convp, int dupesOnly)
     
    DLLEXPORT int CALLCONVENTION tqsl_converterRollBack (tQSL_Converter convp)
     
    DLLEXPORT int CALLCONVENTION tqsl_converterCommit (tQSL_Converter convp)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecords (tQSL_Converter convp, char *key, char *data, int keylen)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecordsV2 (tQSL_Converter convp, char *key, char *data, int keylen)
     
    DLLEXPORT int CALLCONVENTION tqsl_putDuplicateRecord (tQSL_Converter convp, const char *key, const char *data, int keylen)
     
    DLLEXPORT int CALLCONVENTION tqsl_setADIFConverterDateFilter (tQSL_Converter conv, tQSL_Date *start, tQSL_Date *end)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getConverterGABBI (tQSL_Converter conv)
     
    DLLEXPORT int CALLCONVENTION tqsl_getConverterCert (tQSL_Converter conv, tQSL_Cert *certp)
     
    DLLEXPORT int CALLCONVENTION tqsl_getConverterLine (tQSL_Converter conv, int *lineno)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getConverterRecordText (tQSL_Converter conv)
     

    Detailed Description

    The Converter API provides the capability of converting Cabrillo and ADIF files to GABBI output.

    Typedef Documentation

    ◆ tQSL_Converter

    typedef void* tQSL_Converter

    Opaque converter type used by applications to access conversion functions

    Function Documentation

    ◆ tqsl_beginADIFConverter()

    DLLEXPORT int CALLCONVENTION tqsl_beginADIFConverter ( tQSL_Converter * conv,
    const char * filename,
    tQSL_Cert * certs,
    int ncerts,
    tQSL_Location loc )

    Initiates the conversion process for an ADIF file.

    certs and ncerts define a set of certificates that are available to the converter for signing records. Typically, this list will be obtained by calling tqsl_selectCertificates().

    tqsl_endConverter() should be called to free the resources when the conversion is finished.

    ◆ tqsl_beginCabrilloConverter()

    DLLEXPORT int CALLCONVENTION tqsl_beginCabrilloConverter ( tQSL_Converter * conv,
    const char * filename,
    tQSL_Cert * certs,
    int ncerts,
    tQSL_Location loc )

    Initiates the conversion process for a Cabrillo file.

    certs and ncerts define a set of certificates that are available to the converter for signing records. Typically, this list will be obtained by calling tqsl_selectCertificates().

    tqsl_endConverter() should be called to free the resources when the conversion is finished.

    ◆ tqsl_beginConverter()

    DLLEXPORT int CALLCONVENTION tqsl_beginConverter ( tQSL_Converter * convp)

    Create a simple converter object

    Allocates resources for converting logs and processing duplicate records.

    ◆ tqsl_converterCommit()

    DLLEXPORT int CALLCONVENTION tqsl_converterCommit ( tQSL_Converter convp)

    Commits insertions into the duplicates database.

    This is called when a log is created normally and without issue, and so the presumption is that we are "done" with these QSOs.

    ◆ tqsl_converterRollBack()

    DLLEXPORT int CALLCONVENTION tqsl_converterRollBack ( tQSL_Converter convp)

    Roll back insertions into the duplicates database.

    This is called when cancelling creating a log, and causes any records added to the duplicates database to be removed so re-processing that log does not cause the records to be mis-marked as duplicates.

    ◆ tqsl_endConverter()

    DLLEXPORT int CALLCONVENTION tqsl_endConverter ( tQSL_Converter * conv)

    End the conversion process by freeing the used resources.

    ◆ tqsl_getConverterCert()

    DLLEXPORT int CALLCONVENTION tqsl_getConverterCert ( tQSL_Converter conv,
    tQSL_Cert * certp )

    Get the certificate used to sign the most recent QSO record.

    ◆ tqsl_getConverterGABBI()

    DLLEXPORT const char *CALLCONVENTION tqsl_getConverterGABBI ( tQSL_Converter conv)

    This is the main converter function. It returns a single GABBI record.

    Returns the NULL pointer on error or EOF. (Test tQSL_Error to determine which.)

    tQSL_Error is set to TQSL_DATE_OUT_OF_RANGE if QSO date range checking is active and the QSO date is outside the specified range. This is a non-fatal error.

    tQSL_Error is set to TQSL_DUPLICATE_QSO if the QSO has already been processed on the current computer.

    tQSL_Error is set to TQSL_NEW_UPLOAD_DB if a new uploads database was created. This allows TQSL to attempt to re-load the QSOs from the most recent automatic backup (if it exists).

    N.B. On systems that distinguish text-mode files from binary-mode files, notably Windows, the GABBI records should be written in binary mode.

    N.B. If the selected certificate has not been initialized for signing via tqsl_beginSigning(), this function will return a TQSL_SIGNINIT_ERROR. The cert that caused the error can be obtained via tqsl_getConverterCert(), initialized for signing, and then this function can be called again. No data records will be lost in this process.

    ◆ tqsl_getConverterLine()

    DLLEXPORT int CALLCONVENTION tqsl_getConverterLine ( tQSL_Converter conv,
    int * lineno )

    Get the input-file line number last read by the converter, starting at line 1.

    ◆ tqsl_getConverterRecordText()

    DLLEXPORT const char *CALLCONVENTION tqsl_getConverterRecordText ( tQSL_Converter conv)

    Get the text of the last record read by the converter.

    Returns NULL on error.

    ◆ tqsl_getDuplicateRecords()

    DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecords ( tQSL_Converter convp,
    char * key,
    char * data,
    int keylen )

    Bulk read the duplicate DB records

    This is called to retrieve the QSO records from the dupe database. It returns the key/value pair upon each call. Return -1 for end of file, 0 for success, 1 for errors.

    ◆ tqsl_getDuplicateRecordsV2()

    DLLEXPORT int CALLCONVENTION tqsl_getDuplicateRecordsV2 ( tQSL_Converter convp,
    char * key,
    char * data,
    int keylen )

    Bulk read the duplicate DB records

    This is called to retrieve the QSO records from the dupe database. It returns the key/value pair upon each call. Return -1 for end of file, 0 for success, 1 for errors. V2 expects a 256 byte buffer for the "data" string.

    ◆ tqsl_putDuplicateRecord()

    DLLEXPORT int CALLCONVENTION tqsl_putDuplicateRecord ( tQSL_Converter convp,
    const char * key,
    const char * data,
    int keylen )

    Bulk write duplicate DB records

    This is called to store a QSO record into the dupe database.

    Return -1 for duplicate insertion, 0 for success, 1 for errors.

    ◆ tqsl_setADIFConverterDateFilter()

    DLLEXPORT int CALLCONVENTION tqsl_setADIFConverterDateFilter ( tQSL_Converter conv,
    tQSL_Date * start,
    tQSL_Date * end )

    Set QSO date filtering in the converter.

    If start points to a valid date, QSOs prior to that date will be ignored by the converter. Similarly, if end points to a valid date, QSOs after that date will be ignored. Either or both may be NULL (or point to an invalid date) to disable date filtering for the respective range.

    ◆ tqsl_setConverterAllowBadCall()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowBadCall ( tQSL_Converter conv,
    int allow )

    Configure the converter to allow (allow != 0) or disallow (allow == 0) nonamateur call signs in the CALL field. (Note: the test for validity is fairly trivial and will allow some nonamateur calls to get through, but it does catch most common errors.)

    allow defaults to 0 when tqsl_beginADIFConverter or tqsl_beginCabrilloConverter is called.

    ◆ tqsl_setConverterAllowDuplicates()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterAllowDuplicates ( tQSL_Converter convp,
    int ignore )

    Configure the converter to allow (allow != 0) or disallow (allow == 0) duplicate QSOs in a signed log. Duplicate detection is done using QSO details, location details, and certificate serial number.

    allow defaults to 1 for backwards compatibility when tqsl_beginADIFConverter or tqsl_beginCabrilloConverter is called.

    ◆ tqsl_setConverterAppName()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterAppName ( tQSL_Converter convp,
    const char * app )

    Specify the name of the application using the conversion library. This is output in a header record in the exported log file. Call this before calling tqsl_getConverterGABBI.

    app is a c string containing the application name.

    ◆ tqsl_setConverterDupesOnly()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterDupesOnly ( tQSL_Converter convp,
    int dupesOnly )

    Configure the converter to just write duplicate database records No signing, etc.

    dupesOnly defaults to 0.

    ◆ tqsl_setConverterIgnoreCallsigns()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreCallsigns ( tQSL_Converter convp,
    int ignore )

    Configure the converter to ignore (ignore != 0) or include (ignore == 0) callsigns in ADIF logs,

    ignore defaults to 0.

    ◆ tqsl_setConverterIgnoreSeconds()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterIgnoreSeconds ( tQSL_Converter convp,
    int ignore )

    Configure the converter to ignore (ignore != 0) or include (ignore == 0) seconds in times when detecting duplicate QSOs in a signed log. Duplicate detection is done using QSO details, location details, and certificate serial number.

    ignore defaults to 0.

    ◆ tqsl_setConverterQTHDetails()

    DLLEXPORT int CALLCONVENTION tqsl_setConverterQTHDetails ( tQSL_Converter conv,
    int logverify )

    Configure the converter's handing of QTH fields in an adif input file

    allow defaults to 0 when tqsl_beginADIFConverter or tqsl_beginCabrilloConverter is called.

    tqsl-2.8.2/src/doxygen/html/group__CertStuff.html0000644000175000017500000037145315061653721022105 0ustar rmurphyrmurphy TrustedQSL Library API: Certificate Handling API
    TrustedQSL Library API
    Certificate Handling API

    Macros

    #define TQSL_SELECT_CERT_WITHKEYS   1
     Private keys only (no cert)
     
    #define TQSL_SELECT_CERT_EXPIRED   2
     Include expired certs.
     
    #define TQSL_SELECT_CERT_SUPERCEDED   4
     Include superseded certs.
     
    #define TQSL_PK_TYPE_ERR   0
     Error retrieving private key.
     
    #define TQSL_PK_TYPE_NONE   1
     No private key.
     
    #define TQSL_PK_TYPE_UNENC   2
     Private key is not encrypted.
     
    #define TQSL_PK_TYPE_ENC   3
     Private key is encrypted.
     
    #define TQSL_CERT_STATUS_UNK   0
     Status is unknown.
     
    #define TQSL_CERT_STATUS_SUP   1
     Certificate is superceded.
     
    #define TQSL_CERT_STATUS_EXP   2
     Certificate is expired.
     
    #define TQSL_CERT_STATUS_OK   3
     Certificate is valid.
     
    #define TQSL_CERT_STATUS_INV   4
     Invalid serial number.
     

    Functions

    DLLEXPORT int CALLCONVENTION tqsl_selectCertificates (tQSL_Cert **certlist, int *ncerts, const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flag)
     
    DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates (tQSL_Cert **certlist, int *ncerts, const char *type)
     
    DLLEXPORT int CALLCONVENTION tqsl_getSelectedCertificate (tQSL_Cert *cert, const tQSL_Cert **certlist, int idx)
     
    DLLEXPORT int CALLCONVENTION tqsl_isCertificateExpired (tQSL_Cert cert, int *status)
     
    DLLEXPORT int CALLCONVENTION tqsl_isCertificateSuperceded (tQSL_Cert cert, int *status)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateKeyOnly (tQSL_Cert cert, int *keyonly)
     
    DLLEXPORT int CALLCONVENTION tqsl_isCertificateRenewable (tQSL_Cert cert, int *status)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateEncoded (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded (const char *callsign, const char *type, const char *keybuf, const char *certbuf)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerial (tQSL_Cert cert, long *serial)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt (tQSL_Cert cert, char *serial, int serialsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialLength (tQSL_Cert cert)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuer (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganization (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganizationalUnit (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateCallSign (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateAROName (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateEmailAddress (tQSL_Cert cert, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotBeforeDate (tQSL_Cert cert, tQSL_Date *date)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotAfterDate (tQSL_Cert cert, tQSL_Date *date)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotBeforeDate (tQSL_Cert cert, tQSL_Date *date)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotAfterDate (tQSL_Cert cert, tQSL_Date *date)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateDXCCEntity (tQSL_Cert cert, int *dxcc)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress1 (tQSL_Cert cert, char *str, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress2 (tQSL_Cert cert, char *str, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCity (tQSL_Cert cert, char *str, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestState (tQSL_Cert cert, char *str, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestPostalCode (tQSL_Cert cert, char *str, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCountry (tQSL_Cert cert, char *str, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificatePrivateKeyType (tQSL_Cert cert)
     
    DLLEXPORT void CALLCONVENTION tqsl_freeCertificate (tQSL_Cert cert)
     
    DLLEXPORT void CALLCONVENTION tqsl_freeCertificateList (tQSL_Cert *list, int ncerts)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCertificateStatus (long serial)
     
    DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus (long serial, const char *status)
     
    DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile (const char *file, int(*cb)(int type, const char *message, void *userdata), void *user)
     
    DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile (const char *file, long *serial)
     
    DLLEXPORT int CALLCONVENTION tqsl_getNumProviders (int *n)
     
    DLLEXPORT int CALLCONVENTION tqsl_getProvider (int idx, TQSL_PROVIDER *provider)
     
    DLLEXPORT int CALLCONVENTION tqsl_createCertRequest (const char *filename, TQSL_CERT_REQ *req, int(*pwcb)(char *pwbuf, int pwsize, void *userdata), void *user)
     
    DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File (tQSL_Cert cert, const char *filename, const char *p12password)
     
    DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto (tQSL_Cert cert, const char *filename, const char *p12password)
     
    DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64 (tQSL_Cert cert, char *base64, int b64len, const char *p12password)
     
    DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File (const char *filename, const char *p12password, const char *password, int(*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type, const char *message, void *userdata), void *user)
     
    DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64 (const char *base64, const char *p12password, const char *password, int(*pwcb)(char *buf, int bufsiz, void *userdata), int(*cb)(int type, const char *message, void *userdata), void *user)
     
    DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates (char ***calls, int *ncall, const char *filter)
     
    DLLEXPORT void CALLCONVENTION tqsl_freeDeletedCertificateList (char **list, int nloc)
     
    DLLEXPORT int CALLCONVENTION tqsl_restoreCallsignCertificate (const char *callsign)
     
    DLLEXPORT int CALLCONVENTION tqsl_deleteCertificate (tQSL_Cert cert)
     

    Detailed Description

    Certificates are managed by manipulating tQSL_Cert objects. A tQSL_Cert contains:

    • The identity of the organization that issued the certificate (the "issuer").
    • The name and call sign of the amateur radio operator (ARO).
    • The DXCC entity number for which this certificate is valid.
    • The range of QSO dates for which this certificate can be used.
    • The resources needed to digitally sign and verify QSO records.

    The certificate management process consists of:

    • Applying for a certificate. Certificate requests are produced via the tqsl_createCertRequest() function, which produces a certificate-request file to send to the issuer.
    • Importing the certificate file received from the issuer into the local "certificate store," a directory managed by the tQSL library, via tqsl_importTQSLFile().
    • Selecting an appropriate certificate to use to sign a QSO record via tqsl_selectCertificates().

    Function Documentation

    ◆ tqsl_createCertRequest()

    DLLEXPORT int CALLCONVENTION tqsl_createCertRequest ( const char * filename,
    TQSL_CERT_REQ * req,
    int(* pwcb )(char *pwbuf, int pwsize, void *userdata),
    void * user )

    Create a certificate-request Gabbi file.

    The req parameter must be properly populated with the required fields.

    If req->password is NULL and cb is not NULL, the callback will be called to acquire the password. Otherwise req->password will be used as the password. If the password is NULL or an empty string the generated private key will be stored unencrypted.

    If req->signer is not zero and the signing certificate requires a password, the password may be in req->signer_password, else signer_pwcb is called.

    ◆ tqsl_deleteCertificate()

    DLLEXPORT int CALLCONVENTION tqsl_deleteCertificate ( tQSL_Cert cert)

    Delete a certificate and private key

    ◆ tqsl_exportPKCS12Base64()

    DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12Base64 ( tQSL_Cert cert,
    char * base64,
    int b64len,
    const char * p12password )

    Save a key pair and certificates to a Base64 string in PKCS12 format.

    The tQSL_Cert must be initialized for signing (see tqsl_beginSigning()) if the user certificate is being exported.

    The supplied p12password is used to encrypt the PKCS12 data.

    ◆ tqsl_exportPKCS12File()

    DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12File ( tQSL_Cert cert,
    const char * filename,
    const char * p12password )

    Save a key pair and certificates to a file in PKCS12 format.

    The tQSL_Cert must be initialized for signing (see tqsl_beginSigning()) if the user certificate is being exported.

    The supplied p12password is used to encrypt the PKCS12 data.

    ◆ tqsl_exportPKCS12FileWeakCrypto()

    DLLEXPORT int CALLCONVENTION tqsl_exportPKCS12FileWeakCrypto ( tQSL_Cert cert,
    const char * filename,
    const char * p12password )

    Save a key pair and certificates to a file in PKCS12 format. Use downgraded crypto for Apple Keyring compatibility.

    The tQSL_Cert must be initialized for signing (see tqsl_beginSigning()) if the user certificate is being exported.

    The supplied p12password is used to encrypt the PKCS12 data.

    ◆ tqsl_freeCertificate()

    DLLEXPORT void CALLCONVENTION tqsl_freeCertificate ( tQSL_Cert cert)

    Free the memory used by the tQSL_Cert. Once this function is called, cert should not be used again in any way.

    ◆ tqsl_freeCertificateList()

    DLLEXPORT void CALLCONVENTION tqsl_freeCertificateList ( tQSL_Cert * list,
    int ncerts )

    Free the memory used by a certificate list. The allocated list of tQSL_Certs are freed and the pointer array is freed. Once this function is called, the list or the cert should not be used again in any way.

    ◆ tqsl_freeDeletedCertificateList()

    DLLEXPORT void CALLCONVENTION tqsl_freeDeletedCertificateList ( char ** list,
    int nloc )

    Free the list of restorable Callsign Certificates.

    ◆ tqsl_getCertificateAROName()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateAROName ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the ARO name string from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateCallSign()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateCallSign ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the ARO call sign string from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateDXCCEntity()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateDXCCEntity ( tQSL_Cert cert,
    int * dxcc )

    Get the DXCC entity number from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateEmailAddress()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateEmailAddress ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the email address from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateEncoded()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateEncoded ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the encoded certificate for inclusion in a GABBI file.

    ◆ tqsl_getCertificateIssuer()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuer ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the issuer (DN) string from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateIssuerOrganization()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganization ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the issuer's organization name from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateIssuerOrganizationalUnit()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateIssuerOrganizationalUnit ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the issuer's organizational unit name from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateKeyOnly()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateKeyOnly ( tQSL_Cert cert,
    int * keyonly )

    Find out if the "certificate" is just a key pair.

    ◆ tqsl_getCertificateNotAfterDate()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotAfterDate ( tQSL_Cert cert,
    tQSL_Date * date )

    Get the certificate's not-after date from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateNotBeforeDate()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateNotBeforeDate ( tQSL_Cert cert,
    tQSL_Date * date )

    Get the certificate's not-before date from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificatePrivateKeyType()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificatePrivateKeyType ( tQSL_Cert cert)

    Determine the nature of the private key associated with a certificate.

    Returns one of the following values:

    • TQSL_PK_TYPE_ERR - An error occurred. Use tqsl_getErrorString() to examine.
    • TQSL_PK_TYPE_NONE - No matching private key was found.
    • TQSL_PK_TYPE_UNENC - The matching private key is unencrypted.
    • TQSL_PK_TYPE_ENC - The matching private key is encrypted (password protected).

    ◆ tqsl_getCertificateQSONotAfterDate()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotAfterDate ( tQSL_Cert cert,
    tQSL_Date * date )

    Get the QSO not-after date from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateQSONotBeforeDate()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateQSONotBeforeDate ( tQSL_Cert cert,
    tQSL_Date * date )

    Get the QSO not-before date from a tQSL_Cert.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateRequestAddress1()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress1 ( tQSL_Cert cert,
    char * str,
    int bufsiz )

    Get the first address line from the certificate request used in applying for a tQSL_Cert certificate.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateRequestAddress2()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestAddress2 ( tQSL_Cert cert,
    char * str,
    int bufsiz )

    Get the second address line from the certificate request used in applying for a tQSL_Cert certificate.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateRequestCity()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCity ( tQSL_Cert cert,
    char * str,
    int bufsiz )

    Get the city from the certificate request used in applying for a tQSL_Cert certificate.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateRequestCountry()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestCountry ( tQSL_Cert cert,
    char * str,
    int bufsiz )

    Get the country from the certificate request used in applying for a tQSL_Cert certificate.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateRequestPostalCode()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestPostalCode ( tQSL_Cert cert,
    char * str,
    int bufsiz )

    Get the postal (ZIP) code from the certificate request used in applying for a tQSL_Cert certificate.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateRequestState()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateRequestState ( tQSL_Cert cert,
    char * str,
    int bufsiz )

    Get the state from the certificate request used in applying for a tQSL_Cert certificate.

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_getCertificateSerial()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerial ( tQSL_Cert cert,
    long * serial )

    Get the issuer's serial number of the certificate.

    ◆ tqsl_getCertificateSerialExt()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialExt ( tQSL_Cert cert,
    char * serial,
    int serialsiz )

    Get the issuer's serial number of the certificate as a hexadecimal string. Needed for certs with long serial numbers (typically root certs).

    ◆ tqsl_getCertificateSerialLength()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateSerialLength ( tQSL_Cert cert)

    Get the length of the issuer's serial number of the certificate as it will be returned by tqsl_getCertificateSerialExt.

    ◆ tqsl_getCertificateStatus()

    DLLEXPORT int CALLCONVENTION tqsl_getCertificateStatus ( long serial)

    Determine the status of a callsign certificate

    • serial - the serial number of the certificate tqsl_selectCertificates()
    • status - an integer to receive the certificate status

    Returns one of the following values:

    • TQSL_CERT_STATUS_UNK - An error occurred and the status is unknown
    • TQSL_CERT_STATUS_SUP - The certificate has been superceded
    • TQSL_CERT_STATUS_EXP - The certificate has expired
    • TQSL_CERT_STATUS_OK - The certificate is valid
    • TQSL_CERT_STATUS_INV - The serial number supplied is invalid

    ◆ tqsl_getDeletedCallsignCertificates()

    DLLEXPORT int CALLCONVENTION tqsl_getDeletedCallsignCertificates ( char *** calls,
    int * ncall,
    const char * filter )

    Get the list of restorable station locations.

    ◆ tqsl_getKeyEncoded()

    DLLEXPORT int CALLCONVENTION tqsl_getKeyEncoded ( tQSL_Cert cert,
    char * buf,
    int bufsiz )

    Get the encoded private key for inclusion in a backup file.

    ◆ tqsl_getNumProviders()

    DLLEXPORT int CALLCONVENTION tqsl_getNumProviders ( int * n)

    Get the number of certificate providers known to tqsllib.

    ◆ tqsl_getProvider()

    DLLEXPORT int CALLCONVENTION tqsl_getProvider ( int idx,
    TQSL_PROVIDER * provider )

    Get the information for a certificate provider.

    ◆ tqsl_getSelectedCertificate()

    DLLEXPORT int CALLCONVENTION tqsl_getSelectedCertificate ( tQSL_Cert * cert,
    const tQSL_Cert ** certlist,
    int idx )

    Get a particulat certificate from the list returnded by tqsl_selectCertificates. This function exists principally to make it easier for VB programs to access the list of certificates.

    It is the caller's responsibility to ensure that 0 <= idx < ncerts (where ncerts is the value returned by tqsl_selectCertificates)

    ◆ tqsl_getSerialFromTQSLFile()

    DLLEXPORT int CALLCONVENTION tqsl_getSerialFromTQSLFile ( const char * file,
    long * serial )

    Get the serial for the first user cert from a .tq6 file used to support asking the user to save their cert after import

    • file is the path to the file
    • serial is where the serial number is returned

    Returns 0 on success, nonzero on failure.

    ◆ tqsl_importKeyPairEncoded()

    DLLEXPORT int CALLCONVENTION tqsl_importKeyPairEncoded ( const char * callsign,
    const char * type,
    const char * keybuf,
    const char * certbuf )

    Import a base64 encoded certificate and private key from a backup file.

    ◆ tqsl_importPKCS12Base64()

    DLLEXPORT int CALLCONVENTION tqsl_importPKCS12Base64 ( const char * base64,
    const char * p12password,
    const char * password,
    int(* pwcb )(char *buf, int bufsiz, void *userdata),
    int(* cb )(int type, const char *message, void *userdata),
    void * user )

    Load certificates and a private key from a Base64 encoded PKCS12 string.

    ◆ tqsl_importPKCS12File()

    DLLEXPORT int CALLCONVENTION tqsl_importPKCS12File ( const char * filename,
    const char * p12password,
    const char * password,
    int(* pwcb )(char *buf, int bufsiz, void *userdata),
    int(* cb )(int type, const char *message, void *userdata),
    void * user )

    Load certificates and a private key from a PKCS12 file.

    ◆ tqsl_importTQSLFile()

    DLLEXPORT int CALLCONVENTION tqsl_importTQSLFile ( const char * file,
    int(* cb )(int type, const char *message, void *userdata),
    void * user )

    Import a Gabbi cert file received from a CA

    The callback, cb, will be called whenever a certificate is ready to be imported:

    cb(type, message);

    type has several fields that can be accessed via macros:

    TQSL_CERT_CB_CALL_TYPE(type) := TQSL_CERT_CB_MILESTONE | TQSL_CERT_CB_RESULT

    TQSL_CERT_CB_CERT_TYPE(type) := TQSL_CERT_CB_ROOT | TQSL_CERT_CB_CA | TQSL_CERT_CB_USER

    TQSL_CERT_CB_RESULT_TYPE(type) := TQSL_CERT_CB_PROMPT | TQSL_CERT_CB_WARNING | TQSL_CERT_CB_ERROR

    TQSL_CERT_CB_RESULT_TYPE() is meaningful only if TQSL_CERT_CB_CALL_TYPE() == TQSL_CERT_CB_RESULT

    ◆ tqsl_isCertificateExpired()

    DLLEXPORT int CALLCONVENTION tqsl_isCertificateExpired ( tQSL_Cert cert,
    int * status )

    Find out if the "certificate" is expired

    ◆ tqsl_isCertificateRenewable()

    DLLEXPORT int CALLCONVENTION tqsl_isCertificateRenewable ( tQSL_Cert cert,
    int * status )

    Find out if the "certificate" is renewable

    ◆ tqsl_isCertificateSuperceded()

    DLLEXPORT int CALLCONVENTION tqsl_isCertificateSuperceded ( tQSL_Cert cert,
    int * status )

    Find out if the "certificate" is superceded

    ◆ tqsl_restoreCallsignCertificate()

    DLLEXPORT int CALLCONVENTION tqsl_restoreCallsignCertificate ( const char * callsign)

    Restore a deleted callsign certificate by callsign.

    ◆ tqsl_selectCACertificates()

    DLLEXPORT int CALLCONVENTION tqsl_selectCACertificates ( tQSL_Cert ** certlist,
    int * ncerts,
    const char * type )

    Get a list of authority certificates

    Selects a set of certificates from the root or authorities certificate stores The function produces a list of tQSL_Cert objects.

    Each of the tQSL_Cert objects in the list should be freed by calling tqsl_freeCertificate(). tqsl_freeCertificateList() is a better function to use for that as it also frees the allocated array that holds the certificate pointers.

    ◆ tqsl_selectCertificates()

    DLLEXPORT int CALLCONVENTION tqsl_selectCertificates ( tQSL_Cert ** certlist,
    int * ncerts,
    const char * callsign,
    int dxcc,
    const tQSL_Date * date,
    const TQSL_PROVIDER * issuer,
    int flag )

    Get a list of certificates

    Selects a set of certificates from the user's certificate store based on optional selection criteria. The function produces a list of tQSL_Cert objects.

    • certlist - Pointer to a variable that is set by the function to point to the list of tQSL_Cert objects.
    • ncerts - Pointer to an int that is set to the number of objects in the certlist list.
    • callsign - Optional call sign to match.
    • date - Optional QSO date string in ISO format. Only certs that have a QSO date range that encompasses this date will be returned.
    • issuer - Optional issuer (DN) string to match.
    • flag - OR of TQSL_SELECT_CERT_EXPIRED (include expired certs), TQSL_SELECT_CERT_SUPERCEDED and TQSL_SELECT_CERT_WITHKEYS (keys that don't have associated certs will be returned).

    Returns 0 on success, nonzero on failure.

    Each of the tQSL_Cert objects in the list should be freed by calling tqsl_freeCertificate(). tqsl_freeCertificateList() is a better function to use for that as it also frees the allocated array that holds the certificate pointers.

    ◆ tqsl_setCertificateStatus()

    DLLEXPORT int CALLCONVENTION tqsl_setCertificateStatus ( long serial,
    const char * status )

    Store the status of a callsign certificate

    • serial - serial number of the certificate
    • status - the status value to store.
    tqsl-2.8.2/src/doxygen/html/group__Cabrillo.html0000644000175000017500000006216515061653721021724 0ustar rmurphyrmurphy TrustedQSL Library API: Cabrillo API
    TrustedQSL Library API

    Classes

    struct  tqsl_cabrilloField
     

    Macros

    #define TQSL_CABRILLO_MAX_FIELDS   12
     Max field count.
     
    #define TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX   64
     Max field name length.
     
    #define TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX   40
     Max field value length.
     
    #define TQSL_MIN_CABRILLO_MAP_FIELD   5
     First possible call-worked field.
     
    #define TQSL_DEF_CABRILLO_MAP_FIELD   8
     Default call-worked field.
     
    #define TQSLLIB_DEF
     

    Typedefs

    typedef void * tQSL_Cabrillo
     Opaque cabrillo log type.
     

    Enumerations

    enum  TQSL_CABRILLO_ERROR_TYPE {
      TQSL_CABRILLO_NO_ERROR , TQSL_CABRILLO_EOF , TQSL_CABRILLO_NO_START_RECORD , TQSL_CABRILLO_NO_CONTEST_RECORD ,
      TQSL_CABRILLO_UNKNOWN_CONTEST , TQSL_CABRILLO_BAD_FIELD_DATA , TQSL_CABRILLO_EOR
    }
     Cabrillo status values.
     
    enum  TQSL_CABRILLO_FREQ_TYPE { TQSL_CABRILLO_HF , TQSL_CABRILLO_VHF , TQSL_CABRILLO_UNKNOWN }
     

    Functions

    DLLEXPORT const char *CALLCONVENTION tqsl_cabrilloGetError (TQSL_CABRILLO_ERROR_TYPE err)
     
    DLLEXPORT int CALLCONVENTION tqsl_beginCabrillo (tQSL_Cabrillo *cabp, const char *filename)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloContest (tQSL_Cabrillo cab, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloFreqType (tQSL_Cabrillo cab, TQSL_CABRILLO_FREQ_TYPE *type)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloLine (tQSL_Cabrillo cab, int *lineno)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getCabrilloRecordText (tQSL_Cabrillo cab)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloField (tQSL_Cabrillo cab, tqsl_cabrilloField *field, TQSL_CABRILLO_ERROR_TYPE *err)
     
    DLLEXPORT int CALLCONVENTION tqsl_endCabrillo (tQSL_Cabrillo *cabp)
     

    Detailed Description

    These functions and data structures provide a means of parsing a Cabrillo file into its component fields.

    For convenience, the returned fields are identified using field names from the ADIF specification.

    Enumeration Type Documentation

    ◆ TQSL_CABRILLO_FREQ_TYPE

    Frequency type: HF, VHF, or UNKNOWN

    Function Documentation

    ◆ tqsl_beginCabrillo()

    DLLEXPORT int CALLCONVENTION tqsl_beginCabrillo ( tQSL_Cabrillo * cabp,
    const char * filename )

    Initialize a Cabrillo file for reading

    ◆ tqsl_cabrilloGetError()

    DLLEXPORT const char *CALLCONVENTION tqsl_cabrilloGetError ( TQSL_CABRILLO_ERROR_TYPE err)

    Get the Cabrillo error message that corresponds to a particular error value

    ◆ tqsl_endCabrillo()

    DLLEXPORT int CALLCONVENTION tqsl_endCabrillo ( tQSL_Cabrillo * cabp)

    Finish reading a Cabrillo file and release its resources

    ◆ tqsl_getCabrilloContest()

    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloContest ( tQSL_Cabrillo cab,
    char * buf,
    int bufsiz )

    Get the Contest name as specified in the Cabrillo CONTEST line

    ◆ tqsl_getCabrilloField()

    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloField ( tQSL_Cabrillo cab,
    tqsl_cabrilloField * field,
    TQSL_CABRILLO_ERROR_TYPE * err )

    Get the next field of the Cabrillo record

    err is set to TQSL_CABRILLO_NO_ERROR or TQSL_CABRILLO_EOR (end-of-record) if field was populated with data. If err == TQSL_CABRILLO_EOR, this is the last field of the record.

    err == TQSL_CABRILLO_EOF when there is no more data available.

    ◆ tqsl_getCabrilloFreqType()

    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloFreqType ( tQSL_Cabrillo cab,
    TQSL_CABRILLO_FREQ_TYPE * type )

    Get the Frequency type (HF or VHF) as determined by the contest

    ◆ tqsl_getCabrilloLine()

    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloLine ( tQSL_Cabrillo cab,
    int * lineno )

    Get the current line number (starting from 1) of the input file

    ◆ tqsl_getCabrilloRecordText()

    DLLEXPORT const char *CALLCONVENTION tqsl_getCabrilloRecordText ( tQSL_Cabrillo cab)

    Get the text of the current Cabrillo record

    tqsl-2.8.2/src/doxygen/html/group__ADIF.html0000644000175000017500000005751515061653721020703 0ustar rmurphyrmurphy TrustedQSL Library API: ADIF API
    TrustedQSL Library API

    Classes

    struct  tqsl_adifFieldDefinitions
     
    struct  tqsl_adifFieldResults
     

    Macros

    #define TQSL_ADIF_FIELD_NAME_LENGTH_MAX   64
     Max length of ADIF field.
     
    #define TQSL_ADIF_FIELD_SIZE_LENGTH_MAX   10
     Max length of field name.
     
    #define TQSL_ADIF_FIELD_TYPE_LENGTH_MAX   1
     Max length of field type.
     
    #define TQSLLIB_DEF
     

    Typedefs

    typedef void * tQSL_ADIF
     Opaque ADIF type.
     

    Enumerations

    enum  TQSL_ADIF_BOOLEAN { TQSL_FALSE , TQSL_TRUE }
     
    enum  TQSL_ADIF_RANGE_TYPE { TQSL_ADIF_RANGE_TYPE_NONE , TQSL_ADIF_RANGE_TYPE_MINMAX , TQSL_ADIF_RANGE_TYPE_ENUMERATION }
     Specifies the type of range limits to apply to a field.
     
    enum  TQSL_ADIF_GET_FIELD_ERROR {
      TQSL_ADIF_GET_FIELD_SUCCESS , TQSL_ADIF_GET_FIELD_NO_NAME_MATCH , TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH , TQSL_ADIF_GET_FIELD_NO_RANGE_MATCH ,
      TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH , TQSL_ADIF_GET_FIELD_NO_RESULT_ALLOCATION , TQSL_ADIF_GET_FIELD_NAME_LENGTH_OVERFLOW , TQSL_ADIF_GET_FIELD_DATA_LENGTH_OVERFLOW ,
      TQSL_ADIF_GET_FIELD_SIZE_OVERFLOW , TQSL_ADIF_GET_FIELD_TYPE_OVERFLOW , TQSL_ADIF_GET_FIELD_ERRONEOUS_STATE , TQSL_ADIF_GET_FIELD_EOF
    }
     Response values returned from tqsl_getADIFField()
     

    Functions

    DLLEXPORT const char *CALLCONVENTION tqsl_adifGetError (TQSL_ADIF_GET_FIELD_ERROR status)
     
    DLLEXPORT int CALLCONVENTION tqsl_beginADIF (tQSL_ADIF *adifp, const char *filename)
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFField (tQSL_ADIF adif, tqsl_adifFieldResults *field, TQSL_ADIF_GET_FIELD_ERROR *status, const tqsl_adifFieldDefinitions *adifFields, const char *const *typesDefined, unsigned char *(*allocator)(size_t))
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFLine (tQSL_ADIF adif, int *lineno)
     
    DLLEXPORT int CALLCONVENTION tqsl_endADIF (tQSL_ADIF *adifp)
     
    DLLEXPORT int CALLCONVENTION tqsl_adifMakeField (const char *fieldname, char type, const unsigned char *value, int len, unsigned char *buf, int buflen)
     

    Detailed Description

    These functions and data structures provide a means of parsing an ADIF file into its component fields, along with range-checking the field contents.

    Enumeration Type Documentation

    ◆ TQSL_ADIF_BOOLEAN

    Boolean type - TRUE/FALSE

    Function Documentation

    ◆ tqsl_adifGetError()

    DLLEXPORT const char *CALLCONVENTION tqsl_adifGetError ( TQSL_ADIF_GET_FIELD_ERROR status)

    Get the ADIF error message that corresponds to a particular error value

    ◆ tqsl_adifMakeField()

    DLLEXPORT int CALLCONVENTION tqsl_adifMakeField ( const char * fieldname,
    char type,
    const unsigned char * value,
    int len,
    unsigned char * buf,
    int buflen )

    Form an ADIF field string.

    N.B. On systems that distinguish text-mode files from binary-mode files, notably Windows, the text should be written in binary mode.

    ◆ tqsl_beginADIF()

    DLLEXPORT int CALLCONVENTION tqsl_beginADIF ( tQSL_ADIF * adifp,
    const char * filename )

    Initialize an ADIF file for reading

    ◆ tqsl_endADIF()

    DLLEXPORT int CALLCONVENTION tqsl_endADIF ( tQSL_ADIF * adifp)

    End and release an ADIF file

    ◆ tqsl_getADIFField()

    DLLEXPORT int CALLCONVENTION tqsl_getADIFField ( tQSL_ADIF adif,
    tqsl_adifFieldResults * field,
    TQSL_ADIF_GET_FIELD_ERROR * status,
    const tqsl_adifFieldDefinitions * adifFields,
    const char *const * typesDefined,
    unsigned char *(* allocator )(size_t) )

    Get the next field from an ADIF file

    • adif - ADIF handle returned from tqsl_beginADIF()
    • field - pointer to struct that contains the field data and description
    • status - pointer to returned status variable
    • adifFields - pointer to an array of field-definition structures. The last item in the array should have an empty string as its name member.
    • typesDefined - pointer to an array of char pointers that define the allowed field-type strings. The last item in the array should point to an empty string.
    • allocator - pointer to a function that returns a pointer to a memory block of the specified size. This function will be called at most one time during a call to tqsl_getADIFField. The returned pointer will then be used to populate the data member of field. The caller is responsible for freeing this memory, if needed.

    ◆ tqsl_getADIFLine()

    DLLEXPORT int CALLCONVENTION tqsl_getADIFLine ( tQSL_ADIF adif,
    int * lineno )

    Get the current line number (starting from 1) of the input file

    tqsl-2.8.2/src/doxygen/html/globals_vars.html0000644000175000017500000000743715061653721021301 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented variables with links to the documentation:
    tqsl-2.8.2/src/doxygen/html/globals_type.html0000644000175000017500000000665015061653721021303 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented typedefs with links to the documentation:
    tqsl-2.8.2/src/doxygen/html/globals_t.html0000644000175000017500000013575615061653721020577 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented file members with links to the documentation:

    - t -

    tqsl-2.8.2/src/doxygen/html/globals_p.html0000644000175000017500000000520415061653721020553 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented file members with links to the documentation:

    - p -

    tqsl-2.8.2/src/doxygen/html/globals_g.html0000644000175000017500000000626715061653721020554 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented file members with links to the documentation:

    - g -

    tqsl-2.8.2/src/doxygen/html/globals_func.html0000644000175000017500000007302015061653721021250 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented functions with links to the documentation:

    - t -

    tqsl-2.8.2/src/doxygen/html/globals_eval.html0000644000175000017500000000563715061653721021255 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
     
    tqsl-2.8.2/src/doxygen/html/globals_enum.html0000644000175000017500000000614615061653721021266 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented enums with links to the documentation:
    tqsl-2.8.2/src/doxygen/html/globals_defs.html0000644000175000017500000004506515061653721021246 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented macros with links to the documentation:

    - c -

    - d -

    - g -

    - p -

    - t -

    tqsl-2.8.2/src/doxygen/html/globals_d.html0000644000175000017500000000537515061653721020550 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented file members with links to the documentation:

    - d -

    tqsl-2.8.2/src/doxygen/html/globals_0x74.html0000644000175000017500000011175415061653721021026 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    Here is a list of all documented file members with links to the documentation:

    - t -

    tqsl-2.8.2/src/doxygen/html/globals_0x64.html0000644000175000017500000000603715061653721021022 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    Here is a list of all documented file members with links to the documentation:

    - d -

    tqsl-2.8.2/src/doxygen/html/globals.html0000644000175000017500000000540415061653721020236 0ustar rmurphyrmurphy TrustedQSL Library API: File Members
    TrustedQSL Library API
    Here is a list of all documented file members with links to the documentation:

    - c -

    tqsl-2.8.2/src/doxygen/html/functions_vars.html0000644000175000017500000003215715061653721021663 0ustar rmurphyrmurphy TrustedQSL Library API: Class Members - Variables
    TrustedQSL Library API
    Here is a list of all documented variables with links to the class documentation for each member:

    - a -

    - b -

    - c -

    - d -

    - e -

    - f -

    - h -

    - l -

    - m -

    - n -

    - o -

    - p -

    - q -

    - r -

    - s -

    - t -

    - u -

    - v -

    - y -

    tqsl-2.8.2/src/doxygen/html/functions.html0000644000175000017500000003214715061653721020627 0ustar rmurphyrmurphy TrustedQSL Library API: Class Members
    TrustedQSL Library API
    Here is a list of all documented class members with links to the class documentation for each member:

    - a -

    - b -

    - c -

    - d -

    - e -

    - f -

    - h -

    - l -

    - m -

    - n -

    - o -

    - p -

    - q -

    - r -

    - s -

    - t -

    - u -

    - v -

    - y -

    tqsl-2.8.2/src/doxygen/html/ftv2vertline.png0000644000175000017500000000012615061653721021061 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATxݱðScOx@ y}IENDB`tqsl-2.8.2/src/doxygen/html/ftv2splitbar.png0000644000175000017500000000047215061653721021055 0ustar rmurphyrmurphyPNG  IHDRMIDATxݡJCa( %4 bȘͶ3v^EL ,b;{Ï/aYկq:\IIIIIIIIIIIIIIIIII-l揊_t/ϻYQVYivk_ۣI@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$I@$C[V=[fIENDB`tqsl-2.8.2/src/doxygen/html/ftv2pnode.png0000644000175000017500000000034515061653721020341 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATx=QFDk:FPK؃=V@ճ 8SHx0bnrr{򽿾$ TP XOd6"SOB(Q)+YĈ ҪR>Vtsm9(k-@ȧ-$ b [he Kp-l|CApRG'rͭaIENDB`tqsl-2.8.2/src/doxygen/html/ftv2plastnode.png0000644000175000017500000000034515061653721021225 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATx=QFDk:FPK؃=V@ճ 8SHx0bnrr{򽿾$ TP XOd6"SOB(Q)+YĈ ҪR>Vtsm9(k-@ȧ-$ b [he Kp-l|CApRG'rͭaIENDB`tqsl-2.8.2/src/doxygen/html/ftv2ns.png0000644000175000017500000000060415061653721017652 0ustar rmurphyrmurphyPNG  IHDR}\KIDATx1K1 G⁂n lE(nࢋMA@ tK%ܕ ]BI%uͅa,e v祫i\tun0oV\$G.&@Y=%$um6'߫9Q\b)0-ZTH`pcsm 5:>ަI F] jgo[ on Ԭvq?\ 6Tee lQ c3*dWTM\rh61F fIENDB`tqsl-2.8.2/src/doxygen/html/ftv2node.png0000644000175000017500000000012615061653721020156 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATxݱðScOx@ y}IENDB`tqsl-2.8.2/src/doxygen/html/ftv2mo.png0000644000175000017500000000062315061653721017646 0ustar rmurphyrmurphyPNG  IHDR}\ZIDATx1K@iBҡ(h"EI'oک 8R- BTP]zB3 _㒻}]V}dIiJb+|K…,[P\ʘMƢ#F`JݤkA?Y4ck6"Z)0SHM@㋺Wmo4HJ+Qobt *~8_+3Y- PwA+^}+xhϕMAE]TD~EÞߴ^R)`A9pq-۾ۍ3tƛTH) ICxd#1 m@V?Zgo_3-\IENDB`tqsl-2.8.2/src/doxygen/html/ftv2mnode.png0000644000175000017500000000036615061653721020341 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATx!NA\ Um@`5i`h W7] b&ofdY4 c 3v=]\B I=BB;k WN@vy4]Y|M}]x6a }dׇY>||5?>|B"'IENDB`tqsl-2.8.2/src/doxygen/html/ftv2mlastnode.png0000644000175000017500000000036615061653721021225 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATx!NA\ Um@`5i`h W7] b&ofdY4 c 3v=]\B I=BB;k WN@vy4]Y|M}]x6a }dׇY>||5?>|B"'IENDB`tqsl-2.8.2/src/doxygen/html/ftv2link.png0000644000175000017500000000135215061653721020170 0ustar rmurphyrmurphyPNG  IHDR}\IDATxMOS[sa?-XZ(PD4 AWbu`b 77wHFCԁ/`voAPqP@ 980 +y^Z9SW\83g3'Nçl_bpV"ֆXd]3xM[1W *PGz/Eg{ aoV:这1$RW,@56-,m/蹖 r5T*S(Vf89u գwa=<{ҡUr+dDF$`zNܮ0Q3~_^N=vpTLT}kqm<?ZhX_ݥ[) `ga_*2`'=F2EP l=8Wv%THqɿ<"GxH{#֫aJmKsVءM^ T ݛr߽m_?Wİ#uIENDB`tqsl-2.8.2/src/doxygen/html/ftv2lastnode.png0000644000175000017500000000012615061653721021042 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATxݱðScOx@ y}IENDB`tqsl-2.8.2/src/doxygen/html/ftv2folderopen.png0000644000175000017500000000112515061653721021366 0ustar rmurphyrmurphyPNG  IHDR}\IDATx]?oP9i4i;iiZ7`b٬,HU'$*T]TDP6w};C; aӝߟjAInS}9Hӎ|? =_Ɗue*;YEsYBėsٌ ɫYq !Gǿv̇خ F}qb]70)d-}PfY{4@}2ԗNIǃc%UImcƝ>xt9$ OVE*Û#׈r@l$PrHaa dZrqIoT\,tj2FAxv-Lp׌p TI/ \sf; jViTo^cpb]€<a՜y9:+,E f6NEKU}^;nZuUS4 ѬbN.kjT% iV )GJ@TxIENDB`tqsl-2.8.2/src/doxygen/html/ftv2folderclosed.png0000644000175000017500000000115015061653721021674 0ustar rmurphyrmurphyPNG  IHDR}\/IDATx]MO@~uؐlp]#]PYEC\9y`xC &=qvZv3m؃vLN}}ޝZA@n ONp xKxj8s _[D'yye+ 7#rNlk* 0Ь_d_(Öz=xvhzP-䍒̪u$\DJcB4.:Ϗ-}LE #gN;B6䬜@p&h>p9EEάʑ"un$R"?{<%PNt$߶+^<"2Dqq\ҙaA"ԵP}#Ez{.8i p(ADwDE߂z;Kק8t q:uvvݛvEn{MFXgfZ֝*ߩ:jYq#3SWr'  IENDB`tqsl-2.8.2/src/doxygen/html/ftv2doc.png0000644000175000017500000000135215061653721020000 0ustar rmurphyrmurphyPNG  IHDR}\IDATxMOS[sa?-XZ(PD4 AWbu`b 77wHFCԁ/`voAPqP@ 980 +y^Z9SW\83g3'Nçl_bpV"ֆXd]3xM[1W *PGz/Eg{ aoV:这1$RW,@56-,m/蹖 r5T*S(Vf89u գwa=<{ҡUr+dDF$`zNܮ0Q3~_^N=vpTLT}kqm<?ZhX_ݥ[) `ga_*2`'=F2EP l=8Wv%THqɿ<"GxH{#֫aJmKsVءM^ T ݛr߽m_?Wİ#uIENDB`tqsl-2.8.2/src/doxygen/html/ftv2cl.png0000644000175000017500000000070515061653721017632 0ustar rmurphyrmurphyPNG  IHDR}\IDATx;H#Ao4ႇK ,m vڞJ XY B|drcvoİ 0Ò3ͤe״1X8nQ88֧3*rb-$P1@Z-#011HkK wO@!fuc;sB[EA\>]Pzf| +g5b i5mM_q,cod!,{Y,zT8H]𤕘7/8Q!F~6?Y A@Ũ.@TYr8*>?e[6xIENDB`tqsl-2.8.2/src/doxygen/html/ftv2blank.png0000644000175000017500000000012615061653721020320 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATxݱðScOx@ y}IENDB`tqsl-2.8.2/src/doxygen/html/folderopend.svg0000644000175000017500000000621615061653721020751 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/folderopen.svg0000644000175000017500000000630515061653721020604 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/folderopen.png0000644000175000017500000000112515061653721020564 0ustar rmurphyrmurphyPNG  IHDR}\IDATx]?oP9i4i;iiZ7`b٬,HU'$*T]TDP6w};C; aӝߟjAInS}9Hӎ|? =_Ɗue*;YEsYBėsٌ ɫYq !Gǿv̇خ F}qb]70)d-}PfY{4@}2ԗNIǃc%UImcƝ>xt9$ OVE*Û#׈r@l$PrHaa dZrqIoT\,tj2FAxv-Lp׌p TI/ \sf; jViTo^cpb]€<a՜y9:+,E f6NEKU}^;nZuUS4 ѬbN.kjT% iV )GJ@TxIENDB`tqsl-2.8.2/src/doxygen/html/folderclosedd.svg0000644000175000017500000000371415061653721021261 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/folderclosed.svg0000644000175000017500000000371415061653721021115 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/folderclosed.png0000644000175000017500000000115015061653721021072 0ustar rmurphyrmurphyPNG  IHDR}\/IDATx]MO@~uؐlp]#]PYEC\9y`xC &=qvZv3m؃vLN}}ޝZA@n ONp xKxj8s _[D'yye+ 7#rNlk* 0Ь_d_(Öz=xvhzP-䍒̪u$\DJcB4.:Ϗ-}LE #gN;B6䬜@p&h>p9EEάʑ"un$R"?{<%PNt$߶+^<"2Dqq\ҙaA"ԵP}#Ez{.8i p(ADwDE߂z;Kק8t q:uvvݛvEn{MFXgfZ֝*ߩ:jYq#3SWr'  IENDB`tqsl-2.8.2/src/doxygen/html/files.html0000644000175000017500000001027415061653721017716 0ustar rmurphyrmurphy TrustedQSL Library API: File List
    TrustedQSL Library API
    File List
    Here is a list of all documented files with brief descriptions:
    tqsl-2.8.2/src/doxygen/html/dynsections.js0000644000175000017500000001764215061653721020634 0ustar rmurphyrmurphy/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ function toggleVisibility(linkObj) { return dynsection.toggleVisibility(linkObj); } let dynsection = { // helper function updateStripes : function() { $('table.directory tr'). removeClass('even').filter(':visible:even').addClass('even'); $('table.directory tr'). removeClass('odd').filter(':visible:odd').addClass('odd'); }, toggleVisibility : function(linkObj) { const base = $(linkObj).attr('id'); const summary = $('#'+base+'-summary'); const content = $('#'+base+'-content'); const trigger = $('#'+base+'-trigger'); const src=$(trigger).attr('src'); if (content.is(':visible')===true) { content.hide(); summary.show(); $(linkObj).addClass('closed').removeClass('opened'); $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); } else { content.show(); summary.hide(); $(linkObj).removeClass('closed').addClass('opened'); $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); } return false; }, toggleLevel : function(level) { $('table.directory tr').each(function() { const l = this.id.split('_').length-1; const i = $('#img'+this.id.substring(3)); const a = $('#arr'+this.id.substring(3)); if (l'); // add vertical lines to other rows $('span[class=lineno]').not(':eq(0)').append(''); // add toggle controls to lines with fold divs $('div[class=foldopen]').each(function() { // extract specific id to use const id = $(this).attr('id').replace('foldopen',''); // extract start and end foldable fragment attributes const start = $(this).attr('data-start'); const end = $(this).attr('data-end'); // replace normal fold span with controls for the first line of a foldable fragment $(this).find('span[class=fold]:first').replaceWith(''); // append div for folded (closed) representation $(this).after(''); // extract the first line from the "open" section to represent closed content const line = $(this).children().first().clone(); // remove any glow that might still be active on the original line $(line).removeClass('glow'); if (start) { // if line already ends with a start marker (e.g. trailing {), remove it $(line).html($(line).html().replace(new RegExp('\\s*'+start+'\\s*$','g'),'')); } // replace minus with plus symbol $(line).find('span[class=fold]').css('background-image',codefold.plusImg[relPath]); // append ellipsis $(line).append(' '+start+''+end); // insert constructed line into closed div $('#foldclosed'+id).html(line); }); }, }; /* @license-end */ tqsl-2.8.2/src/doxygen/html/doxygen_crawl.html0000644000175000017500000010071615061653721021462 0ustar rmurphyrmurphy Validator / crawler helper tqsl-2.8.2/src/doxygen/html/doxygen.svg0000644000175000017500000003614515061653721020131 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/doxygen.png0000644000175000017500000000730315061653721020110 0ustar rmurphyrmurphyPNG  IHDRh ;IDATx]y\պ~45%TL QPE"q11]8aw*(*" z`8 m,p$%B(8k6lk[߷;?kPx'tz3_Q4g@m ci{~4:Hc'PP7^h zbcP 3}OqNkT(?d ~z<4ǡ؞vz٦Zd,6k]Fz< Zs?sU2Sw1c`[}%ѽ.Լ6BLZ!F8[ T #g]:vu?vbR?wgb$kF~;عƕX?lNʪ,HCgAzlӺg ]jM3oҳ'=$f}GS_co.ȹ:ds:1={9?zqviDp moaEqҵw}~{j{ºFNë[OqOSXO]>muľe5{Jկ(bl}`UyacCAklysA7oJ .Be. Z'-PyF.lp&.j7rez19HG%qz׈c_k_")HJn~֘5 q5#+9T Rܸrzϴ̝ =υ{áOfwg|/$;֙ƭ]W"/< DఽB}yIEc^=[VhM$l];Kr¦* t$]M;I1!M (f<5~z mՠ>کIz;u[ie^ӳNF6B\}7+,'a -yHY,^f~?Hc{Z+4\sٷnߣFơsغD?<vkx0MlذIxdEEAMg*YE7ۙ^[uv[wG=Edn׶l'pGk+C82 dz3H BS[wŘ ~xptmţiQ歉AB1fى4uI]6% 1t.NJphz̠R1"3-"&1[:N mW0_œ 6&)ꦬ}~{m]zMP~^:eQT_*798ˍ 347E¿uSɻU_ NWeNӏ|;;d"ȉ޵ᆴ"ĴMM+bY_E]PXKНIޥoE<_(EP|m,өZߺk,kM`jzeU t36˷r}w:Χ |TܵQK_pໃYd0!a –W$$/\$ 2mLH dHV,:RZJaz*>_NT(‚^SVFU8E܈nd;8\C]=m:bDd=ߞUU5O|]Pv\]2"y[yzg{Y{Ù5;w{N3nĨwKݭ29Id y)P8ũ@mPwjl,6 hWd ump.DžtwR xBδYcxg*vo y򑕓[?V0NO난~󒯷h#Hk8kӍ^q@]ӓ,56-κUn[>]@nϜp[6# 4tn:}8T9_Y$/GK(ђM`dѺ;OB &P{qhJ+閧l2M_1ӫtlya L^y.۽[ u/]iS}N>e1qjf&iT\=kϛX-.84V5u!TE .OH4zwTr. xքHHg hT$yqzp< qrwI]I鲘s":ՖbզL69VW<;3?M3AV#ޯKUr9!qtH+6V/TS^pqgLP'5E ޺ n"2|;W"֬TwtO' +W+Z̖<&nO,I06.Z.h*INڒOegBXZ9hDSʍ A/c`A"z|ş;H#|%OOD mcƤqmu&~n πZj =_n[nN$_bE)8?6l}#bW( d-p&a"9ņ$ڛA!;{~8ޣ10`#kuN Qbh 8Mawhq(bK Z%m֍(J)@> 7% {y ohf>{p.­_%glZ\B2B #Һphݚ[<#SpA7Ht4:|gtL*($Ʃ$;b`=MM5ǾHH.HeA5}rd)T};Q5i2O00;,냔}g]79_{C>h{.II?[Kswz6u;OJa˶zvd l舊yc'rTWӰL |ʽhB T'ò]K(=Kx  L,Pʵu׈ž1ݫ;pGDxZY kf676oھH~޸ 8Up6(? K+?%ݷ/19U?B)l @=ޞkIENDB`tqsl-2.8.2/src/doxygen/html/docd.svg0000644000175000017500000000273715061653721017365 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/docd.png0000644000175000017500000000136415061653721017345 0ustar rmurphyrmurphyPNG  IHDR}\IDATxMLSYB[l7 aT` $(hJXftYh4NWJq@L!A[h=玘ދ`7IN}94aK\@)6d2ǥ >FSŧ;){nv SS%t_],&qj*7/b}> SUcP6 ͡H7 ({dlڝ'"3ġd; 7Rh]gn5j*b)(6CDn,׊X;5B\729K+ f(Ém8_3x\unM W'/çyiz+߼)nȫYY<bxI!Ճ@-ws%"#]'*9RBˑ/9"|??o+L:,ΌSV@EuE[4.lj*2Tå_r8DU8Wj0ҁ|gdl2kq0BMbh4OᠼG/az;#Dϴqڪ|vBR k/gA`zrܘ\l2ctX TQ] S ̿{H?^qU#nBĥSiJi2 F88FlIENDB`tqsl-2.8.2/src/doxygen/html/doc.svg0000644000175000017500000000273715061653721017221 0ustar rmurphyrmurphy tqsl-2.8.2/src/doxygen/html/doc.png0000644000175000017500000000135215061653721017176 0ustar rmurphyrmurphyPNG  IHDR}\IDATxMOS[sa?-XZ(PD4 AWbu`b 77wHFCԁ/`voAPqP@ 980 +y^Z9SW\83g3'Nçl_bpV"ֆXd]3xM[1W *PGz/Eg{ aoV:这1$RW,@56-,m/蹖 r5T*S(Vf89u գwa=<{ҡUr+dDF$`zNܮ0Q3~_^N=vpTLT}kqm<?ZhX_ݥ[) `ga_*2`'=F2EP l=8Wv%THqɿ<"GxH{#֫aJmKsVءM^ T ݛr߽m_?Wİ#uIENDB`tqsl-2.8.2/src/doxygen/html/closed.png0000644000175000017500000000020415061653721017675 0ustar rmurphyrmurphyPNG  IHDR KIDATxm @!Gk7-`&sts@k}2 P%_N .:0Dk›x" ֛)x5IENDB`tqsl-2.8.2/src/doxygen/html/clipboard.js0000644000175000017500000000557215061653721020230 0ustar rmurphyrmurphy/** The code below is based on the Doxygen Awesome project, see https://github.com/jothepro/doxygen-awesome-css MIT License Copyright (c) 2021 - 2022 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ let clipboard_title = "Copy to clipboard" let clipboard_icon = `` let clipboard_successIcon = `` let clipboard_successDuration = 1000 $(function() { if(navigator.clipboard) { const fragments = document.getElementsByClassName("fragment") for(const fragment of fragments) { const clipboard_div = document.createElement("div") clipboard_div.classList.add("clipboard") clipboard_div.innerHTML = clipboard_icon clipboard_div.title = clipboard_title $(clipboard_div).click(function() { const content = this.parentNode.cloneNode(true) // filter out line number and folded fragments from file listings content.querySelectorAll(".lineno, .ttc, .foldclosed").forEach((node) => { node.remove() }) let text = content.textContent // remove trailing newlines and trailing spaces from empty lines text = text.replace(/^\s*\n/gm,'\n').replace(/\n*$/,'') navigator.clipboard.writeText(text); this.classList.add("success") this.innerHTML = clipboard_successIcon window.setTimeout(() => { // switch back to normal icon after timeout this.classList.remove("success") this.innerHTML = clipboard_icon }, clipboard_successDuration); }) fragment.insertBefore(clipboard_div, fragment.firstChild) } } }) tqsl-2.8.2/src/doxygen/html/classes.html0000644000175000017500000000643415061653721020254 0ustar rmurphyrmurphy TrustedQSL Library API: Class Index
    TrustedQSL Library API
    tqsl-2.8.2/src/doxygen/html/cabrillo_8h_source.html0000644000175000017500000006356015061653721022370 0ustar rmurphyrmurphy TrustedQSL Library API: cabrillo.h Source File
    TrustedQSL Library API
    cabrillo.h
    Go to the documentation of this file.
    1/***************************************************************************
    2 cabrillo.h - description
    3 -------------------
    4 begin : Thu Dec 5 2002
    5 copyright : (C) 2002 by ARRL
    6 author : Jon Bloom
    7 email : jbloom@arrl.org
    8 revision : $Id$
    9 ***************************************************************************/
    10
    11#ifndef __CABRILLO_H
    12#define __CABRILLO_H
    13
    14#undef CLIENT_STATIC
    15#ifndef LOTW_SERVER
    16#define CLIENT_STATIC static
    17#else
    18#define CLIENT_STATIC
    19#endif
    20
    22
    32
    33#define TQSL_CABRILLO_MAX_FIELDS 12
    34#define TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX 64
    35#define TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX 40
    36
    38typedef enum {
    39 TQSL_CABRILLO_NO_ERROR,
    40 TQSL_CABRILLO_EOF,
    41 TQSL_CABRILLO_NO_START_RECORD,
    42 TQSL_CABRILLO_NO_CONTEST_RECORD,
    43 TQSL_CABRILLO_UNKNOWN_CONTEST,
    44 TQSL_CABRILLO_BAD_FIELD_DATA,
    45 TQSL_CABRILLO_EOR,
    47
    51typedef enum {
    52 TQSL_CABRILLO_HF,
    53 TQSL_CABRILLO_VHF,
    54 TQSL_CABRILLO_UNKNOWN,
    56
    57// Minimum field number for callsign and default field number
    58// For VHF, default should be 7.
    59#define TQSL_MIN_CABRILLO_MAP_FIELD 5
    60#define TQSL_DEF_CABRILLO_MAP_FIELD 8
    61
    71
    72typedef void * tQSL_Cabrillo;
    73
    74#define TQSLLIB_DEF
    75#include "tqsllib.h"
    76
    77#ifdef __cplusplus
    78extern "C" {
    79#endif
    80
    83
    86
    89
    92
    95
    98
    108
    111
    112#ifdef __cplusplus
    113}
    114#endif
    115
    117
    118#endif // __CABRILLO_H
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloLine(tQSL_Cabrillo cab, int *lineno)
    DLLEXPORT const char *CALLCONVENTION tqsl_cabrilloGetError(TQSL_CABRILLO_ERROR_TYPE err)
    TQSL_CABRILLO_ERROR_TYPE
    Cabrillo status values.
    Definition cabrillo.h:38
    #define TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX
    Max field value length.
    Definition cabrillo.h:35
    DLLEXPORT int CALLCONVENTION tqsl_beginCabrillo(tQSL_Cabrillo *cabp, const char *filename)
    TQSL_CABRILLO_FREQ_TYPE
    Definition cabrillo.h:51
    DLLEXPORT int CALLCONVENTION tqsl_endCabrillo(tQSL_Cabrillo *cabp)
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloFreqType(tQSL_Cabrillo cab, TQSL_CABRILLO_FREQ_TYPE *type)
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloContest(tQSL_Cabrillo cab, char *buf, int bufsiz)
    #define TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX
    Max field name length.
    Definition cabrillo.h:34
    void * tQSL_Cabrillo
    Opaque cabrillo log type.
    Definition cabrillo.h:72
    DLLEXPORT const char *CALLCONVENTION tqsl_getCabrilloRecordText(tQSL_Cabrillo cab)
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloField(tQSL_Cabrillo cab, tqsl_cabrilloField *field, TQSL_CABRILLO_ERROR_TYPE *err)
    Definition cabrillo.h:67
    char name[TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX+1]
    < Cabrillo field
    Definition cabrillo.h:68
    char value[TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX+1]
    Field value.
    Definition cabrillo.h:69
    #define CALLCONVENTION
    Symbol exports - Windows only.
    Definition tqsllib.h:27
    #define DLLEXPORT
    Symbol exports - Windows only.
    Definition tqsllib.h:25
    tqsl-2.8.2/src/doxygen/html/cabrillo_8h.html0000644000175000017500000003670115061653721021005 0ustar rmurphyrmurphy TrustedQSL Library API: cabrillo.h File Reference
    TrustedQSL Library API
    cabrillo.h File Reference
    #include "tqsllib.h"

    Go to the source code of this file.

    Classes

    struct  tqsl_cabrilloField
     

    Macros

    #define CLIENT_STATIC   static
     Static linkage.
     
    #define TQSL_CABRILLO_MAX_FIELDS   12
     Max field count.
     
    #define TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX   64
     Max field name length.
     
    #define TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX   40
     Max field value length.
     
    #define TQSL_MIN_CABRILLO_MAP_FIELD   5
     First possible call-worked field.
     
    #define TQSL_DEF_CABRILLO_MAP_FIELD   8
     Default call-worked field.
     
    #define TQSLLIB_DEF
     

    Typedefs

    typedef void * tQSL_Cabrillo
     Opaque cabrillo log type.
     

    Enumerations

    enum  TQSL_CABRILLO_ERROR_TYPE {
      TQSL_CABRILLO_NO_ERROR , TQSL_CABRILLO_EOF , TQSL_CABRILLO_NO_START_RECORD , TQSL_CABRILLO_NO_CONTEST_RECORD ,
      TQSL_CABRILLO_UNKNOWN_CONTEST , TQSL_CABRILLO_BAD_FIELD_DATA , TQSL_CABRILLO_EOR
    }
     Cabrillo status values.
     
    enum  TQSL_CABRILLO_FREQ_TYPE { TQSL_CABRILLO_HF , TQSL_CABRILLO_VHF , TQSL_CABRILLO_UNKNOWN }
     

    Functions

    DLLEXPORT const char *CALLCONVENTION tqsl_cabrilloGetError (TQSL_CABRILLO_ERROR_TYPE err)
     
    DLLEXPORT int CALLCONVENTION tqsl_beginCabrillo (tQSL_Cabrillo *cabp, const char *filename)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloContest (tQSL_Cabrillo cab, char *buf, int bufsiz)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloFreqType (tQSL_Cabrillo cab, TQSL_CABRILLO_FREQ_TYPE *type)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloLine (tQSL_Cabrillo cab, int *lineno)
     
    DLLEXPORT const char *CALLCONVENTION tqsl_getCabrilloRecordText (tQSL_Cabrillo cab)
     
    DLLEXPORT int CALLCONVENTION tqsl_getCabrilloField (tQSL_Cabrillo cab, tqsl_cabrilloField *field, TQSL_CABRILLO_ERROR_TYPE *err)
     
    DLLEXPORT int CALLCONVENTION tqsl_endCabrillo (tQSL_Cabrillo *cabp)
     
    tqsl-2.8.2/src/doxygen/html/bdwn.png0000644000175000017500000000022315061653721017357 0ustar rmurphyrmurphyPNG  IHDR5ZIDATx DP1lm rj.e D[ɾ|6V3?Ls'(}>+ Kch` ^ލnIENDB`tqsl-2.8.2/src/doxygen/html/bc_sd.png0000644000175000017500000000117315061653721017504 0ustar rmurphyrmurphyPNG  IHDR_ BIDATxkQƿ;3$4b+J-XBP u#q7 ntV@ӂ- q#3? 7;gwXA~*gm,.7'oN<2 .#umx^Xzdis=1SryTY}ŧUKm߼ĘpHL穨`nbOMgVAr kAOopGOOE>PnN,=PJb @giވkg\轭EUv+?E"pB\Y&$vM+Dn)}:Xo 3گ'.f0u9Ljf6%3Gf#sm(,k*ʒJJˢou_~ r]%%mnu]zr5[ưXeIVtsm9(k-@ȧ-$ b [he Kp-l|CApRG'rͭaIENDB`tqsl-2.8.2/src/doxygen/html/arrowdown.png0000644000175000017500000000036615061653721020457 0ustar rmurphyrmurphyPNG  IHDRɪ|IDATx!NA\ Um@`5i`h W7] b&ofdY4 c 3v=]\B I=BB;k WN@vy4]Y|M}]x6a }dׇY>||5?>|B"'IENDB`tqsl-2.8.2/src/doxygen/html/annotated.html0000644000175000017500000001151415061653721020567 0ustar rmurphyrmurphy TrustedQSL Library API: Class List
    TrustedQSL Library API
    Class List
    Here are the classes, structs, unions and interfaces with brief descriptions:
    tqsl-2.8.2/src/doxygen/html/adif_8h_source.html0000644000175000017500000011170315061653721021475 0ustar rmurphyrmurphy TrustedQSL Library API: adif.h Source File
    TrustedQSL Library API
    adif.h
    Go to the documentation of this file.
    1/***************************************************************************
    2 adif.h - description
    3 -------------------
    4 begin : Wed May 15 2002
    5 copyright : (C) 2002 by ARRL
    6 email : MSimcik@localhost.localdomain
    7 revision : $Id$
    8 ***************************************************************************/
    9
    10#ifndef __ADIF_H
    11#define __ADIF_H
    12
    13
    14#include <stdio.h>
    15#include <stdlib.h>
    16
    18
    25
    26
    27#define TQSL_ADIF_FIELD_NAME_LENGTH_MAX 64
    28#define TQSL_ADIF_FIELD_SIZE_LENGTH_MAX 10
    29#define TQSL_ADIF_FIELD_TYPE_LENGTH_MAX 1
    30
    34#ifndef TQSL_ADIF_BOOLEAN
    35typedef enum {
    36 TQSL_FALSE,
    37 TQSL_TRUE
    39#endif
    40
    41typedef void * tQSL_ADIF;
    42
    44typedef enum {
    45 TQSL_ADIF_RANGE_TYPE_NONE,
    46 TQSL_ADIF_RANGE_TYPE_MINMAX,
    47 TQSL_ADIF_RANGE_TYPE_ENUMERATION
    49
    51typedef enum {
    52 TQSL_ADIF_GET_FIELD_SUCCESS,
    53 TQSL_ADIF_GET_FIELD_NO_NAME_MATCH,
    54 TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH,
    55 TQSL_ADIF_GET_FIELD_NO_RANGE_MATCH,
    56 TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH,
    57 TQSL_ADIF_GET_FIELD_NO_RESULT_ALLOCATION,
    58 TQSL_ADIF_GET_FIELD_NAME_LENGTH_OVERFLOW,
    59 TQSL_ADIF_GET_FIELD_DATA_LENGTH_OVERFLOW,
    60 TQSL_ADIF_GET_FIELD_SIZE_OVERFLOW,
    61 TQSL_ADIF_GET_FIELD_TYPE_OVERFLOW,
    62 TQSL_ADIF_GET_FIELD_ERRONEOUS_STATE,
    63 TQSL_ADIF_GET_FIELD_EOF
    65
    77
    88
    89
    90/* function prototypes */
    91
    92#define TQSLLIB_DEF
    93#include "tqsllib.h"
    94
    95#ifdef __cplusplus
    96extern "C" {
    97#endif
    98
    101
    103DLLEXPORT int CALLCONVENTION tqsl_beginADIF(tQSL_ADIF *adifp, const char *filename);
    104
    122 const tqsl_adifFieldDefinitions *adifFields, const char * const *typesDefined,
    123 unsigned char *(*allocator)(size_t) );
    124
    127
    130
    136DLLEXPORT int CALLCONVENTION tqsl_adifMakeField(const char *fieldname, char type, const unsigned char *value, int len,
    137 unsigned char *buf, int buflen);
    138
    139#ifdef __cplusplus
    140}
    141#endif
    142
    144
    145#endif /* __ADIF_H */
    void * tQSL_ADIF
    Opaque ADIF type.
    Definition adif.h:41
    TQSL_ADIF_BOOLEAN
    Definition adif.h:35
    DLLEXPORT int CALLCONVENTION tqsl_getADIFLine(tQSL_ADIF adif, int *lineno)
    DLLEXPORT int CALLCONVENTION tqsl_getADIFField(tQSL_ADIF adif, tqsl_adifFieldResults *field, TQSL_ADIF_GET_FIELD_ERROR *status, const tqsl_adifFieldDefinitions *adifFields, const char *const *typesDefined, unsigned char *(*allocator)(size_t))
    TQSL_ADIF_GET_FIELD_ERROR
    Response values returned from tqsl_getADIFField()
    Definition adif.h:51
    #define TQSL_ADIF_FIELD_TYPE_LENGTH_MAX
    Max length of field type.
    Definition adif.h:29
    DLLEXPORT int CALLCONVENTION tqsl_beginADIF(tQSL_ADIF *adifp, const char *filename)
    DLLEXPORT int CALLCONVENTION tqsl_endADIF(tQSL_ADIF *adifp)
    #define TQSL_ADIF_FIELD_SIZE_LENGTH_MAX
    Max length of field name.
    Definition adif.h:28
    DLLEXPORT const char *CALLCONVENTION tqsl_adifGetError(TQSL_ADIF_GET_FIELD_ERROR status)
    TQSL_ADIF_RANGE_TYPE
    Specifies the type of range limits to apply to a field.
    Definition adif.h:44
    #define TQSL_ADIF_FIELD_NAME_LENGTH_MAX
    Max length of ADIF field.
    Definition adif.h:27
    DLLEXPORT int CALLCONVENTION tqsl_adifMakeField(const char *fieldname, char type, const unsigned char *value, int len, unsigned char *buf, int buflen)
    Definition adif.h:67
    unsigned int max_length
    Max length.
    Definition adif.h:71
    const char ** enumStrings
    Enumerated values.
    Definition adif.h:74
    char name[TQSL_ADIF_FIELD_NAME_LENGTH_MAX+1]
    Field name.
    Definition adif.h:68
    void * userPointer
    user pointer
    Definition adif.h:75
    TQSL_ADIF_RANGE_TYPE rangeType
    Range type.
    Definition adif.h:70
    char type[TQSL_ADIF_FIELD_TYPE_LENGTH_MAX+1]
    Field type.
    Definition adif.h:69
    long signed max_value
    Max value.
    Definition adif.h:73
    long signed min_value
    Min value.
    Definition adif.h:72
    Definition adif.h:79
    int line_no
    Input line where the tag was found.
    Definition adif.h:86
    void * userPointer
    User pointer.
    Definition adif.h:85
    unsigned char * data
    data
    Definition adif.h:83
    char type[TQSL_ADIF_FIELD_TYPE_LENGTH_MAX+1]
    Type.
    Definition adif.h:82
    char name[TQSL_ADIF_FIELD_NAME_LENGTH_MAX+1]
    Field name.
    Definition adif.h:80
    unsigned int adifNameIndex
    Name index.
    Definition adif.h:84
    char size[TQSL_ADIF_FIELD_SIZE_LENGTH_MAX+1]
    Size.
    Definition adif.h:81
    #define CALLCONVENTION
    Symbol exports - Windows only.
    Definition tqsllib.h:27
    #define DLLEXPORT
    Symbol exports - Windows only.
    Definition tqsllib.h:25
    tqsl-2.8.2/src/doxygen/html/adif_8h.html0000644000175000017500000003363115061653721020120 0ustar rmurphyrmurphy TrustedQSL Library API: adif.h File Reference
    TrustedQSL Library API
    adif.h File Reference
    #include <stdio.h>
    #include <stdlib.h>
    #include "tqsllib.h"

    Go to the source code of this file.

    Classes

    struct  tqsl_adifFieldDefinitions
     
    struct  tqsl_adifFieldResults
     

    Macros

    #define TQSL_ADIF_FIELD_NAME_LENGTH_MAX   64
     Max length of ADIF field.
     
    #define TQSL_ADIF_FIELD_SIZE_LENGTH_MAX   10
     Max length of field name.
     
    #define TQSL_ADIF_FIELD_TYPE_LENGTH_MAX   1
     Max length of field type.
     
    #define TQSLLIB_DEF
     

    Typedefs

    typedef void * tQSL_ADIF
     Opaque ADIF type.
     

    Enumerations

    enum  TQSL_ADIF_BOOLEAN { TQSL_FALSE , TQSL_TRUE }
     
    enum  TQSL_ADIF_RANGE_TYPE { TQSL_ADIF_RANGE_TYPE_NONE , TQSL_ADIF_RANGE_TYPE_MINMAX , TQSL_ADIF_RANGE_TYPE_ENUMERATION }
     Specifies the type of range limits to apply to a field.
     
    enum  TQSL_ADIF_GET_FIELD_ERROR {
      TQSL_ADIF_GET_FIELD_SUCCESS , TQSL_ADIF_GET_FIELD_NO_NAME_MATCH , TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH , TQSL_ADIF_GET_FIELD_NO_RANGE_MATCH ,
      TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH , TQSL_ADIF_GET_FIELD_NO_RESULT_ALLOCATION , TQSL_ADIF_GET_FIELD_NAME_LENGTH_OVERFLOW , TQSL_ADIF_GET_FIELD_DATA_LENGTH_OVERFLOW ,
      TQSL_ADIF_GET_FIELD_SIZE_OVERFLOW , TQSL_ADIF_GET_FIELD_TYPE_OVERFLOW , TQSL_ADIF_GET_FIELD_ERRONEOUS_STATE , TQSL_ADIF_GET_FIELD_EOF
    }
     Response values returned from tqsl_getADIFField()
     

    Functions

    DLLEXPORT const char *CALLCONVENTION tqsl_adifGetError (TQSL_ADIF_GET_FIELD_ERROR status)
     
    DLLEXPORT int CALLCONVENTION tqsl_beginADIF (tQSL_ADIF *adifp, const char *filename)
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFField (tQSL_ADIF adif, tqsl_adifFieldResults *field, TQSL_ADIF_GET_FIELD_ERROR *status, const tqsl_adifFieldDefinitions *adifFields, const char *const *typesDefined, unsigned char *(*allocator)(size_t))
     
    DLLEXPORT int CALLCONVENTION tqsl_getADIFLine (tQSL_ADIF adif, int *lineno)
     
    DLLEXPORT int CALLCONVENTION tqsl_endADIF (tQSL_ADIF *adifp)
     
    DLLEXPORT int CALLCONVENTION tqsl_adifMakeField (const char *fieldname, char type, const unsigned char *value, int len, unsigned char *buf, int buflen)
     
    tqsl-2.8.2/src/doxygen/html/.gitignore0000644000175000017500000000001715061653721017710 0ustar rmurphyrmurphy._* #osx cruft tqsl-2.8.2/src/converter.cpp0000644000175000017500000000661515061653721016024 0ustar rmurphyrmurphy/*************************************************************************** converter.cpp - c++ example program for signing a log ------------------- begin : Sun Dec 15 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "sysconfig.h" #endif #include #ifdef HAVE_GETOPT_H #include #endif #include #include #include #include #include #include "tqsllib.h" #include "tqslerrno.h" #include "tqslconvert.h" #include "tqslexc.h" using std::cerr; using std::endl; using std::ofstream; int usage() { cerr << "Usage: converter [-ac] station-location infile [outfile]\n"; exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { enum { UNKNOWN, CABRILLO, ADIF } type = UNKNOWN; int opt; while ((opt = getopt(argc, argv, "ca")) != -1) { switch (opt) { case 'c': type = CABRILLO; break; case 'a': type = ADIF; break; default: usage(); } } if (argc - optind < 2) usage(); tQSL_Converter conv = 0; try { if (tqsl_init()) throw tqslexc(); // Get the specified station location data tQSL_Location loc; if (tqsl_getStationLocation(&loc, argv[optind++])) throw tqslexc(); // Get the callsign and DXCC entity to use char call[256]; int dxcc; if (tqsl_getLocationCallSign(loc, call, sizeof call)) throw tqslexc(); if (tqsl_getLocationDXCCEntity(loc, &dxcc)) throw tqslexc(); // Get a list of available signing certificates tQSL_Cert *certs; int ncerts; if (tqsl_selectCertificates(&certs, &ncerts, call, dxcc, 0, 0, 1)) throw tqslexc(); if (ncerts < 1) throw myexc(string("No certificates available for ") + call); int stat = 1; if (type == UNKNOWN || type == CABRILLO) { if ((stat = tqsl_beginCabrilloConverter(&conv, argv[optind], certs, ncerts, loc)) != 0 && type == CABRILLO) throw tqslexc(); } if (stat) { if (tqsl_beginADIFConverter(&conv, argv[optind], certs, ncerts, loc)) throw tqslexc(); } tqsl_setConverterAllowDuplicates(conv, false); optind++; const char *ofile = (optind < argc) ? argv[optind] : "converted.tq7"; ofstream out; out.open(ofile, std::ios::out|std::ios::trunc|std::ios::binary); if (!out.is_open()) throw myexc(string("Unable to open ") + ofile); bool haveout = false; do { const char *gabbi = tqsl_getConverterGABBI(conv); if (gabbi) { haveout = true; out << gabbi; continue; } if (tQSL_Error == TQSL_SIGNINIT_ERROR) { tQSL_Cert cert; if (tqsl_getConverterCert(conv, &cert)) throw tqslexc(); if (tqsl_beginSigning(cert, 0, 0, 0)) throw tqslexc(); continue; } if (tQSL_Error == TQSL_DUPLICATE_QSO) continue; break; } while (1); out.close(); if (tQSL_Error != TQSL_NO_ERROR) throw tqslexc(); else if (!haveout) cerr << "Empty log file" << endl; } catch(exception& x) { char buf[40] = ""; int lineno; if (conv && !tqsl_getConverterLine(conv, &lineno)) // && lineno > 0) snprintf(buf, sizeof buf, " on line %d", lineno); cerr << "Aborted: " << x.what() << buf << endl; tqsl_converterRollBack(conv); return EXIT_FAILURE; } tqsl_converterCommit(conv); return EXIT_SUCCESS; } tqsl-2.8.2/src/converter.c0000644000175000017500000000640615061653721015462 0ustar rmurphyrmurphy/*************************************************************************** converter.c - "C" example program for signing a log ------------------- begin : Sun Dec 15 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #include #include #include #include #include #include #include "tqsllib.h" #include "tqslerrno.h" #include "tqslconvert.h" int usage() { fprintf(stderr, "Usage: converter [-ac] station-location infile [outfile]\n"); exit(EXIT_FAILURE); } void fail(tQSL_Converter conv) { char buf[40]; const char *err = tqsl_getErrorString(); int lineno; buf[0] = '\0'; if (conv && !tqsl_getConverterLine(conv, &lineno)) // && lineno > 0) sprintf(buf, " on line %d", lineno); fprintf(stderr, "Aborted: %s%s\n", err, buf); if (conv) tqsl_converterRollBack(conv); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { enum { UNKNOWN, CABRILLO, ADIF } type = UNKNOWN; int opt; tQSL_Location loc; tQSL_Converter conv = 0; int stat = 1; char call[256]; int dxcc; tQSL_Cert *certs; int ncerts; int haveout = 0; const char *ofile; int out; while ((opt = getopt(argc, argv, "ca")) != -1) { switch (opt) { case 'c': type = CABRILLO; break; case 'a': type = ADIF; break; default: usage(); } } if (argc - optind < 2) usage(); if (tqsl_init()) fail(conv); // Get the specified station location data if (tqsl_getStationLocation(&loc, argv[optind++])) fail(conv); // Get the callsign and DXCC entity to use if (tqsl_getLocationCallSign(loc, call, sizeof call)) fail(conv); if (tqsl_getLocationDXCCEntity(loc, &dxcc)) fail(conv); // Get a list of available signing certificates if (tqsl_selectCertificates(&certs, &ncerts, call, dxcc, 0, 0, 1)) fail(conv); if (ncerts < 1) { fprintf(stderr, "No certificates available for %s\n", call); exit (EXIT_FAILURE); } if (type == UNKNOWN || type == CABRILLO) { if ((stat = tqsl_beginCabrilloConverter(&conv, argv[optind], certs, ncerts, loc)) != 0 && type == CABRILLO) fail(conv); } if (stat) { if (tqsl_beginADIFConverter(&conv, argv[optind], certs, ncerts, loc)) fail(conv); } tqsl_setConverterAllowDuplicates(conv, 0); optind++; ofile = (optind < argc) ? argv[optind] : "converted.tq8"; out = creat(ofile, 0660); if (out < 0) { fprintf(stderr, "Unable to open %s\n", ofile); exit (EXIT_FAILURE); } tqsl_setConverterAppName(conv, "converter-sample"); do { const char *gabbi = tqsl_getConverterGABBI(conv); if (gabbi) { haveout = 1; write(out, gabbi, strlen(gabbi)); continue; } if (tQSL_Error == TQSL_SIGNINIT_ERROR) { tQSL_Cert cert; if (tqsl_getConverterCert(conv, &cert)) fail(conv); if (tqsl_beginSigning(cert, 0, 0, 0)) fail(conv); continue; } if (tQSL_Error == TQSL_DUPLICATE_QSO) continue; break; } while (1); close(out); if (tQSL_Error != TQSL_NO_ERROR) fail(conv); else if (!haveout) fprintf(stderr, "Empty log file\n"); tqsl_converterCommit(conv); return EXIT_SUCCESS; } tqsl-2.8.2/src/config.xml0000644000175000017500000165232515061653721015306 0ustar rmurphyrmurphy AM ARDOP ATV C4FM CHIP128 CHIP64 CHIP CLO CONTESTI PCW CW DIGITALVOICE DOMINOEX DOMINOF DOMINO DSTAR FAX FM FSK441 FT8 FMHELL FSKHELL HELL80 HFSK PSKHELL HELL ISCAT-A ISCAT-B ISCAT JT4A JT4B JT4C JT4D JT4E JT4F JT4G JT4 JT65A JT65B JT65B2 JT65C JT65C2 JT65 JT6M JT9-1 JT9-10 JT9-2 JT9-30 JT9-5 JT9A JT9B JT9C JT9D JT9E JT9E FAST JT9F JT9F FAST JT9G JT9G FAST JT9H JT9H FAST JT9 FSQCALL FST4 FT4 JS8 MFSK11 MFSK128 MFSK16 MFSK22 MFSK31 MFSK32 MFSK4 MFSK64 MFSK8 Q65 MFSK MSK144 MT63 OLIVIA 16/1000 OLIVIA 16/500 OLIVIA 32/1000 OLIVIA 4/125 OLIVIA 4/250 OLIVIA 8/250 OLIVIA 8/500 OLIVIA OPERA-BEACON OPERA-QSO OPERA PAC2 PAC3 PAC4 PAC PAX2 PAX PKT BPSK125 BPSK31 BPSK63 FSK31 PSK10 PSK1000 PSK125 PSK250 PSK31 PSK500 PSK63 PSK63F PSKAM10 PSKAM31 PSKAM50 PSKFEC31 QPSK125 QPSK250 QPSK31 QPSK500 QPSK63 SIM31 PSK PSK2K Q15 QRA64A QRA64B QRA64C QRA64D QRA64E QRA64 ROS-EME ROS-HF ROS-MF ROS ASCI RTTY RTTYM LSB USB SSB SSTV T10 THOR THRBX THRB AMTORFEC GTOR TOR V4 VOI WINMOR WSPR 1.25CM 1.25M 10M 12M 13CM 15M 160M 17M 1MM 2.5MM 20M 2190M 23CM 2M 2MM 30M 33CM 3CM 40M 4M 4MM 60M 630M 6CM 6M 6MM 70CM 80M 9CM SUBMM 8M 7QP AADX-CW AADX-SSB AP-SPRINT ARI-DX ARRL-10 ARRL-160 ARRL-DX-CW ARRL-DX-SSB ARRL-RTTY ARRL-SCR ARRL-SS-CW ARRL-SS-SSB ARRL-UHF-AUG ARRL-VHF-JAN ARRL-VHF-JUN ARRL-VHF-SEP AZQP BARTG-RTTY BARTG-SPRINT CQ-160-CW CQ-160-SSB CQ-M CQ-VHF CQ-WPX-CW CQ-WPX-RTTY CQ-WPX-SSB CQ-WW-CW CQ-WW-RTTY CQ-WW-SSB CW-Ops CWOPS-Open DARC-WAEDC-CW DARC-WAEDC-RTTY DARC-WAEDC-SSB DE_QSO-PARTY EU Sprint EU-HF EUHFC FCG-FQP FL-QSO-PARTY HELVETIA IARU-HF IL QSO Party IN QSO Party IN-QSO-PARTY JARTS-WW_RTTY JIDX-CW JIDX-SSB MI-QSO-PARTY MRRC-OhQP NA-SPRINT-CW NA-SPRINT-SSB NAQP-CW NAQP-RTTY NAQP-SSB NCCC-CQP NEQP NRAU-BALTIC-CW NRAU-BALTIC-SSB NY-QSO-PARTY OCEANIA-DX-CW OCEANIA-DX-SSB OK-OM-DX PACC RAC CANADA DAY RAC CANADA WINTER RADIO-WW-RTTY RAEM RDAC RDXC REF-160M REF-CW REF-SSB RSGB-160 RSGB-21/28 RSGB-80M-CC RSGB-80M-SPRINT RSGB-AFS-CW RSGB-AFS-SSB RSGB-CLUB-CALLS RSGB-COMMONWEALTH RSGB-IOTA RSGB-LOW-POWER RSGB-NFD RSGB-ROPOCO RSGB-SSB-FD SAC-CW SAC-SSB SARTG-RTTY SC-QSO-PARTY SCC RTTY SP-DX-RTTY SPDXContest STEW-PERRY State QSO Party - GA TARA-RTTY TMC-RTTY UBA-DX-CW UBA-DX-SSB VA-QSO-PARTY VOLTA-RTTY Virginia QSO Party Wisconsin QSO Party XE-RTTY -NONE- CANADA ABU AIL ISLANDS (DELETED) AFGHANISTAN AGALEGA & SAINT BRANDON ISLANDS ALAND ISLANDS ALASKA ALBANIA ALDABRA (DELETED) AMERICAN SAMOA AMSTERDAM & SAINT PAUL ISLANDS ANDAMAN & NICOBAR ISLANDS ANGUILLA ANTARCTICA ARMENIA ASIATIC RUSSIA NEW ZEALAND SUBANTARCTIC ISLANDS AVES ISLAND AZERBAIJAN BAJO NUEVO (DELETED) BAKER & HOWLAND ISLANDS BALEARIC ISLANDS PALAU BLENHEIM REEF (DELETED) BOUVET ISLAND BRITISH NORTH BORNEO (DELETED) BRITISH SOMALILAND (DELETED) BELARUS CANAL ZONE (DELETED) CANARY ISLANDS CELEBES & MOLUCCA ISLANDS (DELETED) CENTRAL KIRIBATI CEUTA & MELILLA CHAGOS ISLANDS CHATHAM ISLAND CHRISTMAS ISLAND CLIPPERTON ISLAND COCOS ISLAND COCOS (KEELING) ISLANDS COMORO ISLANDS (DELETED) CRETE CROZET ISLAND DAMAO, DIU (DELETED) DESECHEO ISLAND DESROCHES (DELETED) DODECANESE EAST MALAYSIA EASTER ISLAND EASTERN KIRIBATI EQUATORIAL GUINEA MEXICO ERITREA ESTONIA ETHIOPIA EUROPEAN RUSSIA FARQUHAR (DELETED) FERNANDO DE NORONHA FRENCH EQUATORIAL AFRICA (DELETED) FRENCH INDO-CHINA (DELETED) FRENCH WEST AFRICA (DELETED) BAHAMAS FRANZ JOSEF LAND BARBADOS FRENCH GUIANA BERMUDA BRITISH VIRGIN ISLANDS BELIZE FRENCH INDIA (DELETED) KUWAIT/SAUDI ARABIA NEUTRAL ZONE (DELETED) CAYMAN ISLANDS CUBA GALAPAGOS ISLANDS DOMINICAN REPUBLIC EL SALVADOR GEORGIA GUATEMALA GRENADA HAITI GUADELOUPE HONDURAS GERMANY (DELETED) JAMAICA MARTINIQUE BONAIRE,CURACAO (NETH ANTILLES) (DELETED) NICARAGUA PANAMA TURKS & CAICOS ISLANDS TRINIDAD & TOBAGO ARUBA GEYSER REEF (DELETED) ANTIGUA & BARBUDA DOMINICA MONTSERRAT SAINT LUCIA SAINT VINCENT GLORIOSO ISLAND ARGENTINA GOA (DELETED) GOLD COAST TOGOLAND (DELETED) GUAM BOLIVIA GUANTANAMO BAY GUERNSEY GUINEA BRAZIL GUINEA-BISSAU HAWAII HEARD ISLAND CHILE IFNI (DELETED) ISLE OF MAN ITALIAN SOMALILAND (DELETED) COLOMBIA ITU HQ JAN MAYEN JAVA (DELETED) ECUADOR JERSEY JOHNSTON ISLAND JUAN DE NOVA, EUROPA JUAN FERNANDEZ ISLAND KALININGRAD KAMARAN ISLANDS (DELETED) KARELO-FINNISH REP (DELETED) GUYANA KAZAKHSTAN KERGUELEN ISLAND PARAGUAY KERMADEC ISLAND KINGMAN REEF (DELETED) KYRGYZSTAN PERU REPUBLIC OF KOREA KURE ISLAND KURIA MURIA ISLAND (DELETED) SURINAME FALKLAND ISLANDS LAKSHADWEEP ISLANDS LAOS URUGUAY LATVIA LITHUANIA LORD HOWE ISLAND VENEZUELA AZORES AUSTRALIA MALYJ VYSOTSKIJ ISLAND (DELETED) MACAO MACQUARIE ISLAND YEMEN ARAB REPUBLIC (DELETED) MALAYA (DELETED) NAURU VANUATU MALDIVES TONGA MALPELO ISLAND NEW CALEDONIA PAPUA NEW GUINEA MANCHURIA (DELETED) MAURITIUS ISLAND MARIANA ISLANDS MARKET REEF MARSHALL ISLANDS MAYOTTE ISLAND NEW ZEALAND MELLISH REEF PITCAIRN ISLAND MICRONESIA MIDWAY ISLAND FRENCH POLYNESIA FIJI ISLANDS MINAMI TORISHIMA MINERVA REEF (DELETED) MOLDOVA MOUNT ATHOS MOZAMBIQUE NAVASSA ISLAND NETHERLANDS BORNEO (DELETED) NETHERLANDS N GUINEA (DELETED) SOLOMON ISLANDS NEWFOUNDLAND LABRADOR (DELETED) NIGER NIUE NORFOLK ISLAND SAMOA NORTH COOK ISLANDS OGASAWARA OKINAWA (DELETED) OKINO TORI-SHIMA (DELETED) ANNOBON PALESTINE (DELETED) PALMYRA & JARVIS ISLANDS PAPUA TERRITORY (DELETED) PETER 1 ISLAND PORTUGUESE TIMOR (DELETED) PRINCE EDWARD & MARION ISLANDS PUERTO RICO ANDORRA REVILLAGIGEDO ASCENSION ISLAND AUSTRIA RODRIGUEZ ISLAND RUANDA-URUNDI (DELETED) BELGIUM SAAR (DELETED) SABLE ISLAND BULGARIA SAINT MARTIN CORSICA CYPRUS SAN ANDRES ISLAND SAN FELIX ISLAND CZECHOSLOVAKIA (DELETED) SAO TOME & PRINCIPE SARAWAK (DELETED) DENMARK FAROE ISLANDS ENGLAND FINLAND SARDINIA SAUDI ARABIA/IRAQ NEUTRAL ZONE (DELETED) FRANCE SERRANA BANK & RONCADOR CAY (DELETED) GERMAN DEMOCRATIC REPUBLIC (DELETED) FEDERAL REPUBLIC OF GERMANY SIKKIM (DELETED) SOMALIA GIBRALTAR SOUTH COOK ISLANDS SOUTH GEORGIA ISLAND GREECE GREENLAND SOUTH ORKNEY ISLANDS HUNGARY SOUTH SANDWICH ISLANDS SOUTH SHETLAND ISLANDS ICELAND PEOPLE'S DEM REP OF YEMEN (DELETED) SOUTHERN SUDAN (DELETED) IRELAND SOVEREIGN MILITARY ORDER OF MALTA SPRATLY ISLANDS ITALY SAINT KITTS & NEVIS SAINT HELENA LIECHTENSTEIN SAINT PAUL ISLAND SAINT PETER AND PAUL ROCKS LUXEMBOURG SINT MAARTEN, SABA, SAINT EUSTATIUS (DELETED) MADEIRA ISLANDS MALTA SUMATRA (DELETED) SVALBARD MONACO SWAN ISLAND (DELETED) TAJIKISTAN NETHERLANDS TANGIER (DELETED) NORTHERN IRELAND NORWAY TERRITORY OF NEW GUINEA (DELETED) TIBET (DELETED) POLAND TOKELAU ISLANDS TRIESTE (DELETED) PORTUGAL TRINDADE & MARTIM VAZ ISLANDS TRISTAN DA CUNHA & GOUGH ISLANDS ROMANIA TROMELIN ISLAND SAINT PIERRE & MIQUELON SAN MARINO SCOTLAND TURKMENISTAN SPAIN TUVALU U K BASES ON CYPRUS SWEDEN US VIRGIN ISLANDS UGANDA SWITZERLAND UKRAINE UNITED NATIONS HQ UNITED STATES OF AMERICA UZBEKISTAN VIET NAM WALES VATICAN CITY SERBIA WAKE ISLAND WALLIS & FUTUNA ISLANDS WEST MALAYSIA WESTERN KIRIBATI WESTERN SAHARA WILLIS ISLAND BAHRAIN BANGLADESH BHUTAN ZANZIBAR (DELETED) COSTA RICA MYANMAR CAMBODIA SRI LANKA CHINA HONG KONG INDIA INDONESIA IRAN IRAQ ISRAEL JAPAN JORDAN DPRK (NORTH KOREA) BRUNEI KUWAIT LEBANON MONGOLIA NEPAL OMAN PAKISTAN PHILIPPINES QATAR SAUDI ARABIA SEYCHELLES ISLANDS SINGAPORE DJIBOUTI SYRIA TAIWAN THAILAND TURKEY UNITED ARAB EMIRATES ALGERIA ANGOLA BOTSWANA BURUNDI CAMEROON CENTRAL AFRICAN REPUBLIC CAPE VERDE CHAD COMOROS REPUBLIC OF THE CONGO DEMOCRATIC REPUBLIC OF THE CONGO BENIN GABON THE GAMBIA GHANA COTE D'IVOIRE KENYA LESOTHO LIBERIA LIBYA MADAGASCAR MALAWI MALI MAURITANIA MOROCCO NIGERIA ZIMBABWE REUNION ISLAND RWANDA SENEGAL SIERRA LEONE ROTUMA REPUBLIC OF SOUTH AFRICA NAMIBIA SUDAN KINGDOM OF ESWATINI TANZANIA TUNISIA EGYPT BURKINA FASO ZAMBIA TOGO WALVIS BAY (DELETED) CONWAY REEF BANABA ISLAND YEMEN PENGUIN ISLANDS (DELETED) CROATIA SLOVENIA BOSNIA-HERZEGOVINA NORTH MACEDONIA CZECH REPUBLIC SLOVAK REPUBLIC PRATAS ISLAND SCARBOROUGH REEF TEMOTU PROVINCE AUSTRAL ISLANDS MARQUESAS ISLANDS PALESTINE TIMOR - LESTE CHESTERFIELD ISLANDS DUCIE ISLAND MONTENEGRO SWAINS ISLAND SAINT BARTHELEMY CURACAO SINT MAARTEN SABA & SAINT EUSTATIUS BONAIRE REPUBLIC OF SOUTH SUDAN REPUBLIC OF KOSOVO Australian Capital Territory New South Wales Victoria Queensland South Australia Western Australia Tasmania Northern Territory Alberta British Columbia Manitoba New Brunswick Newfoundland and Labrador Northwest Territories Nova Scotia Nunavut Ontario Prince Edward Island Quebec Saskatchewan Yukon Territory International Peace Garden Roosevelt Campobello International Park Anhui Beijing Chongqing Fujian Guangdong Gansu Guangxi Guizhou Henan Hubei Hebei Hainan Heilongjiang Hunan Jilin Jiangsu Jiangxi Liaoning Nei Mongol Ningxia Qinghai Sichuan Shandong Shanghai Shaanxi Shanxi Tianjin Xinjiang Xizang Yunnan Zhejiang Africa Asia Antarctica Europe North America Oceania South America War in the Pacific National Historical Park American Memorial Park San Juan National Historic Site Buck Island Reef National Monument Christiansted National Historic Site Christiansted NHS + Buck Island Reef NM Salt River Bay NHP and Ecological Preserve National Historical Park Virgin Islands National Park Virgin Islands Coral Reef National Monument Virgin Islands NP + Virgin Islands Coral Reef National Park of American Samoa Hammarland Somero Ahlainen Alastaro Askainen (Villnäs) Aura Dragsfjärd Eura Eurajoki Halikko Harjavalta Honkajoki Houtskari (Houtskär) Huittinen Hämeenkyrö Ikaalinen Iniö Jämijärvi Kaarina (St. Karins) Kalanti Kankaanpää Karinainen Karjala Karvia Äetsä (Keikyä) Kemiönsaari (Kemiö) Kihniö Kiikala Kiikka Kiikoinen Kisko Kiukainen Kodisjoki Kokemäki (Kumo) Korppoo (Korpo) Koski tl Kullaa Kustavi (Gustavs) Kuusjoki Köyliö (Kjulo) Laitila Lappi Lavia Lemu Lieto Loimaa Loimaan kunta (Loimaan mlk) Lokalahti Luvia Marttila Masku Mellilä Merikarvia Merimasku Metsämaa Mietoinen Mouhijärvi Muurla Mynämäki Naantali (Nådendal) Nakkila Nauvo (Nagu) Noormarkku (Norrmark) Nousiainen Oripää Paimio (Permar) Parainen (Pargas) Parkano Perniö (Bjärnå) Pertteli Piikkiö (Pikis) Pomarkku (Påmark) Pori (Björneborg) Punkalaidun Pyhäranta Pöytyä Raisio (Reso) Rauma (Raumo) Rauman mlk (Raumo lk) Rusko Rymättylä (Rimito) Salo Sauvo Siikainen Suodenniemi Suomusjärvi Säkylä Särkisalo Taivassalo Tarvasjoki Turku (Åbo) Ulvila Uusikaupunki (Nystad) Vahto Sastamala (Vammala) Vampula Vehmaa Velkua Viljakkala Västanfjärd Yläne Artjärvi (Artsjö) Askola Bromarv Espoo (Esbo) Hanko (Hangö) Helsinki (Helsingfors) Hyvinkää (Hyvinge) Inkoo (Ingå) Järvenpää Karjaa (Karis) Karjalohja (Karislojo) Karkkila Kauniainen (Grankulla) Kerava (Kervo) Kirkkonummi (Kyrkslätt) Lapinjärvi (Lappträsk) Liljendal Lohja (Lojo) Lohjan kunta (Lohjan mlk) Loviisa (Lovisa) Myrskylä (Mörskom) Mäntsälä Nummi-Pusula (Nummi) Nurmijärvi Orimattila Pernaja (Perna) Pohja (Pojo) Pornainen (Borgnäs) Porvoo (Borgå) Porvoon mlk (Borgå lk) Pukkila Pusula Ruotsinpyhtää (Strömfors) Sammatti Sipoo (Sibbo) Siuntio (Sjundeå) Snappertuna Tammisaari (Ekenäs) Tammisaaren mlk (Ekenäs lk) Tenhola (Tenala) Tuusula (Tusby) Vantaa (Vanda) Vihti Raasepori Asikkala Eräjärvi Forssa Hattula Hauho Hausjärvi Hollola Humppila Hämeenlinna (Tavastehus) Janakkala Jokioinen Juupajoki Kalvola Kangasala Hämeenkoski (Koski hl) Kuhmalahti Kuorevesi Kuru Kylmäkoski Kärkölä Lahti Lammi Lempäälä Loppi Luopioinen Längelmäki Mänttä Nastola Nokia Orivesi Padasjoki Pirkkala Pälkäne Renko Riihimäki Ruovesi Sahalahti Somerniemi Somero Tammela Tampere (Tammerfors) Toijala Tottijärvi Tuulos Urjala Valkeakoski Vesilahti Viiala Vilppula Virrat Ylöjärvi Ypäjä Hämeenkyrö (Tavastkyro) Ikaalinen Kihniö Mouhijärvi Parkano Viljakkala Akaa Mänttä-Vilppula Anttola Enonkoski Hartola Haukivuori Heinola Heinolan mlk (Heinola lk) Heinävesi Hirvensalmi Joroinen Juva Jäppilä Kangaslampi Kangasniemi Kerimäki Mikkeli (St. Michel) Mikkelin mlk (St. Michel's lk) Mäntyharju Pertunmaa Pieksämäki Pieksänmaa (Pieksämäen mlk) Punkaharju Puumala Rantasalmi Ristiina Savonlinna (Nyslott) Savonranta Sulkava Sysmä Virtasalmi Anjala Elimäki Hamina (Fredrikshamn) Iitti Imatra Jaala Joutseno Karhula Kotka Kouvola Kuusankoski Kymi (Kymmene) Lappeenranta (Villmanstrand) Lemi Luumäki Miehikkälä Nuijamaa Parikkala Pyhtää (Pyttis) Rautjärvi Ruokolahti Saari Savitaipale Sippola Suomenniemi Taipalsaari Uudenkaarlepyyn mlk (Nykarleby lk) Valkeala Vehkalahti Virolahti Ylämaa Anjalankoski Alahärmä Alajärvi Alavus (Alavo) Evijärvi Halsua Hankasalmi Himanka Ilmajoki Isojoki (Stora) Isokyrö (Storkyro) Jalasjärvi Joutsa Jurva Jyväskylä Jyväskylän mlk (Jyväskylä lk) Jämsä Jämsänkoski Kaarlela (Karleby) Kannonkoski Kannus Karijoki (Bötom) Karstula Kaskinen (Kasköo) Kauhajoki Kauhava Kaustinen (Kaustby) Keuruu Kinnula Kivijärvi Kokkola (Gamlakarleby) Konginkangas Konnevesi Korpilahti Korsnäs Kortesjärvi Kristiinankaupunki (Kristinestad) Kruunupyy (Kronoby) Kuhmoinen Kuortane Kurikka Kyyjärvi Kälviä Laihia Lappajärvi Lapua (Lappo) Laukaa Lehtimäki Leivonmäki Lestijärvi Lohtaja Luhanka Luoto (Larsmo) Maalahti (Malax) Maksamaa (Maxmo) Multia Mustasaari (Korsholm) Muurame Nurmo Närpiö (Närpes) Oravainen (Gravais) Perho Peräseinäjoki Petäjävesi Pietarsaari (Jakobstad) Pedersöre (Pietarsaaren mlk) Pihtipudas Purmo Pylkönmäki Saarijärvi Seinäjoki Soini Sumiainen Suolahti Säynätsalo Teuva (Östermark) Toholampi Toivakka Töysä Ullava Uurainen Uusikaarlepyy (Nykarleby) Vaasa (Vasa) Veteli (Vetil) Viitasaari Vimpeli (Vindala) Vähäkyrö (Lillkyro) Vöyri (Vörå) Ylihärmä Ylistaro Ähtäri Ähtävä (Esse) Äänekoski Jepua (Jeppo) Munsala Uudenkaarlepyyn mlk Vöyri-Maksamaa (Vörå-Maxmo) Eno Iisalmi Ilomantsi Joensuu Juankoski Juuka Kaavi Karttula Keitele Kesälahti Kiihtelysvaara Kitee Kiuruvesi Kontiolahti Kuopio Lapinlahti Leppävirta Lieksa Liperi Maaninka Nilsiä Nurmes Outokumpu Pielavesi Polvijärvi Pyhäselkä Rautalampi Rautavaara Rääkkylä Siilinjärvi Sonkajärvi Suonenjoki Tervo Tohmajärvi Tuupovaara Tuusniemi Valtimo Varkaus Varpaisjärvi Vehmersalmi Vesanto Vieremä Värtsilä Alavieska Haapajärvi Haapavesi Hailuoto (Karlö) Haukipudas Hyrynsalmi Ii Kajaani Kajaanin mlk (Kajaani lk) Kalajoki Kempele Kestilä Kiiminki Kuhmo Kuivaniemi Kuusamo Kärsämäki Liminka Lumijoki Merijärvi Muhos Nivala Oulainen Oulu (Uleåborg) Oulunsalo Paltamo Pattijoki Piippola Pudasjärvi Pulkkila Puolanka Pyhäjoki Pyhäjärvi Pyhäntä Raahe (Brahestad) Rantsila Reisjärvi Ristijärvi Ruukki Sievi Siikajoki Sotkamo Suomussalmi Taivalkoski Temmes Tyrnävä Utajärvi Vaala Vihanti Vuolijoki Yli-Ii Ylikiiminki Ylivieska Siikalatva Enontekiö Inari (Enare) Kemi Keminmaa (Kemin mlk) Kemijärvi Kemijärven mlk Kittilä Kolari Muonio Pelkosenniemi Pello Posio Ranua Rovaniemi Rovaniemen mlk (Rovaniemi lk) Salla Savukoski Simo Sodankylä Tervola Tornio (Torneå) Utsjoki Ylitornio (Övertorneå) Brändö Eckerö Finström Föglö Geta Hammarland Jomala Kumlinge Kökar Lemland Lumparland Maarianhamina (Mariehamn) Saltvik Sottunga Sund Vårdö Märket Reef Sapporo-shi Asahikawa-shi Otaru-shi Hakodate-shi Muroran-shi Kushiro-shi Obihiro-shi Kitami-shi Yubari-shi Iwamizawa-shi Abashiri-shi Rumoi-shi Tomakomai-shi Wakkanai-shi Bibai-shi Ashibetsu-shi Ebetsu-shi Akabira-shi Mombetsu-shi Shibetsu-shi Nayoro-shi Mikasa-shi Nemuro-shi Chitose-shi Takikawa-shi Sunagawa-shi Utashinai-shi Fukagawa-shi Furano-shi Noboribetsu-shi Eniwa-shi Kameda-shi Date-shi Kitahiroshima-shi Ishikari-shi Hokuto-shi Akan-gun Ashoro-gun Atsukeshi-gun Atsuta-gun Abashiri-gun Abuta-gun (Shiribeshi) Abuta-gun (Iburi) Ishikari-gun Isoya-gun Iwanai-gun Usu-gun Utasutsu-gun Urakawa-gun Uryu-gun (Sorachi) Esashi-gun Okushiri-gun Oshoro-gun Kasai-gun Kato-gun Kabato-gun Kamiiso-gun Kamikawa-gun (Tokachi) Kamikawa-gun (Kamikawa) Kameda-gun Kayabe-gun Kawakami-gun Kushiro-gun Kudo-gun Sapporo-gun Samani-gun Saru-gun Shizunai-gun Shibetsu-gun Shimamaki-gun Shakotan-gun Shari-gun Shiraoi-gun Shiranuka-gun Suttsu-gun Setana-gun Soya-gun Sorachi-gun (Sorachi) Sorachi-gun (Kamikawa) Chitose-gun Teshio-gun (Rumoi) Teshio-gun (Soya) Tokachi-gun Tokoro-gun Tomamae-gun Nakagawa-gun (Kamikawa) Nakagawa-gun (Tokachi) Niikappu-gun Nishi-gun Nemuro-gun Notsuke-gun Hanasaki-gun Hamamasu-gun Bikuni-gun Hiyama-gun Hiroo-gun Futoro-gun Furuu-gun Furubira-gun Horoizumi-gun Horobetsu-gun Mashike-gun Matsumae-gun Mitsuishi-gun Menashi-gun Mombetsu-gun Yamakoshi-gun Yubari-gun Yufutsu-gun (Iburi) Yufutsu-gun (Kamikawa) Yoichi-gun Rishiri-gun Rumoi-gun Rebun-gun Futami-gun Hidaka-gun Uryu-gun (Kamikawa) Chuo-ku Kita-ku Higashi-ku Shiroishi-ku Toyohira-ku Minami-ku Nishi-ku Atsubetsu-ku Teine-ku Kiyota-ku Aomori-shi Hirosaki-shi Hachinohe-shi Kuroishi-shi Goshogawara-shi Towada-shi Misawa-shi Mutsu-shi Tsugaru-shi Hirakawa-shi Kamikita-gun Kitatsugaru-gun Sannohe-gun Shimokita-gun Nakatsugaru-gun Nishitsugaru-gun Higashitsugaru-gun Minamitsugaru-gun Morioka-shi Kamaishi-shi Miyako-shi Ichinoseki-shi Ofunato-shi Mizusawa-shi Hanamaki-shi Kitakami-shi Kuji-shi Tono-shi Rikuzentakata-shi Esashi-shi Ninohe-shi Hachimantai-shi Oshu-shi Takizawa-shi Isawa-gun Iwate-gun Esashi-gun Kamihei-gun Kunohe-gun Kesen-gun Shimohei-gun Shiwa-gun Nishiiwai-gun Ninohe-gun Hienuki-gun Higashiiwai-gun Waga-gun Akita-shi Noshiro-shi Odate-shi Yokote-shi Honjo-shi Oga-shi Yuzawa-shi Omagari-shi Kazuno-shi Yurihonjo-shi Katagami-shi Daisen-shi Kitaakita-shi Nikaho-shi Senboku-shi Ogachi-gun Kaduno-gun Kawabe-gun Kitaakita-gun Semboku-gun Hiraka-gun Minamiakita-gun Yamamoto-gun Yuri-gun Yamagata-shi Yonezawa-shi Tsuruoka-shi Sakata-shi Shinjo-shi Sagae-shi Kaminoyama-shi Murayama-shi Nagai-shi Tendo-shi Higashine-shi Obanazawa-shi Nan01yo-shi Akumi-gun Kitamurayama-gun Nishiokitama-gun Nishitagawa-gun Nishimurayama-gun Higashiokitama-gun Higashitagawa-gun Higashimurayama-gun Minamiokitama-gun Minamimurayama-gun Mogami-gun Sendai-shi Ishinomaki-shi Shiogama-shi Furukawa-shi Kesennuma-shi Shiroishi-shi Natori-shi Kakuda-shi Tagajo-shi Izumi-shi Iwanuma-shi Tome-shi Kuruhara-shi Higashimatsushima-shi Osaki-shi Tomiya-shi Igu-gun Oshika-gun Katta-gun Kami-gun Kurihara-gun Kurokawa-gun Shida-gun Shibata-gun Tamadukuri-gun Toda-gun Tome-gun Natori-gun Miyagi-gun Motoyoshi-gun Monou-gun Watari-gun Aoba-ku Miyagino-ku Wakabayashi-ku Taihaku-ku Izumi-ku Fukushima-shi Aizuwakamatsu-shi Koriyama-shi Taira-shi Shirakawa-shi Haramachi-shi Sukagawa-shi Kitakata-shi Joban-shi Iwaki-shi Soma-shi Uchigo-shi Nakoso-shi Nihonmatsu-shi Iwaki-shi Wakamatsu-shi Tamura-shi Minamisoma-shi Date-shi Motomiya-shi Asaka-gun Adachi-gun Ishikawa-gun Ishiki-gun Iwase-gun Onuma-gun Kawanuma-gun Kitaaidu-gun Shinobu-gun Soma-gun Date-gun Tamura-gun Nishishirakawa-gun Higashishirakawa-gun Futaba-gun Minamiaidu-gun Yama-gun Niigata-shi Nagaoka-shi Takada-shi Sanjo-shi Kashiwazaki-shi Shibata-shi Niitsu-shi Ojiya-shi Kamo-shi Tokamachi-shi Mitsuke-shi Murakami-shi Tsubame-shi Naoetsu-shi Tochio-shi Itoigawa-shi Arai-shi Gosen-shi Ryotsu-shi Shirone-shi Toyosaka-shi Joetsu-shi Agano-shi Sado-shi Uonuma-shi Minamiuonuma-shi Myoko-shi Tainai-shi Iwafune-gun Kariwa-gun Kitauonuma-gun Kitakambara-gun Koshi-gun Sado-gun Santo-gun Nakauonuma-gun Nakakambara-gun Nakakubiki-gun Nishikambara-gun Nishikubiki-gun Higashikambara-gun Higashikubiki-gun Minamiuonuma-gun Minamikambara-gun Kita-ku Higashi-ku Chuo-ku Konan-ku Akiha-ku Minami-ku Nishi-ku Nishikan-ku Nagano-shi Matsumoto-shi Ueda-shi Okaya-shi Iida-shi Suwa-shi Suzaka-shi Komoro-shi Ina-shi Komagane-shi Nakano-shi Omachi-shi Iiyama-shi Chino-shi Shiojiri-shi Shinonoi-shi Koshoku-shi Saku-shi Chikuma-shi Tomi-shi Azumino-shi Kamiina-gun Kamitakai-gun Kamiminochi-gun Kiso-gun Kitaazumi-gun Kitasaku-gun Sarashina-gun Shimoina-gun Shimotakai-gun Shimominochi-gun Suwa-gun Chiisagata-gun Hanishina-gun Higashichikuma-gun Minamiazumi-gun Minamisaku-gun Chiyoda-ku Chuo-ku Minato-ku Shinjuku-ku Bunkyo-ku Taito-ku Sumida-ku Koto-ku Shinagawa-ku Meguro-ku Ota-ku Setagaya-ku Shibuya-ku Nakano-ku Suginami-ku Toshima-ku Kita-ku Arakawa-ku Itabashi-ku Nerima-ku Adachi-ku Katsushika-ku Edogawa-ku Tokyo 23-wards Hachioji-shi Tachikawa-shi Musashino-shi Mitaka-shi Ome-shi Fuchu-shi Akishima-shi Chofu-shi Machida-shi Koganei-shi Kodaira-shi Hino-shi Higashimurayama-shi Kokubunji-shi Kunitachi-shi Hoya-shi Tanashi-shi Fussa-shi Komae-shi Higashiyamato-shi Kiyose-shi Higashikurume-shi Musashimurayama-shi Tama-shi Inagi-shi Akigawa-shi Hamura-shi Akiruno-shi Nishitokyo-shi Kitatama-gun Nishitama-gun Minamitama-gun Oshima-gun Miyake-gun Hachijo-gun Ogawasara-gun Yokohama-shi Yokosuka-shi Kawasaki-shi Hiratsuka-shi Kamakura-shi Fujisawa-shi Odawara-shi Chigasaki-shi Zushi-shi Sagamihara-shi Miura-shi Hadano-shi Atsugi-shi Yamato-shi Isehara-shi Ebina-shi Zama-shi Minamiashigara-shi Ayase-shi Aiko-gun Ahigarakami-gun Ashigarashimo-gun Koza-gun Tsukui-gun Naka-gun Miura-gun Tsurumi-ku Kanagawa-ku Nishi-ku Naka-ku Minami-ku Hodogaya-ku Isogo-ku Kanazawa-ku Kohoku-ku Totsuka-ku Konan-ku Asahi-ku Midori-ku Seya-ku Sakae-ku Izumi-ku Aoba-ku Tsuzuki-ku Kawasaki-ku Saiwai-ku Nakahara-ku Takatsu-ku Tama-ku Miyamae-ku Asao-ku Midori-ku Chuou-ku Minami-ku Chiba-shi Choshi-shi Ichikawa-shi Funabashi-shi Tateyama-shi Kisarazu-shi Matsudo-shi Noda-shi Sawara-shi Mobara-shi Narita-shi Sakura-shi Togane-shi Yokaichiba-shi Asahi-shi Narashino-shi Kashiwa-shi Katsuura-shi Ichihara-shi Nagareyama-shi Yachiyo-shi Abiko-shi Kamogawa-shi Kimitsu-shi Kamagaya-shi Futtu-shi Urayasu-shi Yotsukaido-shi Sodegaura-shi Yachimata-shi Inzai-shi Shiroi-shi Tomisato-shi Minamiboso-shi Sosa-shi Katori-shi Sanmu-shi Isumi-shi Oamishirasato-shi Awa-gun Isumi-gun Ichihara-gun Inba-gun Kaijo-gun Katori-gun Kimitsu-gun Sambu-gun Sosa-gun Chiba-gun Chosei-gun Higashikatsushika-gun Chuo-ku Hanamigawa-ku Inage-ku Wakaba-ku Midori-ku Mihama-ku Urawa-shi Kawagoe-shi Kumagaya-shi Kawaguchi-shi Omiya-shi Gyoda-shi Chichibu-shi Tokorozawa-shi Hanno-shi Kazo-shi Honjo-shi Higashimatsuyama-shi Iwatsuki-shi Kasukabe-shi Sayama-shi Hanyu-shi Konosu-shi Fukaya-shi Ageo-shi Yono-shi Soka-shi Koshigaya-shi Warabi-shi Toda-shi Iruma-shi Hatogaya-shi Asaka-shi Shiki-shi Wako-shi Niiza-shi Okegawa-shi Kuki-shi Kitamoto-shi Yashio-shi Kamifukuoka-shi Fujimi-shi Misato-shi Hasuda-shi Sakado-shi Satte-shi Tsurugashima-shi Hidaka-shi Yoshikawa-shi Saitama-shi Fujimino-shi Shiraoka-shi Iruma-gun Osato-gun Kitaadachi-gun Kitakatsushika-gun Kitasaitama-gun Kodama-gun Chichibu-gun Hiki-gun Minamisaitama-gun Nishi-ku Kita-ku Omiya-ku Minuma-ku Chuo-ku Sakura-ku Urawa-ku Minami-ku Midori-ku Iwatsuki-ku Mito-shi Hitachi-shi Tsuchiura-shi Koga-shi Ishioka-shi Shimodate-shi Yuki-shi Ryugasaki-shi Nakaminato-shi Shimotsuma-shi Mitsukaido-shi Hitachiota-shi Katsuta-shi Takahagi-shi Kitaibaraki-shi Kasama-shi Toride-shi Iwai-shi Ushiku-shi Tsukuba-shi Hitachinaka-shi Kashima-shi Itako-shi Moriya-shi Hitachiomiya-shi Naka-shi Chikusei-shi Bandou-shi Inashiki-shi Kasumigaura-shi Sakuragawa-shi Kamisu-shi Namegata-shi Hokota-shi Joso-shi Tsukubamirai-shi Omitama-shi Inashiki-gun Kashima-gun Kitasoma-gun Kuji-gun Sashima-gun Taga-gun Tsukuba-gun Naka-gun Namegata-gun Niihari-gun Nishiibaraki-gun Higashiibaraki-gun Makabe-gun Yuki-gun Utsunomiya-shi Ashikaga-shi Tochigi-shi Sano-shi Kanuma-shi Nikko-shi Imaichi-shi Oyama-shi Mooka-shi Otawara-shi Yaita-shi Kuroiso-shi Nasushiobara-shi Sakura-shi Nasukarasuyama-shi Shimotsuke-shi Ashikaga-gun Aso-gun Kamitsuga-gun Kawachi-gun Shioya-gun Shimotsuga-gun Nasu-gun Haga-gun Maebashi-shi Takasaki-shi Kiryu-shi Isesaki-shi Ota-shi Numata-shi Tatebayashi-shi Shibukawa-shi Fujioka-shi Tomioka-shi Annaka-shi Midori-shi Agatsuma-gun Usui-gun Ora-gun Kanra-gun Kitagumma-gun Gumma-gun Sawa-gun Seta-gun Tano-gun Tone-gun Nitta-gun Yamada-gun Kofu-shi Fujiyoshida-shi Enzan-shi Tsuru-shi Yamanashi-shi Otsuki-shi Nirasaki-shi Minami-Alps Hokuto-shi Kai-shi Fuehuki-shi Uenohara-shi Koshu-shi Chuo-shi Kitakoma-gun Kitatsuru-gun Nakakoma-gun Nishiyatsushiro-gun Higashiyatsushiro-gun Higashiyamanashi-gun Minamikoma-gun Minamitsuru-gun Shizuoka-shi Hamamatsu-shi Numadu-shi Shimizu-shi Atami-shi Mishima-shi Fujinomiya-shi Ito-shi Shimada-shi Yoshiwara-shi Iwata-shi Yaidu-shi Fuji-shi Kakegawa-shi Fujieda-shi Gotemba-shi Fukuroi-shi Tenryu-shi Hamakita-shi Shimoda-shi Susono-shi Kosai-shi Izu-shi Omaezaki-shi Kikugawa-shi Izunokuni-shi Makinohara-shi Abe-gun Inasa-gun Ihara-gun Iwata-gun Ogasa-gun Kamo-gun Shida-gun Shuchi-gun Sunto-gun Tagata-gun Haibara-gun Hamana-gun Fuji-gun Aoi-ku Suruga-ku Shimizu-ku Naka-ku Higashi-ku Nishi-ku Minami-ku Kita-ku Hamakita-ku Tenryu-ku Chuo-ku Hamana-ku Gifu-shi Ogaki-shi Takayama-shi Tajimi-shi Seki-shi Nakatsugawa-shi Mino-shi Mizunami-shi Hashima-shi Ena-shi Minokamo-shi Toki-shi Kakamigahara-shi Kani-shi Yamagata-shi Mizuho-shi Hida-shi Motosu-shi Gujo-shi Gero-shi Kaizu-shi Ampachi-gun Inaba-gun Ibi-gun Ena-gun Ono-gun Kaizu-gun Kani-gun Kamo-gun Gujo-gun Toki-gun Hashima-gun Fuwa-gun Mashita-gun Mugi-gun Motosu-gun Yamagata-gun Yoro-gun Yoshiki-gun Nagoya-shi Toyohashi-shi Okazaki-shi Ichinomiya-shi Seto-shi Handa-shi Kasugai-shi Toyokawa-shi Tsushima-shi Hekinan-shi Kariya-shi Toyota-shi Anjo-shi Nishio-shi Gamagori-shi Inuyama-shi Tokoname-shi Moriyama-shi Konan-shi Bisai-shi Komaki-shi Inazawa-shi Shinshiro-shi Tokai-shi Obu-shi Chita-shi Takahama-shi Chiryu-shi Owariasahi-shi Iwakura-shi Toyoake-shi Nissin-shi Tahara-shi Aisai-shi Kiyosu-shi Kitanagoya-shi Yatomi-shi Miyoshi-shi Ama-shi Nagakute-shi Aichi-gun Atsumi-gun Ama-gun Kitashitara-gun Chita-gun Nakashima-gun Nishikasugai-gun Nishikamo-gun Niwa-gun Nukata-gun Haguri-gun Hazu-gun Higashikasugai-gun Higashikamo-gun Hekikai-gun Hoi-gun Minamishitara-gun Yana-gun Chikusa-ku Higashi-ku Kita-ku Nishi-ku Nakamura-ku Naka-ku Showa-ku Mizuho-ku Atsuta-ku Nakagawa-ku Minato-ku Minami-ku Moriyama-ku Midori-ku Meito-ku Tenpaku-ku Tsu-shi Yokkaichi-shi Ise-shi Matsusaka-shi Kuwana-shi Ueno-shi Suzuka-shi Nabari-shi Owase-shi Kameyama-shi Toba-shi Kumano-shi Hisai-shi Ujiyamada-shi Inabe-shi Shima-shi Iga-shi Age-gun Ano-gun Ayama-gun Iinan-gun Ichishi-gun Inabe-gun Kawage-gun Kitamuro-gun Kuwana-gun Shima-gun Suzuka-gun Taki-gun Naga-gun Mie-gun Minamimuro-gun Watarai-gun Kyoto-shi Fukuchiyama-shi Maiduru-shi Ayabe-shi Uji-shi Miyazu-shi Kameoka-shi Joyo-shi Nagaokakyo-shi Muko-shi Yawata-shi Kyotanabe-shi Kyotango-shi Nantan-shi Kizugawa-shi Amada-gun Ikaruga-gun Otokuni-gun Kasa-gun Kitakuwada-gun Kuze-gun Kumano-gun Soraku-gun Takeno-gun Tsuduki-gun Naka-gun Funai-gun Minamikuwada-gun Yoza-gun Kita-ku Kamigyo-ku Sakyo-ku Nakagyo-ku Higashiyama-ku Shimogyo-ku Minami-ku Ukyo-ku Fushimi-ku Yamashina-ku Nishikyo-ku Otsu-shi Hikone-shi Nagahama-shi Omihachiman-shi Yokaichi-shi Kusatsu-shi Moriyama-shi Ritto-shi Koka-shi Yasu-shi Konan-shi Takashima-shi Higashioumi-shi Maibara-shi Ika-gun Inukami-gun Echi-gun Gamou-gun Kanzaki-gun Kurita-gun Koka-gun Sakata-gun Shiga-gun Takashima-gun Higashiazai-gun Yasu-gun Nara-shi Yamatotakada-shi Yamatokoriyama-shi Tenri-shi Kashihara-shi Sakurai-shi Gojo-shi Gose-shi Ikoma-shi Kashiba-shi Katsuragi-shi Uda-shi Ikoma-gun Uda-gun Uchi-gun Kitakatsuragi-gun Shiki-gun Soekami-gun Takaichi-gun Minamikatsuragi-gun Yamabe-gun Yoshino-gun Osaka-shi Sakai-shi Kishiwada-shi Toyonaka-shi Fuse-shi Ikeda-shi Suita-shi Izumiotsu-shi Takatsuki-shi Kaiduka-shi Moriguchi-shi Hirakata-shi Ibaraki-shi Yao-shi Izumisano-shi Tondabayashi-shi Neyagawa-shi Kawachinagano-shi Hiraoka-shi Kawachi-shi Matsubara-shi Daito-shi Izumi-shi Mino-shi Kashiwara-shi Habikino-shi Kadoma-shi Settsu-shi Fujiidera-shi Takaishi-shi Higashiosaka-shi Sennan-shi Shijonawate-shi Katano-shi Osakasayama-shi Hannan-shi Kitakawachi-gun Sennan-gun Senboku-gun Toyono-gun Nakakawachi-gun Mishima-gun Minamikawachi-gun Kita-ku Miyakojima-ku Fukushima-ku Konohana-ku Higashi-ku Nishi-ku Minato-ku Taisho-ku Tennoji-ku Minami-ku Naniwa-ku Oyodo-ku Nishiyodogawa-ku Higashiyodogawa-ku Higashinari-ku Ikuno-ku Asahi-ku Joto-ku Abeno-ku Sumiyoshi-ku Higashisumiyoshi-ku Nishinari-ku Yodogawa-ku Tsurumi-ku Suminoe-ku Hirano-ku Chuo-ku Sakai-ku Naka-ku Higashi-ku Nishi-ku Minami-ku Kita-ku Mihara-ku Wakayama-shi Shingu-shi Kainan-shi Tanabe-shi Gobo-shi Hashimoto-shi Arida-shi Kinokawa-shi Iwade-shi Arida-gun Ito-gun Kaiso-gun Naga-gun Nishimuro-gun Higashimuro-gun Hidaka-gun Kobe-shi Himeji-shi Amagasaki-shi Akashi-shi Nishinomiya-shi Sumoto-shi Ashiya-shi Itami-shi Aioi-shi Toyooka-shi Kakogawa-shi Tatsuno-shi Ako-shi Nishiwaki-shi Takaraduka-shi Miki-shi Takasago-shi Kawanishi-shi Ono-shi Sanda-shi Kasai-shi Sasayama-shi Yabu-shi Tanba-shi Minamiawaji-shi Asago-shi Awaji-shi Shiso-shi Kato-shi Tatsuno-shi Tanbasasayama-shi Akou-gun Asago-gun Arima-gun Izushi-gun Ibo-gun Innami-gun Kako-gun Kasai-gun Kato-gun Kawabe-gun Kanzaki-gun Kinosaki-gun Sayo-gun Shikama-gun Shiso-gun Taka-gun Taki-gun Tsuna-gun Hikami-gun Mikata-gun Mino-gun Mihara-gun Muko-gun Yabu-gun Higashinada-ku Nada-ku Hyogo-ku Nagata-ku Suma-ku Tarumi-ku Kita-ku Chuo-ku Nishi-ku Fukiai-ku Ikuta-ku Toyama-shi Takaoka-shi Shinminato-shi Uodu-shi Himi-shi Namerikawa-shi Kurobe-shi Tonami-shi Oyabe-shi Nanto-shi Imizu-shi Imizu-gun Kaminiikawa-gun Shimoniikawa-gun Nakaniikawa-gun Nishitonami-gun Nei-gun Himi-gun Higashitonami-gun Fukui-shi Tsuruga-shi Takefu-shi Obama-shi Ono-shi Katsuyama-shi Sabae-shi Awara-shi Echizen-shi Sakai-shi Asuwa-gun Imadate-gun Oi-gun Ono-gun Onyu-gun Sakai-gun Tsuruga-gun Nanjo-gun Nyuu-gun Mikata-gun Yoshida-gun Mikatakaminaka-gun Kanazawa-shi Nanao-shi Komatsu-shi Wajima-shi Suzu-shi Kaga-shi Hakui-shi Matsuto-shi Kahoku-shi Hakusan-shi Nomi-shi Nonoichi-shi Ishikawa-gun Enuma-gun Kashima-gun Kahoku-gun Suzu-gun Nomi-gun Hakui-gun Fugeshi-gun Housu-gun Okayama-shi Kurashiki-shi Tsuyama-shi Tamano-shi Kojima-shi Tamashima-shi Kasaoka-shi saidaiji-shi Ibara-shi Soja-shi Takahashi-shi Niimi-shi Bizen-shi Setouchi-shi Akaiwa-shi Maniwa-shi Mimasaka-shi Asakuchi-shi Aida-gun Akaiwa-gun Asakuchi-gun Atetsu-gun Oku-gun Oda-gun Katsuta-gun Kawakami-gun Kibi-gun Kume-gun Kojima-gun Shitsuki-gun Jodo-gun Jobo-gun Tsukubo-gun Tomada-gun Maniwa-gun Mitsu-gun Wake-gun Kaga-gun Kita-ku Naka-ku Higashi-ku Minami-ku Matsue-shi Hamada-shi Izumo-shi Masuda-shi Oda-shi Yasugi-shi Gotsu-shi Hirata-shi Unnan-shi Ano-gun Ama-gun Iishi-gun Ochi-gun Ohara-gun Oki-gun Ochi-gun Kanoashi-gun Suki-gun Chibu-gun Naka-gun Nita-gun Nima-gun Nogi-gun Hikawa-gun Mino-gun Yatsuka-gun Asa-gun Yamaguchi-shi Shimonoseki-shi Ube-shi Hagi-shi Tokuyama-shi Hofu-shi Kudamatsu-shi Iwakuni-shi Onoda-shi Hikari-shi Nagato-shi Yanai-shi Mine-shi Shinnan01yo-shi Shunan-shi San01yoonoda-shi Abu-gun Oshima-gun Otsu-gun Kuga-gun Kumage-gun Saba-gun Tsuno-gun Toyoura-gun Mine-gun Yoshiki-gun Tottori-shi Kurayoshi-shi Yonago-shi Sakaiminato-shi Iwami-gun Ketaka-gun Saihaku-gun Tohaku-gun Hino-gun Yazu-gun Hiroshima-shi Kure-shi Takehara-shi Mihara-shi Onomichi-shi Innoshima-shi Matsunaga-shi Fukuyama-shi Fuchu-shi Miyoshi-shi Syoubara-shi Otake-shi Higashihiroshima-shi Hatsukaichi-shi Akitakata-shi Etajima-shi Aki-gun Asa-gun Ashina-gun Kamo-gun Konu-gun Saeki-gun Jinseki-gun Sera-gun Takata-gun Toyota-gun Numakuma-gun Hiba-gun Fukayasu-gun Futami-gun Mitsugi-gun Yamagata-gun Naka-ku Higashi-ku Minami-ku Nishi-ku Asaminami-ku Asakita-ku Aki-ku Saeki-ku Takamatsu-shi Marugame-shi Sakaide-shi Zentsuji-shi Kan01onji-shi Sanuki-shi Higashikagawa-shi Mitoyo-shi Ayauta-gun Okawa-gun Kagawa-gun Kita-gun Syozu-gun Nakatado-gun Mitoyo-gun Tokushima-shi Naruto-shi Komatsushima-shi Anan-shi Yoshinogawa-shi Awa-shi Mima-shi Miyoshi-shi Awa-gun Itano-gun Oe-gun Kaifu-gun Katsuura-gun Naka-gun Myozai-gun Myodo-gun Mima-gun Miyoshi-gun Matsuyama-shi Imabari-shi Uwajima-shi Yawatahama-shi Niihama-shi Saijo-shi Ozu-shi Iyomishima-shi Kawanoe-shi Iyo-shi Hojo-shi Toyo-shi Shikokuchuo-shi Seiyo-shi Toon-shi Iyo-gun Uma-gun Ochi-gun Onsen-gun Kamiukena-gun Kita-gun Kitauwa-gun Shuso-gun Nii-gun Nishiuwa-gun Higashiuwa-gun Minamiuwa-gun Kochi-shi Muroto-shi Aki-shi Tosa-shi Susaki-shi Nakamura-shi Sukumo-shi Tosashimizu-shi Nankoku-shi Shimanto-shi Konan-shi Kami-shi Agawa-gun Aki-gun Kami-gun Takaoka-gun Tosa-gun Nagaoka-gun Hata-gun Fukuoka-shi Kokura-shi Moji-shi Yahata-shi Tobata-shi Wakamatsu-shi Kurume-shi Omuta-shi Noogata-shi Iizuka-shi Tagawa-shi Yanagawa-shi Amagi-shi Yamada-shi Yame-shi Chikugo-shi Okawa-shi Yukuhashi-shi Buzen-shi Nakama-shi Kitakyushu-shi Ogoori-shi Kasuga-shi Chikushino-shi Onojo-shi Munakata-shi Dazaifu-shi Maebaru-shi Koga-shi Fukutsu-shi Ukiha-shi Miyawaka-shi Kama-shi Asakura-shi Miyama-shi Itoshima-shi Nakagawa-shi Asakura-gun Itoshima-gun Ukiha-gun Onga-gun Kasuya-gun Kaho-gun Kurate-gun Sawara-gun Tagawa-gun Chikushi-gun Chikujo-gun Mii-gun Miike-gun Mizuma-gun Miyako-gun Munakata-gun Yamato-gun Yame-gun Higashi-ku Hakata-ku Chuo-ku Minami-ku Nishi-ku Jonan-ku Sawara-ku Moji-ku Wakamatsu-ku Tobata-ku Kokurakita-ku Kokuraminami-ku Yahatahigashi-ku Yahatanishi-ku Yahata-ku Kokura-ku Saga-shi Karatsu-shi Tosu-shi Taku-shi Imari-shi Takeo-shi Kashima-shi Ogi-shi Ureshino-shi Kanzaki-shi Ogi-gun Kanzaki-gun Kishima-gun Saga-gun Nishimatsuura-gun Higashimatsuura-gun Fujitsu-gun Miyaki-gun Nagasaki-shi Sasebo-shi Shimabara-shi Isahaya-shi Omura-shi Fukue-shi Hirado-shi Matsuura-shi Tsushima-shi Iki-shi Goto-shi Saikai-shi Unzen-shi Minamishimabara-shi Iki-gun Kamiagata-gun Kitatakaki-gun Kitamatsuura-gun Shimoagata-gun Nishisonogi-gun Higashisonogi-gun Minamitakaki-gun Minamimatsuura-gun Kumamoto-shi Yatsushiro-shi Hitoyoshi-shi Arao-shi Minamata-shi Tamana-shi Hondo-shi Yamaga-shi Ushibuka-shi Kikuchi-shi Uto-shi Kamiamakusa-shi Uki-shi Aso-shi Amakusa-shi Koshi-shi Ashikita-gun Aso-gun Amakusa-gun Uto-gun Kamimashiki-gun Kamoto-gun Kikuchi-gun Kuma-gun Shimomashiki-gun Tamana-gun Hotaku-gun Yatsushiro-gun Chuo-ku Higashi-ku Nishi-ku Minami-ku Kita-ku Oita-shi Beppu-shi Nakatsu-shi Hita-shi Saiki-shi Usuki-shi Tsukumi-shi Taketa-shi Tsurusaki-shi Bungotakada-shi Kitsuki-shi Usa-shi Bungoono-shi Yufu-shi Kunisaki-shi Usa-gun Oita-gun Ono-gun Kitaamabe-gun Kusu-gun Shimoge-gun Naoiri-gun Nishikunisaki-gun Hayami-gun Higashikunisaki-gun Hita-gun Minamiamabe-gun Miyazaki-shi Miyakonojo-shi Nobeoka-shi Nichinan-shi Kobayashi-shi Hyuga-shi Kushima-shi Saito-shi Ebino-shi Kitamorokata-gun Koyu-gun Nishiusuki-gun Nishimorokata-gun Higashiusuki-gun Higashimorokata-gun Minaminaka-gun Miyazaki-gun Kagoshima-shi Sendai-shi Kanoya-shi Makurazaki-shi Kushikino-shi Akune-shi Izumi-shi Naze-shi Okuchi-shi Ibusuki-shi Kaseda-shi Kokubu-shi Taniyama-shi Nishinoomote-shi Tarumizu-shi Satsumasendai-shi Hioki-shi Soo-shi Kirishima-shi Ichikikushikino-shi Minamisatsuma-shi Shibushi-shi Amami-shi Minamikyushu-shi Isa-shi Aira-shi Aira-gun Isa-gun Izumi-gun Ibusuki-gun Oshima-gun Kagoshima-gun Kawanabe-gun Kimotsuki-gun Kumage-gun Satsuma-gun Soo-gun Hioki-gun Naha-shi Ishikawa-shi Hirara-shi Ishigaki-shi Koza-shi Ginowan-shi Gushikawa-shi Nago-shi Urasoe-shi Itoman-shi Okinawa-shi Tomigusuku-shi Uruma-shi Miyakojima-shi Nanjo-shi Kunigami-gun Shimajiri-gun Nakagami-gun Miyako-gun Yaeyama-gun Hokkaido-do Aomori-ken Iwate-ken Akita-ken Yamagata-ken Miyagi-ken Fukushima-ken Niigata-ken Nagano-ken Tokyo-to Kanagawa-ken Chiba-ken Saitama-ken Ibaraki-ken Tochigi-ken Gunma-ken Yamanashi-ken Shizuoka-ken Gifu-ken Aichi-ken Mie-ken Kyoto-ken Shiga-ken Nara-ken Osaka-fu Wakayama-ken Hyogo-ken Toyama-ken Fukui-ken Ishikawa-ken Okayama-ken Shimane-ken Yamaguchi-ken Tottori-ken Hiroshima-ken Kagawa-ken Tokushima-ken Ehime-ken Kochi-ken Fukuoka-ken Saga-ken Nagasaki-ken Kumamoto-ken Oita-ken Miyazaki-ken Kagoshima-ken Okinawa-ken Kaliningradskaya oblast' (Kaliningrad Oblast) Aginsky Buryatsky avtonomny okrug (Agin-Buryat Autonomous Okrug) [DELETED] Altayskiy kray (Altai Krai) Amurskaya oblast' (Amur Oblast) Respublika Bashkortostan (Republic of Bashkortostan) (Bashkortostan Republic) Respublika Buryatiya (Republic of Buryatia) Chelyabinskaya oblast' (Chelyabinsk Oblast) Chukotsky avtonomny okrug (Chukotka Autonomous Okrug) Zabaykalsky kray (Zabaykalsky Krai) Yevreyskaya avtonomnaya oblast' (Jewish Autonomous Oblast) Evenkiysky avtonomny okrug (Evenk Autonomous Okrug) [DELETED] Respublika Altay (Altai Republic) (Altay Republits) Respublika Khakasiya (Khakasiya Republits) (Republic of Khakassia) Khabarovskiy kray (Khabarovsk Krai) Khanty-Mansiyskiy avtonomnyy okrug (Khanty-Mansi Autonomous Okrug) Irkutskaya oblast' (Irkutsk Oblast) Yamalo-Nenetsky avtonomny okrug (Yamalo-Nenets Autonomous Okrug) Kemerovskaya oblast' (Kemerovo Oblast) Koryaksky avtonomny okrug (Koryak Autonomous Okrug) [DELETED] Krasnoyarskiy kray (Krasnoyarsk Krai) Kurganskaya oblast' (Kurgan Oblast) Kamchatskiy kray (Kamchatka Krai) Magadanskaya oblast' (Magadan Oblast) Novosibirskaya oblast' (Novosibirsk Oblast) Orenburgskaya oblast' (Orenburg Oblast) Omskaya oblast' (Omsk Oblast) Primorskiy kray (Primorsky Krai) Sakhalinskaya oblast' (Sakhalin Oblast) Sverdlovskaya oblast' (Sverdlovsk Oblast) Taymyrsky Dolgano-Nenetsky avtonomny okru (Taymyr Autonomous Okrug) (Taymyria) [DELETED] Tyumenskaya oblast' (Tyumen Oblast) Tomskaya oblast' (Tomsk Oblast) Respublika Tyva (Tyva Republic) (Tyva Republits) Ust-Ordynsky avtonomny okrug (Ust-Orda Buryat Autonomous Okrug) [DELETED] Respublika Sakha (Yakutiya) Leningradskaya oblast' (Leningrad Oblast) Adygea (Adygea Republic} Astrakhanskaya oblast' (Astrakhan Oblast) Arkhangelskaya oblast' (Arkhangelsk Oblast) Belgorodskaya oblast' (Belgorod Oblast) Bryanskaya oblast' (Bryansk Oblast) Chechenskaya Respublika (Chechnya) Chuvashiya (Chuvashia Republic) (Chuvash Republic) Dagestan Republits (Dagestan Republic) Respublika Ingushetiya (Republic of Ingushetia) Ivanovskaya oblast' (Ivanovo Oblast) Yaroslavskaya oblast' (Yaroslavl Oblast) Kabardino-Balkarskaya Respublika (Kabardino-Balkaria) Karachay-Cherkessia (Karachay-Cherkess Republic) Kaluzhskaya oblast' (Kaluga Oblast) Kirovskaya oblast' (Kirov Oblast) Respublika Karelia (Karelia Republic) Respublika Kalmykiya (Kalmykia Republic) (Kalmykia) Respúblika Komi (Komi Republic) Komi-Permyatsky avtonomny okrug (Komi-Permyak Autonomous Okrug) [DELETED] Krasnodarskiy kray (Krasnodar Krai) Kostromskaya oblast' (Kostroma Oblast) Kurskaya oblast' (Kursk Oblast) Leningradskaya oblast' (Leningrad Oblast) Lipetsk Oblast (Lipetskaya oblast') Moskva (Moscow) Respublika Mordoviya (Republic of Mordovia) Moskovskaya oblast' (Moscow Oblast) Respublika Mariy El (Mari El Republic) Murmanskaya oblast' (Murmansk Oblast) Nizhegorodskaya oblast' (Nizhny Novgorod Oblast) Nenetsky avtonomny okrug (Nenets Autonomous Okrug) Novgorodskaya oblast' (Novgorod Oblast) Orlovskaya oblast' (Oryol Oblast) Penzenskaya oblast' (Penza Oblast) Permskiy kray (Perm Krai) Pskovskaya oblast' (Pskov Oblast) Ryazanskaya oblast' (Ryazan Oblast) Rostovskaya oblast' (Rostov Oblast) Saratovskaya oblast' (Saratov Oblast) Smolenskaya oblast' (Smolensk Oblast) Severnaya Osetiya (North Ossetia-Alania) (North Ossetia-Alania Republic) Sankt-Peterburg (Saint Petersburg) Samarskaya oblast' (Samara Oblast) Stavropolskiy kray (Stavropol Krai) Respublika Tatarstan (Tatarstan) (Tatarstan Republic) Tambovskaya oblast' (Tambov Oblast) Tulskaya oblast' (Tula Oblast) Tverskaya oblast' (Tver Oblast) Udmurtskaja Respublika (Udmurt Republic) Ulyanovskaya oblast' (Ulyanovsk Oblast) Volgogradskaya oblast' (Volgograd Oblast) Vladimirskaya oblast' (Vladimir Oblast) Vologodskaya oblast' (Vologda Oblast) Voronezhskaya oblast' (Voronezh Oblast) Arkhangelskaya oblast' (Arkhangelsk Oblast) Aleutians East Borough Aleutians West Census Area Anchorage Municipality Bethel Census Area Bristol Bay Borough Denali Borough Dillingham Census Area Fairbanks North Star Borough Haines Borough Hoonah-Angoon Census Area Juneau City and Borough Kenai Peninsula Borough Ketchikan Gateway Borough Kodiak Island Borough Lake and Peninsula Borough Matanuska-Susitna Borough Nome Census Area North Slope Borough Northwest Arctic Borough Petersburg Census Area Prince of Wales-Hyder Census Area Sitka City and Borough Skagway Municipality Southeast Fairbanks Census Area Valdez-Cordova Census Area Wade Hampton Census Area Wrangell City and Borough Yakutat City and Borough Yukon-Koyukuk Census Area Prince of Wales-Outer-Ketichikan Census Area Skagway-Hoonah-Angoon Census Area Autauga Baldwin Barbour Bibb Blount Bullock Butler Calhoun Chambers Cherokee Chilton Choctaw Clarke Clay Cleburne Coffee Colbert Conecuh Coosa Covington Crenshaw Cullman Dale Dallas DeKalb Elmore Escambia Etowah Fayette Franklin Geneva Greene Hale Henry Houston Jackson Jefferson Lamar Lauderdale Lawrence Lee Limestone Lowndes Macon Madison Marengo Marion Marshall Mobile Monroe Montgomery Morgan Perry Pickens Pike Randolph Russell St. Clair Shelby Sumter Talladega Tallapoosa Tuscaloosa Walker Washington Wilcox Winston Arkansas Ashley Baxter Benton Boone Bradley Calhoun Carroll Chicot Clark Clay Cleburne Cleveland Columbia Conway Craighead Crawford Crittenden Cross Dallas Desha Drew Faulkner Franklin Fulton Garland Grant Greene Hempstead Hot Spring Howard Independence Izard Jackson Jefferson Johnson Lafayette Lawrence Lee Lincoln Little River Logan Lonoke Madison Marion Miller Mississippi Monroe Montgomery Nevada Newton Ouachita Perry Phillips Pike Poinsett Polk Pope Prairie Pulaski Randolph St. Francis Saline Scott Searcy Sebastian Sevier Sharp Stone Union Van Buren Washington White Woodruff Yell Apache Cochise Coconino Gila Graham Greenlee La Paz Maricopa Mohave Navajo Pima Pinal Santa Cruz Yavapai Yuma Alameda Alpine Amador Butte Calaveras Colusa Contra Costa Del Norte El Dorado Fresno Glenn Humboldt Imperial Inyo Kern Kings Lake Lassen Los Angeles Madera Marin Mariposa Mendocino Merced Modoc Mono Monterey Napa Nevada Orange Placer Plumas Riverside Sacramento San Benito San Bernardino San Diego San Francisco San Joaquin San Luis Obispo San Mateo Santa Barbara Santa Clara Santa Cruz Shasta Sierra Siskiyou Solano Sonoma Stanislaus Sutter Tehama Trinity Tulare Tuolumne Ventura Yolo Yuba Adams Alamosa Arapahoe Archuleta Baca Bent Boulder Broomfield Chaffee Cheyenne Clear Creek Conejos Costilla Crowley Custer Delta Denver Dolores Douglas Eagle El Paso Elbert Fremont Garfield Gilpin Grand Gunnison Hinsdale Huerfano Jackson Jefferson Kiowa Kit Carson La Plata Lake Larimer Las Animas Lincoln Logan Mesa Mineral Moffat Montezuma Montrose Morgan Otero Ouray Park Phillips Pitkin Prowers Pueblo Rio Blanco Rio Grande Routt Saguache San Juan San Miguel Sedgwick Summit Teller Washington Weld Yuma Fairfield Hartford Litchfield Middlesex New Haven New London Tolland Windham Kent New Castle Sussex Alachua Baker Bay Bradford Brevard Broward Calhoun Charlotte Citrus Clay Collier Columbia DeSoto Dixie Duval Escambia Flagler Franklin Gadsden Gilchrist Glades Gulf Hamilton Hardee Hendry Hernando Highlands Hillsborough Holmes Indian River Jackson Jefferson Lafayette Lake Lee Leon Levy Liberty Madison Manatee Marion Martin Miami-Dade Monroe Nassau Okaloosa Okeechobee Orange Osceola Palm Beach Pasco Pinellas Polk Putnam St. Johns St. Lucie Santa Rosa Sarasota Seminole Sumter Suwannee Taylor Union Volusia Wakulla Walton Washington Appling Atkinson Bacon Baker Baldwin Banks Barrow Bartow Ben Hill Berrien Bibb Bleckley Brantley Brooks Bryan Bulloch Burke Butts Calhoun Camden Candler Carroll Catoosa Charlton Chatham Chattahoochee Chattooga Cherokee Clarke Clay Clayton Clinch Cobb Coffee Colquitt Columbia Cook Coweta Crawford Crisp Dade Dawson Decatur DeKalb Dodge Dooly Dougherty Douglas Early Echols Effingham Elbert Emanuel Evans Fannin Fayette Floyd Forsyth Franklin Fulton Gilmer Glascock Glynn Gordon Grady Greene Gwinnett Habersham Hall Hancock Haralson Harris Hart Heard Henry Houston Irwin Jackson Jasper Jeff Davis Jefferson Jenkins Johnson Jones Lamar Lanier Laurens Lee Liberty Lincoln Long Lowndes Lumpkin Macon Madison Marion McDuffie McIntosh Meriwether Miller Mitchell Monroe Montgomery Morgan Murray Muscogee Newton Oconee Oglethorpe Paulding Peach Pickens Pierce Pike Polk Pulaski Putnam Quitman Rabun Randolph Richmond Rockdale Schley Screven Seminole Spalding Stephens Stewart Sumter Talbot Taliaferro Tattnall Taylor Telfair Terrell Thomas Tift Toombs Towns Treutlen Troup Turner Twiggs Union Upson Walker Walton Ware Warren Washington Wayne Webster Wheeler White Whitfield Wilcox Wilkes Wilkinson Worth Hawaii Honolulu Kalawao Kauai Maui Adair Adams Allamakee Appanoose Audubon Benton Black Hawk Boone Bremer Buchanan Buena Vista Butler Calhoun Carroll Cass Cedar Cerro Gordo Cherokee Chickasaw Clarke Clay Clayton Clinton Crawford Dallas Davis Decatur Delaware Des Moines Dickinson Dubuque Emmet Fayette Floyd Franklin Fremont Greene Grundy Guthrie Hamilton Hancock Hardin Harrison Henry Howard Humboldt Ida Iowa Jackson Jasper Jefferson Johnson Jones Keokuk Kossuth Lee Linn Louisa Lucas Lyon Madison Mahaska Marion Marshall Mills Mitchell Monona Monroe Montgomery Muscatine O'Brien Osceola Page Palo Alto Plymouth Pocahontas Polk Pottawattamie Poweshiek Ringgold Sac Scott Shelby Sioux Story Tama Taylor Union Van Buren Wapello Warren Washington Wayne Webster Winnebago Winneshiek Woodbury Worth Wright Ada Adams Bannock Bear Lake Benewah Bingham Blaine Boise Bonner Bonneville Boundary Butte Camas Canyon Caribou Cassia Clark Clearwater Custer Elmore Franklin Fremont Gem Gooding Idaho Jefferson Jerome Kootenai Latah Lemhi Lewis Lincoln Madison Minidoka Nez Perce Oneida Owyhee Payette Power Shoshone Teton Twin Falls Valley Washington Adams Alexander Bond Boone Brown Bureau Calhoun Carroll Cass Champaign Christian Clark Clay Clinton Coles Cook Crawford Cumberland DeKalb DeWitt Douglas DuPage Edgar Edwards Effingham Fayette Ford Franklin Fulton Gallatin Greene Grundy Hamilton Hancock Hardin Henderson Henry Iroquois Jackson Jasper Jefferson Jersey Jo Daviess Johnson Kane Kankakee Kendall Knox LaSalle Lake Lawrence Lee Livingston Logan Macon Macoupin Madison Marion Marshall Mason Massac McDonough McHenry McLean Menard Mercer Monroe Montgomery Morgan Moultrie Ogle Peoria Perry Piatt Pike Pope Pulaski Putnam Randolph Richland Rock Island St. Clair Saline Sangamon Schuyler Scott Shelby Stark Stephenson Tazewell Union Vermilion Wabash Warren Washington Wayne White Whiteside Will Williamson Winnebago Woodford Adams Allen Bartholomew Benton Blackford Boone Brown Carroll Cass Clark Clay Clinton Crawford Daviess DeKalb Dearborn Decatur Delaware Dubois Elkhart Fayette Floyd Fountain Franklin Fulton Gibson Grant Greene Hamilton Hancock Harrison Hendricks Henry Howard Huntington Jackson Jasper Jay Jefferson Jennings Johnson Knox Kosciusko LaPorte LaGrange Lake Lawrence Madison Marion Marshall Martin Miami Monroe Montgomery Morgan Newton Noble Ohio Orange Owen Parke Perry Pike Porter Posey Pulaski Putnam Randolph Ripley Rush Scott Shelby Spencer St. Joseph Starke Steuben Sullivan Switzerland Tippecanoe Tipton Union Vanderburgh Vermillion Vigo Wabash Warren Warrick Washington Wayne Wells White Whitley Allen Anderson Atchison Barber Barton Bourbon Brown Butler Chase Chautauqua Cherokee Cheyenne Clark Clay Cloud Coffey Comanche Cowley Crawford Decatur Dickinson Doniphan Douglas Edwards Elk Ellis Ellsworth Finney Ford Franklin Geary Gove Graham Grant Gray Greeley Greenwood Hamilton Harper Harvey Haskell Hodgeman Jackson Jefferson Jewell Johnson Kearny Kingman Kiowa Labette Lane Leavenworth Lincoln Linn Logan Lyon Marion Marshall McPherson Meade Miami Mitchell Montgomery Morris Morton Nemaha Neosho Ness Norton Osage Osborne Ottawa Pawnee Phillips Pottawatomie Pratt Rawlins Reno Republic Rice Riley Rooks Rush Russell Saline Scott Sedgwick Seward Shawnee Sheridan Sherman Smith Stafford Stanton Stevens Sumner Thomas Trego Wabaunsee Wallace Washington Wichita Wilson Woodson Wyandotte Adair Allen Anderson Ballard Barren Bath Bell Boone Bourbon Boyd Boyle Bracken Breathitt Breckinridge Bullitt Butler Caldwell Calloway Campbell Carlisle Carroll Carter Casey Christian Clark Clay Clinton Crittenden Cumberland Daviess Edmonson Elliott Estill Fayette Fleming Floyd Franklin Fulton Gallatin Garrard Grant Graves Grayson Green Greenup Hancock Hardin Harlan Harrison Hart Henderson Henry Hickman Hopkins Jackson Jefferson Jessamine Johnson Kenton Knott Knox Larue Laurel Lawrence Lee Leslie Letcher Lewis Lincoln Livingston Logan Lyon Madison Magoffin Marion Marshall Martin Mason McCracken McCreary McLean Meade Menifee Mercer Metcalfe Monroe Montgomery Morgan Muhlenberg Nelson Nicholas Ohio Oldham Owen Owsley Pendleton Perry Pike Powell Pulaski Robertson Rockcastle Rowan Russell Scott Shelby Simpson Spencer Taylor Todd Trigg Trimble Union Warren Washington Wayne Webster Whitley Wolfe Woodford Acadia Allen Ascension Assumption Avoyelles Beauregard Bienville Bossier Caddo Calcasieu Caldwell Cameron Catahoula Claiborne Concordia De Soto East Baton Rouge East Carroll East Feliciana Evangeline Franklin Grant Iberia Iberville Jackson Jefferson Jefferson Davis LaSalle Lafayette Lafourche Lincoln Livingston Madison Morehouse Natchitoches Orleans Ouachita Plaquemines Pointe Coupee Rapides Red River Richland Sabine St. Bernard St. Charles St. Helena St. James St. Landry St. Martin St. Mary St. Tammany St. John the Baptist Tangipahoa Tensas Terrebonne Union Vermilion Vernon Washington Webster West Baton Rouge West Carroll West Feliciana Winn Barnstable Berkshire Bristol Dukes Essex Franklin Hampden Hampshire Middlesex Nantucket Norfolk Plymouth Suffolk Worcester Allegany Anne Arundel Baltimore Baltimore City Calvert Caroline Carroll Cecil Charles Dorchester Frederick Garrett Harford Howard Kent Montgomery Prince George's Queen Anne's St. Mary's Somerset Talbot Washington Wicomico Worcester Androscoggin Aroostook Cumberland Franklin Hancock Kennebec Knox Lincoln Oxford Penobscot Piscataquis Sagadahoc Somerset Waldo Washington York Alcona Alger Allegan Alpena Antrim Arenac Baraga Barry Bay Benzie Berrien Branch Calhoun Cass Charlevoix Cheboygan Chippewa Clare Clinton Crawford Delta Dickinson Eaton Emmet Genesee Gladwin Gogebic Grand Traverse Gratiot Hillsdale Houghton Huron Ingham Ionia Iosco Iron Isabella Jackson Kalamazoo Kalkaska Kent Keweenaw Lake Lapeer Leelanau Lenawee Livingston Luce Mackinac Macomb Manistee Marquette Mason Mecosta Menominee Midland Missaukee Monroe Montcalm Montmorency Muskegon Newaygo Oakland Oceana Ogemaw Ontonagon Osceola Oscoda Otsego Ottawa Presque Isle Roscommon Saginaw St. Clair St. Joseph Sanilac Schoolcraft Shiawassee Tuscola Van Buren Washtenaw Wayne Wexford Aitkin Anoka Becker Beltrami Benton Big Stone Blue Earth Brown Carlton Carver Cass Chippewa Chisago Clay Clearwater Cook Cottonwood Crow Wing Dakota Dodge Douglas Faribault Fillmore Freeborn Goodhue Grant Hennepin Houston Hubbard Isanti Itasca Jackson Kanabec Kandiyohi Kittson Koochiching Lac qui Parle Lake Lake of the Woods Le Sueur Lincoln Lyon Mahnomen Marshall Martin McLeod Meeker Mille Lacs Morrison Mower Murray Nicollet Nobles Norman Olmsted Otter Tail Pennington Pine Pipestone Polk Pope Ramsey Red Lake Redwood Renville Rice Rock Roseau St. Louis Scott Sherburne Sibley Stearns Steele Stevens Swift Todd Traverse Wabasha Wadena Waseca Washington Watonwan Wilkin Winona Wright Yellow Medicine Adair Andrew Atchison Audrain Barry Barton Bates Benton Bollinger Boone Buchanan Butler Caldwell Callaway Camden Cape Girardeau Carroll Carter Cass Cedar Chariton Christian Clark Clay Clinton Cole Cooper Crawford Dade Dallas Daviess DeKalb Dent Douglas Dunklin Franklin Gasconade Gentry Greene Grundy Harrison Henry Hickory Holt Howard Howell Iron Jackson Jasper Jefferson Johnson Knox Laclede Lafayette Lawrence Lewis Lincoln Linn Livingston Macon Madison Maries Marion McDonald Mercer Miller Mississippi Moniteau Monroe Montgomery Morgan New Madrid Newton Nodaway Oregon Osage Ozark Pemiscot Perry Pettis Phelps Pike Platte Polk Pulaski Putnam Ralls Randolph Ray Reynolds Ripley St. Charles St. Clair St. Francois St. Louis St. Louis City Ste. Genevieve Saline Schuyler Scotland Scott Shannon Shelby Stoddard Stone Sullivan Taney Texas Vernon Warren Washington Wayne Webster Worth Wright Adams Alcorn Amite Attala Benton Bolivar Calhoun Carroll Chickasaw Choctaw Claiborne Clarke Clay Coahoma Copiah Covington DeSoto Forrest Franklin George Greene Grenada Hancock Harrison Hinds Holmes Humphreys Issaquena Itawamba Jackson Jasper Jefferson Jefferson Davis Jones Kemper Lafayette Lamar Lauderdale Lawrence Leake Lee Leflore Lincoln Lowndes Madison Marion Marshall Monroe Montgomery Neshoba Newton Noxubee Oktibbeha Panola Pearl River Perry Pike Pontotoc Prentiss Quitman Rankin Scott Sharkey Simpson Smith Stone Sunflower Tallahatchie Tate Tippah Tishomingo Tunica Union Walthall Warren Washington Wayne Webster Wilkinson Winston Yalobusha Yazoo Beaverhead Big Horn Blaine Broadwater Carbon Carter Cascade Chouteau Custer Daniels Dawson Deer Lodge Fallon Fergus Flathead Gallatin Garfield Glacier Golden Valley Granite Hill Jefferson Judith Basin Lake Lewis and Clark Liberty Lincoln Madison McCone Meagher Mineral Missoula Musselshell Park Petroleum Phillips Pondera Powder River Powell Prairie Ravalli Richland Roosevelt Rosebud Sanders Sheridan Silver Bow Stillwater Sweet Grass Teton Toole Treasure Valley Wheatland Wibaux Yellowstone Alamance Alexander Alleghany Anson Ashe Avery Beaufort Bertie Bladen Brunswick Buncombe Burke Cabarrus Caldwell Camden Carteret Caswell Catawba Chatham Cherokee Chowan Clay Cleveland Columbus Craven Cumberland Currituck Dare Davidson Davie Duplin Durham Edgecombe Forsyth Franklin Gaston Gates Graham Granville Greene Guilford Halifax Harnett Haywood Henderson Hertford Hoke Hyde Iredell Jackson Johnston Jones Lee Lenoir Lincoln Macon Madison Martin McDowell Mecklenburg Mitchell Montgomery Moore Nash New Hanover Northampton Onslow Orange Pamlico Pasquotank Pender Perquimans Person Pitt Polk Randolph Richmond Robeson Rockingham Rowan Rutherford Sampson Scotland Stanly Stokes Surry Swain Transylvania Tyrrell Union Vance Wake Warren Washington Watauga Wayne Wilkes Wilson Yadkin Yancey Adams Barnes Benson Billings Bottineau Bowman Burke Burleigh Cass Cavalier Dickey Divide Dunn Eddy Emmons Foster Golden Valley Grand Forks Grant Griggs Hettinger Kidder LaMoure Logan McHenry McIntosh McKenzie McLean Mercer Morton Mountrail Nelson Oliver Pembina Pierce Ramsey Ransom Renville Richland Rolette Sargent Sheridan Sioux Slope Stark Steele Stutsman Towner Traill Walsh Ward Wells Williams Adams Antelope Arthur Banner Blaine Boone Box Butte Boyd Brown Buffalo Burt Butler Cass Cedar Chase Cherry Cheyenne Clay Colfax Cuming Custer Dakota Dawes Dawson Deuel Dixon Dodge Douglas Dundy Fillmore Franklin Frontier Furnas Gage Garden Garfield Gosper Grant Greeley Hall Hamilton Harlan Hayes Hitchcock Holt Hooker Howard Jefferson Johnson Kearney Keith Keya Paha Kimball Knox Lancaster Lincoln Logan Loup Madison McPherson Merrick Morrill Nance Nemaha Nuckolls Otoe Pawnee Perkins Phelps Pierce Platte Polk Red Willow Richardson Rock Saline Sarpy Saunders Scotts Bluff Seward Sheridan Sherman Sioux Stanton Thayer Thomas Thurston Valley Washington Wayne Webster Wheeler York Belknap Carroll Cheshire Coos Grafton Hillsborough Merrimack Rockingham Strafford Sullivan Atlantic Bergen Burlington Camden Cape May Cumberland Essex Gloucester Hudson Hunterdon Mercer Middlesex Monmouth Morris Ocean Passaic Salem Somerset Sussex Union Warren Bernalillo Catron Chaves Cibola Colfax Curry De Baca Doña Ana Eddy Grant Guadalupe Harding Hidalgo Lea Lincoln Los Alamos Luna McKinley Mora Otero Quay Rio Arriba Roosevelt San Juan San Miguel Sandoval Santa Fe Sierra Socorro Taos Torrance Union Valencia Carson City Churchill Clark Douglas Elko Esmeralda Eureka Humboldt Lander Lincoln Lyon Mineral Nye Pershing Storey Washoe White Pine Albany Allegany Bronx Broome Cattaraugus Cayuga Chautauqua Chemung Chenango Clinton Columbia Cortland Delaware Dutchess Erie Essex Franklin Fulton Genesee Greene Hamilton Herkimer Jefferson Kings Lewis Livingston Madison Monroe Montgomery Nassau New York Niagara Oneida Onondaga Ontario Orange Orleans Oswego Otsego Putnam Queens Rensselaer Richmond Rockland St. Lawrence Saratoga Schenectady Schoharie Schuyler Seneca Steuben Suffolk Sullivan Tioga Tompkins Ulster Warren Washington Wayne Westchester Wyoming Yates Adams Allen Ashland Ashtabula Athens Auglaize Belmont Brown Butler Carroll Champaign Clark Clermont Clinton Columbiana Coshocton Crawford Cuyahoga Darke Defiance Delaware Erie Fairfield Fayette Franklin Fulton Gallia Geauga Greene Guernsey Hamilton Hancock Hardin Harrison Henry Highland Hocking Holmes Huron Jackson Jefferson Knox Lake Lawrence Licking Logan Lorain Lucas Madison Mahoning Marion Medina Meigs Mercer Miami Monroe Montgomery Morgan Morrow Muskingum Noble Ottawa Paulding Perry Pickaway Pike Portage Preble Putnam Richland Ross Sandusky Scioto Seneca Shelby Stark Summit Trumbull Tuscarawas Union Van Wert Vinton Warren Washington Wayne Williams Wood Wyandot Adair Alfalfa Atoka Beaver Beckham Blaine Bryan Caddo Canadian Carter Cherokee Choctaw Cimarron Cleveland Coal Comanche Cotton Craig Creek Custer Delaware Dewey Ellis Garfield Garvin Grady Grant Greer Harmon Harper Haskell Hughes Jackson Jefferson Johnston Kay Kingfisher Kiowa Latimer Le Flore Lincoln Logan Love Major Marshall Mayes McClain McCurtain McIntosh Murray Muskogee Noble Nowata Okfuskee Oklahoma Okmulgee Osage Ottawa Pawnee Payne Pittsburg Pontotoc Pottawatomie Pushmataha Roger Mills Rogers Seminole Sequoyah Stephens Texas Tillman Tulsa Wagoner Washington Washita Woods Woodward Baker Benton Clackamas Clatsop Columbia Coos Crook Curry Deschutes Douglas Gilliam Grant Harney Hood River Jackson Jefferson Josephine Klamath Lake Lane Lincoln Linn Malheur Marion Morrow Multnomah Polk Sherman Tillamook Umatilla Union Wallowa Wasco Washington Wheeler Yamhill Adams Allegheny Armstrong Beaver Bedford Berks Blair Bradford Bucks Butler Cambria Cameron Carbon Centre Chester Clarion Clearfield Clinton Columbia Crawford Cumberland Dauphin Delaware Elk Erie Fayette Forest Franklin Fulton Greene Huntingdon Indiana Jefferson Juniata Lackawanna Lancaster Lawrence Lebanon Lehigh Luzerne Lycoming McKean Mercer Mifflin Monroe Montgomery Montour Northampton Northumberland Perry Philadelphia Pike Potter Schuylkill Snyder Somerset Sullivan Susquehanna Tioga Union Venango Warren Washington Wayne Westmoreland Wyoming York Bristol Kent Newport Providence Washington Abbeville Aiken Allendale Anderson Bamberg Barnwell Beaufort Berkeley Calhoun Charleston Cherokee Chester Chesterfield Clarendon Colleton Darlington Dillon Dorchester Edgefield Fairfield Florence Georgetown Greenville Greenwood Hampton Horry Jasper Kershaw Lancaster Laurens Lee Lexington Marion Marlboro McCormick Newberry Oconee Orangeburg Pickens Richland Saluda Spartanburg Sumter Union Williamsburg York Aurora Beadle Bennett Bon Homme Brookings Brown Brule Buffalo Butte Campbell Charles Mix Clark Clay Codington Corson Custer Davison Day Deuel Dewey Douglas Edmunds Fall River Faulk Grant Gregory Haakon Hamlin Hand Hanson Harding Hughes Hutchinson Hyde Jackson Jerauld Jones Kingsbury Lake Lawrence Lincoln Lyman Marshall McCook McPherson Meade Mellette Miner Minnehaha Moody Oglala Lakota Pennington Perkins Potter Roberts Sanborn Shannon Spink Stanley Sully Todd Tripp Turner Union Walworth Yankton Ziebach Anderson Bedford Benton Bledsoe Blount Bradley Campbell Cannon Carroll Carter Cheatham Chester Claiborne Clay Cocke Coffee Crockett Cumberland Davidson Decatur DeKalb Dickson Dyer Fayette Fentress Franklin Gibson Giles Grainger Greene Grundy Hamblen Hamilton Hancock Hardeman Hardin Hawkins Haywood Henderson Henry Hickman Houston Humphreys Jackson Jefferson Johnson Knox Lake Lauderdale Lawrence Lewis Lincoln Loudon Macon Madison Marion Marshall Maury McMinn McNairy Meigs Monroe Montgomery Moore Morgan Obion Overton Perry Pickett Polk Putnam Rhea Roane Robertson Rutherford Scott Sequatchie Sevier Shelby Smith Stewart Sullivan Sumner Tipton Trousdale Unicoi Union Van Buren Warren Washington Wayne Weakley White Williamson Wilson Anderson Andrews Angelina Aransas Archer Armstrong Atascosa Austin Bailey Bandera Bastrop Baylor Bee Bell Bexar Blanco Borden Bosque Bowie Brazoria Brazos Brewster Briscoe Brooks Brown Burleson Burnet Caldwell Calhoun Callahan Cameron Camp Carson Cass Castro Chambers Cherokee Childress Clay Cochran Coke Coleman Collin Collingsworth Colorado Comal Comanche Concho Cooke Coryell Cottle Crane Crockett Crosby Culberson Dallam Dallas Dawson DeWitt Deaf Smith Delta Denton Dickens Dimmit Donley Duval Eastland Ector Edwards El Paso Ellis Erath Falls Fannin Fayette Fisher Floyd Foard Fort Bend Franklin Freestone Frio Gaines Galveston Garza Gillespie Glasscock Goliad Gonzales Gray Grayson Gregg Grimes Guadalupe Hale Hall Hamilton Hansford Hardeman Hardin Harris Harrison Hartley Haskell Hays Hemphill Henderson Hidalgo Hill Hockley Hood Hopkins Houston Howard Hudspeth Hunt Hutchinson Irion Jack Jackson Jasper Jeff Davis Jefferson Jim Hogg Jim Wells Johnson Jones Karnes Kaufman Kendall Kenedy Kent Kerr Kimble King Kinney Kleberg Knox La Salle Lamar Lamb Lampasas Lavaca Lee Leon Liberty Limestone Lipscomb Live Oak Llano Loving Lubbock Lynn Madison Marion Martin Mason Matagorda Maverick McCulloch McLennan McMullen Medina Menard Midland Milam Mills Mitchell Montague Montgomery Moore Morris Motley Nacogdoches Navarro Newton Nolan Nueces Ochiltree Oldham Orange Palo Pinto Panola Parker Parmer Pecos Polk Potter Presidio Rains Randall Reagan Real Red River Reeves Refugio Roberts Robertson Rockwall Runnels Rusk Sabine San Augustine San Jacinto San Patricio San Saba Schleicher Scurry Shackelford Shelby Sherman Smith Somervell Starr Stephens Sterling Stonewall Sutton Swisher Tarrant Taylor Terrell Terry Throckmorton Titus Tom Green Travis Trinity Tyler Upshur Upton Uvalde Val Verde Van Zandt Victoria Walker Waller Ward Washington Webb Wharton Wheeler Wichita Wilbarger Willacy Williamson Wilson Winkler Wise Wood Yoakum Young Zapata Zavala Beaver Box Elder Cache Carbon Daggett Davis Duchesne Emery Garfield Grand Iron Juab Kane Millard Morgan Piute Rich Salt Lake San Juan Sanpete Sevier Summit Tooele Uintah Utah Wasatch Washington Wayne Weber Accomack Albemarle Alexandria City Alleghany Amelia Amherst Appomattox Arlington Augusta Bath Bedford Bedford City Bland Botetourt Bristol City Brunswick Buchanan Buckingham Buena Vista City Campbell Caroline Carroll Charles City Charlotte Charlottesville City Chesapeake City Chesterfield Clarke Clifton Forge City Colonial Heights City Covington City Craig Culpeper Cumberland Danville City Dickenson Dinwiddie Emporia City Essex Fairfax Fairfax City Falls Church City Fauquier Floyd Fluvanna Franklin Franklin City Frederick Fredericksburg City Galax City Giles Gloucester Goochland Grayson Greene Greensville Halifax Hampton City Hanover Harrisonburg City Henrico Henry Highland Hopewell City Isle of Wight James City King and Queen King George King William Lancaster Lee Lexington City Loudoun Louisa Lunenburg Lynchburg City Madison Manassas City Manassas Park City Martinsville City Mathews Mecklenburg Middlesex Montgomery Nelson New Kent Newport News City Norfolk City Northampton Northumberland Norton City Nottoway Orange Page Patrick Petersburg City Pittsylvania Poquoson City Portsmouth City Powhatan Prince Edward Prince George Prince William Pulaski Radford City Rappahannock Richmond Richmond City Roanoke Roanoke City Rockbridge Rockingham Russell Salem City Scott Shenandoah Smyth Southampton Spotsylvania Stafford Staunton City Suffolk City Surry Sussex Tazewell Virginia Beach City Warren Washington Waynesboro City Westmoreland Williamsburg City Winchester City Wise Wythe York Addison Bennington Caledonia Chittenden Essex Franklin Grand Isle Lamoille Orange Orleans Rutland Washington Windham Windsor Adams Asotin Benton Chelan Clallam Clark Columbia Cowlitz Douglas Ferry Franklin Garfield Grant Grays Harbor Island Jefferson King Kitsap Kittitas Klickitat Lewis Lincoln Mason Okanogan Pacific Pend Oreille Pierce San Juan Skagit Skamania Snohomish Spokane Stevens Thurston Wahkiakum Walla Walla Whatcom Whitman Yakima Adams Ashland Barron Bayfield Brown Buffalo Burnett Calumet Chippewa Clark Columbia Crawford Dane Dodge Door Douglas Dunn Eau Claire Florence Fond du Lac Forest Grant Green Green Lake Iowa Iron Jackson Jefferson Juneau Kenosha Kewaunee La Crosse Lafayette Langlade Lincoln Manitowoc Marathon Marinette Marquette Menominee Milwaukee Monroe Oconto Oneida Outagamie Ozaukee Pepin Pierce Polk Portage Price Racine Richland Rock Rusk St. Croix Sauk Sawyer Shawano Sheboygan Taylor Trempealeau Vernon Vilas Walworth Washburn Washington Waukesha Waupaca Waushara Winnebago Wood Barbour Berkeley Boone Braxton Brooke Cabell Calhoun Clay Doddridge Fayette Gilmer Grant Greenbrier Hampshire Hancock Hardy Harrison Jackson Jefferson Kanawha Lewis Lincoln Logan Marion Marshall Mason McDowell Mercer Mineral Mingo Monongalia Monroe Morgan Nicholas Ohio Pendleton Pleasants Pocahontas Preston Putnam Raleigh Randolph Ritchie Roane Summers Taylor Tucker Tyler Upshur Wayne Webster Wetzel Wirt Wood Wyoming Albany Big Horn Campbell Carbon Converse Crook Fremont Goshen Hot Springs Johnson Laramie Lincoln Natrona Niobrara Park Platte Sheridan Sublette Sweetwater Teton Uinta Washakie Weston Alagnak National Wild and Scenic River Alagnak River + Katmai National Park Alatna National Wild and Scenic River Aleutian World War II National Historic Area Aniachak National Wild and Scenic River Aniakchak Nat'l Preserve and Monument Aniakchak National Monument Aniakchak National Preserve Aniakchak River + Aniakchak National Monument Aniakchak River + Aniakchak National Preserve Bering Land Bridge National Preserve Cape Krusenstern National Monument Charley National Wild and Scenic River Chilikadrotna National Wild and Scenic River Chilikadrotna River + Lake Clark National Preserve Denali National Park Denali NP + Denali National Preserve Denali Preserve National Preserve Gates of the Arctic National Park Gates of the Arctic National Preserve Gates of the Arctic NP + Gates of the Arctic National Preserve Gates of the Arctic NP + Noatak National Preserve Glacier Bay National Park Glacier Bay National Preserve Glacier Bay NP + Glacier Bay National Preserve Inupiat Heritage Center John National Wild and Scenic River John River + Gates of The Arctic NP Katmai National Park Katmai National Preserve Katmai NP + Katmai National Preserve Kenai Fjords National Park Klondike Gold Rush National Historical Park Kobuk National Wild and Scenic River Kobuk River + Gates of The Arctic National Preserve Kobuk River + Gates of The Arctic NP Kobuk River + Kobuk Valley NP Kobuk Valley National Park Koyukuk National Wild and Scenic River (North Fork) Koyukuk River (North Fork) + Gates of The Arctic NP Lake Clark National Park Lake Clark National Preserve Lake Clark NP + Lake Clark National Preserve Mulchanta River + Lake Clark National Preserve Mulchanta River + Lake Clark NP Mulchatna National Wild and Scenic River Noatak National Preserve Noatak National Wild and Scenic River Noatak River + Gates of The Arctic NP Noatak River + Noatak National Preserve Salmon National Wild and Scenic River Salmon River + kobuk Valley NP Sitka National Historical Park Tinayguk National Wild and Scenic River Tinayguk River + Gates of The Arctic NP Tlikakila National Wild and Scenic River Tlikakila River + Lake Clark NP Wrangell-St. Elias National Park Wrangell-St. Elias National Preserve Wrangell-St. Elias NP + Wrangell-St. Elias National Preserve Yukon-Charley Rivers National Preserve Yukon-Charley Rivers Preserve + Charley River Horseshoe Bend National Military Park Little River Canyon National Preserve Natchez Trace Parkway Russell Cave National Monument Selma to Montgomery National Historic Trail Trail of Tears National Historic Trail Trail of Tears NHT + Little River Canyon PV Tuskegee Airmen National Historic Site Tuskegee Institute National Historic Site Arkansas Post National Memorial Buffalo National River Fort Smith National Historic Site Hot Springs National Park Little Rock Central High School National Historic Site Pea Ridge National Military Park President William Jefferson Clinton Birthplace Home National Historic Site Trail of Tears National Historic Trail Trail of Tears NHT + Arkansas Post NM Trail of Tears NHT + Fort Smith NHS Trail of Tears NHT + Pea Ridge NMP Canyon de Chelly National Monument Casa Grande Ruins National Monument Chiricahua National Monument Coronado National Memorial Fort Bowie National Historic Site Glen Canyon National Recreation Area Glen Canyon Rec Area + Rainbow Bridge National Monument Grand Canyon National Park Hohokam Pima National Monument Hubbell Trading Post National Historic Site Juan Bautista de Anza National Historic Trail Juan Bautista de Anza NHT + Tumacacori NHP Lake Mead National Recreation Area Montezuma Castle National Monument Navajo National Monument Old Spanish National Historic Trail Organ Pipe Cactus National Monument Petrified Forest National Park Pipe Spring National Monument Saguaro National Park Sunset Crater Volcano National Monument Tonto National Monument Tumacacori National Historical Park Tuzigoot National Monument Walnut Canyon National Monument Wupatki National Monument Cabrillo National Monument California National Historic Trail California NHT + Golden Gate NRA California NHT + Lassen Volcanic NP California NHT + Pony Express NHT Castle Mountains National Monument Cesar E. Chavez National Monument Channel Islands National Park Death Valley National Park Devils Postpile National Monument Eugene O'Neill National Historic Site Fort Point National Historic Site Golden Gate National Recreation Area Golden Gate Rec Area + Fort Point NHS Golden Gate Rec Area + Muir Woods NM John Muir National Historic Site Joshua Tree National Park Juan Bautista de Anza National Historic Trail Juan Bautista de Anza National Historic Trail + Golden Gate NRA + Fort Point NHS Juan Bautista de Anza National Historic Trail + Golden Gate NRA + Muir Woods NM Juan Bautista de Anza NHT + California NHT Juan Bautista de Anza NHT + Golden Gate NRA Juan Bautista de Anza NHT + John Muir NHS Juan Bautista de Anza NHT + Old Spanish NHT Juan Bautista de Anza NHT + Santa Monica Mountains NRA Kern National Wild and Scenic River Kern River + Sequoia NP Kings Canyon National Park Kings National Wild and Scenic River Kings River + Kings Canyon NP Lassen Volcanic National Park Lava Beds National Monument Manzanar National Historic Site Merced National Wild and Scenic River Merced River + Yosemite NP Mojave National Preserve Muir Woods National Monument Old Spanish National Historic Trail Old Spanish NHT + Mojave Natioal Preserve Pinnacles National Park Point Reyes National Seashore Pony Express National Historic Trail Pony Express NHT + Golden Gate NRA Port Chicago Naval Magazine National Memorial Redwood National Park Rosie the Riveter/World War II Home Front National Historical Park San Francisco Maritime National Historical Park Santa Monica Mountains National Recreation Area Sequoia National Park Tule Lake Unit Internment Camp National Monument Tuolumne National Wild and Scenic River Tuolumne River + Yosemite NP Whiskeytown Unit National Recreation Area Yosemite National Park Bent's Old Fort National Historic Site Black Canyon of the Gunnison National Park California National Historic Trail Colorado National Monument Curecanti National Recreation Area Dinosaur National Monument Florissant Fossil Beds National Monument Great Sand Dunes National Park Great Sand Dunes National Preserve Great Sand Dunes NP and Great Sand Dunes National Preserve Hovenweep National Monument Mesa Verde National Park Old Spanish National Historic Trail Old Spanish NHT + Colorado NM Old Spanish NHT + Curecanti NRA Old Spanish NHT + Great Sand Dunes National Preserve Old Spanish NHT + Great Sand Dunes NP and Preserve Pony Express National Historic Trail Rocky Mountain National Park Sand Creek Massacre National Historic Site Santa Fe National Historic Trail Santa Fe NHT + Bent's Old Fort NHS Yucca House National Monument Appalachian National Scenic Trail Eightmile National Wild and Scenic River Farmington National Wild and Scenic River New England National Scenic Trail New England NST + Washington-Rochambeau Revolutionary Route NHT Washington-Rochambeau Revolutionary Route National Historic Trail Weir Farm National Historic Site Captain John Smith Chesapeake National Historic Trail Carter G. Woodson Home National Historic Site Chesapeake and Ohio Canal National Historical Park Constitution Gardens Ford's Theatre National Historic Site Franklin Delano Roosevelt Memorial National Memorial Frederick Douglass National Historic Site George Washington Memorial Parkway Korean War Veterans National Memorial Lincoln Memorial National Memorial Lyndon Baines Johnson Memorial Grove on the Potomac National Memorial Martin Luther King, Jr. National Memorial Mary McLeod Bethune Council House National Historic Site Mary McLeod Bethune Council House NHS + Carter G. Woodson Home NHS National Capital Parks National Mall Pennsylvania Avenue National Historic Site Potomac Heritage National Scenic Trail Rock Creek Park Sewall-Belmont House National Historic Site Star-Spangled Banner National Historic Trail Theodore Roosevelt Island National Memorial Thomas Jefferson Memorial National Memorial Vietnam Veterans Memorial National Memorial Washington Monument National Memorial Washington-Rochambeau Revolutionary Route National Historic Trail Washington-Rochambeau Revolutionary Route NHT + George Washington Memorial Parkway White House World War I Memorial National Memorial World War II Memorial National Memorial Captain John Smith Chesapeake National Historic Trail First State National Historical Park Washington-Rochambeau Revolutionary Route National Historic Trail White Clay Creek National Wild and Scenic River Big Cypress National Preserve Biscayne National Park Canaveral National Seashore Castillo de San Marcos National Monument De Soto National Memorial Dry Tortugas National Park Everglades National Park Fort Caroline National Memorial Fort Caroline National Memorial + Timucuan Ecological and Historic Preserve Fort Matanzas National Monument Gulf Islands National Seashore Timucuan Ecological and Historic Preserve National Preserve Wekiva National Wild and Scenic River Andersonville National Historic Site Appalachian National Scenic Trail Chattahoochee River National Recreation Area Chickamauga and Chattanooga National Military Park Cumberland Island National Seashore Fort Frederica National Monument Fort Pulaski National Monument Jimmy Carter National Historic Site Kennesaw Mountain National Battlefield Park Martin Luther King, Jr. National Historic Site Ocmulgee National Monument Trail of Tears National Historic Trail Trail of Tears NHT + Chickamauga and Chattanooga NMP Ala Kahakai National Historic Trail Ala Kahakai NHT + Hawaii Volcanoes NP Ala Kahakai NHT + Kaloko-Honokohau NHP Ala Kahakai NHT + Pu'uhonua o Honaunau NHP Ala Kahakai NHT + Puukohola Heiau NHS Haleakala National Park Hawaii Volcanoes National Park Honouliuli National Monument Kalaupapa National Historical Park Kaloko-Honokohau National Historical Park Pu'uhonua o Honaunau National Historical Park Puukohola Heiau National Historic Site World War II Valor in the Pacific National Monument Effigy Mounds National Monument Herbert Hoover National Historic Site Lewis and Clark National Historic Trail Mormon Pioneer National Historic Trail Mormon Pioneer NHT + Lewis and Clark NHT California National Historic Trail California NHT + City of Rocks NR City of Rocks National Reserve Craters Of The Moon National Monument Craters of the Moon National Monument and Preserve Craters Of The Moon National Preserve Hagerman Fossil Beds National Monument Lewis and Clark National Historic Trail Lewis and Clark NHT + Nez Perce NHP Minidoka National Historic Site Nez Perce National Historical Park Oregon National Historic Trail Oregon NHT + California NHT Oregon NHT + Hagerman Fossil Beds NM Yellowstone National Park Chicago Portage National Historic Site Lewis and Clark National Historic Trail Lincoln Home National Historic Site Mormon Pioneer National Historic Trail Pullman National Monument Trail of Tears National Historic Trail George Rogers Clark National Historical Park Indiana Dunes National Lakeshore Lincoln Boyhood National Memorial Brown v. Board of Education National Historic Site California National Historic Trail California NHT + Oregon NHT + Pony Express NHT California NHT + Pony Express NHT Fort Larned National Historic Site Fort Scott National Historic Site Lewis and Clark + California NHT+ Pony Express NHT Lewis and Clark National Historic Trail Lewis and Clark NHT+ California NHT Nicodemus National Historic Site Oregon National Historic Trail Oregon NHT + California NHT Oregon NHT + Santa Fe NHT + California NHT Pony Express National Historic Trail Santa Fe National Historic Trail Santa Fe NHT + California NHT Santa Fe NHT + Fort Larned NHS Tallgrass Prairie National Preserve Abraham Lincoln Birthplace National Historical Park Big South Fork National River and Recreation Area Cumberland Gap National Historical Park Mammoth Cave National Park Trail of Tears National Historic Trail Cane River Creole NHP and Heritage Area National Historical Park El Camino Real de los Tejas National Historic Trail Jean Lafitte NHP and Preserve National Historical Park New Orleans Jazz National Historical Park Poverty Point National Monument Adams National Historical Park Appalachian National Scenic Trail Blackstone River Valley National Historical Park Boston National Historical Park Boston African American National Historic Site Boston Harbor Islands National Recreation Area Cape Cod National Seashore Frederick Law Olmsted National Historic Site John Fitzgerald Kennedy National Historic Site Longfellow House - Washington's Headquarters National Historic Site Lowell National Historical Park Minute Man National Historical Park New Bedford Whaling National Historical Park New England National Scenic Trail Salem Maritime National Historic Site Saugus Iron Works National Historic Site Springfield Armory National Historic Site Sudbury, Assabet and Concord National Wild and Scenic River Taunton National Wild and Scenic River Washington-Rochambeau Revolutionary Route National Historic Trail Washington-Rochambeau Revolutionary Route NHT + Boston Harbor Islands NRA Westfield National Wild and Scenic River Antietam National Battlefield Appalachian National Scenic Trail Appalachian Trail + Potomac Heritage NST + Chesapeake and Ohio Canal Assateague Island National Seashore Captain John Smith Chesapeake National Historic Trail Captain John Smith Chesapeake NHT + Fort McHenry NM and Shrine Captain John Smith Chesapeake NHT + Piscataway Park Captain John Smith Chesapeake NHT + Star-Spangled Banner NHT Catoctin Mountain Park Chesapeake and Ohio Canal National Historical Park Clara Barton National Historic Site Fort McHenry National Monument and Historic Shrine Fort Washington Park George Washington Memorial Parkway Greenbelt Park Hampton National Historic Site Harpers Ferry National Historical Park Harriet Tubman Underground Railroad National Monument Monocacy National Battlefield National Capital Parks Piscataway Park Potomac Heritage National Scenic Trail Star-Spangled Banner National Historic Trail Thomas Stone National Historic Site Washington-Rochambeau Revolutionary Route National Historic Trail Washington-Rochambeau Revolutionary Route NHT + Star-Spangled Banner NHT Washington-Rochambeau Revolutionary Route NHT + Star-Spangled Banner NHT + Fort McHenry NM Acadia National Park Appalachian National Scenic Trail Katahdin Woods and Waters National Monument Saint Croix Island International Historic Site Father Marquette National Memorial Isle Royale National Park Keweenaw National Historical Park North Country National Scenic Trail North Country NST + Father Marquette National Memorial North Country NST + Pictured Rocks National Lakeshore Pictured Rocks National Lakeshore River Raisin National Battlefield Park Sleeping Bear Dunes National Lakeshore Grand Portage National Monument Mississippi National River and Recreation Areas North Country National Scenic Trail Pipestone National Monument Saint Croix National Scenic Riverway Voyageurs National Park California National Historic Trail California NHT + Pony Express NHT George Washington Carver National Monument Harry S Truman National Historic Site Jefferson National Expansion Memorial National Memorial Lewis and Clark National Historic Trail Lewis and Clark NHT + Pony Express NHT Lewis and Clark NHT+ California NHT Oregon National Historic Trail Oregon NHT + California NHT Oregon NHT + Lewis and Clark NHT Oregon NHT + Santa Fe NHT + California NHT Ozark National Scenic Riverways Pony Express National Historic Trail Santa Fe National Historic Trail Santa Fe NHT + California NHT Trail of Tears National Historic Trail Ulysses S. Grant National Historic Site Wilson's Creek National Battlefield Brices Cross Roads National Battlefield Site Gulf Islands National Seashore Natchez National Historical Park Natchez Trace National Scenic Trail Natchez Trace Parkway Shiloh National Military Park Tupelo National Battlefield Vicksburg National Military Park Big Hole National Battlefield Bighorn Canyon National Recreation Area Flathead National Wild and Scenic River Flathead River + Glacier NP Fort Union Trading Post National Historic Site Glacier National Park Grant-Kohrs Ranch National Historic Site Lewis and Clark National Historic Trail Lewis and Clark NHT + Fort Union Trading Post NHS Lewis and Clark NHT + Nez Perce NHP Lewis and Clark NHT + Nez Perce NHP + Big Hole BF Little Bighorn Battlefield National Monument Nez Perce National Historical Park Nez Perce NHP + Big Hole BF Yellowstone National Park Appalachian National Scenic Trail Blue Ridge Parkway Blue Ridge Parkway + Great Smoky Mountain NP Cape Hatteras National Seashore Cape Lookout National Seashore Carl Sandburg Home National Historic Site Fort Raleigh National Historic Site Great Smoky Mountains National Park Guilford Courthouse National Military Park Moores Creek National Battlefield Overmountain Victory National Historic Trail Overmountain Victory NHT + Blue Ridge Parkway Trail of Tears National Historic Trail Wright Brothers National Memorial Fort Union Trading Post National Historic Site International Peace Garden Knife River Indian Villages National Historic Site Lewis and Clark National Historic Trail Lewis and Clark NHT + Fort Union Trading Post NHS Lewis and Clark NHT + Knife River Indian Villages NHS North Country National Scenic Trail North Country NHT + Lewis and Clark NHT Theodore Roosevelt National Park Agate Fossil Beds National Monument California National Historic Trail California NHT + Chimney Rock NHS California NHT + Oregon NHT + Pony Express NHT California NHT + Scotts Bluff MN Chimney Rock National Historic Site Homestead NM of America National Monument Lewis and Clark + California NHT+ Pony Express NHT Lewis and Clark National Historic Trail Lewis and Clark NHT + Missouri National Recreational River Lewis and Clark NHT+ California NHT Missouri National Recreational River Mormon Pioneer National Historic Trail Mormon Pioneer NHT + California NHT Mormon Pioneer NHT + Lewis and Clark NHT Niobrara National Wild and Scenic River Oregon National Historic Trail Oregon NHT + Mormon Pioneer NHT + California NHT + Pony Express NHT Oregon NHT + Mormon Pioneer NHT + California NHT + Pony Express NHT + Chimney Rock NHS Oregon NHT + Mormon Pioneer NHT + California NHT + Pony Express NHT + Scotts Bluff MN Oregon NHT + Santa Fe NHT + California NHT Pony Express National Historic Trail Pony Express NHT + Chimney Rock NHS Pony Express NHT + Scotts Bluff MN Scotts Bluff National Monument Appalachian National Scenic Trail Lamprey National Wild and Scenic River Saint-Gaudens National Historic Site Appalachian National Scenic Trail Appalachian National ScenicTrail + Delaware National Scenic River Appalachian National ScenicTrail + Delaware Water Gap Delaware National Scenic River Delaware Water Gap National Recreation Area Gateway National Recreation Area Great Egg Harbor National Scenic and Recreational River Maurice National Scenic and Recreational River Morristown National Historical Park Musconetcong National Wild and Scenic River New Jersey Coastal Heritage Trail Route New Jersey Coastal Heritage Trail Route + Great Egg Harbor National Scenic River New Jersey Coastal Heritage Trail Route + Maurice National Scenic River New Jersey Coastal Heritage Trail Route + Pinelands National Reserve New Jersey Coastal Heritage Trail Route + Pinelands National Reserve + Great Egg Harbor National Scenic River Paterson Great Falls National Historical Park Pinelands National Reserve Pinelands National Reserve + Great Egg Harbor National Scenic River Statue of Liberty National Monument Thomas Edison National Historical Park Washington-Rochambeau Revolutionary Route National Historic Trail Washington-Rochambeau Revolutionary Route NHT + Morristown Aztec Ruins National Monument Bandelier National Monument Capulin Volcano National Monument Carlsbad Caverns National Park Chaco Culture National Historical Park El Camino Real de Tierra Adentro National Historic Trail El Malpais National Monument El Morro National Monument Fort Union National Monument Gila Cliff Dwellings National Monument Manhattan Project National Historical Park Old Spanish National Historic Trail Old Spanish NHT + Aztec Ruins NM Pecos National Historical Park Petroglyph National Monument Salinas Pueblo Missions National Monument Santa Fe National Historic Trail Santa Fe NHT + Fort Union NM Santa Fe NHT + Pecos NHP Valles Caldera National Preserve White Sands National Monument California National Historic Trail California NHT + Pony Express NHT Death Valley National Park Great Basin National Park Lake Mead National Recreation Area Old Spanish National Historic Trail Old Spanish NHT + Lake Mead NRA Pony Express National Historic Trail Tule Springs Fossil Beds National Monument African Burial Ground National Monument Appalachian National Scenic Trail Captain John Smith Chesapeake National Historic Trail Castle Clinton National Monument Delaware National Scenic River Eleanor Roosevelt National Historic Site Federal Hall National Memorial Fire Island National Seashore Fort Stanwix National Monument Gateway National Recreation Area General Grant National Memorial Governors Island National Monument Hamilton Grange National Memorial Home of Franklin D. Roosevelt National Historic Site Kate Mullany National Historic Site Lower East Side Tenement National Historic Site Martin Van Buren National Historic Site North Country National Scenic Trail North Country NST + Fort Stanwix NM Sagamore Hill National Historic Site Saint Paul's Church National Historic Site Saratoga National Historical Park Statue of Liberty National Monument Stonewall National Monument Theodore Roosevelt Birthplace National Historic Site Theodore Roosevelt Inaugural National Historic Site Thomas Cole National Historic Site Upper Delaware Scenic and Recreation River Vanderbilt Mansion National Historic Site Washington-Rochambeau Revolutionary Route National Historic Trail Women's Rights National Historical Park Charles Young Buffalo Soldiers National Monument Cuyahoga Valley National Park Dayton Aviation Heritage National Historical Park Fallen Timbers Battlefield and Fort Miamis National Historic Site First Ladies National Historic Site Hopewell Culture National Historical Park James A. Garfield National Historic Site North Country National Scenic Trail North Country NST + Dayton Aviation Heritage NHP Perry's Victory and International Peace Memorial National Memorial William Howard Taft National Historic Site Chickasaw National Recreation Area Oklahoma City National Memorial Santa Fe National Historic Trail Trail of Tears National Historic Trail Trail of Tears NHT + Fort Smith NHS Washita Battlefield National Historic Site California National Historic Trail Crater Lake National Park Fort Vancouver National Historic Site John Day Fossil Beds National Monument Lewis and Clark National Historical Park Lewis and Clark National Historic Trail Lewis and Clark NHT + Lewis and Clark NHP Lewis and Clark NHT + Nez Perce NHP Nez Perce National Historical Park Oregon Caves National Monument Oregon National Historic Trail Oregon NHT + Lewis and Clark NHT Allegheny Portage Railroad National Historic Site Appalachian National Scenic Trail Appalachian National ScenicTrail + Delaware National Scenic River Appalachian National ScenicTrail + Delaware Water Gap Benjamin Franklin National Memorial Captain John Smith Chesapeake National Historic Trail Delaware National Scenic River Delaware Water Gap National Recreation Area Edgar Allan Poe National Historic Site Eisenhower National Historic Site First State National Historical Park Flight 93 National Memorial Fort Necessity National Battlefield Friendship Hill National Historic Site Gettysburg National Military Park Gloria Dei (Old Swedes') Church National Historic Site Hopewell Furnace National Historic Site Independence National Historical Park Johnstown Flood National Memorial North Country National Scenic Trail Potomac Heritage National Scenic Trail Steamtown National Historic Site Thaddeus Kosciuszko National Memorial Upper Delaware Scenic and Recreation River Valley Forge National Historical Park Washington-Rochambeau Revolutionary Route National Historic Trail Washington-Rochambeau Revolutionary Route NHT + Independence HP White Clay Creek National Wild and Scenic River Blackstone River Valley National Historical Park Roger Williams National Memorial Touro Synagogue National Historic Site Washington-Rochambeau Revolutionary Route National Historic Trail Appalachian Trail + Overmountain Men Victory Trail Charles Pinckney National Historic Site Congaree National Park Cowpens National Battlefield Fort Sumter National Monument Historic Camden Revolutionary War Site Kings Mountain National Military Park Ninety Six National Historic Site Overmountain Victory National Historic Trail Overmountain Victory NHT + Cowpens BF Overmountain Victory NHT + Kings Mountain MP Badlands National Park Jewel Cave National Monument Lewis and Clark National Historic Trail Lewis and Clark NHT + Missouri National Recreational River Minuteman Missile National Historic Site Missouri National Recreational River Mount Rushmore National Memorial Wind Cave National Park Andrew Johnson National Historic Site Appalachian National Scenic Trail Appalachian National ScenicTrail + Great Smoky Mountains NP Appalachian Trail + Overmountain Men Victory Trail Big South Fork National River and Recreation Area Chickamauga and Chattanooga National Military Park Cumberland Gap National Historical Park Fort Donelson National Battlefield Great Smoky Mountains National Park Manhattan Project National Historical Park Natchez Trace National Scenic Trail Natchez Trace Parkway Obed National Wild and Scenic River Overmountain Victory National Historic Trail Shiloh National Military Park Stones River National Battlefield Trail of Tears National Historic Trail Trail of Tears NHT + Chickamauga and Chattanooga NMP Trail of Tears NHT + Stones River BF Alibates Flint Quarries National Monument Amistad National Recreation Area Big Bend National Park Big Thicket National Preserve Chamizal National Memorial El Camino Real de los Tejas National Historic Trail El Camino Real de los Tejas NHT + San Antonio Missions NHP El Camino Real de Tierra Adentro National Historic Trail El Camino Real de Tierra Adentro NHT + Chamizal NM Fort Davis National Historic Site Guadalupe Mountains National Park Lake Meredith National Recreation Area Lyndon B. Johnson National Historical Park Padre Island National Seashore Palo Alto Battlefield National Historical Park Rio Grande River + Big Bend NP Rio Grande Wild and Scenic River San Antonio Missions National Historical Park Santa Fe National Historic Trail Waco Mammoth National Monument Arches National Park Bryce Canyon National Park California National Historic Trail California NHT + Pony Express NHT Canyonlands National Park Capitol Reef National Park Cedar Breaks National Monument Dinosaur National Monument Glen Canyon National Recreation Area Golden Spike National Historic Site Hovenweep National Monument Mormon Pioneer National Historic Trail Mormon Pioneer NHT + California NHT + Pony Express NHT Mormon Pioneer NHT + California NHT Mormon Pioneer NHT + Pony Express NHT Natural Bridges National Monument Old Spanish National Historic Trail Old Spanish NHT + Arches NP Pony Express National Historic Trail Rainbow Bridge National Monument Timpanogos Cave National Monument Virgin National Wild and Scenic River Virgin River + Zion NP Zion National Park Appalachian National Scenic Trail Appalachian National ScenicTrail + Shenandoah NP Appomattox Court House National Historical Park Arlington House National Memorial Assateague Island National Seashore Blue Ridge Parkway Booker T. Washington National Monument Captain John Smith Chesapeake National Historic Trail Captain John Smith Chesapeake NHT + Colonial NHP Captain John Smith Chesapeake NHT + George Washington Birthplace Captain John Smith Chesapeake NHT + Richmond NBP Captain John Smith Chesapeake NHT + Star-Spangled Banner NHT + George Washington Memorial Parkway Cedar Creek and Belle Grove National Historical Park Colonial National Historical Park Cumberland Gap National Historical Park Fort Monroe National Monument Fredericksburg and Spotsylvania County Battlefields Memorial National Military Park George Washington Birthplace National Monument George Washington Memorial Parkway Green Springs National Historic Landmark District Harpers Ferry National Historical Park Jamestown + Colonial NHP Jamestown National Historic Site Maggie L. Walker National Historic Site Manassas National Battlefield Park Natural Bridge Overmountain Victory National Historic Trail Petersburg National Battlefield Potomac Heritage National Scenic Trail Potomac Heritage NST + Prince William Forest Park Prince William Forest Park Red Hill Patrick Henry National Memorial Richmond National Battlefield Park Shenandoah National Park Star-Spangled Banner National Historic Trail Washington-Rochambeau Revolutionary Route National Historic Trail Washington-Rochambeau Revolutionary Route NHT + Potomac Heritage NST Wolf Trap National Park for the Performing Arts Appalachian National Scenic Trail Marsh-Billings-Rockefeller National Historical Park Missisquoi and Trout National Wild and Scenic River Ebey's Landing National Historical Reserve Fort Vancouver National Historic Site Klondike Gold Rush - Seattle Unit National Historical Park Lake Chelan National Recreation Area Lake Chelan NRA + North Cascades NP Lake Roosevelt (formerly Coulee Dam) National Recreation Area Lewis and Clark National Historical Park Lewis and Clark National Historic Trail Lewis and Clark NHT + Lewis and Clark NHP Manhattan Project National Historical Park Minidoka National Historic Site Mount Rainier National Park Nez Perce National Historical Park North Cascades National Park Olympic National Park Oregon National Historic Trail Oregon NHT + Lewis and Clark NHT + Fort Vancouver NHS Ross Lake National Recreation Area Ross Lake + North Cascades NP San Juan Island National Historical Park Whitman Mission National Historic Site Wing Luke Museum of the Asian Pacific American Experience Apostle Islands National Lakeshore Ice Age National Scenic Trail Ice Age National Scenic Trail + Saint Croix WR Ice Age National Scientific Reserve Ice Age NST + Ice Age National Scientific Reserve Ice Age NST + Saint Croix National Scenic Riverway + Ice Age National Scientific Reserve North Country National Scenic Trail North Country NST + Saint Croix National Scenic Riverway Saint Croix National Scenic Riverway Saint Croix WR + Ice Age National Scientific Reserve Appalachian National Scenic Trail Appalachian National ScenicTrail + Harpers Ferry HP Bluestone National Scenic River Chesapeake and Ohio Canal National Historical Park Gauley River National Recreation Area Harpers Ferry National Historical Park New River Gorge National River Bighorn Canyon National Recreation Area California National Historic Trail California NHT + Fort Laramie NHS California NHT + Pony Express NHT Devils Tower National Monument Fort Laramie National Historic Site Fossil Butte National Monument Grand Teton National Park John D. Rockefeller Parkway + Grand Teton NP John D. Rockefeller Parkway + Yellowstone NP John D. Rockefeller, Jr. Memorial Parkway Mormon Pioneer National Historic Trail Mormon Pioneer NHT + California NHT + Pony Express NHT Oregon National Historic Trail Oregon NHT + California NHT Oregon NHT + Mormon Pioneer NHT + California NHT + Pony Express NHT Oregon NHT + Mormon Pioneer NHT + California NHT + Pony Express NHT + Fort Laramie NHS Oregon NHT + Santa Fe NHT + California NHT Pony Express National Historic Trail Pony Express NHT + Fort Laramie NHS Yellowstone National Park Hawaii Alabama Arizona Arkansas California Colorado Connecticut Delaware District of Columbia Florida Georgia Idaho Illinois Indiana Iowa Kansas Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi Missouri Montana Nebraska Nevada New Hampshire New Jersey New Mexico New York North Carolina North Dakota Ohio Oklahoma Oregon Pennsylvania Rhode Island South Carolina South Dakota Tennessee Texas Utah Vermont Virginia Washington West Virginia Wisconsin Wyoming Alaska CALL DXCC GRIDSQUARE ITUZ CQZ IOTA ZERR US_STATE US_COUNTY US_PARK ZERR US_STATE US_COUNTY US_PARK ZERR CA_PROVINCE CA_US_PARK ZERR RU_OBLAST ZERR RU_OBLAST ZERR US_STATE US_COUNTY US_PARK ZERR RU_OBLAST ZERR RU_OBLAST ZERR RU_OBLAST ZERR CN_PROVINCE ZERR AU_STATE ZERR DX_US_PARK ZERR DX_US_PARK ZERR DX_US_PARK ZERR DX_US_PARK ZERR DX_US_PARK ZERR JA_PREFECTURE JA_CITY_GUN_KU ZERR FI_KUNTA ZERR FI_KUNTA ZERR FI_KUNTA ZERR AM AMTOR ARDOP ATV C4FM CHIP CLOVER CONTESTI CW DATA DIGITALVOICE DOMINO DSTAR FAX FM FSK31 FSK441 FST4 FT4 FT8 GTOR HELL HFSK IMAGE ISCAT JT4 JT65 JT6M JT9 MFSK16 MFSK8 MINIRTTY MSK144 MT63 OLIVIA OPERA PACKET PACTOR PAX PHONE PSK10 PSK125 PSK2K PSK31 PSK63 PSK63F PSKAM PSKFEC31 Q15 Q65 QRA64 ROS RTTY RTTYM SSB SSTV T10 THOR THROB VOI WINMOR WSPR Aircraft Scatter Aurora-E Aurora Back scatter EchoLink Earth-Moon-Earth Sporadic E F2 Reflection Field Aligned Irregularities Ionoscatter IRLP Meteor scatter Rain scatter Satellite Trans-equatorial Tropospheric ducting lotw-help@arrl.org Logbook of the World https://www.arrl.org/lotw/ AISAT-1 AMSAT India APRS Digipeater AMSAT-OSCAR 10 AMSAT-OSCAR 109 ASRTU-OSCAR 123 AMSAT-OSCAR 13 AMSAT-OSCAR 16 OSCAR 21/RS-14 AMRAD-OSCAR 27 AMSAT-OSCAR 3 AMSAT-OSCAR 4 AMSAT-OSCAR 40 AMSAT-OSCAR 51 AMSAT-OSCAR 6 AMSAT-OSCAR 7 AMSAT-OSCAR 73 AMSAT-OSCAR 8 AMSAT-OSCAR 85 (Fox-1A) AMSAT-OSCAR 91 (RadFxSat / Fox-1B) AMSAT-OSCAR 92 (Fox-1D) ARISS OSCAR 24 BIT Progress-OSCAR 102 (CAS-7B) Bayi Kepu Weixing 1 CAS-2T LilacSat-2 CAMSAT 4A (CAS-4A) CAMSAT 4B (CAS-4B) Delfi OSCAR-64 FUNcube-3 Emirates-OSCAR 88 (Nayif-1) CAS-5A Fuji-OSCAR 12 Fuji-OSCAR 20 Fuji-OSCAR 29 Fuji-OSCAR 99 (NEXUS) FalconSAT 3 HuskySat OSCAR 107 HO-113 Hope-OSCAR 119 Hope-Oscar 68 INSPIRE-Sat7 GreenCube Indonesia-OSCAR 86 (LAPAN-ORARI) Jordan-OSCAR 97(JY1Sat) ARISSat-1 LEDSAT Lusat-OSCAR 19 LituanicaSAT-1 LUSEX-OSCAR 87 LilacSat-OSCAR 90 (LilacSat-1) Cubesat Cubesat MIR Packet Digipeater Mirsat-1 MESAT1-OSCAR 122 Navy-OSCAR 103 (BRICSAT 2) Navy-OSCAR 104 (PSAT 2) Navy-OSCAR 44 BRICsat PSAT Phillipines-OSCAR-101 (Diwata-2) Qatar-OSCAR 100 (Es'hail-2/P4A) Radio Sputnik 1 Radio Sputnik 10 Radio Sputnik 11 Radio Sputnik 12 Radio Sputnik 13 Radio Sputnik 15 Radio Sputnik 2 Radio Sputnik 44 (DOSAAF-85) Radio Sputnik 5 Radio Sputnik 6 Radio Sputnik 7 Radio Sputnik 8 Shuttle Amateur Radio Experiment (SAREX) Digipeater Hades-D Hades-R Hades-ICM Sunsat-OSCAR 35 Saudi-OSCAR 41 Saudi-OSCAR 50 Sumbandila Oscar 67 SONATE-2 Taurus-1 (Jinniuzuo-1) Tevel-1 Tevel-2 Tevel-3 Tevel-4 Tevel-5 Tevel-6 Tevel-7 Tevel-8 TQ-OSCAR 108 (CAS-6 / TQ-1) UKube-1 (FUNcube-2) UOSAT-OSCAR 14 CubeSat VUsat-OSCAR 52 Hope 2A (CAS-3A) Hope 2B (CAS-3B) Hope 2C (CAS-3C) Hope 2D (CAS-3D) Hope 2E (CAS-3E) Hope 2F (CAS-2F) Tevel2-1 Tevel2-2 Tevel2-3 Tevel2-4 Tevel2-5 Tevel2-6 Tevel2-7 Tevel2-8 Tevel2-9 tqsl-2.8.2/src/cabrillo.h0000644000175000017500000000750515061653721015250 0ustar rmurphyrmurphy/*************************************************************************** cabrillo.h - description ------------------- begin : Thu Dec 5 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #ifndef __CABRILLO_H #define __CABRILLO_H #undef CLIENT_STATIC #ifndef LOTW_SERVER #define CLIENT_STATIC static ///< Static linkage #else #define CLIENT_STATIC #endif /*! \file */ /** \defgroup Cabrillo Cabrillo API * * These functions and data structures provide a means of parsing a Cabrillo * file into its component fields. * * For convenience, the returned fields are identified using field names * from the \link ADIF ADIF \endlink specification. */ /** @{ */ #define TQSL_CABRILLO_MAX_FIELDS 12 ///< Max field count #define TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX 64 ///< Max field name length #define TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX 40 ///< Max field value length /// Cabrillo status values typedef enum { TQSL_CABRILLO_NO_ERROR, TQSL_CABRILLO_EOF, TQSL_CABRILLO_NO_START_RECORD, TQSL_CABRILLO_NO_CONTEST_RECORD, TQSL_CABRILLO_UNKNOWN_CONTEST, TQSL_CABRILLO_BAD_FIELD_DATA, TQSL_CABRILLO_EOR, } TQSL_CABRILLO_ERROR_TYPE; ///< Error type /*! \enum TQSL_CABRILLO_FREQ_TYPE * Frequency type: HF, VHF, or UNKNOWN */ typedef enum { TQSL_CABRILLO_HF, TQSL_CABRILLO_VHF, TQSL_CABRILLO_UNKNOWN, } TQSL_CABRILLO_FREQ_TYPE; // Minimum field number for callsign and default field number // For VHF, default should be 7. #define TQSL_MIN_CABRILLO_MAP_FIELD 5 ///< First possible call-worked field #define TQSL_DEF_CABRILLO_MAP_FIELD 8 ///< Default call-worked field /** Cabrillo field data: * * \li \c name - ADIF field name * \li \c value - Field content */ typedef struct { ///< Cabrillo field char name[TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX +1]; ///< Field name char value[TQSL_CABRILLO_FIELD_VALUE_LENGTH_MAX +1]; ///< Field value } tqsl_cabrilloField; typedef void * tQSL_Cabrillo; ///< Opaque cabrillo log type #define TQSLLIB_DEF #include "tqsllib.h" #ifdef __cplusplus extern "C" { #endif /** Get the Cabrillo error message that corresponds to a particular error value */ DLLEXPORT const char* CALLCONVENTION tqsl_cabrilloGetError(TQSL_CABRILLO_ERROR_TYPE err); /** Initialize a Cabrillo file for reading */ DLLEXPORT int CALLCONVENTION tqsl_beginCabrillo(tQSL_Cabrillo *cabp, const char *filename); /** Get the Contest name as specified in the Cabrillo CONTEST line */ DLLEXPORT int CALLCONVENTION tqsl_getCabrilloContest(tQSL_Cabrillo cab, char *buf, int bufsiz); /** Get the Frequency type (HF or VHF) as determined by the contest */ DLLEXPORT int CALLCONVENTION tqsl_getCabrilloFreqType(tQSL_Cabrillo cab, TQSL_CABRILLO_FREQ_TYPE *type); /** Get the current line number (starting from 1) of the input file */ DLLEXPORT int CALLCONVENTION tqsl_getCabrilloLine(tQSL_Cabrillo cab, int *lineno); /** Get the text of the current Cabrillo record */ DLLEXPORT const char* CALLCONVENTION tqsl_getCabrilloRecordText(tQSL_Cabrillo cab); /** Get the next field of the Cabrillo record * * \c err is set to \c TQSL_CABRILLO_NO_ERROR or \c TQSL_CABRILLO_EOR (end-of-record) * if \c field was populated with data. If \c err == \c TQSL_CABRILLO_EOR, this * is the last field of the record. * * \c err == \c TQSL_CABRILLO_EOF when there is no more data available. */ DLLEXPORT int CALLCONVENTION tqsl_getCabrilloField(tQSL_Cabrillo cab, tqsl_cabrilloField *field, TQSL_CABRILLO_ERROR_TYPE *err); /** Finish reading a Cabrillo file and release its resources */ DLLEXPORT int CALLCONVENTION tqsl_endCabrillo(tQSL_Cabrillo *cabp); #ifdef __cplusplus } #endif /** @} */ #endif // __CABRILLO_H tqsl-2.8.2/src/cabrillo.cpp0000644000175000017500000005516015061653721015603 0ustar rmurphyrmurphy/*************************************************************************** cabrillo.cpp - description ------------------- begin : Thu Dec 5 2002 copyright : (C) 2002 by ARRL author : Jon Bloom email : jbloom@arrl.org revision : $Id$ ***************************************************************************/ #include "cabrillo.h" #include #include #include #include #include #include #include #include "tqslerrno.h" #include "winstrdefs.h" using std::map; using std::string; #define TQSL_CABRILLO_MAX_RECORD_LENGTH 120 DLLEXPORTDATA TQSL_CABRILLO_ERROR_TYPE tQSL_Cabrillo_Error; static char errmsgbuf[256]; static char errmsgdata[128]; struct TQSL_CABRILLO; static int freq_to_band(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp); static int freq_to_mhz(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp); static int mode_xlat(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp); static int time_fixer(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp); struct cabrillo_field_def { const char *name; int loc; int (*process)(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp); }; static cabrillo_field_def cabrillo_dummy[] = { { "CALL", 6, 0 }, { "BAND", 0, freq_to_band }, { "MODE", 1, mode_xlat }, { "QSO_DATE", 2, 0 }, { "TIME_ON", 3, time_fixer }, { "FREQ", 0, freq_to_mhz }, { "MYCALL", 4, 0 }, }; /* // Cabrillo QSO template specs // Call in field 6 static cabrillo_field_def cabrillo_c6[] = { { "BAND", 0, freq_to_band }, { "MODE", 1, mode_xlat }, { "QSO_DATE", 2, 0 }, { "TIME_ON", 3, time_fixer }, { "CALL", 6, 0 }, { "FREQ", 0, 0 }, { "MYCALL", 4, 0 }, }; // Call in field 7 static cabrillo_field_def cabrillo_c7[] = { { "BAND", 0, freq_to_band }, { "MODE", 1, mode_xlat }, { "QSO_DATE", 2, 0 }, { "TIME_ON", 3, time_fixer }, { "CALL", 7, 0 }, { "FREQ", 0, 0 }, { "MYCALL", 4, 0 }, }; // Call in field 8 static cabrillo_field_def cabrillo_c8[] = { { "BAND", 0, freq_to_band }, { "MODE", 1, mode_xlat }, { "QSO_DATE", 2, 0 }, { "TIME_ON", 3, time_fixer }, { "CALL", 8, 0 }, { "FREQ", 0, 0 }, { "MYCALL", 4, 0 }, }; // Call in field 9 static cabrillo_field_def cabrillo_c9[] = { { "BAND", 0, freq_to_band }, { "MODE", 1, mode_xlat }, { "QSO_DATE", 2, 0 }, { "TIME_ON", 3, time_fixer }, { "CALL", 9, 0 }, { "FREQ", 0, 0 }, { "MYCALL", 4, 0 }, }; */ struct cabrillo_contest { char *contest_name; TQSL_CABRILLO_FREQ_TYPE type; cabrillo_field_def *fields; int nfields; }; struct TQSL_CABRILLO { int sentinel; FILE *fp; char *filename; cabrillo_contest *contest; int field_idx; char rec[TQSL_CABRILLO_MAX_RECORD_LENGTH+1]; char *datap; int line_no; char *fields[TQSL_CABRILLO_MAX_FIELDS]; }; #define CAST_TQSL_CABRILLO(p) ((struct TQSL_CABRILLO *)p) #ifdef _WIN32 #define strtok_r strtok_s #endif static TQSL_CABRILLO * check_cabrillo(tQSL_Cabrillo cabp) { if (tqsl_init()) return 0; if (cabp == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 0; } if (CAST_TQSL_CABRILLO(cabp)->sentinel != 0x2449) return 0; return CAST_TQSL_CABRILLO(cabp); } static char * tqsl_parse_cabrillo_record(char *rec) { char *cp = strchr(rec, ':'); if (!cp) return 0; *cp++ = 0; if (strlen(rec) > TQSL_CABRILLO_FIELD_NAME_LENGTH_MAX) return 0; while (isspace(*cp)) cp++; char *sp; if ((sp = strchr(cp, '\r')) != 0) *sp = '\0'; if ((sp = strchr(cp, '\n')) != 0) *sp = '\0'; for (sp = cp + strlen(cp); sp != cp; ) { sp--; if (isspace(*sp)) *sp = '\0'; else break; } for (sp = rec; *sp; sp++) *sp = toupper(*sp); return cp; } static int freq_to_band(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp) { if (!strcasecmp(fp->value, "light")) { strncpy(fp->value, "SUBMM", sizeof fp->value); return 0; } int freq = strtol(fp->value, NULL, 10); const char *band = 0; if (freq < 30) { // Handle known CT misbehavior if (!strcmp(fp->value, "7")) freq = 7000; if (!strcmp(fp->value, "14")) freq = 14000; if (!strcmp(fp->value, "21")) freq = 21000; if (!strcmp(fp->value, "28")) freq = 28000; } if (freq >= 1800 && freq <= 2000) band = "160M"; else if (freq >= 3500 && freq <= 4000) band = "80M"; else if (freq >= 7000 && freq <= 7300) band = "40M"; else if (freq >= 10100 && freq <= 10150) band = "30M"; else if (freq >= 14000 && freq <= 14350) band = "20M"; else if (freq >= 18068 && freq <= 18168) band = "17M"; else if (freq >= 21000 && freq <= 21450) band = "15M"; else if (freq >= 24890 && freq <= 24990) band = "12M"; else if (freq >= 28000 && freq <= 29700) band = "10M"; else if (freq == 50) band = "6M"; else if (freq == 70) band = "4M"; else if (freq == 144) band = "2M"; else if (freq == 222) band = "1.25M"; else if (freq == 432) band = "70CM"; else if (freq == 902 || freq == 903) band = "33CM"; else if (!strcasecmp(fp->value, "1.2G") || !strcasecmp(fp->value, "1.2")) band = "23CM"; else if (!strcasecmp(fp->value, "2.3G") || !strcasecmp(fp->value, "2.3")) band = "13CM"; else if (!strcasecmp(fp->value, "3.4G") || !strcasecmp(fp->value, "3.4")) band = "9CM"; else if (!strcasecmp(fp->value, "5.7G") || !strcasecmp(fp->value, "5.7")) band = "6CM"; else if (!strcasecmp(fp->value, "10G") || !strcasecmp(fp->value, "10")) band = "3CM"; else if (!strcasecmp(fp->value, "24G") || !strcasecmp(fp->value, "24")) band = "1.25CM"; else if (!strcasecmp(fp->value, "47G") || !strcasecmp(fp->value, "47")) band = "6MM"; else if (!strcasecmp(fp->value, "75G") || !strcasecmp(fp->value, "75") || !strcasecmp(fp->value, "76G") || !strcasecmp(fp->value, "76")) band = "4MM"; else if (!strcasecmp(fp->value, "119G") || !strcasecmp(fp->value, "119") || !strcasecmp(fp->value, "122G") || !strcasecmp(fp->value, "122") || !strcasecmp(fp->value, "123G") || !strcasecmp(fp->value, "123")) band = "2.5MM"; else if (!strcasecmp(fp->value, "142G") || !strcasecmp(fp->value, "142") || !strcasecmp(fp->value, "134G") || !strcasecmp(fp->value, "134")) band = "2MM"; else if (!strcasecmp(fp->value, "241G") || !strcasecmp(fp->value, "241")|| !strcasecmp(fp->value, "242G") || !strcasecmp(fp->value, "242")) band = "1MM"; else if (!strcasecmp(fp->value, "300G") || !strcasecmp(fp->value, "300") || !strcasecmp(fp->value, "LIGHT")) band = "SUBMM"; if (band && cab->contest->type == TQSL_CABRILLO_UNKNOWN) { if (freq < 1000) cab->contest->type = TQSL_CABRILLO_VHF; else cab->contest->type = TQSL_CABRILLO_HF; } if (band == 0) return 1; strncpy(fp->value, band, sizeof fp->value); return 0; } static int freq_to_mhz(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp) { if (!strcasecmp(fp->value, "light")) { return 0; } int freq = strtol(fp->value, NULL, 10); double freqmhz = freq; freqmhz /= 1000; if (freq < 30) { // Handle known CT misbehavior if (freq == 7) freqmhz = 7.0; if (freq == 14) freqmhz = 14.0; if (freq == 21) freqmhz = 21.0; if (freq == 28) freqmhz = 28.0; } // VHF+ if (!strcasecmp(fp->value, "50")) freqmhz = 50.0; else if (!strcasecmp(fp->value, "70")) freqmhz = 70.0; else if (!strcasecmp(fp->value, "144")) freqmhz = 144.0; else if (!strcasecmp(fp->value, "222")) freqmhz = 222.0; else if (!strcasecmp(fp->value, "432")) freqmhz = 432.0; else if (!strcasecmp(fp->value, "902") || !strcasecmp(fp->value, "903")) freqmhz = 902.0; else if (!strcasecmp(fp->value, "1.2G") || !strcasecmp(fp->value, "1.2")) freqmhz = 1240.0; else if (!strcasecmp(fp->value, "2.3G") || !strcasecmp(fp->value, "2.3")) freqmhz = 2300.0; else if (!strcasecmp(fp->value, "3.4G") || !strcasecmp(fp->value, "3.4")) freqmhz = 3300.0; else if (!strcasecmp(fp->value, "5.7G") || !strcasecmp(fp->value, "5.7")) freqmhz = 5650.0; else if (!strcasecmp(fp->value, "10G") || !strcasecmp(fp->value, "10")) freqmhz = 10000.0; else if (!strcasecmp(fp->value, "24G") || !strcasecmp(fp->value, "24")) freqmhz = 24000.0; else if (!strcasecmp(fp->value, "47G") || !strcasecmp(fp->value, "47")) freqmhz = 47000.0; else if (!strcasecmp(fp->value, "75G") || !strcasecmp(fp->value, "75") || !strcasecmp(fp->value, "76G") || !strcasecmp(fp->value, "76")) freqmhz = 75500.0; else if (!strcasecmp(fp->value, "119G") || !strcasecmp(fp->value, "119")) freqmhz = 119980.0; else if (!strcasecmp(fp->value, "142G") || !strcasecmp(fp->value, "142")) freqmhz = 142000.0; else if (!strcasecmp(fp->value, "241G") || !strcasecmp(fp->value, "241") || !strcasecmp(fp->value, "242G") || !strcasecmp(fp->value, "242")) freqmhz = 241000.0; else if (!strcasecmp(fp->value, "300G") || !strcasecmp(fp->value, "300")) freqmhz = 300000.0; if (freqmhz > 0 && cab->contest->type == TQSL_CABRILLO_UNKNOWN) { if (freqmhz >= 50.0) // VHF cab->contest->type = TQSL_CABRILLO_VHF; else cab->contest->type = TQSL_CABRILLO_HF; } snprintf(fp->value, sizeof fp->value, "%#f", freqmhz); return 0; } static char * tqsl_strtoupper(char *str) { for (char *cp = str; *cp != '\0'; cp++) *cp = toupper(*cp); return str; } /* * Read a line from a cabrillo file. * Start with stripping whitespace, read up until any line-ending character * (\r \n) * Replaces fgets which has a fixed line ending (\n). */ static char *fgets_cab(char *s, int size, FILE *stream) { int status; int ws; while (1) { ws = fgetc(stream); if (ws == EOF) { return 0; } if (!isspace(ws)) { break; } } ungetc(ws, stream); // Push that back onto the stream char format[20]; snprintf(format, sizeof format, "%%%d[^\r\n]", size - 1); // Format allows what's left up to \r or \n status = fscanf(stream, format, s); if (status == 0) return NULL; s[size-1] = '\0'; return s; } static int mode_xlat(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp) { static map modes; static bool modes_loaded = false; if (!modes_loaded) { tqslTrace("mode_xlat", "Loading Cab modes"); modes_loaded = true; // Set default modes modes["CW"] = "CW"; modes["PH"] = "SSB"; modes["FM"] = "FM"; modes["RY"] = "RTTY"; modes["DG"] = "DATA"; FILE *cfile; char modebuf[80]; #ifdef _WIN32 string default_path = string(tQSL_RsrcDir) + "\\cab_modes.dat"; string user_path = string(tQSL_BaseDir) + "\\cab_modes.dat"; #else string default_path = string(tQSL_RsrcDir) + "/cab_modes.dat"; string user_path = string(tQSL_BaseDir) + "/cab_modes.dat"; #endif #ifdef _WIN32 wchar_t* wfilename = utf8_to_wchar(default_path.c_str()); if ((cfile = _wfopen(wfilename, L"r")) == NULL) { #else if ((cfile = fopen(default_path.c_str(), "r")) == NULL) { #endif tqslTrace("mode_xlat", "Can't open def mode file %s: %s", default_path.c_str(), strerror(errno)); } else { while(fgets(modebuf, sizeof modebuf, cfile)) { for (char *p = modebuf + (strlen(modebuf) - 1); p >= modebuf; p--) { if (*p == '\n' || *p == '\r') { *p = '\0'; } else { break; } } char *state = NULL; char *mode = strtok_r(modebuf, ",", &state); char *map = strtok_r(NULL, ",", &state); if (mode && map) modes[tqsl_strtoupper(mode)] = tqsl_strtoupper(map); } } #ifdef _WIN32 free_wchar(wfilename); #endif #ifdef _WIN32 wfilename = utf8_to_wchar(user_path.c_str()); if ((cfile = _wfopen(wfilename, L"r")) == NULL) { #else if ((cfile = fopen(user_path.c_str(), "r")) == NULL) { #endif tqslTrace("mode_xlat", "Can't open user mode file %s: %s", user_path.c_str(), strerror(errno)); } else { while(fgets(modebuf, sizeof modebuf, cfile)) { for (char *p = modebuf + (strlen(modebuf) - 1); p >= modebuf; p--) { if (*p == '\n' || *p == '\r') { *p = '\0'; } else { break; } } char *state = NULL; char *mode = strtok_r(modebuf, ",", &state); char *map = strtok_r(NULL, ",", &state); if (mode && map) modes[tqsl_strtoupper(mode)] = tqsl_strtoupper(map); } } #ifdef _WIN32 free_wchar(wfilename); #endif } map::iterator it; it = modes.find(tqsl_strtoupper(fp->value)); if (it != modes.end()) { strncpy(fp->value, it->second.c_str(), sizeof fp->value); return 0; } return 1; // not found } static int time_fixer(TQSL_CABRILLO *cab, tqsl_cabrilloField *fp) { if (strlen(fp->value) == 0) return 0; char *cp; for (cp = fp->value; *cp; cp++) if (!isdigit(*cp)) break; if (*cp) return 1; snprintf(fp->value, sizeof fp->value, "%04d", static_cast(strtol(fp->value, NULL, 10))); return 0; } static void tqsl_free_cabrillo_contest(struct cabrillo_contest *c) { if (c->contest_name) free(c->contest_name); if (c->fields) free(c->fields); free(c); } static struct cabrillo_contest * tqsl_new_cabrillo_contest(const char *contest_name, int call_field, int contest_type) { cabrillo_contest *c = static_cast(calloc(1, sizeof(struct cabrillo_contest))); if (c == NULL) return NULL; if ((c->contest_name = strdup(contest_name)) == NULL) { tqsl_free_cabrillo_contest(c); return NULL; } c->type = (TQSL_CABRILLO_FREQ_TYPE)contest_type; if ((c->fields = (struct cabrillo_field_def *)calloc(1, sizeof cabrillo_dummy)) == NULL) { tqsl_free_cabrillo_contest(c); return NULL; } memcpy(c->fields, cabrillo_dummy, sizeof cabrillo_dummy); c->fields[0].loc = call_field-1; c->nfields = sizeof cabrillo_dummy / sizeof cabrillo_dummy[0]; return c; } static void tqsl_free_cab(struct TQSL_CABRILLO *cab) { if (!cab || cab->sentinel != 0x2449) return; cab->sentinel = 0; if (cab->filename) free(cab->filename); if (cab->fp) fclose(cab->fp); if (cab->contest) tqsl_free_cabrillo_contest(cab->contest); free(cab); } DLLEXPORT int CALLCONVENTION tqsl_beginCabrillo(tQSL_Cabrillo *cabp, const char *filename) { tqslTrace("tqsl_beginCabrillo", "cabp=0x%lx, filename=%s", cabp, filename); TQSL_CABRILLO_ERROR_TYPE terrno; if (filename == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } struct TQSL_CABRILLO *cab; cab = (struct TQSL_CABRILLO *)calloc(1, sizeof(struct TQSL_CABRILLO)); if (cab == NULL) { tQSL_Error = TQSL_ALLOC_ERROR; goto err; } cab->sentinel = 0x2449; cab->field_idx = -1; #ifdef _WIN32 wchar_t * wfilename = utf8_to_wchar(filename); if ((cab->fp = _wfopen(wfilename, L"rb, ccs=UTF-8")) == NULL) { free_wchar(wfilename); #else if ((cab->fp = fopen(filename, "r")) == NULL) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_beginCabrillo", "open error, errno=%d, error=%s", errno, strerror(errno)); goto err; } #ifdef _WIN32 free_wchar(wfilename); #endif char *cp; terrno = TQSL_CABRILLO_NO_START_RECORD; while ((cp = fgets_cab(cab->rec, sizeof cab->rec, cab->fp)) != 0) { cab->line_no++; if (tqsl_parse_cabrillo_record(cab->rec) != 0 && strstr(cab->rec, "START-OF-LOG")) break; } if (cp != 0) { terrno = TQSL_CABRILLO_NO_CONTEST_RECORD; while ((cp = fgets_cab(cab->rec, sizeof cab->rec, cab->fp)) != 0) { cab->line_no++; char *vp; char *state = NULL; if ((vp = tqsl_parse_cabrillo_record(cab->rec)) != 0 && !strcmp(cab->rec, "CONTEST") && strtok_r(vp, " \t\r\n", &state) != 0) { terrno = TQSL_CABRILLO_UNKNOWN_CONTEST; int callfield, contest_type; if (tqsl_getCabrilloMapEntry(vp, &callfield, &contest_type)) { // No defined contest with this name. // callfield comes back as 0 contest_type = TQSL_CABRILLO_UNKNOWN; } cab->contest = tqsl_new_cabrillo_contest(vp, callfield, contest_type); if (cab->contest == 0) { strncpy(errmsgdata, vp, sizeof errmsgdata); cp = 0; } break; } } } if (cp == 0) { if (ferror(cab->fp)) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; tqslTrace("tqsl_beginCabrillo", "read error, errno=%d, error=%s", errno, strerror(errno)); goto err; } tQSL_Cabrillo_Error = terrno; tQSL_Error = TQSL_CABRILLO_ERROR; goto err; } if ((cab->filename = strdup(filename)) == NULL) { tQSL_Error = TQSL_ALLOC_ERROR; goto err; } *((struct TQSL_CABRILLO **)cabp) = cab; return 0; err: strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile); tQSL_ErrorFile[sizeof tQSL_ErrorFile-1] = 0; tqsl_free_cab(cab); return 1; } DLLEXPORT int CALLCONVENTION tqsl_endCabrillo(tQSL_Cabrillo *cabp) { tqslTrace("tqsl_endCabrillo", "cabp=0x%lx", cabp); TQSL_CABRILLO *cab; if (cabp == 0) return 0; cab = CAST_TQSL_CABRILLO(*cabp); if (!cab || cab->sentinel != 0x2449) return 0; tqsl_free_cab(cab); *cabp = 0; return 0; } DLLEXPORT const char* CALLCONVENTION tqsl_cabrilloGetError(TQSL_CABRILLO_ERROR_TYPE err) { const char *msg = 0; switch (err) { case TQSL_CABRILLO_NO_ERROR: msg = "Cabrillo success"; break; case TQSL_CABRILLO_EOF: msg = "Cabrillo end-of-file"; break; case TQSL_CABRILLO_EOR: msg = "Cabrillo end-of-record"; break; case TQSL_CABRILLO_NO_START_RECORD: msg = "Cabrillo missing START-OF-LOG record"; break; case TQSL_CABRILLO_NO_CONTEST_RECORD: msg = "Cabrillo missing CONTEST record"; break; case TQSL_CABRILLO_UNKNOWN_CONTEST: snprintf(errmsgbuf, sizeof errmsgbuf, "Cabrillo unknown CONTEST: %s", errmsgdata); msg = errmsgbuf; break; case TQSL_CABRILLO_BAD_FIELD_DATA: snprintf(errmsgbuf, sizeof errmsgbuf, "Cabrillo field data error in %s field", errmsgdata); msg = errmsgbuf; break; } if (!msg) { snprintf(errmsgbuf, sizeof errmsgbuf, "Cabrillo unknown error: %d", err); if (errmsgdata[0] != '\0') snprintf(errmsgbuf + strlen(errmsgbuf), sizeof errmsgbuf - strlen(errmsgbuf), " (%s)", errmsgdata); msg = errmsgbuf; } tqslTrace("tqsl_cabrilloGetError", "msg=%s", msg); errmsgdata[0] = '\0'; return msg; } DLLEXPORT int CALLCONVENTION tqsl_getCabrilloField(tQSL_Cabrillo cabp, tqsl_cabrilloField *field, TQSL_CABRILLO_ERROR_TYPE *error) { TQSL_CABRILLO *cab; cabrillo_field_def *fp; const char *fielddat; if ((cab = check_cabrillo(cabp)) == 0) return 1; if (field == 0 || error == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (cab->datap == 0 || cab->field_idx < 0 || cab->field_idx >= cab->contest->nfields) { char *cp; while ((cp = fgets_cab(cab->rec, sizeof cab->rec, cab->fp)) != 0) { cab->line_no++; cab->datap = tqsl_parse_cabrillo_record(cab->rec); if (cab->datap != 0) { if (!strcasecmp(cab->rec, "QSO")) { cab->field_idx = 0; char *state = NULL; char *fieldp = strtok_r(cab->datap, " \t\r\n", &state); memset(cab->fields, 0, sizeof cab->fields); for (int i = 0; fieldp && i < static_cast(sizeof cab->fields / sizeof cab->fields[0]); i++) { cab->fields[i] = fieldp; fieldp = strtok_r(0, " \t\r\n", &state); } break; } else if (!strcasecmp(cab->rec, "END-OF-LOG")) { *error = TQSL_CABRILLO_EOF; return 0; } } } if (cp == 0) { if (ferror(cab->fp)) { tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; goto err; } else { *error = TQSL_CABRILLO_EOF; return 0; } } } // Record data is okay and field index is valid. fp = cab->contest->fields + cab->field_idx; strncpy(field->name, fp->name, sizeof field->name); if (fp->loc < 0) { // New contest // try to guess which field has the 'call-worked' for (int i = 6; i < TQSL_CABRILLO_MAX_FIELDS && cab->fields[i]; i++) { char *p = cab->fields[i]; // Simple parse: a callsign is at least 4 chars long // and has at least one digit and at least one letter // Nothing but alphnumeric and '/' allowed. // First, eliminate grid squares if (strlen(p) == 4) { if (isalpha(p[0]) && isalpha(p[1]) && isdigit(p[2]) && isdigit(p[3])) continue; } int nlet = 0, ndig = 0; for (; *p; p++) { if (isdigit(*p)) { ndig++; } else if (isalpha(*p)) { nlet++; } else if (*p != '/') { ndig = 0; nlet = 0; break; } } if (nlet > 0 && ndig > 0 && nlet+ndig > 3) { // OK, looks like a callsign. Is it possibly a gridsquare? if (strlen(p) == 6) { if ((isalpha(p[0]) && toupper(p[0]) < 'S') && (isalpha(p[1]) && toupper(p[1]) < 'S') && (isdigit(p[2]) && isdigit(p[3])) && (isalpha(p[4]) && toupper(p[4]) < 'Y') && (isalpha(p[5]) && toupper(p[5]) < 'Y')) continue; // Gridsquare. Don't use it. } if (fp->loc < 0) { // No callsign candidate yet fp->loc = i; } else { tQSL_Cabrillo_Error = TQSL_CABRILLO_UNKNOWN_CONTEST; tQSL_Error = TQSL_CABRILLO_ERROR; snprintf(errmsgdata, sizeof errmsgdata, "%s\nUnable to find a unique call-worked field.\n" "Please define a custom Cabrillo entry for this contest.\n", cab->contest->contest_name); goto err; } } } if (fp->loc < 0) { // Still can't find a call. Have to bail. tQSL_Cabrillo_Error = TQSL_CABRILLO_UNKNOWN_CONTEST; tQSL_Error = TQSL_CABRILLO_ERROR; snprintf(errmsgdata, sizeof errmsgdata, "%s\nUnable to find a valid call-worked field.\n" "Please define a custom Cabrillo entry for this contest.\n", cab->contest->contest_name); goto err; } } fielddat = cab->fields[fp->loc]; if (fielddat == 0) { tQSL_Cabrillo_Error = TQSL_CABRILLO_BAD_FIELD_DATA; tQSL_Error = TQSL_CABRILLO_ERROR; strncpy(errmsgdata, field->name, sizeof errmsgdata); goto err; } strncpy(field->value, fielddat, sizeof field->value); if (fp->process && fp->process(cab, field)) { tQSL_Cabrillo_Error = TQSL_CABRILLO_BAD_FIELD_DATA; tQSL_Error = TQSL_CABRILLO_ERROR; strncpy(errmsgdata, field->name, sizeof errmsgdata); goto err; } cab->field_idx++; if (cab->field_idx >= cab->contest->nfields) *error = TQSL_CABRILLO_EOR; else *error = TQSL_CABRILLO_NO_ERROR; return 0; err: cab->datap = NULL; // Ignore this strncpy(tQSL_ErrorFile, cab->filename, sizeof tQSL_ErrorFile); tQSL_ErrorFile[sizeof tQSL_ErrorFile-1] = 0; return 1; } DLLEXPORT int CALLCONVENTION tqsl_getCabrilloContest(tQSL_Cabrillo cabp, char *buf, int bufsiz) { TQSL_CABRILLO *cab; if ((cab = check_cabrillo(cabp)) == 0) return 1; if (buf == 0 || bufsiz <= 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } if (bufsiz < static_cast(strlen(cab->contest->contest_name))+1) { tQSL_Error = TQSL_BUFFER_ERROR; return 1; } strncpy(buf, cab->contest->contest_name, bufsiz); return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCabrilloFreqType(tQSL_Cabrillo cabp, TQSL_CABRILLO_FREQ_TYPE *type) { TQSL_CABRILLO *cab; if ((cab = check_cabrillo(cabp)) == 0) return 1; if (type == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *type = cab->contest->type; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getCabrilloLine(tQSL_Cabrillo cabp, int *lineno) { TQSL_CABRILLO *cab; if ((cab = check_cabrillo(cabp)) == 0) return 1; if (lineno == 0) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *lineno = cab->line_no; return 0; } DLLEXPORT const char* CALLCONVENTION tqsl_getCabrilloRecordText(tQSL_Cabrillo cabp) { TQSL_CABRILLO *cab; if ((cab = check_cabrillo(cabp)) == 0) return 0; return cab->rec; } tqsl-2.8.2/src/adif.h0000644000175000017500000001171515061653721014362 0ustar rmurphyrmurphy/*************************************************************************** adif.h - description ------------------- begin : Wed May 15 2002 copyright : (C) 2002 by ARRL email : MSimcik@localhost.localdomain revision : $Id$ ***************************************************************************/ #ifndef __ADIF_H #define __ADIF_H #include #include /*! \file */ /** \defgroup ADIF ADIF API * * These functions and data structures provide a means of parsing an ADIF * file into its component fields, along with range-checking the field contents. */ /** @{ */ #define TQSL_ADIF_FIELD_NAME_LENGTH_MAX 64 ///< Max length of ADIF field #define TQSL_ADIF_FIELD_SIZE_LENGTH_MAX 10 ///< Max length of field name #define TQSL_ADIF_FIELD_TYPE_LENGTH_MAX 1 ///< Max length of field type /*! \enum TQSL_ADIF_BOOLEAN * Boolean type - TRUE/FALSE */ #ifndef TQSL_ADIF_BOOLEAN typedef enum { TQSL_FALSE, TQSL_TRUE } TQSL_ADIF_BOOLEAN; #endif typedef void * tQSL_ADIF; ///< Opaque ADIF type /// Specifies the type of range limits to apply to a field typedef enum { TQSL_ADIF_RANGE_TYPE_NONE, TQSL_ADIF_RANGE_TYPE_MINMAX, TQSL_ADIF_RANGE_TYPE_ENUMERATION } TQSL_ADIF_RANGE_TYPE; /// Response values returned from tqsl_getADIFField() typedef enum { TQSL_ADIF_GET_FIELD_SUCCESS, TQSL_ADIF_GET_FIELD_NO_NAME_MATCH, TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH, TQSL_ADIF_GET_FIELD_NO_RANGE_MATCH, TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH, TQSL_ADIF_GET_FIELD_NO_RESULT_ALLOCATION, TQSL_ADIF_GET_FIELD_NAME_LENGTH_OVERFLOW, TQSL_ADIF_GET_FIELD_DATA_LENGTH_OVERFLOW, TQSL_ADIF_GET_FIELD_SIZE_OVERFLOW, TQSL_ADIF_GET_FIELD_TYPE_OVERFLOW, TQSL_ADIF_GET_FIELD_ERRONEOUS_STATE, TQSL_ADIF_GET_FIELD_EOF } TQSL_ADIF_GET_FIELD_ERROR; /** An ADIF field definition */ typedef struct { char name[TQSL_ADIF_FIELD_NAME_LENGTH_MAX + 1]; ///< Field name char type[TQSL_ADIF_FIELD_TYPE_LENGTH_MAX + 1]; ///< Field type TQSL_ADIF_RANGE_TYPE rangeType; ///< Range type unsigned int max_length; ///< Max length long signed min_value; ///< Min value long signed max_value; ///< Max value const char **enumStrings; ///< Enumerated values void *userPointer; ///< user pointer } tqsl_adifFieldDefinitions; /** Field returned from parsing */ typedef struct { char name[TQSL_ADIF_FIELD_NAME_LENGTH_MAX + 1]; ///< Field name char size[TQSL_ADIF_FIELD_SIZE_LENGTH_MAX + 1]; ///< Size char type[TQSL_ADIF_FIELD_TYPE_LENGTH_MAX + 1]; ///< Type unsigned char *data; ///< data unsigned int adifNameIndex; ///< Name index void *userPointer; ///< User pointer int line_no; ///< Input line where the tag was found } tqsl_adifFieldResults; /* function prototypes */ #define TQSLLIB_DEF #include "tqsllib.h" #ifdef __cplusplus extern "C" { #endif /** Get the ADIF error message that corresponds to a particular error value */ DLLEXPORT const char* CALLCONVENTION tqsl_adifGetError(TQSL_ADIF_GET_FIELD_ERROR status); /** Initialize an ADIF file for reading */ DLLEXPORT int CALLCONVENTION tqsl_beginADIF(tQSL_ADIF *adifp, const char *filename); /** Get the next field from an ADIF file * * \li \c adif - ADIF handle returned from tqsl_beginADIF() * \li \c field - pointer to struct that contains the field data and description * \li \c status - pointer to returned status variable * \li \c adifFields - pointer to an array of field-definition structures. The last * item in the array should have an empty string as its \c name member. * \li \c typesDefined - pointer to an array of char pointers that define the * allowed field-type strings. The last item in the array should point to * an empty string. * \li \c allocator - pointer to a function that returns a pointer to a memory * block of the specified size. This function will be called at most one * time during a call to tqsl_getADIFField. The returned pointer will then * be used to populate the \c data member of \c field. The caller is * responsible for freeing this memory, if needed. */ DLLEXPORT int CALLCONVENTION tqsl_getADIFField(tQSL_ADIF adif, tqsl_adifFieldResults *field, TQSL_ADIF_GET_FIELD_ERROR *status, const tqsl_adifFieldDefinitions *adifFields, const char * const *typesDefined, unsigned char *(*allocator)(size_t) ); /** Get the current line number (starting from 1) of the input file */ DLLEXPORT int CALLCONVENTION tqsl_getADIFLine(tQSL_ADIF adif, int *lineno); /** End and release an ADIF file */ DLLEXPORT int CALLCONVENTION tqsl_endADIF(tQSL_ADIF *adifp); /** Form an ADIF field string. * * N.B. On systems that distinguish text-mode files from binary-mode files, * notably Windows, the text should be written in binary mode. */ DLLEXPORT int CALLCONVENTION tqsl_adifMakeField(const char *fieldname, char type, const unsigned char *value, int len, unsigned char *buf, int buflen); #ifdef __cplusplus } #endif /** @} */ #endif /* __ADIF_H */ tqsl-2.8.2/src/adif.cpp0000644000175000017500000003632315061653721014717 0ustar rmurphyrmurphy/*************************************************************************** adif.c - description ------------------- begin : Wed May 15 2002 copyright : (C) 2002 by ARRL email : MSimcik@localhost.localdomain revision : $Id$ ***************************************************************************/ //#define TQSLLIB_DEF #include "adif.h" #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "sysconfig.h" #endif #include "tqsllib.h" #include "tqslerrno.h" #include "winstrdefs.h" typedef enum { TQSL_ADIF_STATE_BEGIN, TQSL_ADIF_STATE_GET_NAME, TQSL_ADIF_STATE_GET_SIZE, TQSL_ADIF_STATE_GET_TYPE, TQSL_ADIF_STATE_GET_DATA, TQSL_ADIF_STATE_DONE } TQSL_ADIF_STATE; struct TQSL_ADIF { int sentinel; FILE *fp; char *filename; int line_no; }; #define CAST_TQSL_ADIF(p) ((struct TQSL_ADIF *)p) static char ADIF_ErrorField[TQSL_ADIF_FIELD_NAME_LENGTH_MAX + 1]; static TQSL_ADIF * check_adif(tQSL_ADIF adif) { if (tqsl_init()) return 0; if (adif == 0) return 0; if (CAST_TQSL_ADIF(adif)->sentinel != 0x3345) { tqslTrace("check_adif", "adif no valid sentinel"); return 0; } return CAST_TQSL_ADIF(adif); } static void free_adif(TQSL_ADIF *adif) { tqslTrace("free_adif", NULL); if (adif && adif->sentinel == 0x3345) { adif->sentinel = 0; if (adif->filename) free(adif->filename); if (adif->fp) fclose(adif->fp); free(adif); } } DLLEXPORT int CALLCONVENTION tqsl_beginADIF(tQSL_ADIF *adifp, const char *filename) { tqslTrace("tqsl_beginADIF", "adifp=0x%lx, filename=%s", adifp, filename); if (filename == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } struct TQSL_ADIF *adif; adif = (struct TQSL_ADIF *)calloc(1, sizeof(struct TQSL_ADIF)); if (adif == NULL) { tQSL_Error = TQSL_ALLOC_ERROR; goto err; } adif->sentinel = 0x3345; ADIF_ErrorField[0] = '\0'; tqslTrace("tqsl_beginADIF", "Preparing to open file"); #ifdef _WIN32 wchar_t *wfilename = utf8_to_wchar(filename); if ((adif->fp = _wfopen(wfilename, L"rb, ccs=UTF-8")) == NULL) { free_wchar(wfilename); #else if ((adif->fp = fopen(filename, "rb")) == NULL) { #endif tQSL_Error = TQSL_SYSTEM_ERROR; tQSL_Errno = errno; strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile); tQSL_ErrorFile[sizeof tQSL_ErrorFile-1] = 0; tqslTrace("tqsl_beginADIF", "Error %d errno %d file %s", tQSL_Error, tQSL_Errno, filename); goto err; } #ifdef _WIN32 free_wchar(wfilename); #endif if ((adif->filename = strdup(filename)) == NULL) { tQSL_Error = TQSL_ALLOC_ERROR; goto err; } *((struct TQSL_ADIF **)adifp) = adif; return 0; err: free_adif(adif); return 1; } DLLEXPORT int CALLCONVENTION tqsl_endADIF(tQSL_ADIF *adifp) { tqslTrace("tqsl_endADIF", "adifp=0x%lx", adifp); TQSL_ADIF *adif; if (adifp == 0) return 0; adif = CAST_TQSL_ADIF(*adifp); free_adif(adif); *adifp = 0; return 0; } DLLEXPORT int CALLCONVENTION tqsl_getADIFLine(tQSL_ADIF adifp, int *lineno) { TQSL_ADIF *adif; if (!(adif = check_adif(adifp))) return 1; if (lineno == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *lineno = adif->line_no; return 0; } static void strCatChar(char *str, int character) { while (*str) str++; *str++ = character; *str = '\0'; } DLLEXPORT const char* CALLCONVENTION tqsl_adifGetError(TQSL_ADIF_GET_FIELD_ERROR status) { const char *fmt; static char errorText[512]; switch( status ) { case TQSL_ADIF_GET_FIELD_SUCCESS: fmt = "ADIF success"; break; case TQSL_ADIF_GET_FIELD_NO_NAME_MATCH: fmt = "ADIF field %s no name match"; break; case TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH: fmt = "ADIF field %s no type match"; break; case TQSL_ADIF_GET_FIELD_NO_RANGE_MATCH: fmt = "ADIF field %s no range match"; break; case TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH: fmt = "ADIF field %s no enumeration match"; break; case TQSL_ADIF_GET_FIELD_NO_RESULT_ALLOCATION: fmt = "ADIF field %s no result allocation"; break; case TQSL_ADIF_GET_FIELD_NAME_LENGTH_OVERFLOW: fmt = "ADIF field %s name length overflow"; break; case TQSL_ADIF_GET_FIELD_DATA_LENGTH_OVERFLOW: fmt = "ADIF field %s data length overflow"; break; case TQSL_ADIF_GET_FIELD_SIZE_OVERFLOW: fmt = "ADIF field %s size overflow"; break; case TQSL_ADIF_GET_FIELD_TYPE_OVERFLOW: fmt = "ADIF field %s type overflow"; break; case TQSL_ADIF_GET_FIELD_ERRONEOUS_STATE: fmt = "ADIF erroneously executing default state"; break; case TQSL_ADIF_GET_FIELD_EOF: fmt = "ADIF field %s reached End of File"; break; default: fmt = "ADIF unknown error"; break; } snprintf(errorText, sizeof errorText, fmt, ADIF_ErrorField); tqslTrace("tqsl_getADIFError", "error=%s", errorText); return( errorText ); } static TQSL_ADIF_GET_FIELD_ERROR tqsl_adifGetField(tqsl_adifFieldResults *field, FILE *filehandle, const tqsl_adifFieldDefinitions *adifFields, const char * const *typesDefined, unsigned char *(*allocator)(size_t), int *line_no) { TQSL_ADIF_GET_FIELD_ERROR status; TQSL_ADIF_STATE adifState; int currentCharacter; unsigned int iIndex; unsigned int dataLength = 0; unsigned int dataIndex = 0; TQSL_ADIF_BOOLEAN recordData; /* get the next name value pair */ status = TQSL_ADIF_GET_FIELD_SUCCESS; adifState = TQSL_ADIF_STATE_BEGIN; /* assume that we do not wish to record this data */ recordData = TQSL_FALSE; /* clear the field buffers */ field->name[0] = '\0'; field->size[0] = '\0'; field->type[0] = '\0'; field->data = NULL; field->adifNameIndex = 0; field->userPointer = NULL; field->line_no = -1; while(adifState != TQSL_ADIF_STATE_DONE) { if (EOF != (currentCharacter = fgetc(filehandle))) { if (*line_no == 0) *line_no = 1; if (currentCharacter == '\n') (*line_no)++; switch(adifState) { case TQSL_ADIF_STATE_BEGIN: /* GET STARTED */ /* find the field opening "<", ignoring everything else */ if ('<' == currentCharacter) { adifState = TQSL_ADIF_STATE_GET_NAME; } break; case TQSL_ADIF_STATE_GET_NAME: /* GET FIELD NAME */ /* add field name characters to buffer, until '>' or ':' found */ if (('>' == currentCharacter) || (':' == currentCharacter)) { /* find if the name is a match to a LoTW supported field name */ field->line_no = *line_no; status = TQSL_ADIF_GET_FIELD_NO_NAME_MATCH; adifState = TQSL_ADIF_STATE_GET_SIZE; for(iIndex = 0; (TQSL_ADIF_GET_FIELD_NO_NAME_MATCH == status) && (0 != adifFields[iIndex].name[0]); iIndex++) { /* case insensitive compare */ if (0 == strcasecmp(field->name, adifFields[iIndex].name) || 0 == strcasecmp(adifFields[iIndex].name, "*")) { /* set name index */ field->adifNameIndex = iIndex; /* copy user pointer */ field->userPointer = adifFields[iIndex].userPointer; /* since we know the name, record the data */ recordData = TQSL_TRUE; status = TQSL_ADIF_GET_FIELD_SUCCESS; } if ('>' == currentCharacter) { adifState = TQSL_ADIF_STATE_DONE; } } } else if (strlen(field->name) < TQSL_ADIF_FIELD_NAME_LENGTH_MAX) { /* add to field match string */ strCatChar(field->name, currentCharacter); } else { status = TQSL_ADIF_GET_FIELD_NAME_LENGTH_OVERFLOW; adifState = TQSL_ADIF_STATE_DONE; } break; case TQSL_ADIF_STATE_GET_SIZE: /* GET FIELD SIZE */ /* adding field size characters to buffer, until ':' or '>' found */ if ((':' == currentCharacter) || ('>' == currentCharacter)) { /* reset data copy offset */ dataIndex = 0; /* see if any size was read in */ if (0 != field->size[0]) { /* convert data size to integer */ dataLength = strtol(field->size, NULL, 10); } else { dataLength = 0; } if (':' == currentCharacter) { /* get the type */ adifState = TQSL_ADIF_STATE_GET_TYPE; } else { /* no explicit type, set to LoTW default */ strncpy(field->type, adifFields[(field->adifNameIndex)].type, sizeof field->type); /* get the data */ adifState = dataLength == 0 ? TQSL_ADIF_STATE_DONE : TQSL_ADIF_STATE_GET_DATA; } /* only allocate if we care about the data */ if (recordData) { if (dataLength <= adifFields[(field->adifNameIndex)].max_length) { /* allocate space for data results, and ASCIIZ */ if (NULL != (field->data = (*allocator)(dataLength + 1))) { /* ASCIIZ terminator */ field->data[dataIndex] = 0; } else { status = TQSL_ADIF_GET_FIELD_NO_RESULT_ALLOCATION; adifState = TQSL_ADIF_STATE_DONE; } } else { strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_DATA_LENGTH_OVERFLOW; adifState = TQSL_ADIF_STATE_DONE; } } } else if (strlen(field->size) < TQSL_ADIF_FIELD_SIZE_LENGTH_MAX) { /* add to field size string */ strCatChar(field->size, currentCharacter); } else { strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_SIZE_OVERFLOW; adifState = TQSL_ADIF_STATE_DONE; } break; case TQSL_ADIF_STATE_GET_TYPE: /* GET FIELD TYPE */ /* get the number of characters in the value data */ if ('>' == currentCharacter) { /* check what type of field this is */ /* place default type in, if necessary */ if (0 == field->type[0]) { strncpy(field->type, adifFields[(field->adifNameIndex)].type, sizeof field->type); adifState = dataLength == 0 ? TQSL_ADIF_STATE_DONE : TQSL_ADIF_STATE_GET_DATA; } else { /* find if the type is a match to a LoTW supported data type */ strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH; adifState = TQSL_ADIF_STATE_DONE; for( iIndex = 0; (TQSL_ADIF_GET_FIELD_NO_TYPE_MATCH == status) && (0 != typesDefined[iIndex][0]); iIndex++ ) { /* case insensitive compare */ if (0 == strcasecmp(field->type, typesDefined[iIndex])) { status = TQSL_ADIF_GET_FIELD_SUCCESS; adifState = dataLength == 0 ? TQSL_ADIF_STATE_DONE : TQSL_ADIF_STATE_GET_DATA; } } } } else if (strlen(field->type) < TQSL_ADIF_FIELD_TYPE_LENGTH_MAX) { /* add to field type string */ strCatChar(field->type, currentCharacter); } else { strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_TYPE_OVERFLOW; adifState = TQSL_ADIF_STATE_DONE; } break; case TQSL_ADIF_STATE_GET_DATA: /* GET DATA */ /* read in the prescribed number of characters to form the value */ if (0 != dataLength--) { /* only record if we care about the data */ if (recordData) { /* ASCIIZ copy that is tolerant of binary data too */ field->data[dataIndex++] = (unsigned char)currentCharacter; field->data[dataIndex] = 0; } if (0 == dataLength) adifState = TQSL_ADIF_STATE_DONE; } else { adifState = TQSL_ADIF_STATE_DONE; } break; case TQSL_ADIF_STATE_DONE: /* DONE, should never get here */ default: strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_ERRONEOUS_STATE; adifState = TQSL_ADIF_STATE_DONE; break; } } else { status = TQSL_ADIF_GET_FIELD_EOF; adifState = TQSL_ADIF_STATE_DONE; } } if (TQSL_ADIF_GET_FIELD_SUCCESS == status) { /* check data for enumeration match and range errors */ /* match enumeration */ signed long dataValue; switch(adifFields[(field->adifNameIndex)].rangeType) { case TQSL_ADIF_RANGE_TYPE_NONE: break; case TQSL_ADIF_RANGE_TYPE_MINMAX: dataValue = strtol((const char *)field->data, NULL, 10); if ((dataValue < adifFields[(field->adifNameIndex)].min_value) || (dataValue > adifFields[(field->adifNameIndex)].max_value)) { strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_NO_RANGE_MATCH; } break; case TQSL_ADIF_RANGE_TYPE_ENUMERATION: strncpy(ADIF_ErrorField, field->name, sizeof(ADIF_ErrorField)); status = TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH; for( iIndex = 0; (status == TQSL_ADIF_GET_FIELD_NO_ENUMERATION_MATCH) && (0 != adifFields[(field->adifNameIndex)].enumStrings[iIndex][0]); iIndex++) { /* case insensitive compare */ if (field->data && (0 == strcasecmp((const char *)field->data, adifFields[(field->adifNameIndex)].enumStrings[iIndex]))) { status = TQSL_ADIF_GET_FIELD_SUCCESS; ADIF_ErrorField[0] = '\0'; } } break; } } return( status ); } DLLEXPORT int CALLCONVENTION tqsl_getADIFField(tQSL_ADIF adifp, tqsl_adifFieldResults *field, TQSL_ADIF_GET_FIELD_ERROR *status, const tqsl_adifFieldDefinitions *adifFields, const char * const *typesDefined, unsigned char *(*allocator)(size_t) ) { TQSL_ADIF *adif; if (!(adif = check_adif(adifp))) return 1; if (field == NULL || status == NULL || adifFields == NULL || typesDefined == NULL || allocator == NULL) { tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } *status = tqsl_adifGetField(field, adif->fp, adifFields, typesDefined, allocator, &(adif->line_no)); return 0; } static unsigned char * tqsl_condx_copy(const unsigned char *src, int slen, unsigned char *dest, int *len) { if (slen == 0) return dest; if (slen < 0) slen = strlen((const char *)src); if (*len < slen) { tQSL_Error = TQSL_BUFFER_ERROR; return NULL; } memcpy(dest, src, slen); *len -= slen; return dest+slen; } /* Output an ADIF field to a file descriptor. */ DLLEXPORT int CALLCONVENTION tqsl_adifMakeField(const char *fieldname, char type, const unsigned char *value, int len, unsigned char *buf, int buflen) { if (fieldname == NULL || buf == NULL || buflen <= 0) { /* Silly caller */ tQSL_Error = TQSL_ARGUMENT_ERROR; return 1; } unsigned char *cp; if ((cp = tqsl_condx_copy((const unsigned char *)"<", 1, buf, &buflen)) == NULL) return 1; if ((cp = tqsl_condx_copy((const unsigned char *)fieldname, -1, cp, &buflen)) == NULL) return 1; if (value != NULL && len < 0) len = strlen((const char *)value); if (value != NULL && len != 0) { char nbuf[20]; if ((cp = tqsl_condx_copy((const unsigned char *)":", 1, cp, &buflen)) == NULL) return 1; snprintf(nbuf, sizeof nbuf, "%d", len); if ((cp = tqsl_condx_copy((const unsigned char *)nbuf, -1, cp, &buflen)) == NULL) return 1; if (type && type != ' ' && type != '\0') { if ((cp = tqsl_condx_copy((const unsigned char *)":", 1, cp, &buflen)) == NULL) return 1; if ((cp = tqsl_condx_copy((const unsigned char *)&type, 1, cp, &buflen)) == NULL) return 1; } if ((cp = tqsl_condx_copy((const unsigned char *)">", 1, cp, &buflen)) == NULL) return 1; if ((cp = tqsl_condx_copy(value, len, cp, &buflen)) == NULL) return 1; } else { if ((cp = tqsl_condx_copy((const unsigned char *)">", 1, cp, &buflen)) == NULL) return 1; } if ((cp = tqsl_condx_copy((const unsigned char *)"", 1, cp, &buflen)) == NULL) return 1; return 0; } tqsl-2.8.2/src/LICENSE0000644000175000017500000000450715061653721014314 0ustar rmurphyrmurphyLicense Terms and Conditions Copyright (C) 2001-2020 American Radio Relay League, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Any redistribution of source code must retain the above copyright notice, this list of conditions and the disclaimer shown in Paragraph 5 (below). 2. Redistribution in binary form must reproduce the above copyright notice, this list of conditions and the disclaimer shown in Paragraph 5 (below) in the documentation and/or other materials provided with the distribution. 3. Products derived from or including this software may not use "Logbook of the World" or "LoTW" or any other American Radio Relay League, Incorporated trademarks or servicemarks in their names without prior written permission of the ARRL. See Paragraph 6 (below) for contact information. 4. Use of this software does not imply endorsement by ARRL of products derived from or including this software and vendors may not claim such endorsement. 5. Disclaimer: This software is provided "as-is" without representation, guarantee or warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability or of fitness for a particular purpose. The entire risk as to the quality and performance of the software is solely with you. Should the software prove defective, you (and not the American Radio Relay League, its officers, directors, employees or agents) assume the entire cost of all necessary servicing, repair or correction. In no event will ARRL be liable to you or to any third party for any damages, whether direct or indirect, including lost profits, lost savings, or other incidental or consequential damages arising out of the use or inability to use such software, regardless of whether ARRL has been advised of the possibility of such damages. 6. Contact information: American Radio Relay League, Inc. Attn: Logbook of the World Manager 225 Main St Newington, CT 06111 voice: 860-594-0200 fax: 860-594-0259 email: logbook@arrl.org Worldwide Web: www.arrl.org This software consists of voluntary contributions made by many individuals on behalf of the ARRL. More information on the "Logbook of The World" project and the ARRL is available from the ARRL Web site at www.arrl.org. tqsl-2.8.2/src/Doxyfile0000755000175000017500000035517715061653721015034 0ustar rmurphyrmurphy# Doxyfile 1.9.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). # # Note: # # Use doxygen to compare the used configuration file with the template # configuration file: # doxygen -x [configFile] # Use doxygen to compare the used configuration file with the template # configuration file without replacing the environment variables or CMake type # replacement variables: # doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the configuration # file that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "TrustedQSL Library API" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format # and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to # control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO # Controls the number of sub-directories that will be created when # CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every # level increment doubles the number of directories, resulting in 4096 # directories at level 8 which is the default and also the maximum value. The # sub-directories are organized in 2 levels, the first level always has a fixed # number of 16 directories. # Minimum value: 0, maximum value: 8, default value: 8. # This tag requires that the tag CREATE_SUBDIRS is set to YES. CREATE_SUBDIRS_LEVEL = 8 # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, # Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English # (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, # Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with # English messages), Korean, Korean-en (Korean with English messages), Latvian, # Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, # Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, # Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be # interpreted by doxygen. # The default value is: NO. JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # By default Python docstrings are displayed as preformatted text and doxygen's # special commands cannot be used. By setting PYTHON_DOCSTRING to NO the # doxygen's special commands can be used and the contents of the docstring # documentation blocks is shown as doxygen documentation. # The default value is: YES. PYTHON_DOCSTRING = YES # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". Note that you cannot put \n's in the value part of an alias # to insert newlines (in the resulting output). You can put ^^ in the value part # of an alias to insert a newline as if a physical newline was in the original # file. When you need a literal { or } or , in the value part of an alias you # have to escape them by means of a backslash (\), this can lead to conflicts # with the commands \{ and \} for these it is advised to use the version @{ and # @} or use a double escape (\\{ and \\}) ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice # sources only. Doxygen will then generate output that is more tailored for that # language. For instance, namespaces will be presented as modules, types will be # separated into more groups, etc. # The default value is: NO. OPTIMIZE_OUTPUT_SLICE = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 # The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, # which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual # methods of a class will be included in the documentation. # The default value is: NO. EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If this flag is set to YES, the name of an unnamed parameter in a declaration # will be determined by the corresponding definition. By default unnamed # parameters remain unnamed in the output. # The default value is: YES. RESOLVE_UNNAMED_PARAMS = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # will also hide undocumented C++ concepts if enabled. This option has no effect # if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # With the correct setting of option CASE_SENSE_NAMES doxygen will better be # able to match the capabilities of the underlying filesystem. In case the # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that # are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. # Possible values are: SYSTEM, NO and YES. # The default value is: SYSTEM. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_HEADERFILE tag is set to YES then the documentation for a class # will show which file needs to be included to use the class. # The default value is: YES. SHOW_HEADERFILE = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as documenting some parameters in # a documented function twice, or documenting parameters that don't exist or # using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete # function parameter documentation. If set to NO, doxygen will accept that some # parameters have no documentation without warning. # The default value is: YES. WARN_IF_INCOMPLETE_DOC = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong parameter # documentation, but not about the absence of documentation. If EXTRACT_ALL is # set to YES then this flag will automatically be disabled. See also # WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about # undocumented enumeration values. If set to NO, doxygen will accept # undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: NO. WARN_IF_UNDOC_ENUM_VAL = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = # In the $text part of the WARN_FORMAT command it is possible that a reference # to a more specific place is given. To make it easier to jump to this place # (outside of doxygen) the user can define a custom "cut" / "paste" string. # Example: # WARN_LINE_FORMAT = "'vi $file +$line'" # See also: WARN_FORMAT # The default value is: at line $line of file $file. WARN_LINE_FORMAT = "at line $line of file $file" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). In case the file specified cannot be opened for writing the # warning and error messages are written to standard error. When as file - is # specified the warning and error messages are written to standard output # (stdout). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = tqsllib-doc.h \ tqsllib.h \ tqslerrno.h \ adif.h \ cabrillo.h \ tqslconvert.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. # See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # This tag can be used to specify the character encoding of the source files # that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify # character encoding on a per file pattern basis. Doxygen will compare the file # name with each pattern and apply the encoding instead of the default # INPUT_ENCODING) if there is a match. The character encodings are a list of the # form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding # "INPUT_ENCODING" for further information on supported encodings. INPUT_FILE_ENCODING = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, # *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that doxygen will use the data processed and written to standard output # for further processing, therefore nothing else, like debug statements or used # commands (so in case of a Windows batch file always use @echo OFF), should be # written to standard output. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = # The Fortran standard specifies that for fixed formatted Fortran code all # characters from position 72 are to be considered as comment. A common # extension is to allow longer lines before the automatic comment starts. The # setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can # be processed before the automatic comment starts. # Minimum value: 7, maximum value: 10000, default value: 72. FORTRAN_COMMENT_AFTER = 72 #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: # http://clang.llvm.org/) for more accurate parsing at the cost of reduced # performance. This can be particularly helpful with template rich C++ code for # which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS # tag is set to YES then doxygen will add the directory of each input to the # include path. # The default value is: YES. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the # path to the directory containing a file called compile_commands.json. This # file is the compilation database (see: # http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the # options used when the source files were built. This is equivalent to # specifying the -p option to a clang tool, such as clang-check. These options # will then be passed to the parser. Any options specified with CLANG_OPTIONS # will be added as well. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. CLANG_DATABASE_PATH = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = NO # The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) # that should be ignored while generating the index headers. The IGNORE_PREFIX # tag works for classes, function and member names. The entity will be placed in # the alphabetical list under the first letter of the entity name that remains # after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = tqsllib.css # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). # Note: Since the styling of scrollbars can currently not be overruled in # Webkit/Chromium, the styling will be left out of the default doxygen.css if # one or more extra stylesheets have been specified. So if scrollbar # customization is desired it has to be added explicitly. For an example see the # documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE tag can be used to specify if the generated HTML output # should be rendered with a dark or light theme. # Possible values are: LIGHT always generate light mode output, DARK always # generate dark mode output, AUTO_LIGHT automatically set the mode according to # the user preference, use light mode if no preference is set (the default), # AUTO_DARK automatically set the mode according to the user preference, use # dark mode if no preference is set and TOGGLE allow to user to switch between # light and dark mode via a button. # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE = AUTO_LIGHT # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To # create a documentation set, doxygen will generate a Makefile in the HTML # output directory. Running make will produce the docset in that directory and # running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag determines the URL of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDURL = # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # on Windows. In the beginning of 2021 Microsoft took the original page, with # a.o. the download links, offline the HTML help workshop was already many years # in maintenance mode). You can download the HTML help workshop from the web # archives at Installation executable (see: # http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo # ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location (absolute path # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to # run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine tune the look of the index (see "Fine-tuning the output"). As an # example, the default style sheet generated by doxygen has an example that # shows how to put an image at the root of the tree instead of the PROJECT_NAME. # Since the tree basically has the same information as the tab index, you could # consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the # project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email # addresses. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. OBFUSCATE_EMAILS = YES # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. # Possible values are: png (the default) and svg (looks nicer but requires the # pdf2svg or inkscape tool). # The default value is: png. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FORMULA_FORMAT = png # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # With MATHJAX_VERSION it is possible to specify the MathJax version to be used. # Note that the different versions of MathJax have different requirements with # regards to the different settings, so it is possible that also other MathJax # settings have to be changed when switching between the different MathJax # versions. # Possible values are: MathJax_2 and MathJax_3. # The default value is: MathJax_2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_VERSION = MathJax_2 # When MathJax is enabled you can set the default output format to be used for # the MathJax output. For more details about the output format see MathJax # version 2 (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 # (see: # http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported # for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. The default value is: # - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 # - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # for MathJax version 2 (see # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # For example for MathJax version 3 (see # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /