]> git.ipfire.org Git - people/ms/libloc.git/blame - src/country.c
country: Drop unused CC_LEN
[people/ms/libloc.git] / src / country.c
CommitLineData
ec684c1a
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2019 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <stdlib.h>
19#include <string.h>
20
c12a1385
MT
21#include <libloc/libloc.h>
22#include <libloc/compat.h>
23#include <libloc/country.h>
3eb1eed6 24#include <libloc/network.h>
c12a1385 25#include <libloc/private.h>
ec684c1a 26
3eb1eed6
MT
27static const struct loc_special_country {
28 const char code[3];
29 enum loc_network_flags flags;
30} loc_special_countries[] = {
31 { "A1", LOC_NETWORK_FLAG_ANONYMOUS_PROXY },
32 { "A2", LOC_NETWORK_FLAG_SATELLITE_PROVIDER },
33 { "A3", LOC_NETWORK_FLAG_ANYCAST },
34 { "XD", LOC_NETWORK_FLAG_DROP },
35 { "", 0 },
36};
37
ec684c1a
MT
38struct loc_country {
39 struct loc_ctx* ctx;
40 int refcount;
41
32b16159
MT
42 // Store the country code in a 3 byte buffer. Two bytes for the code, and NULL so
43 // that we can use strcmp() and return a pointer.
44 char code[3];
45 char continent_code[3];
ec684c1a
MT
46
47 char* name;
48};
49
50LOC_EXPORT int loc_country_new(struct loc_ctx* ctx, struct loc_country** country, const char* country_code) {
e73b7709
MT
51 // Check of the country code is valid
52 if (!loc_country_code_is_valid(country_code)) {
53 errno = EINVAL;
54 return 1;
55 }
e646a8f3 56
ec684c1a
MT
57 struct loc_country* c = calloc(1, sizeof(*c));
58 if (!c)
198e382c 59 return 1;
ec684c1a
MT
60
61 c->ctx = loc_ref(ctx);
62 c->refcount = 1;
63
32b16159
MT
64 // Set the country code
65 loc_country_code_copy(c->code, country_code);
ec684c1a
MT
66
67 DEBUG(c->ctx, "Country %s allocated at %p\n", c->code, c);
68 *country = c;
69
70 return 0;
71}
72
73LOC_EXPORT struct loc_country* loc_country_ref(struct loc_country* country) {
74 country->refcount++;
75
76 return country;
77}
78
79static void loc_country_free(struct loc_country* country) {
80 DEBUG(country->ctx, "Releasing country %s %p\n", country->code, country);
81
ec684c1a
MT
82 if (country->name)
83 free(country->name);
84
85 loc_unref(country->ctx);
86 free(country);
87}
88
89LOC_EXPORT struct loc_country* loc_country_unref(struct loc_country* country) {
90 if (--country->refcount > 0)
91 return NULL;
92
93 loc_country_free(country);
ec684c1a
MT
94 return NULL;
95}
96
97LOC_EXPORT const char* loc_country_get_code(struct loc_country* country) {
98 return country->code;
99}
100
101LOC_EXPORT const char* loc_country_get_continent_code(struct loc_country* country) {
102 return country->continent_code;
103}
104
105LOC_EXPORT int loc_country_set_continent_code(struct loc_country* country, const char* continent_code) {
32b16159
MT
106 // Check for valid input
107 if (!continent_code || strlen(continent_code) != 2) {
108 errno = EINVAL;
109 return 1;
110 }
ec684c1a 111
32b16159
MT
112 // Store the code
113 loc_country_code_copy(country->continent_code, continent_code);
ec684c1a
MT
114
115 return 0;
116}
117
118LOC_EXPORT const char* loc_country_get_name(struct loc_country* country) {
119 return country->name;
120}
121
122LOC_EXPORT int loc_country_set_name(struct loc_country* country, const char* name) {
123 if (country->name)
124 free(country->name);
125
32b16159 126 if (name) {
ec684c1a
MT
127 country->name = strdup(name);
128
32b16159
MT
129 // Report error if we could not copy the string
130 if (!country->name)
131 return 1;
132 }
133
ec684c1a
MT
134 return 0;
135}
136
af208e26 137LOC_EXPORT int loc_country_cmp(struct loc_country* country1, struct loc_country* country2) {
32b16159 138 return strncmp(country1->code, country2->code, 2);
ec684c1a
MT
139}
140
b904896a
MT
141int loc_country_new_from_database_v1(struct loc_ctx* ctx, struct loc_stringpool* pool,
142 struct loc_country** country, const struct loc_database_country_v1* dbobj) {
32b16159 143 char buffer[3] = "XX";
ec684c1a
MT
144
145 // Read country code
a7a3d958 146 loc_country_code_copy(buffer, dbobj->code);
ec684c1a
MT
147
148 // Create a new country object
149 int r = loc_country_new(ctx, country, buffer);
150 if (r)
151 return r;
152
32b16159
MT
153 // Copy continent code
154 if (*dbobj->continent_code)
155 loc_country_code_copy((*country)->continent_code, dbobj->continent_code);
ec684c1a
MT
156
157 // Set name
ec684c1a
MT
158 const char* name = loc_stringpool_get(pool, be32toh(dbobj->name));
159 if (name) {
160 r = loc_country_set_name(*country, name);
161 if (r)
162 goto FAIL;
163 }
ec684c1a
MT
164
165 return 0;
166
167FAIL:
168 loc_country_unref(*country);
169 return r;
170}
171
b904896a
MT
172int loc_country_to_database_v1(struct loc_country* country,
173 struct loc_stringpool* pool, struct loc_database_country_v1* dbobj) {
32b16159
MT
174 off_t name = 0;
175
ec684c1a 176 // Add country code
32b16159
MT
177 if (*country->code)
178 loc_country_code_copy(dbobj->code, country->code);
ec684c1a
MT
179
180 // Add continent code
32b16159
MT
181 if (*country->continent_code)
182 loc_country_code_copy(dbobj->continent_code, country->continent_code);
ec684c1a
MT
183
184 // Save the name string in the string pool
32b16159
MT
185 if (country->name)
186 name = loc_stringpool_add(pool, country->name);
187
ec684c1a
MT
188 dbobj->name = htobe32(name);
189
190 return 0;
191}
0f0829ef
MT
192
193LOC_EXPORT int loc_country_code_is_valid(const char* cc) {
194 // It cannot be NULL
195 if (!cc || !*cc)
196 return 0;
197
198 // It must be 2 characters long
199 if (strlen(cc) != 2)
200 return 0;
201
202 // It must only contain A-Z
203 for (unsigned int i = 0; i < 2; i++) {
204 if (cc[i] < 'A' || cc[i] > 'Z')
205 return 0;
206 }
207
e8ebd079
MT
208 // The code cannot begin with an X (those are reserved for private use)
209 if (*cc == 'X')
210 return 0;
211
0f0829ef
MT
212 // Looks valid
213 return 1;
214}
3eb1eed6
MT
215
216LOC_EXPORT int loc_country_special_code_to_flag(const char* cc) {
217 // Check if we got some input
218 if (!cc || !*cc) {
219 errno = EINVAL;
220 return -1;
221 }
222
223 // Return flags for any known special country
224 for (const struct loc_special_country* country = loc_special_countries;
225 country->flags; country++) {
32b16159 226 if (strncmp(country->code, cc, 2) == 0)
3eb1eed6
MT
227 return country->flags;
228 }
229
230 return 0;
231}