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