5687fabe976d863d67302eb5c4cdb1d884233517
[exim.git] / src / src / lookups / lf_sqlperform.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2017 */
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
19 until one can be accessed. It is now also possible to provide the server data
20 as part of the query. This function manages server selection and looping; each
21 lookup has its own function for actually performing the lookup.
22
23 Arguments:
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
30   do_cache       to be set zero if data is changed
31   func           the lookup function to call
32
33 Returns:         the return from the lookup function, or DEFER
34 */
35
36 int
37 lf_sqlperform(const uschar *name, const uschar *optionname,
38   const uschar *optserverlist, const uschar *query,
39   uschar **result, uschar **errmsg, uint *do_cache,
40   int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *))
41 {
42 int sep, rc;
43 uschar *server;
44 const uschar *serverlist;
45 uschar buffer[512];
46 BOOL defer_break = FALSE;
47
48 DEBUG(D_lookup) debug_printf("%s query: %s\n", name, query);
49
50 /* Handle queries that do not have server information at the start. */
51
52 if (Ustrncmp(query, "servers", 7) != 0)
53   {
54   sep = 0;
55   serverlist = optserverlist;
56   while ((server = string_nextinlist(&serverlist, &sep, buffer,
57           sizeof(buffer))) != NULL)
58     {
59     rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache);
60     if (rc != DEFER || defer_break) return rc;
61     }
62   if (optserverlist == NULL)
63     *errmsg = string_sprintf("no %s servers defined (%s option)", name,
64       optionname);
65   }
66
67 /* Handle queries that do have server information at the start. */
68
69 else
70   {
71   int qsep;
72   const uschar *s, *ss;
73   const uschar *qserverlist;
74   uschar *qserver;
75   uschar qbuffer[512];
76
77   s = query + 7;
78   while (isspace(*s)) s++;
79   if (*s++ != '=')
80     {
81     *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
82     return DEFER;
83     }
84   while (isspace(*s)) s++;
85
86   ss = Ustrchr(s, ';');
87   if (ss == NULL)
88     {
89     *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
90       name);
91     return DEFER;
92     }
93
94   if (ss == s)
95     {
96     *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
97       query);
98     return DEFER;
99     }
100
101   qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
102   qsep = 0;
103
104   while ((qserver = string_nextinlist(&qserverlist, &qsep, qbuffer,
105            sizeof(qbuffer))) != NULL)
106     {
107     if (Ustrchr(qserver, '/') != NULL)
108       server = qserver;
109     else
110       {
111       int len = Ustrlen(qserver);
112
113       sep = 0;
114       serverlist = optserverlist;
115       while ((server = string_nextinlist(&serverlist, &sep, buffer,
116               sizeof(buffer))) != NULL)
117         {
118         if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
119           break;
120         }
121
122       if (server == NULL)
123         {
124         *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
125           qserver, optionname);
126         return DEFER;
127         }
128       }
129
130     rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache);
131     if (rc != DEFER || defer_break) return rc;
132     }
133   }
134
135 return DEFER;
136 }
137
138 /* End of lf_sqlperform.c */