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("%s>\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, "%s>", 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