]> git.ipfire.org Git - location/libloc.git/blobdiff - src/country.c
Make sources around that we can run tests without location installed
[location/libloc.git] / src / country.c
index 909895047f922eeb5578c016b21f29f51a7af5f2..0f133198e4ec50f1adcdf46bf334f511ecc071ec 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include <loc/libloc.h>
-#include <loc/compat.h>
-#include <loc/country.h>
-#include <loc/private.h>
+#include <libloc/libloc.h>
+#include <libloc/compat.h>
+#include <libloc/country.h>
+#include <libloc/network.h>
+#include <libloc/private.h>
+
+static const struct loc_special_country {
+       const char code[3];
+       enum loc_network_flags flags;
+} loc_special_countries[] = {
+       { "A1", LOC_NETWORK_FLAG_ANONYMOUS_PROXY },
+       { "A2", LOC_NETWORK_FLAG_SATELLITE_PROVIDER },
+       { "A3", LOC_NETWORK_FLAG_ANYCAST },
+       { "XD", LOC_NETWORK_FLAG_DROP },
+       { "", 0 },
+};
 
 struct loc_country {
        struct loc_ctx* ctx;
@@ -34,6 +46,12 @@ struct loc_country {
 };
 
 LOC_EXPORT int loc_country_new(struct loc_ctx* ctx, struct loc_country** country, const char* country_code) {
+       // Check of the country code is valid
+       if (!loc_country_code_is_valid(country_code)) {
+               errno = EINVAL;
+               return 1;
+       }
+
        struct loc_country* c = calloc(1, sizeof(*c));
        if (!c)
                return -ENOMEM;
@@ -118,13 +136,16 @@ LOC_EXPORT int loc_country_cmp(struct loc_country* country1, struct loc_country*
        return strcmp(country1->code, country2->code);
 }
 
-int loc_country_new_from_database_v0(struct loc_ctx* ctx, struct loc_stringpool* pool,
-               struct loc_country** country, const struct loc_database_country_v0* dbobj) {
+int loc_country_new_from_database_v1(struct loc_ctx* ctx, struct loc_stringpool* pool,
+               struct loc_country** country, const struct loc_database_country_v1* dbobj) {
        char buffer[3];
 
        // Read country code
        loc_country_code_copy(buffer, dbobj->code);
 
+       // Terminate buffer
+       buffer[2] = '\0';
+
        // Create a new country object
        int r = loc_country_new(ctx, country, buffer);
        if (r)
@@ -152,8 +173,8 @@ FAIL:
        return r;
 }
 
-int loc_country_to_database_v0(struct loc_country* country,
-               struct loc_stringpool* pool, struct loc_database_country_v0* dbobj) {
+int loc_country_to_database_v1(struct loc_country* country,
+               struct loc_stringpool* pool, struct loc_database_country_v1* dbobj) {
        // Add country code
        for (unsigned int i = 0; i < 2; i++) {
                dbobj->code[i] = country->code[i] ? country->code[i] : '\0';
@@ -172,3 +193,43 @@ int loc_country_to_database_v0(struct loc_country* country,
 
        return 0;
 }
+
+LOC_EXPORT int loc_country_code_is_valid(const char* cc) {
+       // It cannot be NULL
+       if (!cc || !*cc)
+               return 0;
+
+       // It must be 2 characters long
+       if (strlen(cc) != 2)
+               return 0;
+
+       // It must only contain A-Z
+       for (unsigned int i = 0; i < 2; i++) {
+               if (cc[i] < 'A' || cc[i] > 'Z')
+                       return 0;
+       }
+
+       // The code cannot begin with an X (those are reserved for private use)
+       if (*cc == 'X')
+               return 0;
+
+       // Looks valid
+       return 1;
+}
+
+LOC_EXPORT int loc_country_special_code_to_flag(const char* cc) {
+       // Check if we got some input
+       if (!cc || !*cc) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       // Return flags for any known special country
+       for (const struct loc_special_country* country = loc_special_countries;
+                       country->flags; country++) {
+               if (strcmp(country->code, cc) == 0)
+                       return country->flags;
+       }
+
+       return 0;
+}