]> git.ipfire.org Git - location/libloc.git/blob - src/country.c
7aac0dba3ae50acffffb52284cdcfeb7fc73fe92
[location/libloc.git] / src / country.c
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>
22 #include <loc/compat.h>
23 #include <loc/country.h>
24 #include <loc/private.h>
25
26 struct loc_country {
27 struct loc_ctx* ctx;
28 int refcount;
29
30 char* code;
31 char* continent_code;
32
33 char* name;
34 };
35
36 LOC_EXPORT int loc_country_new(struct loc_ctx* ctx, struct loc_country** country, const char* country_code) {
37 if (!loc_country_code_is_valid(country_code))
38 return -EINVAL;
39
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
55 LOC_EXPORT struct loc_country* loc_country_ref(struct loc_country* country) {
56 country->refcount++;
57
58 return country;
59 }
60
61 static 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
77 LOC_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
86 LOC_EXPORT const char* loc_country_get_code(struct loc_country* country) {
87 return country->code;
88 }
89
90 LOC_EXPORT const char* loc_country_get_continent_code(struct loc_country* country) {
91 return country->continent_code;
92 }
93
94 LOC_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
106 LOC_EXPORT const char* loc_country_get_name(struct loc_country* country) {
107 return country->name;
108 }
109
110 LOC_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
120 LOC_EXPORT int loc_country_cmp(struct loc_country* country1, struct loc_country* country2) {
121 return strcmp(country1->code, country2->code);
122 }
123
124 int 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) {
126 char buffer[3];
127
128 // Read country code
129 loc_country_code_copy(buffer, dbobj->code);
130
131 // Terminate buffer
132 buffer[2] = '\0';
133
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
140 loc_country_code_copy(buffer, dbobj->continent_code);
141
142 r = loc_country_set_continent_code(*country, buffer);
143 if (r)
144 goto FAIL;
145
146 // Set name
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 }
153
154 return 0;
155
156 FAIL:
157 loc_country_unref(*country);
158 return r;
159 }
160
161 int loc_country_to_database_v1(struct loc_country* country,
162 struct loc_stringpool* pool, struct loc_database_country_v1* dbobj) {
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
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 }
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 }
181
182 LOC_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 }