<commit_before>/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */

#include <GeoIP.h>
#include <GeoIPCity.h>
#include <glib.h>
#include <json-glib/json-glib.h>
#include <libsoup/soup.h>

static const char *attribution_text = "This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com\n";

enum ERROR_CODES {
        INVALID_IP_ADDRESS_ERR = 0,
        INVALID_ENTRY_ERR,
        DATABASE_ERR
};
static char *error_message_array [] = {
        "Invalid IP address input",
        "Can not find the IP address in the database",
        "Can not open GeoLiteCity/GeoIP Binary database. Set GEOIP_DATABASE_PATH env variable."
};

static void
add_json_object_for_address (JsonBuilder *builder,
                             const char  *name,
                             const char  *code,
                             const char  *type)
{
        if (!name && !code)
                return;
        json_builder_begin_object (builder);
        if (name) {
                json_builder_set_member_name (builder, "name");
                json_builder_add_string_value (builder, name);
        }
        if (code) {
                json_builder_set_member_name (builder, "code");
                json_builder_add_string_value (builder, code);
        }
        json_builder_set_member_name (builder, "type");
        json_builder_add_string_value (builder, type);
        json_builder_end_object (builder);
}

static void
print_error_in_json (int        error_code,
                     const char *extra_info)
{
        g_print ("{\"results\":\"%s",error_message_array[error_code]);
        if (extra_info)
                g_print (" - %s\"", extra_info);
        else
                g_print ("\"");
        g_print (",\"status\":\"ERROR\"}\n");
}

static JsonBuilder*
add_result_attr_to_json_tree (const char *ipaddress,
                              GeoIP      *gi)
{
        const char *timezone = NULL;
        JsonBuilder *builder;
        GeoIPRecord *gir;

        gir = GeoIP_record_by_addr (gi, ipaddress);
        if (gir == NULL) {
                print_error_in_json (INVALID_ENTRY_ERR, ipaddress);
                return NULL;
        }

        builder = json_builder_new ();

        json_builder_begin_object (builder); /* begin */

        json_builder_set_member_name (builder, "results");
        json_builder_begin_object (builder); /* begin results object */

        json_builder_set_member_name (builder, ipaddress);
        json_builder_begin_array (builder); /* begin ipaddress array */

        json_builder_begin_object (builder); /* begin ipaddress object */

        json_builder_set_member_name (builder, "location");
        json_builder_begin_object (builder); /* begin location object */
        json_builder_set_member_name (builder, "latitude");
        json_builder_add_double_value (builder, gir->latitude);
        json_builder_set_member_name (builder, "longitude");
        json_builder_add_double_value (builder, gir->longitude);
        json_builder_end_object (builder); /* end location object */

        json_builder_set_member_name (builder, "address");
        json_builder_begin_array (builder); /* begin address array */

        /* Before adding any entry check if that's NULL.
           If NULL then don't add it to the JSON output.
        */
        add_json_object_for_address (builder, gir->city, NULL, "city");
        add_json_object_for_address (builder,
                                     GeoIP_region_name_by_code (gir->country_code, gir->region),
                                     gir->region,
                                     "region");
        add_json_object_for_address (builder, NULL, gir->postal_code, "postalcode");
        add_json_object_for_address (builder, gir->country_name, gir->country_code, "country");

        json_builder_end_array (builder); /* end address array  */

        timezone = GeoIP_time_zone_by_country_and_region(gir->country_code, gir->region);
        if (timezone) {
                json_builder_set_member_name (builder, "timezone");
                json_builder_add_string_value (builder, timezone);
        }

        json_builder_set_member_name (builder, "accuracy");
        json_builder_add_string_value (builder, "city");

        json_builder_set_member_name (builder, "attribution");
        json_builder_add_string_value (builder, attribution_text);

        json_builder_end_object (builder); /* end ipaddress object */

        json_builder_end_array (builder); /* end ipaddress array */

        json_builder_end_object (builder); /* end results object */

        json_builder_set_member_name (builder, "status");
        json_builder_add_string_value (builder, "OK");

        json_builder_end_object (builder); /* end */

        GeoIPRecord_delete (gir);

        return builder;
}

