]> git.ipfire.org Git - location/libloc.git/blame - src/country.c
network: Sort result of excluded lists
[location/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
21#include <loc/libloc.h>
c2108435 22#include <loc/compat.h>
ec684c1a
MT
23#include <loc/country.h>
24#include <loc/private.h>
25
26struct loc_country {
27 struct loc_ctx* ctx;
28 int refcount;
29
30 char* code;
31 char* continent_code;
32
33 char* name;
34};
35
36LOC_EXPORT int loc_country_new(struct loc_ctx* ctx, struct loc_country** country, const char* country_code) {
37 struct loc_country* c = calloc(1, sizeof(*c));
38 if (!c)
39 return -ENOMEM;
40
41 c->ctx = loc_ref(ctx);
42 c->refcount = 1;
43
44 c->code = strdup(country_code);
45
46 DEBUG(c->ctx, "Country %s allocated at %p\n", c->code, c);
47 *country = c;
48
49 return 0;
50}
51
52LOC_EXPORT struct loc_country* loc_country_ref(struct loc_country* country) {
53 country->refcount++;
54
55 return country;
56}
57
58static void loc_country_free(struct loc_country* country) {
59 DEBUG(country->ctx, "Releasing country %s %p\n", country->code, country);
60
61 if (country->code)
62 free(country->code);
63
64 if (country->continent_code)
65 free(country->continent_code);
66
67 if (country->name)
68 free(country->name);
69
70 loc_unref(country->ctx);
71 free(country);
72}
73
74LOC_EXPORT struct loc_country* loc_country_unref(struct loc_country* country) {
75 if (--country->refcount > 0)
76 return NULL;
77
78 loc_country_free(country);
79
80 return NULL;
81}
82
83LOC_EXPORT const char* loc_country_get_code(struct loc_country* country) {
84 return country->code;
85}
86
87LOC_EXPORT const char* loc_country_get_continent_code(struct loc_country* country) {
88 return country->continent_code;
89}
90
91LOC_EXPORT int loc_country_set_continent_code(struct loc_country* country, const char* continent_code) {
92 // XXX validate input
93
94 // Free previous value
95 if (country->continent_code)
96 free(country->continent_code);
97
98 country->continent_code = strdup(continent_code);
99
100 return 0;
101}
102
103LOC_EXPORT const char* loc_country_get_name(struct loc_country* country) {
104 return country->name;
105}
106
107LOC_EXPORT int loc_country_set_name(struct loc_country* country, const char* name) {
108 if (country->name)
109 free(country->name);
110
111 if (name)
112 country->name = strdup(name);
113
114 return 0;
115}
116
af208e26 117LOC_EXPORT int loc_country_cmp(struct loc_country* country1, struct loc_country* country2) {
ec684c1a
MT
118 return strcmp(country1->code, country2->code);
119}
120
b904896a
MT
121int loc_country_new_from_database_v1(struct loc_ctx* ctx, struct loc_stringpool* pool,
122 struct loc_country** country, const struct loc_database_country_v1* dbobj) {
ec684c1a
MT
123 char buffer[3];
124
125 // Read country code
a7a3d958 126 loc_country_code_copy(buffer, dbobj->code);
ec684c1a 127
61d3516b
MT
128 // Terminate buffer
129 buffer[2] = '\0';
130
ec684c1a
MT
131 // Create a new country object
132 int r = loc_country_new(ctx, country, buffer);
133 if (r)
134 return r;
135
136 // Continent Code
a7a3d958 137 loc_country_code_copy(buffer, dbobj->continent_code);
ec684c1a
MT
138
139 r = loc_country_set_continent_code(*country, buffer);
140 if (r)
141 goto FAIL;
142
143 // Set name
ec684c1a
MT
144 const char* name = loc_stringpool_get(pool, be32toh(dbobj->name));
145 if (name) {
146 r = loc_country_set_name(*country, name);
147 if (r)
148 goto FAIL;
149 }
ec684c1a
MT
150
151 return 0;
152
153FAIL:
154 loc_country_unref(*country);
155 return r;
156}
157
b904896a
MT
158int loc_country_to_database_v1(struct loc_country* country,
159 struct loc_stringpool* pool, struct loc_database_country_v1* dbobj) {
ec684c1a
MT
160 // Add country code
161 for (unsigned int i = 0; i < 2; i++) {
162 dbobj->code[i] = country->code[i] ? country->code[i] : '\0';
163 }
164
165 // Add continent code
d7c9d57b
MT
166 if (country->continent_code) {
167 for (unsigned int i = 0; i < 2; i++) {
168 dbobj->continent_code[i] = country->continent_code[i] ? country->continent_code[i] : '\0';
169 }
ec684c1a
MT
170 }
171
172 // Save the name string in the string pool
173 off_t name = loc_stringpool_add(pool, country->name ? country->name : "");
174 dbobj->name = htobe32(name);
175
176 return 0;
177}
0f0829ef
MT
178
179LOC_EXPORT int loc_country_code_is_valid(const char* cc) {
180 // It cannot be NULL
181 if (!cc || !*cc)
182 return 0;
183
184 // It must be 2 characters long
185 if (strlen(cc) != 2)
186 return 0;
187
188 // It must only contain A-Z
189 for (unsigned int i = 0; i < 2; i++) {
190 if (cc[i] < 'A' || cc[i] > 'Z')
191 return 0;
192 }
193
194 // Looks valid
195 return 1;
196}