#include "sys_defs.h"
#include <stddef.h>
#include <string.h>
#include "cfg_parser.h"
#include <mymalloc.h>
#include <vstring.h>
#include <msg.h>
#include <dict.h>
#include "db_common.h"
#define DB_COMMON_KEY_DOMAIN (1 << 0)
#define DB_COMMON_KEY_USER (1 << 1)
#define DB_COMMON_VALUE_DOMAIN (1 << 2)
#define DB_COMMON_VALUE_USER (1 << 3)
#define DB_COMMON_KEY_PARTIAL (1 << 4)
typedef struct {
DICT *dict;
STRING_LIST *domain;
int flags;
int nparts;
} DB_COMMON_CTX;
void *db_common_alloc(DICT *dict)
{
DB_COMMON_CTX *ctx;
ctx = (DB_COMMON_CTX *) mymalloc(sizeof *ctx);
ctx->dict = dict;
ctx->domain = 0;
ctx->flags = 0;
ctx->nparts = 0;
return ((void *) ctx);
}
int db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query)
{
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) *ctxPtr;
const char *cp;
int dynamic = 0;
if (ctx == 0)
ctx = (DB_COMMON_CTX *) (*ctxPtr = db_common_alloc(dict));
for (cp = format; *cp; ++cp)
if (*cp == '%')
switch (*++cp) {
case '%':
break;
case 'u':
ctx->flags |=
query ? DB_COMMON_KEY_USER | DB_COMMON_KEY_PARTIAL
: DB_COMMON_VALUE_USER;
dynamic = 1;
break;
case 'd':
ctx->flags |=
query ? DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_PARTIAL
: DB_COMMON_VALUE_DOMAIN;
dynamic = 1;
break;
case 's':
case 'S':
dynamic = 1;
break;
case 'U':
ctx->flags |= DB_COMMON_KEY_PARTIAL | DB_COMMON_KEY_USER;
dynamic = 1;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (ctx->nparts < *cp - '0')
ctx->nparts = *cp - '0';
case 'D':
ctx->flags |= DB_COMMON_KEY_PARTIAL | DB_COMMON_KEY_DOMAIN;
dynamic = 1;
break;
default:
msg_fatal("db_common_parse: %s: Invalid %s template: %s",
ctx->dict->name, query ? "query" : "result", format);
}
return dynamic;
}
void db_common_parse_domain(CFG_PARSER *parser, void *ctxPtr)
{
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxPtr;
char *domainlist;
const char *myname = "db_common_parse_domain";
domainlist = cfg_get_str(parser, "domain", "", 0, 0);
if (*domainlist) {
ctx->domain = string_list_init(MATCH_FLAG_RETURN, domainlist);
if (ctx->domain == 0)
msg_fatal("%s: %s: domain match list creation using '%s' failed",
myname, parser->name, domainlist);
}
myfree(domainlist);
}
int db_common_dict_partial(void *ctxPtr)
{
#if 0
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxPtr;
return (ctx->domain || ctx->flags & DB_COMMON_KEY_PARTIAL);
#endif
return (0);
}
void db_common_free_ctx(void *ctxPtr)
{
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxPtr;
if (ctx->domain)
string_list_free(ctx->domain);
myfree((char *) ctxPtr);
}
int db_common_expand(void *ctxArg, const char *format, const char *value,
const char *key, VSTRING *result,
db_quote_callback_t quote_func)
{
const char *myname = "db_common_expand";
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxArg;
const char *vdomain = 0;
const char *kdomain = 0;
const char *domain = 0;
int dflag = key ? DB_COMMON_VALUE_DOMAIN : DB_COMMON_KEY_DOMAIN;
char *vuser = 0;
char *kuser = 0;
ARGV *parts = 0;
int i;
const char *cp;
if (value == 0)
return (0);
if (*value == 0) {
if (key)
msg_warn("table \"%s:%s\": empty lookup result for: \"%s\""
" -- ignored", ctx->dict->type, ctx->dict->name, key);
else
msg_warn("table \"%s:%s\": empty query string"
" -- ignored", ctx->dict->type, ctx->dict->name);
return (0);
}
if (key) {
if (ctx->flags & (DB_COMMON_VALUE_DOMAIN | DB_COMMON_VALUE_USER))
if ((vdomain = strrchr(value, '@')) != 0)
++vdomain;
if (((!vdomain || !*vdomain) && (ctx->flags & DB_COMMON_VALUE_DOMAIN) != 0)
|| (vdomain == value + 1 && (ctx->flags & DB_COMMON_VALUE_USER) != 0))
return (0);
if (ctx->flags & (DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_USER))
if ((kdomain = strrchr(key, '@')) != 0)
++kdomain;
if (((!kdomain || !*kdomain) && (ctx->flags & DB_COMMON_KEY_DOMAIN) != 0)
|| (kdomain == key + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0)) {
msg_warn("%s: %s: lookup key '%s' skipped after query", myname,
ctx->dict->name, value);
return (0);
}
} else {
if (ctx->flags & (DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_USER))
if ((vdomain = strrchr(value, '@')) != 0)
++vdomain;
if (((!vdomain || !*vdomain) && (ctx->flags & DB_COMMON_KEY_DOMAIN) != 0)
|| (vdomain == value + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0))
return (0);
}
if (ctx->nparts > 0) {
parts = argv_split(key ? kdomain : vdomain, ".");
if (parts->argc < ctx->nparts) {
argv_free(parts);
return (0);
}
for (i = 0; i < ctx->nparts; i++)
if (*parts->argv[parts->argc - i - 1] == 0) {
argv_free(parts);
return (0);
}
}
if (VSTRING_LEN(result) > 0)
VSTRING_ADDCH(result, ',');
#define QUOTE_VAL(d, q, v, buf) do { \
if (q) \
q(d, v, buf); \
else \
vstring_strcat(buf, v); \
} while (0)
for (cp = format; *cp; cp++) {
if (*cp == '%') {
switch (*++cp) {
case '%':
VSTRING_ADDCH(result, '%');
break;
case 's':
QUOTE_VAL(ctx->dict, quote_func, value, result);
break;
case 'u':
if (vdomain) {
if (vuser == 0)
vuser = mystrndup(value, vdomain - value - 1);
QUOTE_VAL(ctx->dict, quote_func, vuser, result);
} else
QUOTE_VAL(ctx->dict, quote_func, value, result);
break;
case 'd':
if (!(ctx->flags & dflag))
msg_panic("%s: %s: %s: bad query/result template context",
myname, ctx->dict->name, format);
if (!vdomain)
msg_panic("%s: %s: %s: expanding domain-less key or value",
myname, ctx->dict->name, format);
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
break;
case 'S':
if (key)
QUOTE_VAL(ctx->dict, quote_func, key, result);
else
QUOTE_VAL(ctx->dict, quote_func, value, result);
break;
case 'U':
if (key) {
if (kdomain) {
if (kuser == 0)
kuser = mystrndup(key, kdomain - key - 1);
QUOTE_VAL(ctx->dict, quote_func, kuser, result);
} else
QUOTE_VAL(ctx->dict, quote_func, key, result);
} else {
if (vdomain) {
if (vuser == 0)
vuser = mystrndup(value, vdomain - value - 1);
QUOTE_VAL(ctx->dict, quote_func, vuser, result);
} else
QUOTE_VAL(ctx->dict, quote_func, value, result);
}
break;
case 'D':
if (!(ctx->flags & DB_COMMON_KEY_DOMAIN))
msg_panic("%s: %s: %s: bad query/result template context",
myname, ctx->dict->name, format);
if ((domain = key ? kdomain : vdomain) == 0)
msg_panic("%s: %s: %s: expanding domain-less key or value",
myname, ctx->dict->name, format);
QUOTE_VAL(ctx->dict, quote_func, domain, result);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (!(ctx->flags & DB_COMMON_KEY_DOMAIN)
|| ctx->nparts < *cp - '0')
msg_panic("%s: %s: %s: bad query/result template context",
myname, ctx->dict->name, format);
if (!parts || parts->argc < ctx->nparts)
msg_panic("%s: %s: %s: key has too few domain labels",
myname, ctx->dict->name, format);
QUOTE_VAL(ctx->dict, quote_func,
parts->argv[parts->argc - (*cp - '0')], result);
break;
default:
msg_fatal("%s: %s: invalid %s template '%s'", myname,
ctx->dict->name, key ? "result" : "query",
format);
}
} else
VSTRING_ADDCH(result, *cp);
}
VSTRING_TERMINATE(result);
if (vuser)
myfree(vuser);
if (kuser)
myfree(kuser);
if (parts)
argv_free(parts);
return (1);
}
int db_common_check_domain(void *ctxPtr, const char *addr)
{
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxPtr;
char *domain;
if (ctx->domain) {
if ((domain = strrchr(addr, '@')) != NULL)
++domain;
if (domain == NULL || domain == addr + 1)
return (0);
if (match_list_match(ctx->domain, domain) == 0)
return (ctx->domain->error);
}
return (1);
}
void db_common_sql_build_query(VSTRING *query, CFG_PARSER *parser)
{
const char *myname = "db_common_sql_build_query";
char *table;
char *select_field;
char *where_field;
char *additional_conditions;
if ((table = cfg_get_str(parser, "table", NULL, 1, 0)) == 0)
msg_fatal("%s: 'table' parameter not defined", myname);
if ((select_field = cfg_get_str(parser, "select_field", NULL, 1, 0)) == 0)
msg_fatal("%s: 'select_field' parameter not defined", myname);
if ((where_field = cfg_get_str(parser, "where_field", NULL, 1, 0)) == 0)
msg_fatal("%s: 'where_field' parameter not defined", myname);
additional_conditions = cfg_get_str(parser, "additional_conditions",
"", 0, 0);
vstring_sprintf(query, "SELECT %s FROM %s WHERE %s='%%s' %s",
select_field, table, where_field,
additional_conditions);
myfree(table);
myfree(select_field);
myfree(where_field);
myfree(additional_conditions);
}