1 #line 982 "../../src/builtin/snarf.m4"
2 /* -*- buffer-read-only: t -*- vi: set ro:
3 THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT.
4 */
5 #line 982
6 #ifdef HAVE_CONFIG_H
7 #line 982
8 # include <config.h>
9 #line 982
10 #endif
11 #line 982
12 #include <sys/types.h>
13 #line 982
14
15 #line 982
16 #include "mailfromd.h"
17 #line 982
18 #include "prog.h"
19 #line 982
20 #include "builtin.h"
21 #line 982
22
23 #line 982
24
25 #line 1022 "../../src/builtin/snarf.m4"
26
27 /* End of snarf.m4 */
28 #line 1 "geoip2.bi"
29 /* This file is part of Mailfromd. -*- c -*-
30 Copyright (C) 2020-2021 Sergey Poznyakoff
31
32 This program is free software; you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation; either version 3, or (at your option)
35 any later version.
36
37 This program is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details.
41
42 You should have received a copy of the GNU General Public License
43 along with this program. If not, see <http://www.gnu.org/licenses/>. */
44
45
46 #ifdef WITH_GEOIP2
47 #line 18
48
49 #include <inttypes.h>
50 #include <maxminddb.h>
51
52 #define DEFAULT_DIR "/usr/share/GeoIP"
53 #define DEFAULT_FILE "GeoLite2-City.mmdb"
54 #define GEOIP2_DEFAULT_DATABASE DEFAULT_DIR "/" DEFAULT_FILE
55
56 struct geoip2_storage {
57 char *dbname;
58 MMDB_s db;
59 int is_open;
60 };
61
62 static void *
geoip2_alloc(void)63 geoip2_alloc(void)
64 {
65 struct geoip2_storage *gs = mu_zalloc(sizeof(*gs));
66 gs->is_open = 0;
67 return gs;
68 }
69
70 static void
geoip2_close(struct geoip2_storage * gs)71 geoip2_close(struct geoip2_storage *gs)
72 {
73 if (gs->is_open) {
74 MMDB_close(&gs->db);
75 gs->is_open = 0;
76 }
77 }
78
79 static void
geoip2_destroy(void * data)80 geoip2_destroy(void *data)
81 {
82 struct geoip2_storage *gs = data;
83 geoip2_close(gs);
84 free(gs->dbname);
85 free(gs);
86 }
87
88
89 #line 58
90
91 #line 58
92 static int GEOIP2_id;
93 #line 58 "geoip2.bi"
94
95
96 static struct geoip2_storage *
geoip2_open(eval_environ_t env)97 geoip2_open(eval_environ_t env)
98 {
99 int rc;
100 struct geoip2_storage *gs = env_get_builtin_priv(env,GEOIP2_id);
101 if (!gs->is_open) {
102 if (!gs->dbname)
103 gs->dbname = mu_strdup(GEOIP2_DEFAULT_DATABASE);
104 rc = MMDB_open(gs->dbname, MMDB_MODE_MMAP, &gs->db);
105 if (!(rc == MMDB_SUCCESS))
106 #line 69
107 (
108 #line 69
109 env_throw_bi(env, mfe_failure, NULL, "can't open database \"%s\": %s",gs->dbname,MMDB_strerror(rc))
110 #line 69
111 )
112 #line 72
113 ;
114 gs->is_open = 1;
115 }
116 return gs;
117 }
118
119 void
120 #line 78
bi_geoip2_dbname(eval_environ_t env)121 bi_geoip2_dbname(eval_environ_t env)
122 #line 78
123
124 #line 78
125
126 #line 78 "geoip2.bi"
127 {
128 #line 78
129
130 #line 78
131
132 #line 78
133
134 #line 78
135
136 #line 78
137
138 #line 78
139
140 #line 78
141 adjust_stack(env, 0);
142 #line 78
143
144 #line 78
145
146 #line 78
147 if (builtin_module_trace(BUILTIN_IDX_geoip2))
148 #line 78
149 prog_trace(env, "geoip2_dbname");;
150 #line 78
151
152 {
153 struct geoip2_storage *gs = env_get_builtin_priv(env,GEOIP2_id);
154
155 #line 81
156 do {
157 #line 81
158 pushs(env, gs->dbname ? gs->dbname : GEOIP2_DEFAULT_DATABASE);
159 #line 81
160 goto endlab;
161 #line 81
162 } while (0);
163 }
164 endlab:
165 #line 83
166 env_function_cleanup_flush(env, NULL);
167 #line 83
168 return;
169 #line 83
170 }
171
172 void
173 #line 85
bi_geoip2_open(eval_environ_t env)174 bi_geoip2_open(eval_environ_t env)
175 #line 85
176
177 #line 85
178
179 #line 85 "geoip2.bi"
180 {
181 #line 85
182
183 #line 85
184
185 #line 85
186
187 #line 85
188 char * name;
189 #line 85
190
191 #line 85
192 get_string_arg(env, 0, &name);
193 #line 85
194
195 #line 85
196
197 #line 85
198 adjust_stack(env, 1);
199 #line 85
200
201 #line 85
202
203 #line 85
204 if (builtin_module_trace(BUILTIN_IDX_geoip2))
205 #line 85
206 prog_trace(env, "geoip2_open %s",name);;
207 #line 85
208
209 {
210 struct geoip2_storage *gs = env_get_builtin_priv(env,GEOIP2_id);
211 geoip2_close(gs);
212 free(gs->dbname);
213 gs->dbname = mu_strdup(name);
214 geoip2_open(env);
215 }
216
217 #line 93
218 env_function_cleanup_flush(env, NULL);
219 #line 93
220 return;
221 #line 93
222 }
223
224 static void
conv_utf_string(eval_environ_t env,MMDB_entry_data_s * dptr)225 conv_utf_string(eval_environ_t env, MMDB_entry_data_s *dptr)
226 {
227 heap_obstack_grow(env, (void*)dptr->utf8_string, dptr->data_size);
228 }
229
230 static void
conv_uint16(eval_environ_t env,MMDB_entry_data_s * dptr)231 conv_uint16(eval_environ_t env, MMDB_entry_data_s *dptr)
232 {
233 heap_obstack_sprintf(env, "%" PRIu16, dptr->uint16);
234 }
235
236 static void
conv_uint32(eval_environ_t env,MMDB_entry_data_s * dptr)237 conv_uint32(eval_environ_t env, MMDB_entry_data_s *dptr)
238 {
239 heap_obstack_sprintf(env, "%" PRIu32, dptr->uint32);
240 }
241
242 static void
conv_int32(eval_environ_t env,MMDB_entry_data_s * dptr)243 conv_int32(eval_environ_t env, MMDB_entry_data_s *dptr)
244 {
245 heap_obstack_sprintf(env, "%" PRIi32, dptr->int32);
246 }
247
248 static void
conv_bool(eval_environ_t env,MMDB_entry_data_s * dptr)249 conv_bool(eval_environ_t env, MMDB_entry_data_s *dptr)
250 {
251 heap_obstack_sprintf(env, "%01d", dptr->boolean ? 1 : 0);
252 }
253
254 static void
conv_double(eval_environ_t env,MMDB_entry_data_s * dptr)255 conv_double(eval_environ_t env, MMDB_entry_data_s *dptr)
256 {
257 heap_obstack_sprintf(env, "%g", dptr->double_value);
258 }
259
260 static void
conv_float(eval_environ_t env,MMDB_entry_data_s * dptr)261 conv_float(eval_environ_t env, MMDB_entry_data_s *dptr)
262 {
263 heap_obstack_sprintf(env, "%g", dptr->float_value);
264 }
265
266 static void (*entry_conv[]) (eval_environ_t, MMDB_entry_data_s *) = {
267 [MMDB_DATA_TYPE_UTF8_STRING] = conv_utf_string,
268 [MMDB_DATA_TYPE_UINT16] = conv_uint16,
269 [MMDB_DATA_TYPE_UINT32] = conv_uint32,
270 [MMDB_DATA_TYPE_INT32] = conv_int32,
271 [MMDB_DATA_TYPE_BOOLEAN] = conv_bool,
272 [MMDB_DATA_TYPE_DOUBLE] = conv_double,
273 [MMDB_DATA_TYPE_FLOAT] = conv_float
274 };
275
276 void
277 #line 147
bi_geoip2_get(eval_environ_t env)278 bi_geoip2_get(eval_environ_t env)
279 #line 147
280
281 #line 147
282
283 #line 147 "geoip2.bi"
284 {
285 #line 147
286
287 #line 147
288
289 #line 147
290
291 #line 147
292 char * MFL_DATASEG ip;
293 #line 147
294 char * MFL_DATASEG pathstr;
295 #line 147
296
297 #line 147
298 get_string_arg(env, 0, &ip);
299 #line 147
300 get_string_arg(env, 1, &pathstr);
301 #line 147
302
303 #line 147
304
305 #line 147
306 adjust_stack(env, 2);
307 #line 147
308
309 #line 147
310
311 #line 147
312 if (builtin_module_trace(BUILTIN_IDX_geoip2))
313 #line 147
314 prog_trace(env, "geoip2_get %s %s",ip, pathstr);;
315 #line 147
316
317 {
318 struct geoip2_storage *gs = geoip2_open(env);
319 MMDB_lookup_result_s result;
320 int mmdb_error;
321 int gai_error;
322 MMDB_entry_data_s entry_data;
323 int rc;
324 struct mu_wordsplit ws;
325
326 result = MMDB_lookup_string(&gs->db, ip, &gai_error, &mmdb_error);
327 if (!(gai_error == 0))
328 #line 158
329 (
330 #line 158
331 env_throw_bi(env, mfe_failure, "geoip2_get", "%s: %s",ip,gai_strerror(gai_error))
332 #line 158
333 )
334 #line 161
335 ;
336
337 if (!(mmdb_error == MMDB_SUCCESS))
338 #line 163
339 (
340 #line 163
341 env_throw_bi(env, mfe_failure, "geoip2_get", "%s: %s: %s",pathstr,ip,MMDB_strerror(mmdb_error))
342 #line 163
343 )
344 #line 166
345 ;
346
347 if (!(result.found_entry != 0))
348 #line 168
349 (
350 #line 168
351 env_throw_bi(env, mfe_not_found, "geoip2_get", _("IP not found in the database"))
352 #line 168
353 )
354 #line 170
355 ;
356
357 ws.ws_delim = ".";
358 rc = mu_wordsplit(pathstr, &ws, WRDSF_DELIM);
359 if (rc != 0) {
360 char const *errstr = mu_wordsplit_strerror(&ws);
361 mu_wordsplit_free(&ws);
362 (
363 #line 177
364 env_throw_bi(env, mfe_failure, "geoip2_get", "can't split string %s: %s",pathstr,errstr)
365 #line 177
366 );
367 #line 180
368 }
369
370 rc = MMDB_aget_value(&result.entry, &entry_data,
371 (const char * const* const) ws.ws_wordv);
372 mu_wordsplit_free(&ws);
373
374 if (!(rc == MMDB_SUCCESS))
375 #line 186
376 (
377 #line 186
378 env_throw_bi(env, (rc == MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR ||
379 #line 186
380 rc == MMDB_INVALID_LOOKUP_PATH_ERROR)
381 #line 186
382 ? mfe_range : mfe_failure, "geoip2_get", "%s %s: MMDB_aget_value %s",pathstr,ip,MMDB_strerror(rc))
383 #line 186
384 )
385 #line 191
386 ;
387
388 if (!entry_data.has_data)
389
390 #line 194
391 do {
392 #line 194
393 pushs(env, "");
394 #line 194
395 goto endlab;
396 #line 194
397 } while (0);
398
399 if (!(entry_data.type >= 0
400 #line 196
401 && entry_data.type <= sizeof (entry_conv) / sizeof (entry_conv[0])
402 #line 196
403 && entry_conv[entry_data.type]))
404 #line 196
405 (
406 #line 196
407 env_throw_bi(env, mfe_failure, "geoip2_get", "%s: can't format %s of type %d",ip,pathstr,entry_data.type)
408 #line 196
409 )
410 #line 201
411 ;
412
413 heap_obstack_begin(env);
414 heap_obstack_sprintf(env, "%s","string result:");
415 entry_conv[entry_data.type] (env, &entry_data);
416 do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
417
418 #line 207
419 do {
420 #line 207
421 push(env, (STKVAL) (heap_obstack_finish(env)));
422 #line 207
423 goto endlab;
424 #line 207
425 } while (0);
426 }
427 endlab:
428 #line 209
429 env_function_cleanup_flush(env, NULL);
430 #line 209
431 return;
432 #line 209
433 }
434
435 struct object_type {
436 enum { OBJ_MAP, OBJ_ARRAY } type;
437 size_t count;
438 unsigned level;
439 struct object_type *prev;
440 };
441
442 static inline void
object_type_push(struct object_type ** otp,int type,size_t count)443 object_type_push(struct object_type **otp, int type, size_t count)
444 {
445 struct object_type *t = mu_alloc(sizeof(*t));
446 t->type = type;
447 t->count = count;
448 t->prev = *otp;
449 t->level = t->prev ? t->prev->level + 1 : 1;
450 *otp = t;
451 }
452
453 static inline void
object_type_pop(struct object_type ** otp)454 object_type_pop(struct object_type **otp)
455 {
456 struct object_type *t = *otp;
457 *otp = t->prev;
458 free(t);
459 }
460
461 void
462 #line 237
bi_geoip2_get_json(eval_environ_t env)463 bi_geoip2_get_json(eval_environ_t env)
464 #line 237
465
466 #line 237
467
468 #line 237 "geoip2.bi"
469 {
470 #line 237
471
472 #line 237
473
474 #line 237
475 long __bi_argcnt;
476 #line 237
477 char * MFL_DATASEG ip;
478 #line 237
479 long indent;
480 #line 237
481
482 #line 237
483 get_string_arg(env, 1, &ip);
484 #line 237
485 get_numeric_arg(env, 2, &indent);
486 #line 237
487
488 #line 237
489 get_numeric_arg(env, 0, &__bi_argcnt);
490 #line 237
491 adjust_stack(env, __bi_argcnt + 1);
492 #line 237
493
494 #line 237
495
496 #line 237
497 if (builtin_module_trace(BUILTIN_IDX_geoip2))
498 #line 237
499 prog_trace(env, "geoip2_get_json %s %lu",ip, ((__bi_argcnt > 1) ? indent : 0));;
500 #line 237
501
502 {
503 struct geoip2_storage *gs = geoip2_open(env);
504 MMDB_lookup_result_s result;
505 int mmdb_error;
506 int gai_error;
507 int rc;
508 MMDB_entry_data_list_s *data_list, *p;
509 struct object_type *type = NULL;
510 int iskey = 1;
511 size_t i;
512 char *indent_str = NULL;
513
514 result = MMDB_lookup_string(&gs->db, ip, &gai_error, &mmdb_error);
515 if (!(gai_error == 0))
516 #line 251
517 (
518 #line 251
519 env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s: %s",ip,gai_strerror(gai_error))
520 #line 251
521 )
522 #line 254
523 ;
524
525 if (!(mmdb_error == MMDB_SUCCESS))
526 #line 256
527 (
528 #line 256
529 env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s: %s",ip,MMDB_strerror(mmdb_error))
530 #line 256
531 )
532 #line 259
533 ;
534
535 if (!(result.found_entry != 0))
536 #line 261
537 (
538 #line 261
539 env_throw_bi(env, mfe_not_found, "geoip2_get_json", _("IP not found in the database"))
540 #line 261
541 )
542 #line 263
543 ;
544
545 rc = MMDB_get_entry_data_list(&result.entry, &data_list);
546 if (!(rc == MMDB_SUCCESS))
547 #line 266
548 (
549 #line 266
550 env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s: MMDB_aget_value %s",ip,MMDB_strerror(rc))
551 #line 266
552 )
553 #line 269
554 ;
555
556 /*MMDB_dump_entry_data_list(stdout, data_list, 4);*/
557
558 indent = ((__bi_argcnt > 1) ? indent : 0);
559 if (indent) {
560 indent_str = mu_alloc(indent+1);
561 memset(indent_str, ' ', indent);
562 indent_str[indent] = 0;
563 }
564
565 heap_obstack_begin(env);
566 for (p = data_list; p; p = p->next) {
567 if (iskey && type && indent_str) {
568 do { char __c = '\n'; heap_obstack_grow(env, &__c, 1); } while(0);
569 for (i = 0; i < type->level; i++)
570
571 #line 285
572 do {
573 #line 285
574 char *__s = indent_str;
575 #line 285
576 heap_obstack_grow(env, __s, strlen(__s));
577 #line 285
578 } while (0);
579 }
580
581 if (type == NULL && p->entry_data.type != MMDB_DATA_TYPE_MAP) {
582 heap_obstack_cancel(env);
583 free(indent_str);
584 MMDB_free_entry_data_list(data_list);
585 (
586 #line 292
587 env_throw_bi(env, mfe_failure, "geoip2_get_json", "%s",_("malformed data list"))
588 #line 292
589 );
590 #line 295
591 }
592
593 switch (p->entry_data.type) {
594 case MMDB_DATA_TYPE_MAP:
595 object_type_push(&type, OBJ_MAP, p->entry_data.data_size);
596 do { char __c = '{'; heap_obstack_grow(env, &__c, 1); } while(0);
597 iskey = 1;
598 continue;
599
600 case MMDB_DATA_TYPE_ARRAY:
601 object_type_push(&type, OBJ_ARRAY, p->entry_data.data_size);
602 do { char __c = '['; heap_obstack_grow(env, &__c, 1); } while(0);
603 continue;
604
605 case MMDB_DATA_TYPE_UTF8_STRING:
606 do { char __c = '"'; heap_obstack_grow(env, &__c, 1); } while(0);
607 heap_obstack_grow(env, (char*)p->entry_data.utf8_string, p->entry_data.data_size);
608 do { char __c = '"'; heap_obstack_grow(env, &__c, 1); } while(0);
609 if (iskey)
610 do { char __c = ':'; heap_obstack_grow(env, &__c, 1); } while(0);
611 break;
612
613 case MMDB_DATA_TYPE_DOUBLE:
614 heap_obstack_sprintf(env, "%g",p->entry_data.double_value);
615 break;
616
617 case MMDB_DATA_TYPE_BYTES:
618 do { char __c = '['; heap_obstack_grow(env, &__c, 1); } while(0);
619 for (i = 0; i < p->entry_data.data_size; i++) {
620 if (i) do { char __c = ','; heap_obstack_grow(env, &__c, 1); } while(0);
621 heap_obstack_grow(env, "%d", p->entry_data.bytes[i]);
622 }
623 do { char __c = ']'; heap_obstack_grow(env, &__c, 1); } while(0);
624 break;
625
626 case MMDB_DATA_TYPE_UINT16:
627 heap_obstack_sprintf(env, "%u",p->entry_data.uint16);
628 break;
629
630 case MMDB_DATA_TYPE_UINT32:
631 heap_obstack_sprintf(env, "%" PRIu32,p->entry_data.uint32);
632 break;
633
634 case MMDB_DATA_TYPE_INT32:
635 heap_obstack_sprintf(env, "%" PRIi32,p->entry_data.int32);
636 break;
637
638 case MMDB_DATA_TYPE_UINT64:
639 heap_obstack_sprintf(env, "%" PRIu64,p->entry_data.uint64);
640 break;
641
642 case MMDB_DATA_TYPE_UINT128:
643
644 #line 347
645 do {
646 #line 347
647 char *__s = "'N/A";
648 #line 347
649 heap_obstack_grow(env, __s, strlen(__s));
650 #line 347
651 } while (0);//FIXME
652 break;
653
654 case MMDB_DATA_TYPE_BOOLEAN:
655
656 #line 351
657 do {
658 #line 351
659 char *__s = p->entry_data.boolean ? "true" : "false";
660 #line 351
661 heap_obstack_grow(env, __s, strlen(__s));
662 #line 351
663 } while (0);
664 break;
665
666 case MMDB_DATA_TYPE_FLOAT:
667 heap_obstack_sprintf(env, "%g",p->entry_data.float_value);
668 break;
669
670 default:
671 heap_obstack_cancel(env);
672 free(indent_str);
673 MMDB_free_entry_data_list(data_list);
674 (
675 #line 362
676 env_throw_bi(env, mfe_failure, "geoip2_get_json", _("unsupported MMDB data type %d"),p->entry_data.type)
677 #line 362
678 );
679 #line 365
680 }
681
682 if (type) {
683 iskey = !iskey;
684 if (iskey == 1) {
685 while (type && --type->count == 0) {
686 if (indent_str) {
687 do { char __c = '\n'; heap_obstack_grow(env, &__c, 1); } while(0);
688 for (i = 1; i < type->level; i++)
689
690 #line 374
691 do {
692 #line 374
693 char *__s = indent_str;
694 #line 374
695 heap_obstack_grow(env, __s, strlen(__s));
696 #line 374
697 } while (0);
698 }
699 do { char __c = type->type == OBJ_MAP
700 #line 376
701 ? '}' : ']'; heap_obstack_grow(env, &__c, 1); } while(0);
702 #line 378
703 object_type_pop(&type);
704 }
705 if (type) {
706 do { char __c = ','; heap_obstack_grow(env, &__c, 1); } while(0);
707 }
708 }
709 }
710 }
711 do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
712 free(indent_str);
713 MMDB_free_entry_data_list(data_list);
714
715 if (type) {
716 while (type)
717 object_type_pop(&type);
718 (
719 #line 393
720 env_throw_bi(env, mfe_failure, "geoip2_get_json", _("malformed data list: reported and actual number of keys differ"))
721 #line 393
722 );
723 #line 395
724 }
725
726
727 #line 397
728 do {
729 #line 397
730 push(env, (STKVAL) (heap_obstack_finish(env)));
731 #line 397
732 goto endlab;
733 #line 397
734 } while (0);
735 }
736 endlab:
737 #line 399
738 env_function_cleanup_flush(env, NULL);
739 #line 399
740 return;
741 #line 399
742 }
743 #line 982 "../../src/builtin/snarf.m4"
744
745 #line 982
746
747 #line 982
748 #endif /* WITH_GEOIP2 */
749 #line 982
750
751 #line 982
752 void
753 #line 982
geoip2_init_builtin(void)754 geoip2_init_builtin(void)
755 #line 982
756 {
757 #line 982
758
759 #line 982
760 #ifdef WITH_GEOIP2
761 #line 982
762 pp_define("WITH_GEOIP2");
763 #line 982
764 #line 58 "geoip2.bi"
765 GEOIP2_id = builtin_priv_register(geoip2_alloc, geoip2_destroy,
766 #line 58
767 NULL);
768 #line 78 "geoip2.bi"
769 va_builtin_install_ex("geoip2_dbname", bi_geoip2_dbname, 0, dtype_string, 0, 0, 0|0, dtype_unspecified);
770 #line 85 "geoip2.bi"
771 va_builtin_install_ex("geoip2_open", bi_geoip2_open, 0, dtype_unspecified, 1, 0, 0|0, dtype_string);
772 #line 147 "geoip2.bi"
773 va_builtin_install_ex("geoip2_get", bi_geoip2_get, 0, dtype_string, 2, 0, 0|0, dtype_string, dtype_string);
774 #line 237 "geoip2.bi"
775 va_builtin_install_ex("geoip2_get_json", bi_geoip2_get_json, 0, dtype_string, 2, 1, 0|0, dtype_string, dtype_number);
776
777 #line 982 "../../src/builtin/snarf.m4"
778
779 #line 982
780 #endif /* WITH_GEOIP2 */
781 #line 982
782 }
783 #line 982 "../../src/builtin/snarf.m4"
784
785