Commit | Line | Data |
---|---|---|
ffc92d69 JH |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
5 | /* Copyright (c) Jeremy Harris 2019 */ | |
6 | /* See the file NOTICE for conditions of use and distribution. */ | |
7 | ||
8 | #include "../exim.h" | |
9 | #include "lf_functions.h" | |
10 | #include <jansson.h> | |
11 | ||
12 | ||
13 | ||
14 | /* All use of allocations will be done against the POOL_SEARCH memory, | |
15 | which is freed once by search_tidyup(). Make the free call a dummy. | |
16 | This burns some 300kB in handling a 37kB JSON file, for the benefit of | |
17 | a fast free. The alternative of staying with malloc is nearly as bad, | |
18 | eyeballing the activity there are 20% the number of free vs. alloc | |
19 | calls (before the big bunch at the end). */ | |
20 | ||
21 | static void * | |
22 | json_malloc(size_t nbytes) | |
23 | { | |
24 | void * p = store_get((int)nbytes); | |
25 | /* debug_printf("%s %d: %p\n", __FUNCTION__, (int)nbytes, p); */ | |
26 | return p; | |
27 | } | |
28 | static void | |
29 | json_free(void * p) | |
30 | { | |
31 | /* debug_printf("%s: %p\n", __FUNCTION__, p); */ | |
32 | } | |
33 | ||
34 | /************************************************* | |
35 | * Open entry point * | |
36 | *************************************************/ | |
37 | ||
38 | /* See local README for interface description */ | |
39 | ||
40 | static void * | |
41 | json_open(uschar *filename, uschar **errmsg) | |
42 | { | |
43 | FILE * f; | |
44 | ||
45 | json_set_alloc_funcs(json_malloc, json_free); | |
46 | ||
47 | if (!(f = Ufopen(filename, "rb"))) | |
48 | { | |
49 | int save_errno = errno; | |
50 | *errmsg = string_open_failed(errno, "%s for json search", filename); | |
51 | errno = save_errno; | |
52 | return NULL; | |
53 | } | |
54 | return f; | |
55 | } | |
56 | ||
57 | ||
58 | ||
59 | /************************************************* | |
60 | * Check entry point * | |
61 | *************************************************/ | |
62 | ||
63 | static BOOL | |
64 | json_check(void *handle, uschar *filename, int modemask, uid_t *owners, | |
65 | gid_t *owngroups, uschar **errmsg) | |
66 | { | |
67 | return lf_check_file(fileno((FILE *)handle), filename, S_IFREG, modemask, | |
68 | owners, owngroups, "json", errmsg) == 0; | |
69 | } | |
70 | ||
71 | ||
72 | ||
73 | /************************************************* | |
74 | * Find entry point for lsearch * | |
75 | *************************************************/ | |
76 | ||
77 | /* See local README for interface description */ | |
78 | ||
79 | static int | |
80 | json_find(void *handle, uschar *filename, const uschar *keystring, int length, | |
81 | uschar **result, uschar **errmsg, uint *do_cache) | |
82 | { | |
83 | FILE * f = handle; | |
84 | json_t * j, * j0; | |
85 | json_error_t jerr; | |
86 | uschar * key; | |
87 | int sep = 0; | |
88 | ||
89 | length = length; /* Keep picky compilers happy */ | |
90 | do_cache = do_cache; /* Keep picky compilers happy */ | |
91 | ||
92 | rewind(f); | |
93 | if (!(j = json_loadf(f, 0, &jerr))) | |
94 | { | |
95 | *errmsg = string_sprintf("json error on open: %.*s\n", | |
96 | JSON_ERROR_TEXT_LENGTH, jerr.text); | |
97 | return FAIL; | |
98 | } | |
99 | j0 = j; | |
100 | ||
101 | for (int k = 1; (key = string_nextinlist(&keystring, &sep, NULL, 0)); k++) | |
102 | { | |
103 | BOOL numeric = TRUE; | |
104 | for (uschar * s = key; *s; s++) if (!isdigit(*s)) { numeric = FALSE; break; } | |
105 | ||
106 | if (!(j = numeric | |
107 | ? json_array_get(j, (size_t) strtoul(CS key, NULL, 10)) | |
108 | : json_object_get(j, CCS key) | |
109 | ) ) | |
110 | { | |
42c7f0b4 | 111 | DEBUG(D_lookup) debug_printf_indent("%s, for key %d: '%s'\n", |
ffc92d69 JH |
112 | numeric |
113 | ? US"bad index, or not json array" | |
114 | : US"no such key, or not json object", | |
115 | k, key); | |
116 | json_decref(j0); | |
117 | return FAIL; | |
118 | } | |
119 | } | |
120 | ||
121 | switch (json_typeof(j)) | |
122 | { | |
123 | case JSON_STRING: | |
124 | *result = string_copyn(CUS json_string_value(j), json_string_length(j)); | |
125 | break; | |
126 | case JSON_INTEGER: | |
127 | *result = string_sprintf("%" JSON_INTEGER_FORMAT, json_integer_value(j)); | |
128 | break; | |
129 | case JSON_REAL: | |
130 | *result = string_sprintf("%f", json_real_value(j)); | |
131 | break; | |
132 | case JSON_TRUE: *result = US"true"; break; | |
133 | case JSON_FALSE: *result = US"false"; break; | |
134 | case JSON_NULL: *result = NULL; break; | |
135 | default: *result = US json_dumps(j, 0); break; | |
136 | } | |
137 | json_decref(j0); | |
138 | return OK; | |
139 | } | |
140 | ||
141 | ||
142 | ||
143 | /************************************************* | |
144 | * Close entry point * | |
145 | *************************************************/ | |
146 | ||
147 | /* See local README for interface description */ | |
148 | ||
149 | static void | |
150 | json_close(void *handle) | |
151 | { | |
152 | (void)fclose((FILE *)handle); | |
153 | } | |
154 | ||
155 | ||
156 | ||
157 | /************************************************* | |
158 | * Version reporting entry point * | |
159 | *************************************************/ | |
160 | ||
161 | /* See local README for interface description. */ | |
162 | ||
163 | #include "../version.h" | |
164 | ||
165 | void | |
166 | json_version_report(FILE *f) | |
167 | { | |
168 | fprintf(f, "Library version: json: Jansonn version %s\n", JANSSON_VERSION); | |
169 | } | |
170 | ||
171 | ||
172 | static lookup_info json_lookup_info = { | |
173 | US"json", /* lookup name */ | |
174 | lookup_absfile, /* uses absolute file name */ | |
175 | json_open, /* open function */ | |
176 | json_check, /* check function */ | |
177 | json_find, /* find function */ | |
178 | json_close, /* close function */ | |
179 | NULL, /* no tidy function */ | |
180 | NULL, /* no quoting function */ | |
181 | json_version_report /* version reporting */ | |
182 | }; | |
183 | ||
184 | ||
185 | #ifdef DYNLOOKUP | |
186 | #define json_lookup_module_info _lookup_module_info | |
187 | #endif | |
188 | ||
189 | static lookup_info *_lookup_list[] = { &json_lookup_info }; | |
190 | lookup_module_info json_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; | |
191 | ||
192 | /* End of lookups/json.c */ |