/* See LICENSE file for copyright and license details. */ #ifndef LIBGEOME_H #define LIBGEOME_H #include #include #define LIBGEOME_DATUM_LATITUDE UINT64_C(0x0000000000000001) #define LIBGEOME_DATUM_LONGITUDE UINT64_C(0x0000000000000002) #define LIBGEOME_DATUM_ALTITUDE UINT64_C(0x0000000000000004) /** * The highest bit in `.requested_data` that is used * in the applications version of `struct libgeome_data` * * You can an #if'ed CPP warning to detected when this * value has been changed, so you can add support for * new data in your application. When you do this, you * can also always set the `.requested_data` to * `LIBGEOME_LAST_DATUM - 1U | LIBGEOME_LAST_DATUM` * to get all data your application support. */ #define LIBGEOME_LAST_DATUM LIBGEOME_DATUM_ALTITUDE /** * Machine portability class */ enum libgeome_portability { /** * No data available about the machine's * portability class */ LIBGEOME_UNKNOWN_PORTABILITY, /** * libgeome guesses that the machine is * stationary (e.g. desktop computer) */ LIBGEOME_GUESSED_STATIONARY, /** * libgeome guesses that the machine is * movable but is usually not moving around * while in use, or that these movement do * not need to be closely tracked (e.g. * laptop computer) */ LIBGEOME_GUESSED_PORTABLE, /** * libgeome guesses that the machine is * frequently on the move even when in use * and that it may be desirable to keep * the location updated with short intervals * (e.g. mobile telephone) */ LIBGEOME_GUESSED_MOBILE, /** * The user has specified that the machine * is only being moved, a significant distance, * in exceptional circumstances and only when * powered off */ LIBGEOME_STATIONARY, /** * The user has specified that the machine * is at moved from time to time, regardless * of whether it is powered on or off, but it * is not usually useful to keep the location * up to date with short intervals */ LIBGEOME_PORTABLE, /** * The user hsa specified that the is often * on the move when in use and that it is * useful to keep the locations updated with * short intervals */ LIBGEOME_MOBILE }; /** * Geolocation data */ struct libgeome_data { /** * Requested data, data that was not retrieved will be cleared */ uint64_t requested_data; /** * GPS latitude (geodetic) in degrees north * * Bit in `.requested_data`: LIBGEOME_DATUM_LATITUDE */ double latitude; /** * GPS longitude (geodetic) in degrees east * * Bit in `.requested_data`: LIBGEOME_DATUM_LONGITUDE */ double longitude; /** * Ellipsoidal altitude in meters * * Bit in `.requested_data`: LIBGEOME_DATUM_ALTITUDE */ double altitude; }; /** * Library context */ struct libgeome_context { /** * The application is free to used this field as sees fit */ union { const void *cptr; void *ptr; int i; unsigned int u; size_t n; } user_data; /** * Print error message * * @param ctx Function pointer container * @param fmt Format string * @param ... Format argument */ void (*print_error)(struct libgeome_context *ctx, const char *fmt, ...); /** * Print error message for an error that the library * cannot recover from. The library will abort the * process after calling this function. * * @param ctx Function pointer container * @param fmt Format string * @param ... Format argument */ void (*print_abort)(struct libgeome_context *ctx, const char *fmt, ...); /** * Print debug message * * @param ctx Function pointer container * @param fmt Format string * @param ... Format argument */ void (*print_debug)(struct libgeome_context *ctx, const char *fmt, ...); }; /** * Geolocation network service description */ struct libgeome_netservice { /** * Geolocation data that may be provided by the service * * 0 if unknown (always known (non-zero) when retrieved * from libgeome_netservices) * * See `struct libgeome_data.requested_data` */ uint64_t can_fetch; /** * A unique number assigned to each unique service, * so that alternatives that user the same service * can be recognised * * Only set when stated so in the source * * This is used because a service may have multiple * ways to fetch the data, as all supported ones * are added in case one is removed in the future; * this could be multiple APIs or even multiple * URLs * * These number are sorted and start from 0, * and increment by one for each new service that's * not just another way to use the service in the * previous entry */ size_t service_id; /** * Expected maximum output size */ size_t limit; /** * Expected maximum invokation duration */ unsigned int alarm_seconds; /** * Path command to run to get the location * (this would be "curl") */ const char *path; /** * Command to run to get the location * (this would be curl with some parameters * and an URL) */ const char *const *args; /** * Whether `.path` or `.args` contain %-patterns * * See `libgeome_get_from_patterned_command` for more information * * @since 2.0 */ unsigned patterned : 1; }; /** * Built in list of geolocation network service * * `.service_id` is set * * Be aware these services may have terms of use that * restrict how you are allowed to use them. */ extern const struct libgeome_netservice libgeome_netservices[]; /** * The number of elements in `libgeome_netservices` */ extern const size_t libgeome_netservices_count; /** * The default file for `libgeome_get_from_file` * * By default this is `/etc/geolocation`, but it can be * changed at compile-time * * @since 2.0 */ extern const char *const libgeome_default_geolocation_file; /** * Create a basic initialisation for `struct libgeome_context` * * Note that the implementation will use `ctx_out->user_data` to store `procname` * there. It will not make a copy of `procname`, so `procname` must be valid while * the context is in use * * `*ctx_out->print_error` and `*ctx_out->print_abort` will print plain * error messages, but `*ctx_out->print_debug` will not do anything. * If you want debug outputs, you can assign `ctx_out->print_error` or * `ctx_out->print_abort` to `ctx_out->print_debug`. * * @param ctx_out Structure to initialise * @param procname The name of the process, will be prefixed to all outputs * using the format `"%s: ", procname`. It may be a good idea * to add prepend ": libgeome: " to make it clear that the * output comes from libgeome */ void libgeome_basic_context(struct libgeome_context *ctx_out, const char *procname); /** * Get the machine's partability class * * @param ctx Library context * @param out Output parameter * @return 0 on success, -1 on failure * * @since 2.0 */ int libgeome_get_portability(struct libgeome_context *ctx, enum libgeome_portability *out); /** * Get a very rough location guess based on * the current timezone's offset from UTC * * This can always be used to get the longitude, * but only the longitude * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise */ int libgeome_get_from_time(struct libgeome_context *ctx, struct libgeome_data *out); /** * Get a rather rough location guess based on * timezone data: the nominally the timezone's * most populous city * * It is not guaranteed that the needed information * is installed on the machine, and even if it is, * does not necessarily contain needed data for the * user's timezone * * This function will get both the latitude and * the longitude but nothing more, provided it found * data for the timezone * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise */ int libgeome_get_from_timezone(struct libgeome_context *ctx, struct libgeome_data *out); /** * Get the user's location from a file where it has * been manually stored * * This function will get both the latitude and * the longitude but nothing more * * The default file stored in `libgeome_default_geolocation_file` * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @param path The file to read, `NULL` to use the default * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise */ int libgeome_get_from_file(struct libgeome_context *ctx, struct libgeome_data *out, const char *path); /** * Spawn a program and read it's standard output * to get the user's location data * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @param limit Number of bytes to stop reading output after, zero for default * @param alarm_sec If non-zero, the number of seconds to let the subprocess live * @param path Path to command to spawn * @param argv Command line arguments for the process, including the name of the command * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise */ int libgeome_get_from_command(struct libgeome_context *ctx, struct libgeome_data *out, size_t limit, unsigned int alarm_sec, const char *path, const char *const *argv); /** * Spawn a program and read it's standard output * to get the user's location data * * `path` and elements of `argv` are subject to %-substitution * using the following rules: * * - The string is parsed from left to right * - Any '%' trigger substitutation * - If the next character is not '%', the "%%" is replaced with a literal "%" * - Otherwise the next character character must be '{' and '%' marks the beginning * of a %-pattern. * - Within a %-pattern "%%" is replaced with "%" and "%}" with "}", and no other * use of "%" is invalid (nested patterns are disallowed). * - A %-pattern ends with the first other occurance of a '}' * - Each %-pattern shall be on one of the two forms: * - "%%{%u:%s}", , * - "%%{!%u:%s}", , * The if the first pattern is used the pattern is deleted and only replaced with * if `out->requested_data & ` is non-zero. * The if the second pattern is used the pattern is deleted and only replaced with * if `out->requested_data & ` is zero. * must be positive. * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @param limit Number of bytes to stop reading output after, zero for default * @param alarm_sec If non-zero, the number of seconds to let the subprocess live * @param path Path to command to spawn * @param argv Command line arguments for the process, including the name of the command * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise * * @since 2.0 */ int libgeome_get_from_patterned_command(struct libgeome_context *ctx, struct libgeome_data *out, size_t limit, unsigned int alarm_sec, const char *path, const char *const *argv); /** * Spawn a program and read it's standard output * to get the user's location data * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @param svc Parameters for the command to run * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise */ int libgeome_get_from_netservice(struct libgeome_context *ctx, struct libgeome_data *out, const struct libgeome_netservice *svc); #endif