2015-09-01 08:19:52 -07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Jan-Piet Mens <jpmens@gmail.com> and OwnTracks
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* JAN-PIET MENS OR OWNTRACKS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <getopt.h>
|
2015-08-23 05:28:29 -07:00
|
|
|
#include <ctype.h>
|
2015-08-20 10:16:26 -07:00
|
|
|
#include <time.h>
|
|
|
|
#include "json.h"
|
|
|
|
#include "storage.h"
|
2015-08-22 07:42:35 -07:00
|
|
|
#include "util.h"
|
2015-08-25 11:22:50 -07:00
|
|
|
#include "misc.h"
|
2015-09-10 06:39:25 -07:00
|
|
|
#include "version.h"
|
2015-08-22 07:42:35 -07:00
|
|
|
|
2015-10-01 23:44:09 -07:00
|
|
|
#define STRINGCOLUMN(x) (!strcmp(x, "addr") || !strcmp(x, "locality"))
|
|
|
|
|
2015-08-26 12:07:20 -07:00
|
|
|
/*
|
|
|
|
* Print the value in a single JSON node. If string, easy. If number account for
|
|
|
|
* what we call 'integer' types which shouldn't be printed as floats.
|
|
|
|
*/
|
2015-08-26 10:27:06 -07:00
|
|
|
|
2015-08-26 12:07:20 -07:00
|
|
|
static void print_one(JsonNode *j, JsonNode *inttypes)
|
|
|
|
{
|
2015-08-26 10:27:06 -07:00
|
|
|
/* Check if the value should be an "integer" (ie not float) */
|
|
|
|
if (j->tag == JSON_NUMBER) {
|
2015-08-26 12:07:20 -07:00
|
|
|
if (json_find_member(inttypes, j->key)) {
|
|
|
|
printf("%.lf", j->number_);
|
|
|
|
} else {
|
2015-08-26 10:27:06 -07:00
|
|
|
printf("%lf", j->number_);
|
2015-08-24 11:16:13 -07:00
|
|
|
}
|
2015-08-26 10:27:06 -07:00
|
|
|
} else if (j->tag == JSON_STRING) {
|
2015-10-01 23:44:09 -07:00
|
|
|
char *quote = "";
|
|
|
|
|
|
|
|
if (STRINGCOLUMN(j->key)) {
|
|
|
|
quote = "\"";
|
|
|
|
}
|
|
|
|
printf("%s%s%s", quote, j->string_, quote);
|
2015-08-26 12:07:20 -07:00
|
|
|
} else if (j->tag == JSON_BOOL) {
|
|
|
|
printf("%s", (j->bool_) ? "true" : "false");
|
|
|
|
} else if (j->tag == JSON_NULL) {
|
|
|
|
printf("null");
|
2015-08-24 11:16:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-16 08:26:27 -07:00
|
|
|
static void print_xml_line(char *line, void *param)
|
2015-09-16 06:27:11 -07:00
|
|
|
{
|
2015-09-16 08:26:27 -07:00
|
|
|
FILE *fp = (FILE *)param;
|
2015-09-16 06:27:11 -07:00
|
|
|
|
2015-09-16 08:26:27 -07:00
|
|
|
fprintf(fp, "%s\n", line);
|
2015-09-16 06:27:11 -07:00
|
|
|
}
|
2015-09-16 08:26:27 -07:00
|
|
|
|
2015-10-01 23:44:09 -07:00
|
|
|
static void csv_title(JsonNode *node, char *column)
|
|
|
|
{
|
|
|
|
char *quote = "";
|
|
|
|
|
|
|
|
if (STRINGCOLUMN(column)) {
|
|
|
|
quote = "\"";
|
|
|
|
}
|
|
|
|
printf("%s%s%s%c", quote, column, quote, (node->next) ? ',' : '\n');
|
|
|
|
}
|
|
|
|
|
2015-08-26 12:07:20 -07:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* default ALL.
|
|
|
|
*/
|
|
|
|
|
2015-08-26 10:27:06 -07:00
|
|
|
void csv_output(JsonNode *json, output_type otype, JsonNode *fields)
|
2015-08-22 07:42:35 -07:00
|
|
|
{
|
2015-08-26 12:07:20 -07:00
|
|
|
JsonNode *node, *inttypes;
|
2015-08-22 07:42:35 -07:00
|
|
|
JsonNode *arr, *one, *j;
|
2015-08-26 10:27:06 -07:00
|
|
|
short virgin = 1;
|
2015-08-22 14:06:52 -07:00
|
|
|
|
2015-08-26 12:07:20 -07:00
|
|
|
/* 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));
|
2015-08-26 13:31:18 -07:00
|
|
|
json_append_member(inttypes, "dist", json_mkbool(1));
|
|
|
|
json_append_member(inttypes, "trip", json_mkbool(1));
|
2015-08-26 12:07:20 -07:00
|
|
|
|
2015-08-22 07:42:35 -07:00
|
|
|
arr = json_find_member(json, "locations");
|
|
|
|
json_foreach(one, arr) {
|
2015-08-26 10:27:06 -07:00
|
|
|
/* Headings */
|
|
|
|
if (virgin) {
|
2015-10-01 23:44:09 -07:00
|
|
|
|
2015-08-26 10:27:06 -07:00
|
|
|
virgin = !virgin;
|
2015-08-22 07:42:35 -07:00
|
|
|
|
2015-08-26 10:27:06 -07:00
|
|
|
if (fields) {
|
|
|
|
json_foreach(node, fields) {
|
2015-10-01 23:44:09 -07:00
|
|
|
csv_title(node, node->string_);
|
2015-08-26 10:27:06 -07:00
|
|
|
}
|
|
|
|
} else {
|
2015-10-01 23:44:09 -07:00
|
|
|
json_foreach(node, one) {
|
|
|
|
if (node->key)
|
|
|
|
csv_title(node, node->key);
|
2015-08-26 10:27:06 -07:00
|
|
|
}
|
|
|
|
}
|
2015-08-22 07:42:35 -07:00
|
|
|
}
|
|
|
|
|
2015-08-26 10:27:06 -07:00
|
|
|
/* Now the values */
|
|
|
|
if (fields) {
|
|
|
|
json_foreach(node, fields) {
|
|
|
|
if ((j = json_find_member(one, node->string_)) != NULL) {
|
2015-08-26 12:07:20 -07:00
|
|
|
print_one(j, inttypes);
|
2015-08-26 10:27:06 -07:00
|
|
|
printf("%c", node->next ? ',' : '\n');
|
2015-09-02 02:45:29 -07:00
|
|
|
} else {
|
|
|
|
/* specified field not in JSON for this row */
|
|
|
|
printf("%c", node->next ? ',' : '\n');
|
2015-08-26 10:27:06 -07:00
|
|
|
}
|
|
|
|
}
|
2015-08-22 08:32:28 -07:00
|
|
|
} else {
|
2015-08-26 10:27:06 -07:00
|
|
|
json_foreach(j, one) {
|
2015-08-26 12:07:20 -07:00
|
|
|
print_one(j, inttypes);
|
2015-08-26 10:27:06 -07:00
|
|
|
printf("%c", j->next ? ',' : '\n');
|
|
|
|
}
|
2015-08-22 08:32:28 -07:00
|
|
|
}
|
2015-08-22 07:42:35 -07:00
|
|
|
}
|
2015-08-26 12:07:20 -07:00
|
|
|
json_delete(inttypes);
|
2015-08-22 07:42:35 -07:00
|
|
|
}
|
2015-08-20 10:16:26 -07:00
|
|
|
|
|
|
|
void usage(char *prog)
|
|
|
|
{
|
|
|
|
printf("Usage: %s [options..] [file ...]\n", prog);
|
|
|
|
printf(" --help -h this message\n");
|
|
|
|
printf(" --list -l list users (or a user's (-u) devices\n");
|
2015-08-23 05:35:14 -07:00
|
|
|
printf(" --user username -u specify username ($OCAT_USERNAME)\n");
|
|
|
|
printf(" --device devicename -d specify device name ($OCAT_DEVICE)\n");
|
|
|
|
printf(" --from <time> -F from date/time; default -6H\n");
|
|
|
|
printf(" --to <time> -T to date/time; default now\n");
|
2015-09-01 13:13:44 -07:00
|
|
|
printf(" specify <time> as YYYY-MM-DDTHH:MM:SS\n");
|
|
|
|
printf(" YYYY-MM-DDTHH:MM\n");
|
|
|
|
printf(" YYYY-MM-DDTHH\n");
|
|
|
|
printf(" YYYY-MM-DD\n");
|
|
|
|
printf(" YYYY-MM\n");
|
|
|
|
printf(" --limit <number> -N last <number> points\n");
|
|
|
|
printf(" --format json -f output format (default: JSON)\n");
|
|
|
|
printf(" csv (overrides $OCAT_FORMAT\n");
|
|
|
|
printf(" geojson Geo-JSON points\n");
|
|
|
|
printf(" linestring Geo-JSON LineString\n");
|
2015-08-29 12:11:03 -07:00
|
|
|
printf(" gpx\n");
|
2015-09-16 06:27:11 -07:00
|
|
|
printf(" xml\n");
|
2015-08-23 01:59:17 -07:00
|
|
|
printf(" raw\n");
|
2015-09-01 13:13:44 -07:00
|
|
|
printf(" payload Like RAW but JSON payload only\n");
|
|
|
|
printf(" --fields tst,lat,lon,... Choose fields for CSV. (dflt: ALL)\n");
|
|
|
|
printf(" --last -L JSON object with last users\n");
|
2015-09-28 10:04:37 -07:00
|
|
|
#if WITH_KILL
|
2015-09-01 13:13:44 -07:00
|
|
|
printf(" --killdata requires -u and -d\n");
|
2015-09-14 23:35:58 -07:00
|
|
|
#endif
|
2015-09-10 03:17:14 -07:00
|
|
|
printf(" --storage -S storage dir (%s)\n", STORAGEDEFAULT);
|
2015-09-01 23:22:40 -07:00
|
|
|
printf(" --norevgeo -G disable ghash to reverge-geo lookups\n");
|
2015-09-11 01:30:16 -07:00
|
|
|
printf(" --precision ghash precision (dflt: %d)\n", GHASHPREC);
|
2015-09-11 05:44:21 -07:00
|
|
|
printf(" --version -v print version information\n");
|
2015-09-24 03:49:14 -07:00
|
|
|
printf(" --dump / --load [<db>] dump/load content of db (default ghash)\n");
|
2015-09-01 09:21:07 -07:00
|
|
|
printf("\n");
|
|
|
|
printf("Options override these environment variables:\n");
|
|
|
|
printf(" $OCAT_USERNAME\n");
|
|
|
|
printf(" $OCAT_DEVICE\n");
|
|
|
|
printf(" $OCAT_FORMAT\n");
|
|
|
|
printf(" $OCAT_STORAGEDIR\n");
|
2015-08-21 12:11:42 -07:00
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:39:25 -07:00
|
|
|
void print_versioninfo()
|
|
|
|
{
|
|
|
|
printf("This is OwnTracks Recorder, version %s\n", VERSION);
|
|
|
|
printf("built with:\n");
|
2015-09-28 10:04:37 -07:00
|
|
|
#ifdef WITH_LMDB
|
|
|
|
printf("\tWITH_LMDB = yes\n");
|
2015-09-10 06:39:25 -07:00
|
|
|
#endif
|
2015-09-19 07:11:53 -07:00
|
|
|
#ifdef WITH_LUA
|
|
|
|
printf("\tWITH_LUA = yes\n");
|
|
|
|
#endif
|
2015-09-28 10:04:37 -07:00
|
|
|
#ifdef WITH_HTTP
|
|
|
|
printf("\tWITH_HTTP = yes\n");
|
2015-09-10 12:04:10 -07:00
|
|
|
#endif
|
2015-09-28 10:04:37 -07:00
|
|
|
#ifdef WITH_PING
|
|
|
|
printf("\tWITH_PING = yes\n");
|
2015-09-14 23:42:26 -07:00
|
|
|
#endif
|
2015-09-28 10:04:37 -07:00
|
|
|
#ifdef WITH_KILL
|
|
|
|
printf("\tWITH_KILL = yes\n");
|
2015-09-10 06:39:25 -07:00
|
|
|
#endif
|
|
|
|
printf("\tSTORAGEDEFAULT = \"%s\"\n", STORAGEDEFAULT);
|
2015-09-11 06:48:56 -07:00
|
|
|
printf("\tDOCROOT = \"%s\"\n", DOCROOT);
|
2015-09-11 01:30:16 -07:00
|
|
|
printf("\tGHASHPREC = %d\n", GHASHPREC);
|
2015-09-10 06:39:25 -07:00
|
|
|
printf("\tDEFAULT_HISTORY_HOURS = %d\n", DEFAULT_HISTORY_HOURS);
|
2015-09-14 07:29:13 -07:00
|
|
|
printf("\tJSON_INDENT = \"%s\"\n", (JSON_INDENT) ? JSON_INDENT : "NULL");
|
2015-09-10 06:39:25 -07:00
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2015-09-24 03:49:14 -07:00
|
|
|
char *progname = *argv, *p, *lmdbname = NULL;
|
2015-08-20 10:16:26 -07:00
|
|
|
int c;
|
2015-09-14 23:35:58 -07:00
|
|
|
int list = 0, last = 0, limit = 0, dumpghash = FALSE, loadghash = FALSE;
|
2015-09-28 10:04:37 -07:00
|
|
|
#if WITH_KILL
|
2015-09-14 23:35:58 -07:00
|
|
|
int killdata = FALSE;
|
|
|
|
#endif
|
2015-09-01 23:22:40 -07:00
|
|
|
int revgeo = TRUE;
|
2015-08-21 12:11:42 -07:00
|
|
|
char *username = NULL, *device = NULL, *time_from = NULL, *time_to = NULL;
|
2015-08-20 10:16:26 -07:00
|
|
|
JsonNode *json, *obj, *locs;
|
2015-08-21 12:11:42 -07:00
|
|
|
time_t now, s_lo, s_hi;
|
2015-08-22 07:42:35 -07:00
|
|
|
output_type otype = JSON;
|
2015-08-26 10:27:06 -07:00
|
|
|
JsonNode *fields = NULL;
|
2015-09-16 08:26:27 -07:00
|
|
|
FILE *xmlp = stdout;
|
2015-08-22 07:42:35 -07:00
|
|
|
|
2015-08-23 05:31:55 -07:00
|
|
|
if ((p = getenv("OCAT_USERNAME")) != NULL) {
|
|
|
|
username = strdup(p);
|
|
|
|
}
|
|
|
|
if ((p = getenv("OCAT_DEVICE")) != NULL) {
|
|
|
|
device = strdup(p);
|
|
|
|
}
|
|
|
|
|
2015-08-23 05:28:29 -07:00
|
|
|
if ((p = getenv("OCAT_FORMAT")) != NULL) {
|
|
|
|
switch (tolower(*p)) {
|
|
|
|
case 'j': otype = JSON; break;
|
|
|
|
case 'c': otype = CSV; break;
|
|
|
|
case 'g': otype = GEOJSON; break;
|
|
|
|
case 'r': otype = RAW; break;
|
2015-09-01 12:03:50 -07:00
|
|
|
case 'p': otype = RAWPAYLOAD; break;
|
2015-09-01 12:45:57 -07:00
|
|
|
case 'l': otype = LINESTRING; break;
|
2015-08-23 05:28:29 -07:00
|
|
|
}
|
|
|
|
}
|
2015-08-20 10:16:26 -07:00
|
|
|
|
2015-08-25 11:22:50 -07:00
|
|
|
if ((p = getenv("OCAT_STORAGEDIR")) != NULL) {
|
|
|
|
strcpy(STORAGEDIR, p);
|
|
|
|
}
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
time(&now);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
static struct option long_options[] = {
|
|
|
|
{ "help", no_argument, 0, 'h'},
|
2015-09-11 05:44:21 -07:00
|
|
|
{ "version", no_argument, 0, 'v'},
|
2015-08-20 10:16:26 -07:00
|
|
|
{ "list", no_argument, 0, 'l'},
|
|
|
|
{ "user", required_argument, 0, 'u'},
|
|
|
|
{ "device", required_argument, 0, 'd'},
|
2015-08-21 12:11:42 -07:00
|
|
|
{ "from", required_argument, 0, 'F'},
|
|
|
|
{ "to", required_argument, 0, 'T'},
|
2015-08-29 07:34:20 -07:00
|
|
|
{ "limit", required_argument, 0, 'N'},
|
2015-08-22 07:42:35 -07:00
|
|
|
{ "format", required_argument, 0, 'f'},
|
2015-08-25 11:22:50 -07:00
|
|
|
{ "storage", required_argument, 0, 'S'},
|
2015-08-25 09:01:50 -07:00
|
|
|
{ "last", no_argument, 0, 'L'},
|
2015-08-26 10:27:06 -07:00
|
|
|
{ "fields", required_argument, 0, 1},
|
2015-09-07 08:40:50 -07:00
|
|
|
{ "precision", required_argument, 0, 2},
|
2015-09-24 03:49:14 -07:00
|
|
|
{ "dump", optional_argument, 0, 3},
|
|
|
|
{ "load", optional_argument, 0, 4},
|
2015-09-28 10:04:37 -07:00
|
|
|
#if WITH_KILL
|
2015-08-23 06:04:54 -07:00
|
|
|
{ "killdata", no_argument, 0, 'K'},
|
2015-09-14 23:35:58 -07:00
|
|
|
#endif
|
2015-09-01 23:22:40 -07:00
|
|
|
{ "norevgeo", no_argument, 0, 'G'},
|
2015-08-20 10:16:26 -07:00
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
int optindex = 0;
|
|
|
|
|
2015-09-11 05:44:21 -07:00
|
|
|
c = getopt_long(argc, argv, "hlu:d:F:T:f:KLS:GN:v", long_options, &optindex);
|
2015-08-20 10:16:26 -07:00
|
|
|
if (c == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (c) {
|
2015-08-26 10:27:06 -07:00
|
|
|
case 1: /* No short option */
|
2015-08-26 12:07:20 -07:00
|
|
|
if (strcmp(optarg, "ALL") != 0)
|
|
|
|
fields = json_splitter(optarg, ",");
|
2015-08-26 10:27:06 -07:00
|
|
|
break;
|
2015-09-07 08:40:50 -07:00
|
|
|
case 2:
|
|
|
|
geohash_setprec(atoi(optarg));
|
|
|
|
break;
|
2015-09-14 11:54:05 -07:00
|
|
|
case 3:
|
|
|
|
dumpghash = TRUE;
|
2015-09-24 03:49:14 -07:00
|
|
|
if (optarg)
|
|
|
|
lmdbname = strdup(optarg);
|
2015-09-14 11:54:05 -07:00
|
|
|
break;
|
2015-09-14 13:07:56 -07:00
|
|
|
case 4:
|
|
|
|
loadghash = TRUE;
|
2015-09-24 03:49:14 -07:00
|
|
|
if (optarg)
|
|
|
|
lmdbname = strdup(optarg);
|
2015-09-14 13:07:56 -07:00
|
|
|
break;
|
2015-09-11 05:44:21 -07:00
|
|
|
case 'v':
|
2015-09-10 06:39:25 -07:00
|
|
|
print_versioninfo();
|
|
|
|
break;
|
2015-08-20 10:16:26 -07:00
|
|
|
case 'l':
|
|
|
|
list = 1;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
username = strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
device = strdup(optarg);
|
|
|
|
break;
|
2015-08-21 12:11:42 -07:00
|
|
|
case 'F':
|
|
|
|
time_from = strdup(optarg);
|
|
|
|
break;
|
2015-08-29 07:34:20 -07:00
|
|
|
case 'N':
|
|
|
|
limit = atoi(optarg);
|
|
|
|
break;
|
2015-09-01 23:22:40 -07:00
|
|
|
case 'G':
|
|
|
|
revgeo = FALSE;
|
|
|
|
break;
|
2015-08-25 11:22:50 -07:00
|
|
|
case 'S':
|
|
|
|
strcpy(STORAGEDIR, optarg);
|
|
|
|
break;
|
2015-08-21 12:11:42 -07:00
|
|
|
case 'T':
|
|
|
|
time_to = strdup(optarg);
|
2015-08-20 10:16:26 -07:00
|
|
|
break;
|
2015-08-22 07:42:35 -07:00
|
|
|
case 'f':
|
|
|
|
if (!strcmp(optarg, "json"))
|
|
|
|
otype = JSON;
|
|
|
|
else if (!strcmp(optarg, "geojson"))
|
|
|
|
otype = GEOJSON;
|
2015-09-01 12:45:57 -07:00
|
|
|
else if (!strcmp(optarg, "linestring"))
|
|
|
|
otype = LINESTRING;
|
2015-08-23 01:59:17 -07:00
|
|
|
else if (!strcmp(optarg, "raw"))
|
|
|
|
otype = RAW;
|
2015-09-01 12:03:50 -07:00
|
|
|
else if (!strcmp(optarg, "payload"))
|
|
|
|
otype = RAWPAYLOAD;
|
2015-09-16 06:27:11 -07:00
|
|
|
else if (!strcmp(optarg, "xml"))
|
|
|
|
otype = XML;
|
2015-08-29 12:11:03 -07:00
|
|
|
else if (!strcmp(optarg, "gpx"))
|
|
|
|
otype = GPX;
|
2015-08-22 07:42:35 -07:00
|
|
|
else if (!strcmp(optarg, "csv"))
|
|
|
|
otype = CSV;
|
|
|
|
else {
|
|
|
|
fprintf(stderr, "%s: unrecognized output format\n", progname);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
break;
|
2015-09-28 10:04:37 -07:00
|
|
|
#if WITH_KILL
|
2015-08-23 06:04:54 -07:00
|
|
|
case 'K':
|
|
|
|
killdata = 1;
|
|
|
|
break;
|
2015-09-14 23:35:58 -07:00
|
|
|
#endif
|
2015-08-25 09:01:50 -07:00
|
|
|
case 'L':
|
|
|
|
last = 1;
|
|
|
|
break;
|
2015-08-20 10:16:26 -07:00
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
/* getopt_long already printed message */
|
|
|
|
usage(progname);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= (optind);
|
|
|
|
argv += (optind);
|
|
|
|
|
2015-09-24 03:49:14 -07:00
|
|
|
// printf("lmdbname = %s\n", (lmdbname) ? lmdbname : "NULL");
|
|
|
|
|
2015-09-14 13:07:56 -07:00
|
|
|
if (loadghash) {
|
2015-09-24 03:49:14 -07:00
|
|
|
storage_gcache_load(lmdbname);
|
2015-09-14 13:07:56 -07:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2015-09-14 11:54:05 -07:00
|
|
|
if (dumpghash) {
|
2015-09-24 03:49:14 -07:00
|
|
|
storage_gcache_dump(lmdbname);
|
2015-09-14 11:54:05 -07:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2015-09-24 03:49:14 -07:00
|
|
|
storage_init(revgeo);
|
|
|
|
|
|
|
|
|
2015-09-28 10:04:37 -07:00
|
|
|
#if WITH_KILL
|
2015-08-23 06:04:54 -07:00
|
|
|
if (killdata) {
|
2015-08-23 06:43:18 -07:00
|
|
|
JsonNode *obj; //, *killed, *f;
|
2015-08-23 06:04:54 -07:00
|
|
|
|
|
|
|
if (!username || !device) {
|
|
|
|
fprintf(stderr, "%s: killdata requires username and device\n", progname);
|
|
|
|
return (-2);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "Storage deleted these files:\n");
|
2015-08-23 06:43:18 -07:00
|
|
|
if ((obj = kill_datastore(username, device)) != NULL) {
|
|
|
|
char *js;
|
|
|
|
// if ((killed = json_find_member(obj, "results")) != NULL) { // get array
|
|
|
|
// json_foreach(f, killed) {
|
|
|
|
// fprintf(stderr, " %s\n", f->string_);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
2015-09-02 11:03:41 -07:00
|
|
|
js = json_stringify(obj, JSON_INDENT);
|
2015-09-01 04:59:11 -07:00
|
|
|
printf("%s\n", js);
|
2015-08-23 06:43:18 -07:00
|
|
|
free(js);
|
|
|
|
json_delete(obj);
|
2015-08-23 06:04:54 -07:00
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
2015-09-14 23:35:58 -07:00
|
|
|
#endif
|
2015-08-23 06:04:54 -07:00
|
|
|
|
2015-08-25 09:01:50 -07:00
|
|
|
if (last) {
|
2015-08-29 13:52:08 -07:00
|
|
|
JsonNode *user_array;
|
2015-08-25 09:01:50 -07:00
|
|
|
|
2015-09-10 09:50:19 -07:00
|
|
|
if ((user_array = last_users(username, device)) != NULL) {
|
2015-08-25 09:01:50 -07:00
|
|
|
|
2015-09-15 10:38:34 -07:00
|
|
|
if (otype == JSON) {
|
|
|
|
char *js;
|
|
|
|
if ((js = json_stringify(user_array, JSON_INDENT)) != NULL) {
|
|
|
|
printf("%s\n", js);
|
|
|
|
free(js);
|
|
|
|
}
|
|
|
|
json_delete(user_array);
|
|
|
|
} else if (otype == CSV) {
|
|
|
|
JsonNode *o = json_mkobject();
|
|
|
|
|
|
|
|
json_append_member(o, "locations", user_array);
|
|
|
|
csv_output(o, CSV, fields);
|
|
|
|
json_delete(o);
|
|
|
|
|
2015-09-16 06:27:11 -07:00
|
|
|
} else if (otype == XML) {
|
|
|
|
JsonNode *o = json_mkobject();
|
|
|
|
|
|
|
|
json_append_member(o, "locations", user_array);
|
2015-09-16 08:26:27 -07:00
|
|
|
xml_output(o, XML, fields, print_xml_line, xmlp);
|
2015-09-16 06:27:11 -07:00
|
|
|
json_delete(o);
|
|
|
|
|
2015-09-15 10:38:34 -07:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: unsupported output type for LAST\n", progname);
|
2015-08-29 13:52:08 -07:00
|
|
|
}
|
|
|
|
}
|
2015-08-25 09:01:50 -07:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-09-16 06:30:28 -07:00
|
|
|
lowercase(username);
|
|
|
|
lowercase(device);
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
if (!username && device) {
|
|
|
|
fprintf(stderr, "%s: device name without username doesn't make sense\n", progname);
|
|
|
|
return (-2);
|
|
|
|
}
|
|
|
|
|
2015-08-29 07:34:20 -07:00
|
|
|
/* If no from time specified but limit, set from to this month */
|
|
|
|
if (limit) {
|
2015-08-29 09:49:54 -07:00
|
|
|
if (time_from == NULL) {
|
|
|
|
time_from = strdup(yyyymm(now));
|
|
|
|
}
|
2015-08-29 07:34:20 -07:00
|
|
|
}
|
|
|
|
|
2015-08-21 12:11:42 -07:00
|
|
|
if (make_times(time_from, &s_lo, time_to, &s_hi) != 1) {
|
|
|
|
fprintf(stderr, "%s: bad time(s) specified\n", progname);
|
|
|
|
return (-2);
|
|
|
|
}
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
if (list) {
|
|
|
|
char *js;
|
|
|
|
|
2015-08-29 11:50:13 -07:00
|
|
|
json = lister(username, device, 0, s_hi, FALSE);
|
2015-08-20 10:16:26 -07:00
|
|
|
if (json == NULL) {
|
|
|
|
fprintf(stderr, "%s: cannot list\n", progname);
|
|
|
|
exit(2);
|
|
|
|
}
|
2015-08-23 02:19:25 -07:00
|
|
|
if (otype == JSON) {
|
2015-09-02 11:03:41 -07:00
|
|
|
js = json_stringify(json, JSON_INDENT);
|
2015-08-23 02:19:25 -07:00
|
|
|
printf("%s\n", js);
|
|
|
|
free(js);
|
|
|
|
} else {
|
|
|
|
JsonNode *f, *arr;
|
|
|
|
|
|
|
|
if ((arr = json_find_member(json, "results")) != NULL) { // get array
|
|
|
|
json_foreach(f, arr) {
|
|
|
|
printf("%s\n", f->string_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
json_delete(json);
|
2015-08-20 11:36:07 -07:00
|
|
|
|
|
|
|
return (0);
|
2015-08-20 10:16:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 0 && !username && !device) {
|
|
|
|
fprintf(stderr, "%s: nothing to do. Specify filename or --user and --device\n", progname);
|
|
|
|
return (-1);
|
2015-08-24 11:16:13 -07:00
|
|
|
} else if (argc == 0 && (!username || !device)) {
|
|
|
|
fprintf(stderr, "%s: must specify username and device\n", progname);
|
|
|
|
return (-1);
|
|
|
|
} else if ((username || device) && (argc > 0)) {
|
2015-08-20 10:16:26 -07:00
|
|
|
fprintf(stderr, "%s: filename with --user and --device is not supported\n", progname);
|
|
|
|
return (-1);
|
|
|
|
}
|
2015-08-20 12:33:16 -07:00
|
|
|
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
/*
|
|
|
|
* If any files were passed on the command line, we assume these are *.rec
|
|
|
|
* and process those. Otherwise, we expect a `user' and `device' and process
|
|
|
|
* "today"
|
|
|
|
*/
|
|
|
|
|
|
|
|
obj = json_mkobject();
|
|
|
|
locs = json_mkarray();
|
|
|
|
|
|
|
|
|
|
|
|
if (argc) {
|
|
|
|
int n;
|
|
|
|
|
|
|
|
for (n = 0; n < argc; n++) {
|
2015-08-29 13:20:49 -07:00
|
|
|
locations(argv[n], obj, locs, s_lo, s_hi, otype, 0, fields);
|
2015-08-20 10:16:26 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JsonNode *arr, *f;
|
|
|
|
|
2015-08-26 13:31:18 -07:00
|
|
|
/*
|
|
|
|
* Obtain a list of .rec files from lister(), possibly limited by s_lo/s_hi times,
|
|
|
|
* process each and build the JSON `obj' with an array of locations.
|
|
|
|
*/
|
|
|
|
|
2015-08-29 11:50:13 -07:00
|
|
|
if ((json = lister(username, device, s_lo, s_hi, (limit > 0) ? TRUE : FALSE)) != NULL) {
|
2015-08-29 09:49:54 -07:00
|
|
|
if ((arr = json_find_member(json, "results")) != NULL) { // get array
|
|
|
|
json_foreach(f, arr) {
|
2015-08-29 13:20:49 -07:00
|
|
|
locations(f->string_, obj, locs, s_lo, s_hi, otype, limit, fields);
|
2015-08-29 11:50:13 -07:00
|
|
|
// printf("%s\n", f->string_);
|
2015-08-20 10:16:26 -07:00
|
|
|
}
|
|
|
|
}
|
2015-08-29 09:49:54 -07:00
|
|
|
json_delete(json);
|
2015-08-20 10:16:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
json_append_member(obj, "locations", locs);
|
2015-08-22 07:42:35 -07:00
|
|
|
|
|
|
|
|
|
|
|
if (otype == JSON) {
|
2015-09-02 11:03:41 -07:00
|
|
|
char *js = json_stringify(obj, JSON_INDENT);
|
2015-08-22 07:42:35 -07:00
|
|
|
|
|
|
|
if (js != NULL) {
|
|
|
|
printf("%s\n", js);
|
|
|
|
free(js);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (otype == CSV) {
|
2015-08-26 10:27:06 -07:00
|
|
|
csv_output(obj, CSV, fields);
|
2015-09-16 06:27:11 -07:00
|
|
|
} else if (otype == XML) {
|
2015-09-16 08:26:27 -07:00
|
|
|
xml_output(obj, XML, fields, print_xml_line, xmlp);
|
2015-09-01 12:03:50 -07:00
|
|
|
} else if (otype == RAW || otype == RAWPAYLOAD) {
|
2015-08-23 01:59:17 -07:00
|
|
|
/* We've already done what we need to do in locations() */
|
2015-09-01 12:45:57 -07:00
|
|
|
} else if (otype == LINESTRING) {
|
|
|
|
JsonNode *geolinestring = geo_linestring(locs);
|
|
|
|
char *js;
|
|
|
|
|
|
|
|
if (geolinestring != NULL) {
|
2015-09-02 11:03:41 -07:00
|
|
|
js = json_stringify(geolinestring, JSON_INDENT);
|
2015-09-01 12:45:57 -07:00
|
|
|
if (js != NULL) {
|
|
|
|
printf("%s\n", js);
|
|
|
|
free(js);
|
|
|
|
}
|
|
|
|
json_delete(geolinestring);
|
|
|
|
}
|
|
|
|
|
2015-08-22 07:42:35 -07:00
|
|
|
} else if (otype == GEOJSON) {
|
|
|
|
JsonNode *geojson = geo_json(locs);
|
|
|
|
char *js;
|
|
|
|
|
2015-08-22 14:06:52 -07:00
|
|
|
if (geojson != NULL) {
|
2015-09-02 11:03:41 -07:00
|
|
|
js = json_stringify(geojson, JSON_INDENT);
|
2015-08-22 14:06:52 -07:00
|
|
|
if (js != NULL) {
|
|
|
|
printf("%s\n", js);
|
|
|
|
free(js);
|
|
|
|
}
|
2015-08-26 12:07:20 -07:00
|
|
|
json_delete(geojson);
|
2015-08-22 07:42:35 -07:00
|
|
|
}
|
2015-08-29 12:11:03 -07:00
|
|
|
} else if (otype == GPX) {
|
|
|
|
char *xml = gpx_string(locs);
|
|
|
|
|
|
|
|
if (xml)
|
|
|
|
printf("%s\n", xml);
|
2015-08-22 07:42:35 -07:00
|
|
|
}
|
2015-08-20 10:16:26 -07:00
|
|
|
|
2015-08-26 12:07:20 -07:00
|
|
|
json_delete(obj);
|
|
|
|
if (fields)
|
|
|
|
json_delete(fields);
|
|
|
|
|
2015-08-20 10:16:26 -07:00
|
|
|
return (0);
|
|
|
|
}
|