static JsonBuilder*
add_result_attr_to_json_tree_geoipdb (const char *ipaddress,
                                      GeoIP      *gi)
{
        JsonBuilder *builder;
        const char *country_name;
        const char *country_code;

        country_code = GeoIP_country_code_by_addr (gi, ipaddress);
        country_name = GeoIP_country_name_by_addr (gi, ipaddress);

        if (!country_name && !country_code) {
                print_error_in_json (INVALID_ENTRY_ERR, ipaddress);
                return NULL;
        }

        builder = json_builder_new ();

        json_builder_begin_object (builder); /* begin */

        json_builder_set_member_name (builder, "results");
        json_builder_begin_object (builder); /* begin results object */

        json_builder_set_member_name (builder, ipaddress);
        json_builder_begin_array (builder); /* begin ipaddress array */
        json_builder_begin_object (builder); /* begin ipaddress object */

        json_builder_set_member_name (builder, "address");
        json_builder_begin_array (builder); /* begin address array */

        /* Before adding any entry check if that's NULL.
           If NULL then don't add it to the JSON output.
        */
        add_json_object_for_address (builder,
                                     GeoIP_country_name_by_addr (gi, ipaddress),
                                     GeoIP_country_code_by_addr (gi, ipaddress),
                                     "country");

        json_builder_end_array (builder); /* end address array  */

        json_builder_set_member_name (builder, "accuracy");
        json_builder_add_string_value (builder, "country");

        json_builder_set_member_name (builder, "attribution");
        json_builder_add_string_value (builder, attribution_text);

        json_builder_end_object (builder); /* end ipaddress object */

        json_builder_end_array (builder); /* end ipaddress array */

        json_builder_end_object (builder); /* end results object */

        json_builder_set_member_name (builder, "status");
        json_builder_add_string_value (builder, "OK");

        json_builder_end_object (builder); /* end */

        return builder;
}

static void
print_json_data (JsonBuilder *builder)
{
        JsonNode *node;
        JsonGenerator *generator;
        char *json_data;
        gsize length;

        node = json_builder_get_root (builder);

        generator = json_generator_new ();
        json_generator_set_root (generator, node);
        json_data = json_generator_to_data (generator, &length);
        g_print ("%*s\n", (int) length, json_data);

        g_free (json_data);
        json_node_free (node);
        g_object_unref (generator);
}<commit_msg>geoip-lookup: Use same JSON format as other free services<commit_after>/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */

#include <GeoIP.h>
#include <GeoIPCity.h>
#include <glib.h>
#include <json-glib/json-glib.h>
#include <libsoup/soup.h>

static const char *attribution_text = "This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com\n";

enum ERROR_CODES {
        INVALID_IP_ADDRESS_ERR = 0,
        INVALID_ENTRY_ERR,
        DATABASE_ERR
};
static char *error_message_array [] = {
        "Invalid IP address '%s'",
        "Can not find the IP address '%s' in the database",
        "Can not open GeoLiteCity/GeoIP Binary database. Set GEOIP_DATABASE_PATH env variable."
};

static void
print_error_in_json (int        error_code,
                     const char *extra_info)
{
        g_print ("{\"error_code\":%d, \"error_message\":\"", error_code);
        if (extra_info)
                g_print (error_message_array[error_code], extra_info);
        else
                g_print (error_message_array[error_code]);
        g_print ("\"}\n");
}

