JSON lookup
[exim.git] / src / src / lookups / json.c
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 /*************************************************
15 *              Open entry point                  *
16 *************************************************/
17
18 /* See local README for interface description */
19
20 static void *
21 json_open(uschar *filename, uschar **errmsg)
22 {
23 FILE *f = Ufopen(filename, "rb");
24 if (f == NULL)
25   {
26   int save_errno = errno;
27   *errmsg = string_open_failed(errno, "%s for json search", filename);
28   errno = save_errno;
29   return NULL;
30   }
31 return f;
32 }
33
34
35
36 /*************************************************
37 *             Check entry point                  *
38 *************************************************/
39
40 static BOOL
41 json_check(void *handle, uschar *filename, int modemask, uid_t *owners,
42   gid_t *owngroups, uschar **errmsg)
43 {
44 return lf_check_file(fileno((FILE *)handle), filename, S_IFREG, modemask,
45   owners, owngroups, "json", errmsg) == 0;
46 }
47
48
49
50 /*************************************************
51 *         Find entry point for lsearch           *
52 *************************************************/
53
54 /* See local README for interface description */
55
56 static int
57 json_find(void *handle, uschar *filename, const uschar *keystring, int length,
58   uschar **result, uschar **errmsg, uint *do_cache)
59 {
60 FILE * f = handle;
61 json_t * j, * j0;
62 json_error_t jerr;
63 uschar * key;
64 int sep = 0;
65
66 length = length;        /* Keep picky compilers happy */
67 do_cache = do_cache;    /* Keep picky compilers happy */
68
69 rewind(f);
70 if (!(j = json_loadf(f, 0, &jerr)))
71   {
72   enum json_error_code je = json_error_code(&jerr);
73   *errmsg = string_sprintf("json err %d on open", je);
74   return FAIL;
75   }
76 j0 = j;
77
78 for (int k = 1;  (key = string_nextinlist(&keystring, &sep, NULL, 0)); k++)
79   {
80   BOOL numeric = TRUE;
81   for (uschar * s = key; *s; s++) if (!isdigit(*s)) { numeric = FALSE; break; }
82
83   if (!(j = numeric
84         ? json_array_get(j, (size_t) strtoul(CS key, NULL, 10))
85         : json_object_get(j, CCS key)
86      ) )
87     {
88     DEBUG(D_lookup) debug_printf("%s, for key %d: '%s'\n",
89       numeric
90       ? US"bad index, or not json array"
91       : US"no such key, or not json object",
92       k, key);
93     json_decref(j0);
94     return FAIL;
95     }
96   }
97
98 switch (json_typeof(j))
99   {
100   case JSON_STRING:
101     *result = string_copyn(CUS json_string_value(j), json_string_length(j));
102     break;
103   case JSON_INTEGER:
104     *result = string_sprintf("%" JSON_INTEGER_FORMAT, json_integer_value(j));
105     break;
106   case JSON_REAL:
107     *result = string_sprintf("%f", json_real_value(j));
108     break;
109   case JSON_TRUE:       *result = US"true";     break;
110   case JSON_FALSE:      *result = US"false";    break;
111   case JSON_NULL:       *result = NULL;         break;
112   default:              *result = US json_dumps(j, 0); break;
113   }
114 json_decref(j0);
115 return OK;
116 }
117
118
119
120 /*************************************************
121 *              Close entry point                 *
122 *************************************************/
123
124 /* See local README for interface description */
125
126 static void
127 json_close(void *handle)
128 {
129 (void)fclose((FILE *)handle);
130 }
131
132
133
134 /*************************************************
135 *         Version reporting entry point          *
136 *************************************************/
137
138 /* See local README for interface description. */
139
140 #include "../version.h"
141
142 void
143 json_version_report(FILE *f)
144 {
145 fprintf(f, "Library version: json: Jansonn version %s\n", JANSSON_VERSION);
146 }
147
148
149 static lookup_info json_lookup_info = {
150   US"json",                      /* lookup name */
151   lookup_absfile,                /* uses absolute file name */
152   json_open,                  /* open function */
153   json_check,                 /* check function */
154   json_find,                  /* find function */
155   json_close,                 /* close function */
156   NULL,                          /* no tidy function */
157   NULL,                          /* no quoting function */
158   json_version_report         /* version reporting */
159 };
160
161
162 #ifdef DYNLOOKUP
163 #define json_lookup_module_info _lookup_module_info
164 #endif
165
166 static lookup_info *_lookup_list[] = { &json_lookup_info };
167 lookup_module_info json_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
168
169 /* End of lookups/json.c */