summaryrefslogtreecommitdiff
path: root/libdigidoc/DigiDocError.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdigidoc/DigiDocError.c')
-rw-r--r--libdigidoc/DigiDocError.c604
1 files changed, 604 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocError.c b/libdigidoc/DigiDocError.c
new file mode 100644
index 0000000..9f9f2f3
--- /dev/null
+++ b/libdigidoc/DigiDocError.c
@@ -0,0 +1,604 @@
+#ifdef WIN32
+ #include <windows.h>
+#else
+ #ifdef USEPTHREADS
+ #include <pthread.h>
+ #endif
+ #include <sys/types.h>
+ #include <unistd.h>
+#endif
+#include <string.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocDebug.h>
+
+#define ERR_MAX 179 //number of error codes. Increment, if you add a new error code
+
+ErrorMessage g_ddocErrorStrings[ERR_MAX] = {
+/* ERR_OK */ {"No errors", NO_ERRORS},
+/* ERR_UNSUPPORTED_DIGEST */ {"Digest type is not supported", LIBRARY},
+/* ERR_FILE_READ */ {"Could not open file for reading", USER},
+/* ERR_FILE_WRITE */ {"Could not open file for writing", USER},
+/* ERR_DIGEST_LEN */ {"Wrong digest length", LIBRARY},
+/* ERR_BUF_LEN */ {"Insufficient target buffer length", LIBRARY},
+/* ERR_SIGNATURE_LEN */ {"Wrong signature length", LIBRARY},
+/* ERR_PRIVKEY_READ */ {"Failed to read the private key", TECHNICAL},
+/* ERR_PUBKEY_READ */ {"Failed to read the public key", TECHNICAL},
+/* ERR_CERT_READ */ {"Failed to read certificate", USER},
+/* ERR_SIGNEDINFO_CREATE */ {"Could not create SignedInfo object", LIBRARY},
+/* ERR_SIGNEDINFO_DATA */ {"Could not create SignedInfo object", LIBRARY},
+/* ERR_SIGNEDINFO_FINAL */ {"Could not create SignedInfo object", LIBRARY},
+/* ERR_UNSUPPORTED_FORMAT */ {"Wrong signed document format", TECHNICAL},
+/* ERR_BAD_INDEX */ {"Bad index", LIBRARY},
+/* ERR_TIMESTAMP_DECODE */ {"Failed to decode timestamp", TECHNICAL},
+/* ERR_DIGIDOC_PARSE */ {"Error in document parsing", USER},
+/* ERR_UNSUPPORTED_SIGNATURE */ {"Signature type is not supported", LIBRARY},
+/* ERR_CERT_STORE_READ */ {"Could not read read certificate from certificate store", TECHNICAL},
+/* ERR_SIGPROP_DIGEST */ {"Wrong signature properties digest", TECHNICAL},
+/* ERR_COMPARE */ {"Wrong signature", USER},
+/* ERR_DOC_DIGEST */ {"Wrong document digest", USER},
+/* ERR_MIME_DIGEST */ {"Wrong document mime digest", TECHNICAL},
+/* ERR_SIGNATURE */ {"Wrong signature", TECHNICAL},
+/* ERR_CERT_INVALID */ {"Invalid certificate", TECHNICAL},
+/* ERR_OCSP_UNSUCCESSFUL */ {"OCSP request unsuccessful", TECHNICAL},
+/* ERR_OCSP_UNKNOWN_TYPE */ {"Unknown OCSP type", TECHNICAL},
+/* ERR_OCSP_NO_BASIC_RESP */ {"No OCSP basic responce", TECHNICAL},
+/* ERR_OCSP_WRONG_VERSION */ {"Wrong OCSP version", TECHNICAL},
+/* ERR_OCSP_WRONG_RESPID */ {"Wrong OCSP response id", TECHNICAL},
+/* ERR_OCSP_ONE_RESPONSE */ {"Incorrect OCSP response count", TECHNICAL},
+/* ERR_OCSP_RESP_STATUS */ {"Incorrect OCSP response status", USER},
+/* ERR_OCSP_NO_SINGLE_EXT */ {"No single OCSP responce", TECHNICAL},
+/* ERR_OCSP_NO_NONCE */ {"NONCE is missing", LIBRARY},
+/* ERR_NOTARY_NO_SIGNATURE */ {"Missing signature for Notary", TECHNICAL},
+/* ERR_NOTARY_SIG_MATCH */ {"Notary signature mismatch", USER},
+/* ERR_SIGNERS_CERT_NOT_TRUSTED */ {"Signers cert not trusted, missing CA cert!", USER},
+/* ERR_WRONG_CERT */ {"Wrong certificate", USER},
+/* ERR_NULL_POINTER */ {"Null pointer exception", LIBRARY},
+/* ERR_NULL_CERT_POINTER */ {"Certificate pointer is null", LIBRARY},
+/* ERR_NULL_SER_NUM_POINTER */ {"Certificate Number pointer is null", LIBRARY},
+/* ERR_NULL_KEY_POINTER */ {"Key pointer is null", LIBRARY},
+/* ERR_EMPTY_STRING */ {"Empty string", LIBRARY},
+/* ERR_BAD_DATAFILE_INDEX */ {"Datafile index out of range", LIBRARY},
+/* ERR_BAD_DATAFILE_COUNT */ {"Datafile count is out of sync", LIBRARY},
+/* ERR_BAD_ATTR_COUNT */ {"Attribute counter is out of sync", LIBRARY},
+/* ERR_BAD_ATTR_INDEX */ {"Attribute index is out of range", LIBRARY},
+/* ERR_BAD_SIG_INDEX */ {"Signature index is out of range", LIBRARY},
+/* ERR_BAD_SIG_COUNT */ {"Signature count is out of sync", LIBRARY},
+/* ERR_BAD_ROLE_INDEX */ {"Role index is out of range", LIBRARY},
+/* ERR_BAD_DOCINFO_COUNT */ {"Document info count is out of sync", LIBRARY},
+/* ERR_BAD_DOCINFO_INDEX */ {"Document info index is out of range", LIBRARY},
+/* ERR_BAD_NOTARY_INDEX */ {"Notary index is out of range", LIBRARY},
+/* ERR_BAD_NOTARY_ID */ {"Bad notary ID", LIBRARY},
+/* ERR_BAD_NOTARY_COUNT */ {"Notary count is out of sync", LIBRARY},
+/* ERR_X509_DIGEST */ {"X509 digest creation failed", LIBRARY},
+/* ERR_CERT_LENGTH */ {"Wrong certificate length", LIBRARY},
+/* ERR_PKCS_LIB_LOAD */ {"PKCS #11 DLL load failed", TECHNICAL},
+/* ERR_PKCS_SLOT_LIST */ {"Getting PKCS #11 slot list failed", TECHNICAL},
+/* ERR_PKCS_WRONG_SLOT */ {"No such PKCS #11 slot", TECHNICAL},
+/* ERR_PKCS_LOGIN */ {"No EstID card, wrong PIN or PIN blocked", USER},
+/* ERR_PKCS_PK */ {"Locating private key from EstID failed", TECHNICAL},
+/* ERR_PKCS_CERT_LOC */ {"Reading certificate from EstID failed", TECHNICAL},
+/* ERR_PKCS_CERT_DECODE */ {"Decoding certificate failed", LIBRARY},
+/* ERR_PKCS_SIGN_DATA */ {"Signing data with EstID failed", USER},
+/* ERR_PKCS_CARD_READ */ {"Reading EstID card failed", USER},
+/* ERR_CSP_NO_CARD_DATA */ {"No EstID card, or card can not be read", USER},
+/* ERR_CSP_OPEN_STORE */ {"Can not open system store", TECHNICAL},
+/* ERR_CSP_CERT_FOUND*/ {"Certificate not found from store, probably cetificate not registered", USER},
+/* ERR_CSP_SIGN */ {"CSP signing failed", USER},
+/* ERR_CSP_NO_HASH_START */ {"Can not start CSP hashing", TECHNICAL},
+/* ERR_CSP_NO_HASH */ {"CSP hash failed", LIBRARY},
+/* ERR_CSP_NO_HASH_RESULT */ {"Can not read CSP's hashing result", LIBRARY},
+/* ERR_CSP_OPEN_KEY */ {"Can not open key", TECHNICAL},
+/* ERR_CSP_READ_KEY */ {"Can not read key", TECHNICAL},
+/* ERR_OCSP_SIGN_NOT_SUPPORTED */ {"Requuested OCSP sign method not suported", LIBRARY},
+/* ERR_OCSP_SIGN_CSP_NAME */ {"Can not add Signer's name to requst", LIBRARY},
+/* ERR_CSP_CERT_DECODE */ {"Decoding certificate failed", TECHNICAL},
+/* ERR_OCSP_SIGN_PKCS_NAME */ {"Can not add Signer's name to requst", TECHNICAL},
+/* ERR_OCSP_SIGN_OSLL_CERT */ {"Cannot add cert to OCSP request", TECHNICAL},
+/* ERR_OCSP_SIGN */ {"Can not sign OCSP request", USER},
+/* ERR_CERT_ISSUER */ {"Cert not issued by this CA, or wrong cert signature", USER},
+/* ERR_OCSP_PKCS12_CONTAINER */ {"Can not open pkcs12 container", USER},
+/* ERR_MODIFY_SIGNED_DOC */ {"Cannot modify signed doc. Remove signatures first.", USER},
+/* ERR_NOTARY_EXISTS */ {"Cannot remove signature if notary exists", USER},
+/* ERR_UNSUPPORTED_CERT_SEARCH */ {"Unsuported CERT_SEARCH method", LIBRARY},
+/* ERR_INCORRECT_CERT_SEARCH */ {"Incorrct CERT_SEARCH pattern", LIBRARY},
+/* ERR_BAD_OCSP_RESPONSE_DIGEST */{"Incorrect Notary signature digest", USER},
+/* ERR_LAST_ESTID_CACHED */ {"Wrong certificate in cache. Please try again.", USER},
+/* ERR_BAD_DATAFILE_XML */ {"XML content cannot contain the first XML line", USER},
+/* ERR_UNSUPPORTED_VERSION */ {"Unsupported SK-XML version. Please upgrade!", TECHNICAL},
+/* ERR_UNSUPPORTED_CHARSET */ {"Unsupported charset", TECHNICAL},
+/* ERR_PKCS12_EXPIRED */ {"PKCS#12 certificate has expired. Please get a new onew from www.sk.ee", USER},
+/* ERR_CSP_USER_CANCEL */ {"User canceled certificate selection", USER},
+/* ERR_CSP_NODEFKEY_CONTAINER */ {"Can't find default key container", TECHNICAL},
+/* ERR_CONNECTION_FAILURE */ {"Connection error", USER},
+/* ERR_WRONG_URL_OR_PROXY */ {"Wrong URL or Proxy", USER},
+/* ERR_NULL_PARAM */ {"Mandatory parameter is NULL", LIBRARY},
+/* ERR_BAD_ALLOC */ {"Memory allocation error", LIBRARY},
+/* ERR_CONF_FILE */ {"Error opening configuration file", USER},
+/* ERR_CONF_LINE */ {"Error in configuration file", USER},
+/* ERR_OCSP_CERT_REVOKED */ { "Certificate has been revoked!", USER},
+/* ERR_OCSP_CERT_UNKNOWN */ { "Certificate status unknow! Not supported by this CA?", USER},
+/* ERR_OCSP_PKCS12_NO_FILE */ { "PKCS#12 token file not defined!", USER},
+/* ERR_OCSP_PKCS12_NO_PASSWD */ { "PKCS#12 token file password not defined!", USER},
+/* ERR_BAD_DATAFILE_CONTENT_TYPE */ { "Invalid DataFile content type!", TECHNICAL},
+/* ERR_OCSP_WRONG_URL */ { "Wrong OCSP responder URL!", USER},
+/* ERR_OCSP_MALFORMED */ { "Malformed OCSP request!", TECHNICAL},
+/* ERR_OCSP_INTERNALERR */ { "Internal error in OCSP responder!", USER},
+/* ERR_OCSP_TRYLATER */ { "Try later! OCSP responder is busy", USER},
+/* ERR_OCSP_SIGREQUIRED */ { "Must sign OCSP requests!", USER},
+/* ERR_OCSP_UNAUTHORIZED */ { "Unauthorized OCSP request!", USER},
+/* ERR_UNKNOWN_CA */ { "Unknown Certificate issuer!", USER},
+
+/* ERR_DENC_ENC_METHOD */ { "Invalid encryption method!", TECHNICAL},
+/* ERR_DENC_ENC_XMLNS */ { "Invalid xml namespace!", TECHNICAL},
+/* ERR_DENC_BAD_PROP_IDX */ { "Invalid EncryptionProperty index!", TECHNICAL},
+/* ERR_DENC_BAD_KEY_IDX */ { "Invalid EncryptedKey index!", TECHNICAL},
+/* ERR_DENC_KEY_STATUS */ { "Transport key not ready!", USER},
+/* ERR_DENC_DATA_STATUS */ { "Invalid data status for this operation!", USER},
+/* ERR_DENC_DECRYPT */ { "Failed to decrypt the data!", USER},
+/* ERR_CHARSET_CONVERT */ { "Error converting charsets!", TECHNICAL },
+/* ERR_COMPRESS */ { "Error compressing the data!", TECHNICAL },
+/* ERR_DECOMPRESS */ { "Error decompressing the data!", TECHNICAL },
+/* ERR_OCSP_CERT_NOTFOUND */ { "OCSP Responders cetificate not found!", USER },
+/* ERR_INVALID_CONTENT */ { "Invalid characters in manifest or addres!", USER },
+/* ERR_DENC_NO_KEY_FOUND */ { "No transport key for this smartcard!", USER },
+/* ERR_OCSP_RESP_NOT_TRUSTED */ { "OCSP responder is not trusted! No certificate for this responder in local certstore!", USER },
+/* ERR_PRIV_CERT_NOT_FOUND */ { "Certificate not found!", USER },
+/* ERR_NO_OCSP */ { "Signature has no OCSP confirmation!", USER },
+/* ERR_OCSP_WRONG_SIGNATURE */ { "OCSP signature is wrong!", USER },
+/* ERR_BAD_PARAM */ { "Invalid parameter!", TECHNICAL },
+/* ERR_GENERIC_SOAP_ERR */ { "Generic SOAP error", TECHNICAL },
+
+/* ERR_TS_TIMESTAMPINFO_TYPE */ { "Invalid Timestamp type", TECHNICAL },
+/* ERR_TS_BAD_INCLUDEINFO_IDX */ { "Invalid Include index", TECHNICAL },
+/* ERR_TS_BAD_TIMESTAMPINFO_IDX */ { "Invalid TimestampInfo index", TECHNICAL },
+/* ERR_TS_CREATE_TS_REQ */ { "Error creating timestamp request", TECHNICAL },
+/* ERR_CREATE_NONCE */ { "Error creating nonce", TECHNICAL },
+/* ERR_TXT2OID */ { "Error converting text to OID", TECHNICAL },
+/* ERR_HTTP_ERR */ { "Invalid HTTP response code", TECHNICAL },
+/* ERR_BAD_CERTID_IDX */ { "Invalid Include index", TECHNICAL },
+/* ERR_BAD_CERTVALUE_IDX */ { "Invalid Include index", TECHNICAL },
+/* ERR_TS_VERIFY */ { "Timestamp verification error", USER },
+/* ERR_TS_REQUEST */ { "Error getting timestamp", USER },
+/* ERR_TSA_NOT_TRUSTED */ { "TSA is not trusted! No certificate for this TSA in local certstore!", USER },
+/* ERR_ORPHONED_SIGNATURE */ { "Incomplete or orphoned signature!", TECHNICAL },
+
+
+/* ERR_WPKI_UNKNOWN_USER */ { "Unknown WPKI user!", USER },
+/* ERR_WPKI_INVALID_PHONE_NO */ { "Invalid phone number for this WPKI user!", USER },
+/* ERR_WPKI_UNTRUSTED_SRVICE */ { "WPKI service is not trusted!", USER },
+/* ERR_WPKI_UNTRUSTED_USER */ { "Service demands customer authentication!", USER },
+
+/* ERR_WPKI_UNUSABLE_PHONE */ { "Error signing with customers mobile phone! Unusable phone type?", USER },
+/* ERR_WPKI_TIMEOUT */ { "Timeout during mobile signing!", USER },
+/* ERR_WPKI_CANCELLED */ { "User cancelled mobile signing!", USER },
+/* ERR_WPKI_MID_NOT_READY */ { "MID not ready!", USER },
+/* ERR_WPKI_PHONE_NOT_REACHABLE */ { "Users phone is not reachable!", USER },
+/* ERR_WPKI_SENDING_ERROR */ { "Error sending signing request to users mobile phone!", USER },
+/* ERR_WPKI_SIM_ERROR */ { "SIM card error!", USER },
+/* ERR_WPKI_SERVICE_ERR */ { "Mobile signing service internal error!", USER },
+//AM 18.03.08
+/* ERR_ZIP_FILE_READ */ { "File not found in BDOC!", USER },
+/* ERR_ZIP */ { "Error in BDocZip!", USER },
+/* ERR_MANIFEST */ { "Can't parse manifest!", USER },
+/* ERR_DATAFILE_NOT_MANIFEST */ { "Datafile is not described in manifest.xml!", USER },
+/* ERR_SIG_INVALID_PROFILE */ { "Signature does not correspond to profile in manifest.xml!", USER },
+/* ERR_SIGNERS_CERT_NON_REPU */ { "Signers cert does not have non-repudiation bit set!", USER },
+/* ERR_OCSP_NONCE_SIGVAL_NOMATCH */ { "Calculated signature hash doesn't match to OCSP responder nonce field!", USER },
+/* ERR_VALIDATE */ { "Validation error! Invalid ddoc or cdoc document.", USER },
+/* ERR_OCSP_NONCE_INVALID */ { "Invalid nonce length!", TECHNICAL },
+/* ERR_SIGVAL_ASN1 */ { "Invalid signature value! Missing or wrong asn.1 signature structure", TECHNICAL },
+/* ERR_MAX_1_ROLES */ { "Currently supports no more than 1 ClaimedRoles!", USER },
+/* ERR_DF_NAME */ { "Failed to parse DataFile name. Invalid file name!", USER },
+/* ERR_DF_WRONG_DIG */ { "Invalid DataFile digest! Alternate digest matches.", USER },
+/* ERR_ISSUER_XMLNS */ { "X509IssuerName or X509IssuerSerial missing xmlns atribute", USER },
+/* ERR_OLD_VERSION */ { "SK-XML 1.0 and DIGIDOC-XML 1.1 and 1.2 are old signature formats and schould not be used for new documents", USER },
+/* ERR_TEST_SIGNATURE */ { "Test signature!", USER },
+/* ERR_UNKNOWN_ERROR */ { "Multiple errors. Check the error list!", USER },
+/* ERR_TRANSFORM_UNSUPPORTED */ { "Transform elements are currently not supported!", USER },
+/* ERR_NETWORK_SYNC */ { "Error writing file! Network synchronize timeout.", USER },
+/* ERR_XML_VALIDATION */ { "Signature xml structure validation error", USER },
+
+/* */ {"", NO_ERRORS}
+};
+
+
+//==========< global variables >====================
+
+//int g_ddocLastError = ERR_OK;
+
+#define INITIAL_MAX_THREADS 1
+#define NOT_FOUND -1
+
+#if defined(WIN32)
+ #define THREAD_ID DWORD
+#elif defined(USEPTHREADS)
+ #define THREAD_ID pthread_t
+#else
+ #define THREAD_ID pid_t
+#endif
+
+typedef struct ThreadErrors_st {
+ THREAD_ID tid;
+ int currentErrorIdx;
+ int readErrorIdx;
+ ErrorInfo ddocLastErrors[ERROR_BUF_LENGTH];
+} ThreadErrors;
+
+static int g_threads = 0;
+
+static ThreadErrors **ddocErrors = NULL;
+
+// Following mutual exclusion objects are here to
+// protect access to ddocErrors and g_threads; whenever we access these variables
+// we have to use lock/unlock.
+
+#if defined(USEPTHREADS)
+ pthread_mutex_t m_ddocErrors = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(WIN32)
+ //My bad, no static initializer for critical sections; initialized in DigiDocLib.c
+ CRITICAL_SECTION cs_ddocErrors;
+#endif
+
+// Returns unique thread identifier
+static THREAD_ID getTid(void)
+{
+#if defined(WIN32)
+ return GetCurrentThreadId();
+#elif defined(USEPTHREADS)
+ return pthread_self();
+#else
+ return getpid();
+#endif
+}
+
+static void lock(void)
+{
+#if defined WIN32
+ EnterCriticalSection(&cs_ddocErrors);
+#elif defined USEPTHREADS
+ pthread_mutex_lock(&m_ddocErrors);
+#else
+ // Hope it will be optimized away..
+#endif
+}
+
+
+static void unlock(void)
+{
+#if defined WIN32
+ LeaveCriticalSection(&cs_ddocErrors);
+#elif defined USEPTHREADS
+ pthread_mutex_unlock(&m_ddocErrors);
+#else
+ // Hope it will be optimized away..
+#endif
+}
+
+
+// Grows or creates the array of pointers to ThreadErrors
+// Will be always called with locked mutex.
+static int growErrorTable(void)
+{
+ int slotsToAllocate;
+ int i;
+ ThreadErrors **tmpErrors;
+
+ // printf("growErrorTable init : g_threads=%d, ddocErrors=%p\n", g_threads, ddocErrors);
+ if (g_threads == 0)
+ slotsToAllocate = INITIAL_MAX_THREADS; // We have no table so far at all
+ else
+ slotsToAllocate = g_threads * 2; // We'll double the table size everytime
+ tmpErrors = (ThreadErrors**)realloc(ddocErrors, slotsToAllocate * sizeof(ThreadErrors *)); // MEMLEAK: ???
+ if (tmpErrors == NULL)
+ return ERR_BAD_ALLOC;
+ ddocErrors = tmpErrors;
+ for (i = g_threads; i < slotsToAllocate; i++) // Initialize new entries;
+ ddocErrors[i] = NULL;
+ g_threads = slotsToAllocate;
+ // printf("growErrorTable leave : g_threads=%d, ddocErrors=%p\n", g_threads, ddocErrors);
+ return ERR_OK;
+}
+
+static int isThreadEqual(THREAD_ID tid1, THREAD_ID tid2)
+{
+#if defined(WIN32)
+ return tid1 == tid2;
+#elif defined(USETHREADS)
+ return pthread_equal(tid1, tid2);
+#else
+ return tid1 == tid2;
+#endif
+}
+
+// Finds slot number in ddocErrors[] whose pointer points to ThreadErrors belonging to threadID
+// or returns NOT_FOUND;
+static int findSlotByTid(THREAD_ID threadID)
+{
+ int i;
+
+ lock();
+ if (ddocErrors == NULL) {
+ unlock();
+ return NOT_FOUND;
+ }
+
+ for (i = 0; i < g_threads; i++)
+ if (ddocErrors[i] && isThreadEqual(ddocErrors[i]->tid,threadID)) {
+ unlock();
+ return i;
+ }
+ unlock();
+ return NOT_FOUND;
+}
+
+
+// Finds thread's ThreadError structure address, returns NULL if the thread doesn't have it (yet).
+static ThreadErrors *findThreadErrorsByTid(THREAD_ID threadID)
+{
+ ThreadErrors *tmpThreadErrors;
+ int slot = findSlotByTid(threadID);
+
+ if (slot == NOT_FOUND)
+ return NULL;
+ lock();
+ tmpThreadErrors = ddocErrors[slot];
+ unlock();
+ return tmpThreadErrors;
+}
+
+// Creates ThreadErrors structure for thread Tid, returns pointer to
+// created object; returns NULL if the object wasn't created.
+static ThreadErrors *addThreadErrorsByTid(THREAD_ID Tid)
+{
+ int i, slot = NOT_FOUND;
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors != NULL) // Already present, do nothing
+ return threadErrors;
+ lock();
+ for (i = 0; i < g_threads; i++) {
+ if (ddocErrors[i] == NULL) // Won't enter here if g_threads == 0
+ slot = i; // first free slot found
+ }
+ if (slot == NOT_FOUND) {
+ if (growErrorTable() == ERR_OK) {
+ for (i = 0; i < g_threads; i++) { //Try again...
+ if (ddocErrors[i] == NULL)
+ slot = i;
+ }
+ } else {
+ unlock();
+ return NULL;
+ }
+ }
+
+ threadErrors = (ThreadErrors*)malloc(sizeof(ThreadErrors)); // MEMLEAK: ???
+ if (threadErrors == NULL) {
+ unlock();
+ return NULL;
+ }
+
+ memset(threadErrors, 0, sizeof(ThreadErrors));
+ threadErrors->tid = Tid;
+ threadErrors->readErrorIdx = -1;
+ threadErrors->currentErrorIdx = -1;
+
+ ddocErrors[slot] = threadErrors;
+ unlock();
+ return threadErrors;
+}
+
+// Releases memory allocated for ThreadError structure of thread threadID
+EXP_OPTION void freeThreadErrorsByTid(THREAD_ID threadID)
+{
+ ThreadErrors *threadErrors;
+ int slot = findSlotByTid(threadID);
+
+ if (slot == NOT_FOUND)
+ return;
+
+ threadErrors = findThreadErrorsByTid(threadID);
+
+ lock();
+ free(threadErrors);
+ ddocErrors[slot] = NULL;
+ unlock();
+}
+
+//================< error handling functions> =================================
+
+//returns textual explanation of the error code
+EXP_OPTION char* getErrorString(int code)
+{
+ if(code < ERR_MAX && code >= 0)
+ return g_ddocErrorStrings[code].errorMessage;
+ else
+ return "No error message defined for this error";
+}
+
+EXP_OPTION ErrorClass getErrorClass(int code)
+{
+ if(code < ERR_MAX && code >= 0)
+ return g_ddocErrorStrings[code].errorClass;
+ else
+ return NO_ERRORS;
+}
+
+//returns the last
+EXP_OPTION ErrorInfo* getErrorInfo()
+{
+ ErrorInfo *pErrInfo = 0;
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+
+ if(threadErrors->readErrorIdx >= 0 &&
+ threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code != ERR_OK) {
+ pErrInfo = &(threadErrors->ddocLastErrors[threadErrors->readErrorIdx]);
+ threadErrors->readErrorIdx--;
+ if(threadErrors->readErrorIdx < 0) //roll over
+ threadErrors->readErrorIdx = ERROR_BUF_LENGTH - 1;
+ }
+ else
+ pErrInfo = 0;
+
+ return pErrInfo;
+}
+
+//returns 1, if all errors are read and 0 otherwise
+EXP_OPTION int hasUnreadErrors()
+{
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+ return (threadErrors->readErrorIdx >= 0 ?
+ threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code : ERR_OK);
+}
+
+//returns -1, if all errors are read and valid index otherwise
+EXP_OPTION int getLastErrorsIdx()
+{
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return -1;
+ return threadErrors->readErrorIdx;
+}
+
+//returns NULL, if all errors are read and valid ErrorInfo structre pointer otherwise
+// does not mark error as read so it can be found again
+EXP_OPTION ErrorInfo* getErrorsInfo(int nIdx)
+{
+ ErrorInfo *pErrInfo = 0;
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+
+ if(nIdx >= 0 &&
+ threadErrors->ddocLastErrors[nIdx].code != ERR_OK) {
+ pErrInfo = &(threadErrors->ddocLastErrors[nIdx]);
+ }
+ else
+ pErrInfo = 0;
+
+ return pErrInfo;
+}
+
+
+EXP_OPTION void clearErrors()
+{
+ THREAD_ID Tid = getTid();
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return;
+ memset(threadErrors->ddocLastErrors, 0, sizeof(ErrorInfo) * ERROR_BUF_LENGTH);
+ threadErrors->readErrorIdx = -1;
+ threadErrors->currentErrorIdx = -1;
+}
+
+
+EXP_OPTION void resetError(ErrorInfo *pErrInfo)
+{
+ pErrInfo->code = ERR_OK;
+ pErrInfo->fileName = "";
+ pErrInfo->line = 0;
+ pErrInfo->assertion = "";
+}
+
+
+EXP_OPTION void addError(int code, char *fileName, int line, char *assertion)
+{
+ //no errors found yet. Set a trace-back mark to the end of array.
+ //printf("Error : %d at %s line %d, assertion %s\n", code, fileName, line, assertion);
+
+ ThreadErrors *threadErrors;
+ THREAD_ID Tid = getTid(); //Find our identity
+
+ threadErrors = findThreadErrorsByTid(Tid);
+ // printf("addError init: tid=%ld, threadErrors=%p\n", Tid, threadErrors);
+ if (threadErrors == NULL) { //This Tid has no entry in ThreadErrors table
+ threadErrors = addThreadErrorsByTid(Tid); // MEMLEAK: ???
+ if (threadErrors == NULL)
+ return; // What else can we do?
+ }
+
+ // printf("addError step 1 : tid=%ld, threadErrors=%p\n", Tid, threadErrors);
+ if(threadErrors->currentErrorIdx < 0)
+ resetError(&(threadErrors->ddocLastErrors[ERROR_BUF_LENGTH - 1]));
+
+ threadErrors->currentErrorIdx++;
+
+ //index at the end -> roll it over to the beginning
+ if(threadErrors->currentErrorIdx == ERROR_BUF_LENGTH-1)
+ threadErrors->currentErrorIdx = 0;
+
+ //set the information
+ ddocDebug(4, "addError", "Index: %d Error : %d at %s line %d, assertion %s", threadErrors->currentErrorIdx, code, fileName, line, assertion);
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].code = code;
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].fileName = fileName;
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].line = line;
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].assertion = assertion;
+
+ //index at the end? Set the traceback mark to the beginning
+ if(threadErrors->currentErrorIdx == ERROR_BUF_LENGTH - 1)
+ resetError(&(threadErrors->ddocLastErrors[0]));
+ else //set the traceback mark to the next position
+ resetError(&(threadErrors->ddocLastErrors[threadErrors->currentErrorIdx + 1]));
+
+ threadErrors->readErrorIdx = threadErrors->currentErrorIdx;
+}
+
+//--------------------------------------------------
+// Checks DigiDoc library internal errors
+//--------------------------------------------------
+EXP_OPTION int checkDigiDocErrors()
+{
+ char *errorClass[] = {"NO_ERRORS", "TECHNICAL", "USER", "LIBRARY"};
+ int err = ERR_OK;
+ while(hasUnreadErrors()) {
+ ErrorInfo* pErr = getErrorInfo();
+ char* pErrStr = getErrorString(pErr->code);
+ printf("Error: %d - %s; file: %s line: %d; failed condition: %s, error class : %s\n",
+ pErr->code, pErrStr, pErr->fileName, pErr->line, pErr->assertion, errorClass[getErrorClass(pErr->code)]);
+ err = pErr->code;
+ }
+ clearErrors();
+ return err;
+}
+
+EXP_OPTION int getLastError()
+{
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+ return (threadErrors->readErrorIdx >= 0 ?
+ threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code : ERR_OK);
+}
+
+
+EXP_OPTION int checkUnknownErr(SignedDoc* pSigDoc)
+{
+ int n, m = getLastErrorsIdx(), err1 = 0, err2 = 0;
+ ErrorInfo* pErr;
+
+ // list all errors
+ for(n = m; n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ if(!err1 && pErr) {
+ err1 = pErr->code;
+ }
+ else if(!err2 && pErr && pErr->code != err1)
+ err2 = pErr->code;
+ }
+ return ((err1 != err2 && err2) ? ERR_UNKNOWN_ERROR : err1);
+}
+