static JsonBuilder*
add_result_attr_to_json_tree (const char *ipaddress,
                              GeoIP      *gi)
{
        const char *timezone = NULL;
        JsonBuilder *builder;
        GeoIPRecord *gir;

        gir = GeoIP_record_by_addr (gi, ipaddress);
        if (gir == NULL) {
                print_error_in_json (INVALID_ENTRY_ERR, ipaddress);
                return NULL;
        }

        builder = json_builder_new ();

        json_builder_begin_object (builder); /* begin */

        json_builder_set_member_name (builder, "ip");
        json_builder_add_string_value (builder, ipaddress);

        json_builder_set_member_name (builder, "latitude");
        json_builder_add_double_value (builder, gir->latitude);
        json_builder_set_member_name (builder, "longitude");
        json_builder_add_double_value (builder, gir->longitude);

        const char *accuracy = "country";

        /* Country level information */
        if (gir->country_name != NULL) {
                json_builder_set_member_name (builder, "country_name");
                json_builder_add_string_value (builder, gir->country_name);
        }
        if (gir->country_code != NULL) {
                json_builder_set_member_name (builder, "country_code");
                json_builder_add_string_value (builder, gir->country_code);

                /* Region level information */
                if (gir->region != NULL) {
                    accuracy = "region";
                    json_builder_set_member_name (builder, "region");
                    json_builder_add_string_value (builder,
                                                   GeoIP_region_name_by_code (gir->country_code, gir->region));
                }
        }
        if (gir->area_code > 0) {
                json_builder_set_member_name (builder, "areacode");
                json_builder_add_int_value (builder, gir->area_code);
        }

        /* City level information */
        if (gir->city != NULL) {
                accuracy = "city";
                json_builder_set_member_name (builder, "city");
                json_builder_add_string_value (builder, gir->city);
        }
        if (gir->postal_code != NULL) {
                json_builder_set_member_name (builder, "zipcode");
                json_builder_add_string_value (builder, gir->postal_code);
        }
        if (gir->metro_code > 0) {
                json_builder_set_member_name (builder, "metro_code");
                json_builder_add_int_value (builder, gir->metro_code);
        }

        json_builder_set_member_name (builder, "accuracy");
        json_builder_add_string_value (builder, accuracy);

        timezone = GeoIP_time_zone_by_country_and_region(gir->country_code, gir->region);
        if (timezone) {
                json_builder_set_member_name (builder, "timezone");
                json_builder_add_string_value (builder, timezone);
        }

        json_builder_set_member_name (builder, "attribution");
        json_builder_add_string_value (builder, attribution_text);

        json_builder_end_object (builder); /* end */

        GeoIPRecord_delete (gir);

        return builder;
}

static JsonBuilder*
add_result_attr_to_json_tree_geoipdb (const char *ipaddress,
                                      GeoIP      *gi)
{
        JsonBuilder *builder;
        const char *country_name;
        const char *country_code;

        country_code = GeoIP_country_code_by_addr (gi, ipaddress);
        country_name = GeoIP_country_name_by_addr (gi, ipaddress);

        if (!country_name && !country_code) {
                print_error_in_json (INVALID_ENTRY_ERR, ipaddress);
                return NULL;
        }

        builder = json_builder_new ();

        json_builder_begin_object (builder); /* begin */

        json_builder_set_member_name (builder, "ip");
        json_builder_add_string_value (builder, ipaddress);

        json_builder_set_member_name (builder, "country_code");
        json_builder_add_string_value (builder, country_code);
        json_builder_set_member_name (builder, "country_name");
        json_builder_add_string_value (builder, country_name);

        json_builder_set_member_name (builder, "accuracy");
        json_builder_add_string_value (builder, "country");

        json_builder_set_member_name (builder, "attribution");
        json_builder_add_string_value (builder, attribution_text);

        json_builder_end_object (builder); /* end */

        return builder;
}

static void
print_json_data (JsonBuilder *builder)
{
        JsonNode *node;
        JsonGenerator *generator;
        char *json_data;
        gsize length;

        node = json_builder_get_root (builder);

        generator = json_generator_new ();
        json_generator_set_root (generator, node);
        json_data = json_generator_to_data (generator, &length);
        g_print ("%*s\n", (int) length, json_data);

        g_free (json_data);
        json_node_free (node);
        g_object_unref (generator);
}
{'fraction_non_alphanumeric': 0.09636535800131109, 'fraction_numerical': 0.0005827081360623498, 'mean_word_length': 2.4001981178801386, 'pattern_counts': {'":': 4, '<': 13, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4254846', 'n_tokens_mistral': 4074, 'n_tokens_neox': 3923, 'n_words': 852}