Testsuite: output changes resulting
[exim.git] / src / src / lookups / lf_sqlperform.c
CommitLineData
b7670459
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
b7670459
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8
9#include "../exim.h"
10#include "lf_functions.h"
11
12
13
14/*************************************************
15* Call SQL server(s) to run an actual query *
16*************************************************/
17
18/* All the SQL lookups are of the same form, with a list of servers to try
19until one can be accessed. It is now also possible to provide the server data
20as part of the query. This function manages server selection and looping; each
21lookup has its own function for actually performing the lookup.
22
23Arguments:
24 name the lookup name, e.g. "MySQL"
25 optionname the name of the servers option, e.g. "mysql_servers"
26 optserverlist the value of the servers option
27 query the query
28 result where to pass back the result
29 errmsg where to pass back an error message
14b3c5bc 30 do_cache to be set zero if data is changed
b7670459
PH
31 func the lookup function to call
32
33Returns: the return from the lookup function, or DEFER
34*/
35
36int
55414b25
JH
37lf_sqlperform(const uschar *name, const uschar *optionname,
38 const uschar *optserverlist, const uschar *query,
0b4dfe7a
JH
39 uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts,
40 int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *))
b7670459 41{
0b4dfe7a 42int rc;
b7670459 43uschar *server;
b7670459
PH
44BOOL defer_break = FALSE;
45
0b4dfe7a 46DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts);
b7670459
PH
47
48/* Handle queries that do have server information at the start. */
49
0b4dfe7a 50if (Ustrncmp(query, "servers", 7) == 0)
b7670459 51 {
0b4dfe7a 52 int qsep = 0;
55414b25
JH
53 const uschar *s, *ss;
54 const uschar *qserverlist;
b7670459 55 uschar *qserver;
b7670459
PH
56
57 s = query + 7;
0b4dfe7a 58 skip_whitespace(&s);
b7670459
PH
59 if (*s++ != '=')
60 {
61 *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
62 return DEFER;
63 }
0b4dfe7a 64 skip_whitespace(&s);
b7670459
PH
65
66 ss = Ustrchr(s, ';');
0b4dfe7a 67 if (!ss)
b7670459
PH
68 {
69 *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
70 name);
71 return DEFER;
72 }
73
74 if (ss == s)
75 {
76 *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
77 query);
78 return DEFER;
79 }
80
bb07bcd3 81 qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
b7670459 82
0b4dfe7a 83 while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0)))
b7670459 84 {
0b4dfe7a 85 if (Ustrchr(qserver, '/'))
b7670459
PH
86 server = qserver;
87 else
88 {
89 int len = Ustrlen(qserver);
0b4dfe7a 90 const uschar * serverlist = optserverlist;
b7670459 91
0b4dfe7a 92 for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);)
b7670459
PH
93 if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
94 break;
b7670459 95
0b4dfe7a 96 if (!server)
b7670459
PH
97 {
98 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
99 qserver, optionname);
100 return DEFER;
101 }
102 }
103
0b4dfe7a
JH
104 if (is_tainted(server))
105 {
106 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
107 return DEFER;
108 }
109
110 rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
b7670459
PH
111 if (rc != DEFER || defer_break) return rc;
112 }
113 }
114
0b4dfe7a
JH
115/* Handle queries that do not have server information at the start. */
116
117else
118 {
119 const uschar * serverlist = NULL;
120
121 /* If options are present, scan for a server definition. Default to
122 the "optserverlist" srgument. */
123
124 if (opts)
125 {
126 uschar * ele;
127 for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); )
128 if (Ustrncmp(ele, "servers=", 8) == 0)
129 { serverlist = ele + 8; break; }
130 }
131
132 if (!serverlist)
133 serverlist = optserverlist;
134 if (!serverlist)
135 *errmsg = string_sprintf("no %s servers defined (%s option)", name,
136 optionname);
137 else
138 for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); )
139 {
140 /* If not a full spec assume from options; scan main list for matching
141 hostname */
142
143 if (!Ustrchr(server, '/'))
144 {
145 int len = Ustrlen(server);
146 const uschar * slist = optserverlist;
147 uschar * ele;
148 for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); )
149 if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/')
150 break;
151 if (!ele)
152 {
153 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
154 server, optionname);
155 return DEFER;
156 }
157 server = ele;
158 }
159
160 if (is_tainted(server))
161 {
162 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
163 return DEFER;
164 }
165
166 rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
167 if (rc != DEFER || defer_break) return rc;
168 }
169 }
170
b7670459
PH
171return DEFER;
172}
173
174/* End of lf_sqlperform.c */