Пример #1
0
int main(int argc, char **argv)
{
    double lat, lon;

    if (argc != 3) {
	fprintf(stderr, "Usage: %s lat lon\n", argv[0]);
	return 1;
    }

    lat = safe_atof(argv[1]);
    lon = safe_atof(argv[2]);

    if (lat > 90. || lat < -90.) {
	fprintf(stderr, " -90 <= lat=%s(%.f) <= 90 ?\n", argv[1], lat);
	return 1;
    }

    if (lon > 180. || lat < -180.) {
	fprintf(stderr, " -180 <= lon=%s(%.f) <= 180 ?\n", argv[2], lon);
	return 1;
    }

    printf(" lat= %f lon= %f geoid correction= %f\n",
	   lat, lon, wgs84_separation(lat, lon));

    return 0;
}
Пример #2
0
timestamp_t iso8601_to_unix(char *isotime)
/* ISO8601 UTC to Unix UTC, no leapsecond correction. */
{
#ifndef __clang_analyzer__
#ifndef USE_QT
    char *dp = NULL;
    double usec = 0;
    struct tm tm;
    memset(&tm,0,sizeof(tm));

#ifdef HAVE_STRPTIME
    dp = strptime(isotime, "%Y-%m-%dT%H:%M:%S", &tm);
#else
    /* Fallback for systems without strptime (i.e. Windows)
       This is a simplistic conversion for iso8601 strings only,
       rather than embedding a full copy of strptime() that handles all formats */
    double sec;
    unsigned int tmp; // Thus avoiding needing to test for (broken) negative date/time numbers in token reading - only need to check the upper range
    bool failed = false;
    char *isotime_tokenizer = strdup(isotime);
    if (isotime_tokenizer) {
      char *tmpbuf;
      char *pch = strtok_r(isotime_tokenizer, "-T:", &tmpbuf);
      int token_number = 0;
      while (pch != NULL) {
	token_number++;
	// Give up if encountered way too many tokens.
	if (token_number > 10) {
	  failed = true;
	  break;
	}
	switch (token_number) {
	case 1: // Year token
	  tmp = atoi(pch);
	  if (tmp < 9999)
	    tm.tm_year = tmp - 1900; // Adjust to tm year
	  else
	    failed = true;
	  break;
	case 2: // Month token
	  tmp = atoi(pch);
	  if (tmp < 13)
	    tm.tm_mon = tmp - 1; // Month indexing starts from zero
	  else
	    failed = true;
	  break;
	case 3: // Day token
	  tmp = atoi(pch);
	  if (tmp < 32)
	    tm.tm_mday = tmp;
	  else
	    failed = true;
	  break;
	case 4: // Hour token
	  tmp = atoi(pch);
	  if (tmp < 24)
	    tm.tm_hour = tmp;
	  else
	    failed = true;
	  break;
	case 5: // Minute token
	  tmp = atoi(pch);
	  if (tmp < 60)
	    tm.tm_min = tmp;
	  else
	    failed = true;
	  break;
	case 6: // Seconds token
	  sec = safe_atof(pch);
	  // NB To handle timestamps with leap seconds
	  if (sec >= 0.0 && sec < 61.5 ) {
	    tm.tm_sec = (unsigned int)sec; // Truncate to get integer value
	    usec = sec - (unsigned int)sec; // Get the fractional part (if any)
	  }
	  else
	    failed = true;
	  break;
	default: break;
	}
	pch = strtok_r(NULL, "-T:", &tmpbuf);
      }
      free(isotime_tokenizer);
      // Split may result in more than 6 tokens if the TZ has any t's in it
      // So check that we've seen enough tokens rather than an exact number
      if (token_number < 6)
	failed = true;
    }
    if (failed)
      memset(&tm,0,sizeof(tm));
    else {
      // When successful this normalizes tm so that tm_yday is set
      //  and thus tm is valid for use with other functions
      if (mktime(&tm) == (time_t)-1)
	// Failed mktime - so reset the timestamp
	memset(&tm,0,sizeof(tm));
    }
#endif
    if (dp != NULL && *dp == '.')
	usec = strtod(dp, NULL);
    /*
     * It would be nice if we could say mktime(&tm) - timezone + usec instead,
     * but timezone is not available at all on some BSDs. Besides, when working
     * with historical dates the value of timezone after an ordinary tzset(3)
     * can be wrong; you have to do a redirect through the IANA historical
     * timezone database to get it right.
     */
    return (timestamp_t)mkgmtime(&tm) + usec;
#else
    double usec = 0;

    QString t(isotime);
    QDateTime d = QDateTime::fromString(isotime, Qt::ISODate);
    QStringList sl = t.split(".");
    if (sl.size() > 1)
	usec = sl[1].toInt() / pow(10., (double)sl[1].size());
    return (timestamp_t)(d.toTime_t() + usec);
#endif
#endif /* __clang_analyzer__ */
}
Пример #3
0
int read_pqr_box ( FILE * fp, system_t * system ) {

	char buffer[MAXLINE], token[7][MAXLINE];
	char msg[MAXLINE];
	int basis_set[3];

	output("INPUT: (read_pqr_box) checking input pqr for basis info\n");

	//flags to make sure we set all basis vectors
	basis_set[0]=basis_set[1]=basis_set[2]=0; 
	while ( fgets(buffer, MAXLINE, fp) != NULL ) {
		sscanf(buffer, "%s %s %s %s %s %s %s", 
			token[0], token[1], token[2], token[3], token[4], token[5], token[6]);

		if ( (!strncmp(token[0],"END",3)) ) break; //if end of molecule, then stop searching

		if ( (!strcmp(token[0],"REMARK")) && (!strcmp(token[1],"BOX")) && (!strcmp(token[3],"=")) ) {
			if (!strcmp(token[2],"BASIS[0]")) { //set basis[0]
				{ if (safe_atof(token[4],&(system->pbc->basis[0][0]))) continue; } //make sure each conversion is successful
				{ if (safe_atof(token[5],&(system->pbc->basis[0][1]))) continue; }
				{ if (safe_atof(token[6],&(system->pbc->basis[0][2]))) continue; }
				//if we get this far, then we've successfully read in the basis vector
				basis_set[0] = 1;
			}
			if (!strcmp(token[2],"BASIS[1]")) { //set basis[0]
				{ if (safe_atof(token[4],&(system->pbc->basis[1][0]))) continue; } //make sure each conversion is successful
				{ if (safe_atof(token[5],&(system->pbc->basis[1][1]))) continue; }
				{ if (safe_atof(token[6],&(system->pbc->basis[1][2]))) continue; }
				//if we get this far, then we've successfully read in the basis vector
				basis_set[1] = 1;
			}
			if (!strcmp(token[2],"BASIS[2]")) { //set basis[0]
				{ if (safe_atof(token[4],&(system->pbc->basis[2][0]))) continue; } //make sure each conversion is successful
				{ if (safe_atof(token[5],&(system->pbc->basis[2][1]))) continue; }
				{ if (safe_atof(token[6],&(system->pbc->basis[2][2]))) continue; }
				//if we get this far, then we've successfully read in the basis vector
				basis_set[2] = 1;
			}
			else continue;
		}
		else continue;
	}

	if (basis_set[0] == 1) {
		sprintf(msg,"INPUT: basis[0] successfully read from pqr {%.5lf %.5lf %.5lf}\n", 
			system->pbc->basis[0][0], system->pbc->basis[0][1], system->pbc->basis[0][2]);
		output(msg);
	} else {
		sprintf(msg,"INPUT: unable to read basis[0] from pqr file.\n");
		error(msg);
	}	
	if (basis_set[1] == 1) {
		sprintf(msg,"INPUT: basis[1] successfully read from pqr {%.5lf %.5lf %.5lf}\n", 
			system->pbc->basis[1][0], system->pbc->basis[1][1], system->pbc->basis[1][2]);
		output(msg);
	}	else {
		sprintf(msg,"INPUT: unable to read basis[1] from pqr file.\n");
		error(msg);
	}	
	if (basis_set[2] == 1) {
		sprintf(msg,"INPUT: basis[2] successfully read from pqr {%.5lf %.5lf %.5lf}\n", 
			system->pbc->basis[2][0], system->pbc->basis[2][1], system->pbc->basis[2][2]);
		output(msg);
	}	else {
		sprintf(msg,"INPUT: unable to read basis[2] from pqr file.\n");
		error(msg);
	}

	return 0;
}
Пример #4
0
static int json_internal_read_object(const char *cp,
				     const struct json_attr_t *attrs,
				     const struct json_array_t *parent,
				     int offset,
				     const char **end)
{
    enum
    { init, await_attr, in_attr, await_value, in_val_string,
	in_escape, in_val_token, post_val, post_array
    } state = 0;
#ifdef CLIENTDEBUG_ENABLE
    char *statenames[] = {
	"init", "await_attr", "in_attr", "await_value", "in_val_string",
	"in_escape", "in_val_token", "post_val", "post_array",
    };
#endif /* CLIENTDEBUG_ENABLE */
    char attrbuf[JSON_ATTR_MAX + 1], *pattr = NULL;
    char valbuf[JSON_VAL_MAX + 1], *pval = NULL;
    bool value_quoted = false;
    char uescape[5];		/* enough space for 4 hex digits and a NUL */
    const struct json_attr_t *cursor;
    int substatus, n, maxlen = 0;
    unsigned int u;
    const struct json_enum_t *mp;
    char *lptr;

    if (end != NULL)
	*end = NULL;		/* give it a well-defined value on parse failure */

    /* stuff fields with defaults in case they're omitted in the JSON input */
    for (cursor = attrs; cursor->attribute != NULL; cursor++)
	if (!cursor->nodefault) {
	    lptr = json_target_address(cursor, parent, offset);
	    if (lptr != NULL)
		switch (cursor->type) {
		case t_integer:
		    memcpy(lptr, &cursor->dflt.integer, sizeof(int));
		    break;
		case t_uinteger:
		    memcpy(lptr, &cursor->dflt.uinteger, sizeof(unsigned int));
		    break;
		case t_short:
		    memcpy(lptr, &cursor->dflt.shortint, sizeof(short));
		    break;
		case t_ushort:
		    memcpy(lptr, &cursor->dflt.ushortint,
		           sizeof(unsigned short));
		    break;
		case t_time:
		case t_real:
		    memcpy(lptr, &cursor->dflt.real, sizeof(double));
		    break;
		case t_string:
		    if (parent != NULL
			&& parent->element_type != t_structobject
			&& offset > 0)
			return JSON_ERR_NOPARSTR;
		    lptr[0] = '\0';
		    break;
		case t_boolean:
		    memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
		    break;
		case t_character:
		    lptr[0] = cursor->dflt.character;
		    break;
		case t_object:	/* silences a compiler warning */
		case t_structobject:
		case t_array:
		case t_check:
		case t_ignore:
		    break;
		}
	}

    json_debug_trace((1, "JSON parse of '%s' begins.\n", cp));

    /* parse input JSON */
    for (; *cp != '\0'; cp++) {
	json_debug_trace((2, "State %-14s, looking at '%c' (%p)\n",
			  statenames[state], *cp, cp));
	switch (state) {
	case init:
	    if (isspace((unsigned char) *cp))
		continue;
	    else if (*cp == '{')
		state = await_attr;
	    else {
		json_debug_trace((1,
				  "Non-WS when expecting object start.\n"));
#ifndef JSON_MINIMAL
		if (end != NULL)
		    *end = cp;
#endif /* JSON_MINIMAL */
		return JSON_ERR_OBSTART;
	    }
	    break;
	case await_attr:
	    if (isspace((unsigned char) *cp))
		continue;
	    else if (*cp == '"') {
		state = in_attr;
		pattr = attrbuf;
#ifndef JSON_MINIMAL
		if (end != NULL)
		    *end = cp;
#endif /* JSON_MINIMAL */
	    } else if (*cp == '}')
		break;
	    else {
		json_debug_trace((1, "Non-WS when expecting attribute.\n"));
#ifndef JSON_MINIMAL
		if (end != NULL)
		    *end = cp;
#endif /* JSON_MINIMAL */
		return JSON_ERR_ATTRSTART;
	    }
	    break;
	case in_attr:
	    if (pattr == NULL)
		/* don't update end here, leave at attribute start */
		return JSON_ERR_NULLPTR;
	    if (*cp == '"') {
		*pattr++ = '\0';
		json_debug_trace((1, "Collected attribute name %s\n",
				  attrbuf));
		for (cursor = attrs; cursor->attribute != NULL; cursor++) {
		    json_debug_trace((2, "Checking against %s\n",
				      cursor->attribute));
		    if (strcmp(cursor->attribute, attrbuf) == 0)
			break;
		}
		if (cursor->attribute == NULL) {
		    json_debug_trace((1,
				      "Unknown attribute name '%s' (attributes begin with '%s').\n",
				      attrbuf, attrs->attribute));
		    /* don't update end here, leave at attribute start */
		    return JSON_ERR_BADATTR;
		}
		state = await_value;
		if (cursor->type == t_string)
		    maxlen = (int)cursor->len - 1;
		else if (cursor->type == t_check)
		    maxlen = (int)strlen(cursor->dflt.check);
		else if (cursor->type == t_time || cursor->type == t_ignore)
		    maxlen = JSON_VAL_MAX;
		else if (cursor->map != NULL)
		    maxlen = (int)sizeof(valbuf) - 1;
		pval = valbuf;
	    } else if (pattr >= attrbuf + JSON_ATTR_MAX - 1) {
		json_debug_trace((1, "Attribute name too long.\n"));
		/* don't update end here, leave at attribute start */
		return JSON_ERR_ATTRLEN;
	    } else
		*pattr++ = *cp;
	    break;
	case await_value:
	    if (isspace((unsigned char) *cp) || *cp == ':')
		continue;
	    else if (*cp == '[') {
		if (cursor->type != t_array) {
		    json_debug_trace((1,
				      "Saw [ when not expecting array.\n"));
#ifndef JSON_MINIMAL
		    if (end != NULL)
			*end = cp;
#endif /* JSON_MINIMAL */
		    return JSON_ERR_NOARRAY;
		}
		substatus = json_read_array(cp, &cursor->addr.array, &cp);
		if (substatus != 0)
		    return substatus;
		state = post_array;
	    } else if (cursor->type == t_array) {
		json_debug_trace((1,
				  "Array element was specified, but no [.\n"));
#ifndef JSON_MINIMAL
		if (end != NULL)
		    *end = cp;
#endif /* JSON_MINIMAL */
		return JSON_ERR_NOBRAK;
	    } else if (*cp == '"') {
		value_quoted = true;
		state = in_val_string;
		pval = valbuf;
	    } else {
		value_quoted = false;
		state = in_val_token;
		pval = valbuf;
		*pval++ = *cp;
	    }
	    break;
	case in_val_string:
	    if (pval == NULL)
		/* don't update end here, leave at value start */
		return JSON_ERR_NULLPTR;
	    if (*cp == '\\')
		state = in_escape;
	    else if (*cp == '"') {
		*pval++ = '\0';
		json_debug_trace((1, "Collected string value %s\n", valbuf));
		state = post_val;
	    } else if (pval > valbuf + JSON_VAL_MAX - 1
		       || pval > valbuf + maxlen) {
		json_debug_trace((1, "String value too long.\n"));
		/* don't update end here, leave at value start */
		return JSON_ERR_STRLONG;	/*  */
	    } else
		*pval++ = *cp;
	    break;
	case in_escape:
	    if (pval == NULL)
		/* don't update end here, leave at value start */
		return JSON_ERR_NULLPTR;
	    switch (*cp) {
	    case 'b':
		*pval++ = '\b';
		break;
	    case 'f':
		*pval++ = '\f';
		break;
	    case 'n':
		*pval++ = '\n';
		break;
	    case 'r':
		*pval++ = '\r';
		break;
	    case 't':
		*pval++ = '\t';
		break;
	    case 'u':
		for (n = 0; n < 4 && cp[n] != '\0'; n++)
		    uescape[n] = *cp++;
		--cp;
		(void)sscanf(uescape, "%04x", &u);
		*pval++ = (char)u;	/* will truncate values above 0xff */
		break;
	    default:		/* handles double quote and solidus */
		*pval++ = *cp;
		break;
	    }
	    state = in_val_string;
	    break;
	case in_val_token:
	    if (pval == NULL)
		/* don't update end here, leave at value start */
		return JSON_ERR_NULLPTR;
	    if (isspace((unsigned char) *cp) || *cp == ',' || *cp == '}') {
		*pval = '\0';
		json_debug_trace((1, "Collected token value %s.\n", valbuf));
		state = post_val;
		if (*cp == '}' || *cp == ',')
		    --cp;
	    } else if (pval > valbuf + JSON_VAL_MAX - 1) {
		json_debug_trace((1, "Token value too long.\n"));
		/* don't update end here, leave at value start */
		return JSON_ERR_TOKLONG;
	    } else
		*pval++ = *cp;
	    break;
	    /* coverity[unterminated_case] */
	case post_val:
	    /*
	     * We know that cursor points at the first spec matching
	     * the current attribute.  We don't know that it's *the*
	     * correct spec; our dialect allows there to be any number
	     * of adjacent ones with the same attrname but different
	     * types.  Here's where we try to seek forward for a
	     * matching type/attr pair if we're not looking at one.
	     */
	    for (;;) {
		int seeking = cursor->type;
		if (value_quoted && (cursor->type == t_string || cursor->type == t_time))
		    break;
		if ((strcmp(valbuf, "true")==0 || strcmp(valbuf, "false")==0)
			&& seeking == t_boolean)
		    break;
		if (isdigit((unsigned char) valbuf[0])) {
		    bool decimal = strchr(valbuf, '.') != NULL;
		    if (decimal && seeking == t_real)
			break;
		    if (!decimal && (seeking == t_integer || seeking == t_uinteger))
			break;
		}
		if (cursor[1].attribute==NULL)	/* out of possiblities */
		    break;
		if (strcmp(cursor[1].attribute, attrbuf)!=0)
		    break;
		++cursor;
	    }
	    if (value_quoted
		&& (cursor->type != t_string && cursor->type != t_character
		    && cursor->type != t_check && cursor->type != t_time
		    && cursor->type != t_ignore && cursor->map == 0)) {
		json_debug_trace((1,
				  "Saw quoted value when expecting non-string.\n"));
		return JSON_ERR_QNONSTRING;
	    }
	    if (!value_quoted
		&& (cursor->type == t_string || cursor->type == t_check
		    || cursor->type == t_time || cursor->map != 0)) {
		json_debug_trace((1,
				  "Didn't see quoted value when expecting string.\n"));
		return JSON_ERR_NONQSTRING;
	    }
	    if (cursor->map != 0) {
		for (mp = cursor->map; mp->name != NULL; mp++)
		    if (strcmp(mp->name, valbuf) == 0) {
			goto foundit;
		    }
		json_debug_trace((1, "Invalid enumerated value string %s.\n",
				  valbuf));
		return JSON_ERR_BADENUM;
	      foundit:
		(void)snprintf(valbuf, sizeof(valbuf), "%d", mp->value);
	    }
	    lptr = json_target_address(cursor, parent, offset);
	    if (lptr != NULL)
		switch (cursor->type) {
		case t_integer:
		    {
			int tmp = atoi(valbuf);
			memcpy(lptr, &tmp, sizeof(int));
		    }
		    break;
		case t_uinteger:
		    {
			unsigned int tmp = (unsigned int)atoi(valbuf);
			memcpy(lptr, &tmp, sizeof(unsigned int));
		    }
		    break;
		case t_short:
		    {
			short tmp = atoi(valbuf);
			memcpy(lptr, &tmp, sizeof(short));
		    }
		    break;
		case t_ushort:
		    {
			unsigned short tmp = (unsigned int)atoi(valbuf);
			memcpy(lptr, &tmp, sizeof(unsigned short));
		    }
		    break;
		case t_time:
		    {
			double tmp = iso8601_to_unix(valbuf);
			memcpy(lptr, &tmp, sizeof(double));
		    }
		    break;
		case t_real:
		    {
			double tmp = safe_atof(valbuf);
			memcpy(lptr, &tmp, sizeof(double));
		    }
		    break;
		case t_string:
		    if (parent != NULL
			&& parent->element_type != t_structobject
			&& offset > 0)
			return JSON_ERR_NOPARSTR;
		    (void)strlcpy(lptr, valbuf, cursor->len);
		    break;
		case t_boolean:
		    {
			bool tmp = (strcmp(valbuf, "true") == 0);
			memcpy(lptr, &tmp, sizeof(bool));
		    }
		    break;
		case t_character:
		    if (strlen(valbuf) > 1)
			/* don't update end here, leave at value start */
			return JSON_ERR_STRLONG;
		    else
			lptr[0] = valbuf[0];
		    break;
		case t_ignore:	/* silences a compiler warning */
		case t_object:	/* silences a compiler warning */
		case t_structobject:
		case t_array:
		    break;
		case t_check:
		    if (strcmp(cursor->dflt.check, valbuf) != 0) {
			json_debug_trace((1,
					  "Required attribute value %s not present.\n",
					  cursor->dflt.check));
			/* don't update end here, leave at start of attribute */
			return JSON_ERR_CHECKFAIL;
		    }
		    break;
		}
	case post_array:
	    if (isspace((unsigned char) *cp))
		continue;
	    else if (*cp == ',')
		state = await_attr;
	    else if (*cp == '}') {
		++cp;
		goto good_parse;
	    } else {
		json_debug_trace((1, "Garbage while expecting comma or }\n"));
#ifndef JSON_MINIMAL
		if (end != NULL)
		    *end = cp;
#endif /* JSON_MINIMAL */
		return JSON_ERR_BADTRAIL;
	    }
	    break;
	}
    }

  good_parse:
    /* in case there's another object following, consume trailing WS */
    while (isspace((unsigned char) *cp))
	++cp;
    if (end != NULL)
	*end = cp;
    json_debug_trace((1, "JSON parse ends.\n"));
    return 0;
}
Пример #5
0
int lookupGeoIPWebService(
   const int iRetGeo,
   DB_QCN_HOST_IPADDR& qhip,
   DB_QCN_GEO_IPADDR&  qgip,
   DB_QCN_TRIGGER&     qtrig,
   const double* dmxy,
   const double* dmz
)
{
                 int iReturn = iRetGeo; // "seed" our return code with the initial return code value
                 char *strURL = NULL, *strReply = NULL;

                 // the switch is the reply/return code from the lookup query into the qcn_geo_ipaddr table
                 // note that we may want to set error return code (iRetGeo) to 0 if it seems that this record
                 // will never get input, otherwise it will "nak" and retry (but if it's a bad GeoIP lookup, why bother?)

                 switch(iRetGeo) {
                    case ERR_DB_NOT_FOUND:  // no record, need to do a maxmind/geoip web service lookup!
                       strURL   = new char[BYTESIZE_URL];
                       strReply = new char[BYTESIZE_CURL];
                       memset(strURL, 0x00, sizeof(char) * BYTESIZE_URL);
                       memset(strReply, 0x00, sizeof(char) * BYTESIZE_CURL);
                       sprintf(strURL, FORMAT_MAXMIND, qtrig.ipaddr);
                       if (strlen(qtrig.ipaddr) > 6 && strlen(qtrig.ipaddr) < 16 &&  execute_curl(strURL, strReply, 512))  {
                          // returned OK, now check strReply -- should be a single line of comma-delimited fields:
                          // Returns: ISO 3166 Two-letter Country Code, Region Code, City, Latitude, Longitude, Error code
                          // good reply: (note 4 commas/5 fields)
                          //    GB,K2,Oxford,51.750000,-1.250000
                          // error reply: (note 5 commas/6 fields all null except last)
                          //    ,,,,,IP_NOT_FOUND
                          char* strComma[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
                          int i = 0;
                          strComma[0] = strchr(strReply, ',');  // get the first comma
                          for (i = 1; strComma[0] && i < 6; i++)  { // parse out fields
                             // search for next comma if last value wasn't NULL and haven't gone past the end of strReply
                             if (strComma[i-1] && strlen(strReply) > (size_t)(strComma[i-1] - strReply + 1)) {
                                strComma[i] = strchr(strComma[i-1]+1, ','); // note we skip a char to move off current comma ptr
                                if (!strComma[i]) break;  // if this is null, i.e.no comma found, may as well break
                             }
                          }
                          if (i<4 || strComma[4] || strComma[5]) { // if this isn't null, or less than 4 commas found, then there was an error
                            iReturn = 0; // ip not found, but this is a bad format web service lookup, so let's not bother retrying...
                            log_messages.printf(
                              SCHED_MSG_LOG::MSG_CRITICAL,
                              "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2] Maxmind/GeoIP web lookup for IP %s via %s to %s failed\nReply: %s\n",
                              qtrig.hostid, qtrig.result_name, qtrig.time_received, qtrig.ipaddr, "libcurl", strURL, strReply
                            );
                          }
                          else {
                            // seems like a legit reply, so parse out
                            // note we need to insert into qcn_geo_ipaddr, get insert_id(), then insert into host_ipaddr & trigger
                            iReturn = 0; // success

                            // initialize vars for the copies
                            memset(&qgip.country, 0x00, sizeof(qgip.country));
                            memset(&qgip.region, 0x00, sizeof(qgip.region));
                            memset(&qgip.city, 0x00, sizeof(qgip.city));

                            // set location as geoip
                            strcpy(qhip.location, "geoip");    // mark as geoip (also noted in field  geoipaddr i.e points to qcn_geo_ipaddr record)

                            qgip.time_lookup = dtime(); // returns a double of current time, # of seconds since epoch

                            strncpy(qgip.country, strReply, strComma[0]-strReply);  // first comma entry is country; note length is OK starting from strReply
                            strncpy(qgip.region, strComma[0]+1, strComma[1]-strComma[0]-1);  // next is region, note subtract 1 from length (, position)
                            strncpy(qgip.city, strComma[1]+1, strComma[2]-strComma[1]-1);  // next is city

                            char *strTmp = new char[32];
                            memset(strTmp, 0x00, sizeof(char) * 32);
                            strncpy(strTmp, strComma[2]+1, strComma[3]-strComma[2]-1);  // next is latitude
                            qgip.latitude = safe_atof(strTmp);

                            memset(strTmp, 0x00, sizeof(char) * 32);
                            strComma[4] = strReply + strlen(strReply);  // make a fake endpoint
                            strncpy(strTmp, strComma[3]+1, strComma[4]-strComma[3]-1);  // next is longitude
                            qgip.longitude = safe_atof(strTmp);

                            delete [] strTmp;

                            iReturn = qgip.insert();
                            if (!iReturn) { // success, get insert_id
                               int iInsertID = qgip.db->insert_id();
                               if (iInsertID>0) {
                                    // now make a host record
                                    qhip.geoipaddrid = iInsertID;  // mark the geoip database id used 
                                    qtrig.geoipaddrid = qhip.geoipaddrid;
                                    qtrig.latitude   = qgip.latitude;
                                    qtrig.longitude  = qgip.longitude;
                                    qhip.latitude    = qgip.latitude;
                                    qhip.longitude   = qgip.longitude;
                                    qhip.levelvalue = 0;
                                    qhip.levelid    = 0;
                                    qhip.alignid    = 0;
                                    qtrig.levelvalue = 0;
                                    qtrig.levelid    = 0;
                                    qtrig.alignid    = 0;
                                    iReturn = qhip.insert();
                                    if (!iReturn) { // success, insert trigger, if fails retcode sent below
                                        qtrig.hostipaddrid = qhip.db->insert_id(); // need the qcn_host_ipaddr id for trigger table
                                        iReturn = qtrig.insert();
                                        if (iReturn) {
                                            log_messages.printf(
                                              SCHED_MSG_LOG::MSG_CRITICAL,
                                              "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2] Maxmind/GeoIP web lookup -- trigger %s insert failed\n",
                                              qtrig.hostid, qtrig.result_name, qtrig.time_received, qtrig.ipaddr
                                            );
                                        }
                                        else {
                                            doTriggerMemoryInsert(qtrig, dmxy, dmz);
                                            log_messages.printf(
                                              SCHED_MSG_LOG::MSG_DEBUG,
                                              "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2] Maxmind/GeoIP web lookup -- trigger %s insert success\n",
                                              qtrig.hostid, qtrig.result_name, qtrig.time_received, qtrig.ipaddr
                                            );
                                        }
                                    }
                                    else {
                                       iReturn = 0; // well we tried, return 0 so doesn't bother with this trigger again
                                       log_messages.printf(
                                            SCHED_MSG_LOG::MSG_CRITICAL,
                                            "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2] Maxmind/GeoIP web lookup -- host_ipaddr %s insert failed\n",
                                            qtrig.hostid, qtrig.result_name, qtrig.time_received, qhip.ipaddr
                                       );
                                    } // failed qhip insert
                               } // insertid
                               else { // failed qgip insert id
                                  log_messages.printf(
                                    SCHED_MSG_LOG::MSG_CRITICAL,
                                    "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2] Maxmind/GeoIP web lookup -- invalid insert id on geo_ipaddr %s\n",
                                    qtrig.hostid, qtrig.result_name, qtrig.time_received, qhip.ipaddr
                                  );
                               }
                            }
                            else { // bad geo_ipaddr insert
                                  log_messages.printf(
                                    SCHED_MSG_LOG::MSG_CRITICAL,
                                    "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2] Maxmind/GeoIP web lookup -- geo_ipaddr %s insert failed\n",
                                    qtrig.hostid, qtrig.result_name, qtrig.time_received, qhip.ipaddr
                                  );
                            }
                          }
                       }
                       else { // error in curl execution, set iReturn to non-zero so it can try again, should we insert trigger anyway?
                          iReturn = 2;
                          log_messages.printf(
                             SCHED_MSG_LOG::MSG_CRITICAL,
                             "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [2a] Maxmind/GeoIP web lookup of IP %s via %s to %s failed\n",
                             qtrig.hostid, qtrig.result_name, qtrig.time_received, qtrig.ipaddr, "libcurl", strURL
                          );
                       }
                       break;
                    case 0:  // record found already in geoip table, insert into host table and set lat/lng for qcn_trigger
                       qhip.geoipaddrid = qgip.id;  // mark the geoip database id used 
                       qhip.latitude    = qgip.latitude;
                       qhip.longitude   = qgip.longitude;
                       qtrig.latitude   = qgip.latitude;
                       qtrig.longitude  = qgip.longitude;
                       qhip.levelvalue = 0;
                       qhip.levelid    = 0;
                       qhip.alignid    = 0;
                       qtrig.levelvalue = 0;
                       qtrig.levelid    = 0;
                       qtrig.alignid    = 0;

                       iReturn = qhip.insert();  // note if the insert fails, return code will be set and returned below
                       qtrig.geoipaddrid = qhip.geoipaddrid;
                       if (!iReturn) { // success, insert trigger, if fails retcode sent below
                           qtrig.hostipaddrid = qhip.db->insert_id();
                           iReturn = qtrig.insert();  // note if the insert fails, return code will be set and returned below
                       }
                       if (iReturn) { // error, print out debug info
              char* strErr = new char[512];
              memset(strErr, 0x00, 512);
              qtrig.db_print(strErr);
              log_messages.printf(
                SCHED_MSG_LOG::MSG_CRITICAL, "geoip lookup trigger insert\nerrcode %d - %s\n", iReturn, strErr);
              memset(strErr, 0x00, 512);
              qhip.db_print(strErr);
              log_messages.printf(
                SCHED_MSG_LOG::MSG_CRITICAL, "qhip trigger insert\nerrcode %d - %s\n", iReturn, strErr);
              delete [] strErr;  strErr = NULL;
                       }
                       else {
                          doTriggerMemoryInsert(qtrig, dmxy, dmz);
                          // trigger got in OK
                           log_messages.printf(
                             SCHED_MSG_LOG::MSG_DEBUG,
                             "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [3] Trigger inserted after qcn_geo_ipaddr lookup; mag=%lf at (%lf, %lf) - sync offset %f at %f!\n",
                             qtrig.hostid, qtrig.result_name, qtrig.time_received, qtrig.magnitude, qtrig.latitude, qtrig.longitude, qtrig.sync_offset, qtrig.time_sync
                           );
                       }
                       break;
                    default:  // other database error, iReturn will be returned below
                       log_messages.printf(
                          SCHED_MSG_LOG::MSG_CRITICAL,
                          "[QCN] [HOST#%d] [RESULTNAME=%s] [TIME=%lf] [3] - Database error encountered on qcn_geo_ipaddr lookup!\n",
                          qtrig.hostid, qtrig.result_name, qtrig.time_received
                       );
                 }
                 if (strURL) delete [] strURL; // don't forget to get rid of these dynamic strings!
                 if (strReply) delete [] strReply;

                 return iReturn;
}