Add "server=" feature to MySQL and PostgreSQL lookups.
[exim.git] / src / src / lookups / lf_sqlperform.c
1 /* $Cambridge: exim/src/src/lookups/lf_sqlperform.c,v 1.1 2007/08/23 10:16:51 ph10 Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 1995 - 2007 */
8 /* See the file NOTICE for conditions of use and distribution. */
9
10
11 #include "../exim.h"
12 #include "lf_functions.h"
13
14
15
16 /*************************************************
17 *    Call SQL server(s) to run an actual query   *
18 *************************************************/
19
20 /* All the SQL lookups are of the same form, with a list of servers to try
21 until one can be accessed. It is now also possible to provide the server data
22 as part of the query. This function manages server selection and looping; each
23 lookup has its own function for actually performing the lookup.
24
25 Arguments:
26   name           the lookup name, e.g. "MySQL"
27   optionname     the name of the servers option, e.g. "mysql_servers"
28   optserverlist  the value of the servers option
29   query          the query
30   result         where to pass back the result
31   errmsg         where to pass back an error message
32   do_cache       to be set FALSE if data is changed
33   func           the lookup function to call
34
35 Returns:         the return from the lookup function, or DEFER
36 */
37
38 int
39 lf_sqlperform(uschar *name, uschar *optionname, uschar *optserverlist,
40   uschar *query, uschar **result, uschar **errmsg, BOOL *do_cache,
41   int(*fn)(uschar *, uschar *, uschar **, uschar **, BOOL *, BOOL *))
42 {
43 int sep, rc;
44 uschar *server;
45 uschar *serverlist;
46 uschar buffer[512];
47 BOOL defer_break = FALSE;
48
49 DEBUG(D_lookup) debug_printf("%s query: %s\n", name, query);
50
51 /* Handle queries that do not have server information at the start. */
52
53 if (Ustrncmp(query, "servers", 7) != 0)
54   {
55   sep = 0;
56   serverlist = optserverlist;
57   while ((server = string_nextinlist(&serverlist, &sep, buffer,
58           sizeof(buffer))) != NULL)
59     {
60     rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache);
61     if (rc != DEFER || defer_break) return rc;
62     }
63   if (optserverlist == NULL)
64     *errmsg = string_sprintf("no %s servers defined (%s option)", name,
65       optionname);
66   }
67
68 /* Handle queries that do have server information at the start. */
69
70 else
71   {
72   int qsep;
73   uschar *s, *ss;
74   uschar *qserverlist;
75   uschar *qserver;
76   uschar qbuffer[512];
77
78   s = query + 7;
79   while (isspace(*s)) s++;
80   if (*s++ != '=')
81     {
82     *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
83     return DEFER;
84     }
85   while (isspace(*s)) s++;
86
87   ss = Ustrchr(s, ';');
88   if (ss == NULL)
89     {
90     *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
91       name);
92     return DEFER;
93     }
94
95   if (ss == s)
96     {
97     *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
98       query);
99     return DEFER;
100     }
101
102   qserverlist = string_sprintf("%.*s", ss - s, s);
103   qsep = 0;
104
105   while ((qserver = string_nextinlist(&qserverlist, &qsep, qbuffer,
106            sizeof(qbuffer))) != NULL)
107     {
108     if (Ustrchr(qserver, '/') != NULL)
109       server = qserver;
110     else
111       {
112       int len = Ustrlen(qserver);
113
114       sep = 0;
115       serverlist = optserverlist;
116       while ((server = string_nextinlist(&serverlist, &sep, buffer,
117               sizeof(buffer))) != NULL)
118         {
119         if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
120           break;
121         }
122
123       if (server == NULL)
124         {
125         *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
126           qserver, optionname);
127         return DEFER;
128         }
129       }
130
131     rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache);
132     if (rc != DEFER || defer_break) return rc;
133     }
134   }
135
136 return DEFER;
137 }
138
139 /* End of lf_sqlperform.c */