/* MCVE v3.x C API (c) 2002 by Main Street Softworks, Inc. Written by Brad House This API is being released to the public domain to be modified and used in any manor the holder of this code sees fit. For any questions please contact support@mainstreetsoftworks.com */ #include "libmonetra_main.h" #include "monetra.h" static M_QUEUE *M_FindQueue (M_CONN * myconn, char *identifier) { _M_CONN *conn = (_M_CONN *) (*myconn); M_QUEUE *ptr = NULL; ptr = conn->queue; while (ptr != NULL) { if (ptr->status == M_PENDING && strcmp (ptr->identifier, identifier) == 0) return (ptr); ptr = (M_QUEUE *) ptr->next; if (ptr == conn->queue) break; } return (NULL); } void M_StoreResponseValues (M_QUEUE * queue, char *option, char *value) { if (strcmp (option, "code") == 0) { if (strcmp (value, "AUTH") == 0) queue->code = M_AUTH; else if (strcmp (value, "DENY") == 0) queue->code = M_DENY; else if (strcmp (value, "DUPL") == 0) queue->code = M_DUPL; else if (strcmp (value, "CALL") == 0) queue->code = M_CALL; else if (strcmp (value, "PKUP") == 0) queue->code = M_PKUP; else if (strcmp (value, "RETRY") == 0) queue->code = M_RETRY; else if (strcmp (value, "SETUP") == 0) queue->code = M_SETUP; else if (strcmp (value, "SUCCESS") == 0) queue->code = M_SUCCESS; else if (strcmp (value, "FAIL") == 0) queue->code = M_FAIL; else if (strcmp (value, "TIMEOUT") == 0) queue->code = M_TIMEOUT; else queue->code = M_DENY; } else if (strcmp (option, "avs") == 0) { if (strcmp (value, "GOOD") == 0) queue->avs = M_GOOD; else if (strcmp (value, "BAD") == 0) queue->avs = M_BAD; else if (strcmp (value, "STREET") == 0) queue->avs = M_STREET; else if (strcmp (value, "ZIP") == 0) queue->avs = M_ZIP; else queue->avs = M_UNKNOWN; } else if (strcmp (option, "cv") == 0) { if (strcmp (value, "GOOD") == 0) queue->cv = M_GOOD; else if (strcmp (value, "BAD") == 0) queue->cv = M_BAD; else queue->cv = M_UNKNOWN; } else if (strcmp (option, "auth") == 0) { queue->auth = strdup (value); } else if (strcmp (option, "verbiage") == 0) { queue->text = strdup (value); } else if (strcmp (option, "item") == 0) { queue->item = strdup (value); } else if (strcmp (option, "batch") == 0) { queue->batch = strdup (value); } else if (strcmp (option, "ttid") == 0 || strcmp (option, "tid") == 0 || strcmp (option, "sid") == 0 || strcmp (option, "did") == 0) { queue->tid = M_atoll (value); } } void M_ProcessResponse (M_CONN * myconn, char *identifier, char *message) { long pos = 0; int len = 0; char *line = NULL, *option = NULL, *value = NULL; M_QUEUE *ptr = NULL; // int is_comma_delimiated=0; M_lock (myconn); ptr = M_FindQueue (myconn, identifier); if (ptr == NULL) { M_unlock (myconn); return; } ptr->status = M_DONE; while ((pos = M_ReadLine (message, pos, &line)) != -1) { if (!M_ParseLine (line, &option, &value)) { // is_comma_delimiated=1; ptr->iscommadelimited = 1; free (line); break; } M_StoreResponseValues (ptr, option, value); ptr->parsed_resp = (M_TRANS *) realloc (ptr->parsed_resp, (ptr->resp_fields + 1) * sizeof (M_TRANS)); ptr->parsed_resp[ptr->resp_fields].key = MC_SAFE_strdup (option); ptr->parsed_resp[ptr->resp_fields].value = MC_SAFE_strdup (value); ptr->resp_fields++; free (option); free (value); free (line); } if (ptr->iscommadelimited) { len = strlen (message); ptr->response = (char *) malloc (len + 1); memcpy (ptr->response, message, len); ptr->response[len] = 0; ptr->code = M_SUCCESS; } M_unlock (myconn); } static int M_IP_GetTransParams (char *data, int len, int *start, int *fs, int *finish) { int i; (*start) = -1; (*fs) = -1; (*finish) = -1; for (i = 0; i < len; i++) { switch (data[i]) { case 0x02: if ((*start) == -1) { (*start) = i; } break; case 0x1c: if ((*start) != -1) { (*fs) = i; } break; case 0x03: if ((*start) != -1 && (*fs) != -1) { (*finish) = i; } break; default: break; } if ((*start) != -1 && (*fs) != -1 && (*finish) != -1) { return (1); } } return (0); } static void M_debug_outputbuffer(const char *buffer, int len) { int i, c; for (i=0; i=32 && c<=126) { } else { c=32; } printf("BUFFER: %05d: %c -- HEX: 0x%02X DEC: %02d\r\n", i, c, buffer[i], buffer[i]); } } /* return 1 on success, return 0 on critical failure */ int M_ProcessBuffer (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); int parse_offset = 0, parse_start = 0, parse_fs = 0, parse_finish = 0; char *identifier = NULL, *message = NULL; M_lock (myconn); if (conn->inbuf != NULL) { parse_offset = 0; while (parse_offset < conn->inbuf_cnt && M_IP_GetTransParams (conn->inbuf + parse_offset, conn->inbuf_cnt - parse_offset, &parse_start, &parse_fs, &parse_finish)) { if (parse_start != 0) { M_unlock (myconn); printf("error, first character of buffer is NOT STX. Either bad response from Monetra, or memory corruption from integrated app!\r\n"); printf("Parse offset: %d of %d bytes\r\n", parse_offset, conn->inbuf_cnt); M_debug_outputbuffer(conn->inbuf, conn->inbuf_cnt); return(0); // printf ("error error, should never get here!\r\n"); // return; } conn->inbuf[parse_offset + parse_fs] = 0; conn->inbuf[parse_offset + parse_finish] = 0; identifier = conn->inbuf + (parse_offset + parse_start + 1); message = conn->inbuf + (parse_offset + parse_fs + 1); M_ProcessResponse (myconn, identifier, message); parse_offset += (parse_finish + 1); } if (parse_offset < conn->inbuf_cnt) { memmove (conn->inbuf, conn->inbuf + parse_offset, conn->inbuf_cnt - parse_offset); conn->inbuf_cnt -= parse_offset; conn->inbuf[conn->inbuf_cnt] = 0; } else { free (conn->inbuf); conn->inbuf = NULL; conn->inbuf_cnt = 0; conn->inbuf_alloc = 0; } } M_unlock (myconn); return(1); } M_QUEUE *M_NewQueueSlot (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); M_QUEUE *ptr = NULL, *base = NULL, *last = NULL; ptr = (M_QUEUE *) malloc (sizeof (M_QUEUE)); ptr->next = NULL; ptr->prev = NULL; ptr->status = M_UNUSED; ptr->identifier[0] = 0; ptr->type = 0; ptr->admin = 0; ptr->status = M_NEW; ptr->transaction_fields = 0; ptr->transaction = NULL; ptr->code = -1; ptr->avs = -1; ptr->cv = -1; ptr->auth = NULL; ptr->text = NULL; ptr->tid = -1; ptr->item = NULL; ptr->batch = NULL; ptr->resp_fields = 0; ptr->parsed_resp = NULL; ptr->response = NULL; ptr->iscommadelimited = 0; ptr->separated = NULL; ptr->columns = 0; ptr->rows = 0; base = conn->queue; /* Circular queue! */ if (base == NULL) { conn->queue = ptr; ptr->next = ptr; ptr->prev = ptr; } else { last = base->prev; last->next = ptr; ptr->prev = last; ptr->next = base; base->prev = ptr; } conn->queue_length++; return (ptr); } char *M_StructureTransaction (M_CONN * myconn, M_QUEUE * queue) { char *transaction = NULL; char *temp=NULL; int alloc_len=0; int len=0, templen=0; int i; alloc_len=4096; transaction = (char *) malloc (alloc_len); memset (transaction, 0, alloc_len); if (queue->type == MC_TRAN_PING) { M_snprintf(transaction, alloc_len, "%s", "PING\r\n"); return (transaction); } for (i = 0; i < queue->transaction_fields; i++) { M_asprintf (&temp, "%s=%s\r\n", queue->transaction[i].key, queue->transaction[i].value); if (temp != NULL) { templen=strlen(temp); while (len+templen+1 > alloc_len) { transaction=(char *)realloc(transaction, alloc_len+4096); memset(transaction+alloc_len, 0, 4096); alloc_len+=4096; } memcpy(transaction+len, temp, templen); len+=templen; free(temp); temp=NULL; } } return (transaction); } int M_SendTransaction (M_CONN * myconn, M_QUEUE * queue) { _M_CONN *conn = (_M_CONN *) (*myconn); char *transaction = NULL; char *id = NULL; int ret = 0; id = M_GenerateIdentifier (); transaction = M_StructureTransaction (myconn, queue); if (conn->conn_method == M_FILE) ret = M_SendTransaction_File (myconn, id, transaction); #ifndef DISABLE_IP else ret = M_SendTransaction_IP (myconn, id, transaction); #endif free (transaction); // pos=M_AddOutstandingAuth(myconn, identifier); M_lock (myconn); queue->status = M_PENDING; strcpy (queue->identifier, id); free (id); M_unlock (myconn); return (ret); } int M_verify_trans_in_queue(M_CONN * myconn, M_uintptr identifier) { _M_CONN *conn = (_M_CONN *) (*myconn); void *trans=(void *)identifier; int ret=0; M_QUEUE *queue=NULL, *ptr=NULL; M_lock(myconn); if (conn->validate_identifier) { queue=conn->queue; ptr=queue; while (ptr != NULL) { if (ptr == trans) { ret=1; break; } ptr=ptr->next; /* Don't remember if it's circular .. but just in case */ if (ptr == queue) break; } } else { ret=1; } M_unlock(myconn); return(ret); }