diff --git a/docroot/owntracks.xsl b/docroot/owntracks.xsl index c7b0fab..aaeb889 100644 --- a/docroot/owntracks.xsl +++ b/docroot/owntracks.xsl @@ -14,6 +14,7 @@ , + diff --git a/http.c b/http.c index 5d95c37..22e5eda 100644 --- a/http.c +++ b/http.c @@ -229,6 +229,22 @@ static int json_response(struct mg_connection *conn, JsonNode *json) return (MG_TRUE); } +static void emit_xml_line(char *line, void *param) +{ + struct mg_connection *conn = (struct mg_connection *)param; + + mg_printf_data(conn, line); + mg_printf_data(conn, "\n"); +} + +static int xml_response(struct mg_connection *conn, JsonNode *obj) +{ + /* TODO: support fields? */ + xml_output(obj, CSV, NULL, emit_xml_line, conn); + + json_delete(obj); + return (MG_TRUE); +} /* * We are being called with the portion behind /api/0/ as in @@ -317,6 +333,8 @@ static int dispatch(struct mg_connection *conn, const char *uri) otype = JSON; else if (!strcmp(buf, "linestring")) otype = LINESTRING; + else if (!strcmp(buf, "xml")) + otype = XML; else { mg_send_status(conn, 400); mg_printf_data(conn, "unrecognized format\n"); @@ -372,6 +390,8 @@ static int dispatch(struct mg_connection *conn, const char *uri) if (otype == JSON) { return (json_response(conn, obj)); + } else if (otype == XML) { + return (xml_response(conn, obj)); } else if (otype == LINESTRING) { JsonNode *geoline = geo_linestring(locs); diff --git a/ocat.c b/ocat.c index 7e12a32..b050f9f 100644 --- a/ocat.c +++ b/ocat.c @@ -55,44 +55,13 @@ static void print_one(JsonNode *j, JsonNode *inttypes) } } -/* - * Print the value in a single JSON node as XML. If string, easy. If number account for - * what we call 'integer' types which shouldn't be printed as floats. - */ - -static void emit_one(JsonNode *j, JsonNode *inttypes) +static void print_xml_line(char *line, void *param) { - if (!strcmp(j->key, "_type")) - return; + FILE *fp = (FILE *)param; - printf(" <%s>", j->key); - /* Check if the value should be an "integer" (ie not float) */ - if (j->tag == JSON_NUMBER) { - if (json_find_member(inttypes, j->key)) { - printf("%.lf", j->number_); - } else { - printf("%lf", j->number_); - } - } else if (j->tag == JSON_STRING) { - char *bp; - - for (bp = j->string_; bp && *bp; bp++) { - switch (*bp) { - case '&': printf("&"); break; - case '<': printf("<"); break; - case '>': printf(">"); break; - case '"': printf("""); break; - case '\'': printf("'"); break; - default: putc(*bp, stdout); break; - } - } - } else if (j->tag == JSON_BOOL) { - printf("%s", (j->bool_) ? "true" : "false"); - } else if (j->tag == JSON_NULL) { - printf("null"); - } - printf("\n", j->key); + fprintf(fp, "%s\n", line); } + /* * Output location data as CSV. If `fields' is not NULL, it's a JSON * array of JSON elment names which should be printed instead of the @@ -154,47 +123,6 @@ void csv_output(JsonNode *json, output_type otype, JsonNode *fields) json_delete(inttypes); } - -void xml_output(JsonNode *json, output_type otype, JsonNode *fields) -{ - JsonNode *node, *inttypes; - JsonNode *arr, *one, *j; - - /* Prime the inttypes object with types we consider "integer" */ - inttypes = json_mkobject(); - json_append_member(inttypes, "batt", json_mkbool(1)); - json_append_member(inttypes, "vel", json_mkbool(1)); - json_append_member(inttypes, "cog", json_mkbool(1)); - json_append_member(inttypes, "tst", json_mkbool(1)); - json_append_member(inttypes, "alt", json_mkbool(1)); - json_append_member(inttypes, "dist", json_mkbool(1)); - json_append_member(inttypes, "trip", json_mkbool(1)); - - printf("\n\ - \n"); - printf("\n"); - - arr = json_find_member(json, "locations"); - json_foreach(one, arr) { - printf(" \n"); - if (fields) { - json_foreach(node, fields) { - if ((j = json_find_member(one, node->string_)) != NULL) { - emit_one(j, inttypes); - } - } - } else { - json_foreach(j, one) { - emit_one(j, inttypes); - } - } - printf(" \n\n"); - } - printf("\n"); - - json_delete(inttypes); -} - void usage(char *prog) { printf("Usage: %s [options..] [file ...]\n", prog); @@ -277,6 +205,7 @@ int main(int argc, char **argv) time_t now, s_lo, s_hi; output_type otype = JSON; JsonNode *fields = NULL; + FILE *xmlp = stdout; if ((p = getenv("OCAT_USERNAME")) != NULL) { username = strdup(p); @@ -478,7 +407,7 @@ int main(int argc, char **argv) JsonNode *o = json_mkobject(); json_append_member(o, "locations", user_array); - xml_output(o, CSV, fields); + xml_output(o, XML, fields, print_xml_line, xmlp); json_delete(o); } else { @@ -596,7 +525,7 @@ int main(int argc, char **argv) } else if (otype == CSV) { csv_output(obj, CSV, fields); } else if (otype == XML) { - xml_output(obj, XML, fields); + xml_output(obj, XML, fields, print_xml_line, xmlp); } else if (otype == RAW || otype == RAWPAYLOAD) { /* We've already done what we need to do in locations() */ } else if (otype == LINESTRING) { diff --git a/storage.c b/storage.c index acd388a..ee51778 100644 --- a/storage.c +++ b/storage.c @@ -953,3 +953,88 @@ JsonNode *kill_datastore(char *user, char *device) return (obj); } #endif /* HAVE_KILL */ + +/* + * Print the value in a single JSON node as XML by invoking func(). If string, + * easy. If number account for what we call 'integer' types which shouldn't be + * printed as floats. + */ + +static void emit_one(JsonNode *j, JsonNode *inttypes, void (func)(char *line, void *param), void *param) +{ + static UT_string *line = NULL; + + + if (!strcmp(j->key, "_type")) + return; + + utstring_renew(line); + utstring_printf(line, " <%s>", j->key); + /* Check if the value should be an "integer" (ie not float) */ + if (j->tag == JSON_NUMBER) { + if (json_find_member(inttypes, j->key)) { + utstring_printf(line, "%.lf", j->number_); + } else { + utstring_printf(line, "%lf", j->number_); + } + } else if (j->tag == JSON_STRING) { + char *bp; + + for (bp = j->string_; bp && *bp; bp++) { + switch (*bp) { + case '&': utstring_printf(line, "&"); break; + case '<': utstring_printf(line, "<"); break; + case '>': utstring_printf(line, ">"); break; + case '"': utstring_printf(line, """); break; + case '\'': utstring_printf(line, "'"); break; + default: utstring_printf(line, "%c", *bp); break; + } + } + } else if (j->tag == JSON_BOOL) { + utstring_printf(line, "%s", (j->bool_) ? "true" : "false"); + } else if (j->tag == JSON_NULL) { + utstring_printf(line, "null"); + } + utstring_printf(line, "", j->key); + func(utstring_body(line), param); +} + +void xml_output(JsonNode *json, output_type otype, JsonNode *fields, void (*func)(char *s, void *param), void *param) +{ + JsonNode *node, *inttypes; + JsonNode *arr, *one, *j; + + /* Prime the inttypes object with types we consider "integer" */ + inttypes = json_mkobject(); + json_append_member(inttypes, "batt", json_mkbool(1)); + json_append_member(inttypes, "vel", json_mkbool(1)); + json_append_member(inttypes, "cog", json_mkbool(1)); + json_append_member(inttypes, "tst", json_mkbool(1)); + json_append_member(inttypes, "alt", json_mkbool(1)); + json_append_member(inttypes, "dist", json_mkbool(1)); + json_append_member(inttypes, "trip", json_mkbool(1)); + + func("\n\ + ", param); + func("", param); + + arr = json_find_member(json, "locations"); + json_foreach(one, arr) { + func(" ", param); + if (fields) { + json_foreach(node, fields) { + if ((j = json_find_member(one, node->string_)) != NULL) { + emit_one(j, inttypes, func, param); + } + } + } else { + json_foreach(j, one) { + emit_one(j, inttypes, func, param); + } + } + func(" \n", param); + } + func("", param); + + json_delete(inttypes); +} diff --git a/storage.h b/storage.h index 35c3131..e584062 100644 --- a/storage.h +++ b/storage.h @@ -29,5 +29,6 @@ char *gpx_string(JsonNode *json); void storage_init(int revgeo); void storage_gcache_dump(); void storage_gcache_load(); +void xml_output(JsonNode *json, output_type otype, JsonNode *fields, void (*func)(char *s, void *param), void *param); #endif