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