python: Do not use any GNU-style initialisers for structs
[people/ms/libloc.git] / src / python / database.c
CommitLineData
9cdf6c53
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 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 <Python.h>
18
9fc7f001
MT
19#include <loc/libloc.h>
20#include <loc/database.h>
21
1da9cd39 22#include "locationmodule.h"
86ca7ef7 23#include "as.h"
9cdf6c53 24#include "database.h"
31edab76 25#include "network.h"
9cdf6c53
MT
26
27static PyObject* Database_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
9cdf6c53 28 DatabaseObject* self = (DatabaseObject*)type->tp_alloc(type, 0);
9cdf6c53
MT
29
30 return (PyObject*)self;
31}
32
33static void Database_dealloc(DatabaseObject* self) {
34 if (self->db)
35 loc_database_unref(self->db);
36
6fd96715
MT
37 if (self->path)
38 free(self->path);
39
9cdf6c53
MT
40 Py_TYPE(self)->tp_free((PyObject* )self);
41}
42
43static int Database_init(DatabaseObject* self, PyObject* args, PyObject* kwargs) {
44 const char* path = NULL;
45
46 if (!PyArg_ParseTuple(args, "s", &path))
47 return -1;
48
6fd96715
MT
49 self->path = strdup(path);
50
9cdf6c53 51 // Open the file for reading
6fd96715 52 FILE* f = fopen(self->path, "r");
774eea26
MT
53 if (!f) {
54 PyErr_SetFromErrno(PyExc_IOError);
9cdf6c53 55 return -1;
774eea26 56 }
9cdf6c53
MT
57
58 // Load the database
38e07ee0 59 int r = loc_database_new(loc_ctx, &self->db, f);
9cdf6c53
MT
60 fclose(f);
61
62 // Return on any errors
63 if (r)
64 return -1;
65
66 return 0;
67}
68
6fd96715
MT
69static PyObject* Database_repr(DatabaseObject* self) {
70 return PyUnicode_FromFormat("<Database %s>", self->path);
71}
72
d99b0256
MT
73static PyObject* Database_get_description(DatabaseObject* self) {
74 const char* description = loc_database_get_description(self->db);
75
76 return PyUnicode_FromString(description);
77}
78
79static PyObject* Database_get_vendor(DatabaseObject* self) {
80 const char* vendor = loc_database_get_vendor(self->db);
81
82 return PyUnicode_FromString(vendor);
83}
84
4bf49d00
MT
85static PyObject* Database_get_license(DatabaseObject* self) {
86 const char* license = loc_database_get_license(self->db);
87
88 return PyUnicode_FromString(license);
89}
90
53524b2d
MT
91static PyObject* Database_get_created_at(DatabaseObject* self) {
92 time_t created_at = loc_database_created_at(self->db);
93
94 return PyLong_FromLong(created_at);
95}
96
86ca7ef7
MT
97static PyObject* Database_get_as(DatabaseObject* self, PyObject* args) {
98 struct loc_as* as = NULL;
99 uint32_t number = 0;
100
101 if (!PyArg_ParseTuple(args, "i", &number))
102 return NULL;
103
104 // Try to retrieve the AS
105 int r = loc_database_get_as(self->db, &as, number);
86ca7ef7 106
4a0a0f7e
MT
107 // We got an AS
108 if (r == 0) {
86ca7ef7
MT
109 PyObject* obj = new_as(&ASType, as);
110 loc_as_unref(as);
111
112 return obj;
86ca7ef7
MT
113
114 // Nothing found
4a0a0f7e
MT
115 } else if (r == 1) {
116 Py_RETURN_NONE;
117 }
118
119 // Unexpected error
120 return NULL;
86ca7ef7
MT
121}
122
31edab76
MT
123static PyObject* Database_lookup(DatabaseObject* self, PyObject* args) {
124 struct loc_network* network = NULL;
125 const char* address = NULL;
126
127 if (!PyArg_ParseTuple(args, "s", &address))
128 return NULL;
129
130 // Try to retrieve a matching network
131 int r = loc_database_lookup_from_string(self->db, address, &network);
132
133 // We got a network
134 if (r == 0) {
135 PyObject* obj = new_network(&NetworkType, network);
136 loc_network_unref(network);
137
138 return obj;
139
140 // Nothing found
141 } else if (r == 1) {
142 Py_RETURN_NONE;
927e82f2
MT
143
144 // Invalid input
145 } else if (r == -EINVAL) {
146 PyErr_Format(PyExc_ValueError, "Invalid IP address: %s", address);
147 return NULL;
31edab76
MT
148 }
149
150 // Unexpected error
151 return NULL;
152}
153
afb426df
MT
154static PyObject* new_database_enumerator(PyTypeObject* type, struct loc_database_enumerator* enumerator) {
155 DatabaseEnumeratorObject* self = (DatabaseEnumeratorObject*)type->tp_alloc(type, 0);
156 if (self) {
157 self->enumerator = loc_database_enumerator_ref(enumerator);
158 }
159
160 return (PyObject*)self;
161}
162
163static PyObject* Database_search_as(DatabaseObject* self, PyObject* args) {
164 const char* string = NULL;
165
166 if (!PyArg_ParseTuple(args, "s", &string))
167 return NULL;
168
169 struct loc_database_enumerator* enumerator;
170
171 int r = loc_database_enumerator_new(&enumerator, self->db);
172 if (r) {
173 PyErr_SetFromErrno(PyExc_SystemError);
174 return NULL;
175 }
176
177 // Search string we are searching for
178 loc_database_enumerator_set_string(enumerator, string);
179
180 PyObject* obj = new_database_enumerator(&DatabaseEnumeratorType, enumerator);
181 loc_database_enumerator_unref(enumerator);
182
183 return obj;
184}
185
9cdf6c53 186static struct PyMethodDef Database_methods[] = {
86ca7ef7
MT
187 {
188 "get_as",
189 (PyCFunction)Database_get_as,
190 METH_VARARGS,
191 NULL,
192 },
31edab76
MT
193 {
194 "lookup",
195 (PyCFunction)Database_lookup,
196 METH_VARARGS,
197 NULL,
198 },
afb426df
MT
199 {
200 "search_as",
201 (PyCFunction)Database_search_as,
202 METH_VARARGS,
203 NULL,
204 },
9cdf6c53
MT
205 { NULL },
206};
207
d99b0256 208static struct PyGetSetDef Database_getsetters[] = {
53524b2d
MT
209 {
210 "created_at",
211 (getter)Database_get_created_at,
212 NULL,
213 NULL,
214 NULL,
215 },
d99b0256
MT
216 {
217 "description",
218 (getter)Database_get_description,
219 NULL,
220 NULL,
221 NULL,
222 },
4bf49d00
MT
223 {
224 "license",
225 (getter)Database_get_license,
226 NULL,
227 NULL,
228 NULL,
229 },
d99b0256
MT
230 {
231 "vendor",
232 (getter)Database_get_vendor,
233 NULL,
234 NULL,
53524b2d 235 NULL,
d99b0256
MT
236 },
237 { NULL },
238};
239
9cdf6c53
MT
240PyTypeObject DatabaseType = {
241 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
242 .tp_name = "location.Database",
243 .tp_basicsize = sizeof(DatabaseObject),
244 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
245 .tp_new = Database_new,
246 .tp_dealloc = (destructor)Database_dealloc,
247 .tp_init = (initproc)Database_init,
248 .tp_doc = "Database object",
249 .tp_methods = Database_methods,
250 .tp_getset = Database_getsetters,
251 .tp_repr = (reprfunc)Database_repr,
9cdf6c53 252};
afb426df
MT
253
254static PyObject* DatabaseEnumerator_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
255 DatabaseEnumeratorObject* self = (DatabaseEnumeratorObject*)type->tp_alloc(type, 0);
256
257 return (PyObject*)self;
258}
259
260static void DatabaseEnumerator_dealloc(DatabaseEnumeratorObject* self) {
261 loc_database_enumerator_unref(self->enumerator);
262
263 Py_TYPE(self)->tp_free((PyObject* )self);
264}
265
266static PyObject* DatabaseEnumerator_next(DatabaseEnumeratorObject* self) {
267 struct loc_as* as = loc_database_enumerator_next_as(self->enumerator);
268 if (as) {
269 PyObject* obj = new_as(&ASType, as);
270 loc_as_unref(as);
271
272 return obj;
273 }
274
275 // Nothing found, that means the end
276 PyErr_SetNone(PyExc_StopIteration);
277 return NULL;
278}
279
280PyTypeObject DatabaseEnumeratorType = {
281 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
282 .tp_name = "location.DatabaseEnumerator",
283 .tp_basicsize = sizeof(DatabaseEnumeratorObject),
284 .tp_flags = Py_TPFLAGS_DEFAULT,
285 .tp_alloc = PyType_GenericAlloc,
286 .tp_new = DatabaseEnumerator_new,
287 .tp_dealloc = (destructor)DatabaseEnumerator_dealloc,
288 .tp_iter = PyObject_SelfIter,
289 .tp_iternext = (iternextfunc)DatabaseEnumerator_next,
afb426df 290};