Skip to content

Commit

Permalink
sub-*sql: Merge subscribe implementations into a common function
Browse files Browse the repository at this point in the history
  • Loading branch information
bruceg committed Jan 13, 2012
1 parent 6e33629 commit 9f95594
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 544 deletions.
181 changes: 12 additions & 169 deletions sub-mysql.c
Expand Up @@ -35,24 +35,7 @@
#include <sys/stat.h>
#include <unistd.h>

static stralloc addr = {0};
static stralloc domain = {0};
static stralloc lcaddr = {0};
static stralloc line = {0};
static stralloc logline = {0};
static stralloc quoted = {0};

static int stralloc_cat_table(stralloc *s,
const struct subdbinfo *info,
const char *table)
{
if (!stralloc_cats(s,info->base_table)) return 0;
if (table) {
if (!stralloc_append(s,"_")) return 0;
if (!stralloc_cats(s,table)) return 0;
}
return 1;
}

/* close connection to SQL server, if open */
static void _closesub(struct subdbinfo *info)
Expand All @@ -75,153 +58,6 @@ static const char *_opensub(struct subdbinfo *info)
return (char *) 0;
}

static void safe_query(struct subdbinfo *info,const stralloc* query)
{
if (mysql_real_query((MYSQL*)info->conn,query->s,query->len))
strerr_die2x(111,FATAL,mysql_error((MYSQL*)info->conn));
}

/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber
* database table. Comment is e.g. the subscriber from line or name. It
* is added to the log. Event is the action type, e.g. "probe",
* "manual", etc. The direction (sub/unsub) is inferred from
* flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it
* is used in place of the calculated hash. This makes it possible to
* add addresses with a hash that does not exist. forcehash has to be
* 0..99. For unsubscribes, the address is only removed if forcehash
* matches the actual hash. This way, ezmlm-manage can be prevented from
* touching certain addresses that can only be removed by
* ezmlm-unsub. Usually, this would be used for sublist addresses (to
* avoid removal) and sublist aliases (to prevent users from subscribing
* them (although the cookie mechanism would prevent the resulting
* duplicate message from being distributed. */
static int _subscribe(struct subdbinfo *info,
const char *table,
const char *userhost,
int flagadd,
const char *comment,
const char *event,
int forcehash)
{
MYSQL_RES *result;
MYSQL_ROW row;
char *cpat;
char szhash[3] = "00";

unsigned int j;
unsigned char ch;

domain.len = 0; /* clear domain */
/* lowercase and check address */
if (!stralloc_copys(&addr,userhost)) die_nomem();
if (addr.len > 255) /* this is 401 in std ezmlm. 255 */
/* should be plenty! */
strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG));
j = byte_rchr(addr.s,addr.len,'@');
if (j == addr.len)
strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT));
cpat = addr.s + j;
case_lowerb(cpat + 1,addr.len - j - 1);
if (!stralloc_ready(&quoted,2 * addr.len + 1)) die_nomem();
quoted.len = mysql_escape_string(quoted.s,addr.s,addr.len);
/* stored unescaped, so it should be ok if quoted.len is >255, as */
/* long as addr.len is not */

if (forcehash < 0) {
if (!stralloc_copy(&lcaddr,&addr)) die_nomem();
case_lowerb(lcaddr.s,j); /* make all-lc version of address */
ch = subhashsa(&lcaddr);
} else
ch = (forcehash % 100);

szhash[0] = '0' + ch / 10; /* hash for sublist split */
szhash[1] = '0' + (ch % 10);

if (flagadd) {
if (!stralloc_copys(&line,"LOCK TABLES ")) die_nomem();
if (!stralloc_cat_table(&line,info,table)) die_nomem();
if (!stralloc_cats(&line," WRITE")) die_nomem();
safe_query(info,&line);
if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem();
if (!stralloc_cat_table(&line,info,table)) die_nomem();
if (!stralloc_cats(&line," WHERE address='")) die_nomem();
if (!stralloc_cat(&line,&quoted)) die_nomem(); /* addr */
if (!stralloc_cats(&line,"'")) die_nomem();
safe_query(info,&line);
if (!(result = mysql_use_result((MYSQL*)info->conn)))
strerr_die2x(111,FATAL,mysql_error((MYSQL*)info->conn));
if ((row = mysql_fetch_row(result))) { /* there */
while (mysql_fetch_row(result)); /* use'm up */
mysql_free_result(result);
if (mysql_query((MYSQL*)info->conn,"UNLOCK TABLES"))
strerr_die2x(111,FATAL,mysql_error((MYSQL*)info->conn));
return 0; /* there */
} else { /* not there */
mysql_free_result(result);
if (mysql_errno((MYSQL*)info->conn)) /* or ERROR */
strerr_die2x(111,FATAL,mysql_error((MYSQL*)info->conn));
if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem();
if (!stralloc_cat_table(&line,info,table)) die_nomem();
if (!stralloc_cats(&line," (address,hash) VALUES ('"))
die_nomem();
if (!stralloc_cat(&line,&quoted)) die_nomem(); /* addr */
if (!stralloc_cats(&line,"',")) die_nomem();
if (!stralloc_cats(&line,szhash)) die_nomem(); /* hash */
if (!stralloc_cats(&line,")")) die_nomem();
safe_query(info,&line);
if (mysql_query((MYSQL*)info->conn,"UNLOCK TABLES"))
strerr_die2x(111,FATAL,mysql_error((MYSQL*)info->conn));
}
} else { /* unsub */
if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem();
if (!stralloc_cat_table(&line,info,table)) die_nomem();
if (!stralloc_cats(&line," WHERE address='")) die_nomem();
if (!stralloc_cat(&line,&quoted)) die_nomem(); /* addr */
if (forcehash >= 0) {
if (!stralloc_cats(&line,"' AND hash=")) die_nomem();
if (!stralloc_cats(&line,szhash)) die_nomem();
} else {
if (!stralloc_cats(&line,"' AND hash BETWEEN 0 AND 52"))
die_nomem();
}
safe_query(info,&line);
if (mysql_affected_rows((MYSQL*)info->conn) == 0)
return 0; /* address wasn't there*/
}

/* log to subscriber log */
/* INSERT INTO t_slog (address,edir,etype,fromline) */
/* VALUES('address',{'+'|'-'},'etype','[comment]') */

if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem();
if (!stralloc_cat_table(&logline,info,table)) die_nomem();
if (!stralloc_cats(&logline,
"_slog (address,edir,etype,fromline) VALUES ('")) die_nomem();
if (!stralloc_cat(&logline,&quoted)) die_nomem();
if (flagadd) { /* edir */
if (!stralloc_cats(&logline,"','+','")) die_nomem();
} else {
if (!stralloc_cats(&logline,"','-','")) die_nomem();
}
if (*(event + 1)) /* ezmlm-0.53 uses '' for ezmlm-manage's work */
if (!stralloc_catb(&logline,event+1,1)) die_nomem(); /* etype */
if (!stralloc_cats(&logline,"','")) die_nomem();
if (comment && *comment) {
j = str_len(comment);
if (!stralloc_ready(&quoted,2 * j + 1)) die_nomem();
quoted.len = mysql_escape_string(quoted.s,comment,j); /* from */
if (!stralloc_cat(&logline,&quoted)) die_nomem();
}
if (!stralloc_cats(&logline,"')")) die_nomem();

if (mysql_real_query((MYSQL*)info->conn,logline.s,logline.len))
; /* log (ignore errors) */
if (!stralloc_0(&addr))
; /* ignore errors */
logaddr(table,event,addr.s,comment); /* also log to old log */
return 1; /* desired effect */
}

static void die_sqlerror(struct subdbinfo *info)
{
strerr_die2x(111,FATAL,mysql_error((MYSQL*)info->conn));
Expand Down Expand Up @@ -251,10 +87,10 @@ MYSQL_STMT *_prepbind(struct subdbinfo *info,
return stmt;
}

int sql_insert(struct subdbinfo *info,
struct stralloc *q,
unsigned int nparams,
struct stralloc *params)
int sql_exec(struct subdbinfo *info,
struct stralloc *q,
unsigned int nparams,
struct stralloc *params)
{
int rows;
MYSQL_STMT *stmt;
Expand Down Expand Up @@ -403,6 +239,13 @@ const char sql_putsubs_where_defn[] = "hash BETWEEN ? AND ?";
const char sql_searchlog_select_defn[] = "UNIX_TIMESTAMP(tai), CONCAT(edir,etype,' ',address,' ',fromline)";
const char sql_searchlog_where_defn[] = "fromline LIKE concat('%',?,'%') OR address LIKE concat('%',?,'%')";

/* Definition of clauses for subscribe queries */
const char sql_subscribe_select_where_defn[] = "address=?";
const char sql_subscribe_list_values_defn[] = "(?,?)";
const char sql_subscribe_delete1_where_defn[] = "address=? and hash BETWEEN 0 AND 52";
const char sql_subscribe_delete2_where_defn[] = "address=? and hash=?";
const char sql_subscribe_slog_values_defn[] = "(?,?,?,?)";

/* Definition of VALUES clause for insert in tagmsg */
const char sql_tagmsg_values_defn[] = "(?,NOW(),?,?,?)";

Expand Down Expand Up @@ -445,6 +288,6 @@ struct sub_plugin sub_plugin = {
sub_sql_putsubs,
sub_sql_rmtab,
sub_sql_searchlog,
_subscribe,
sub_sql_subscribe,
sub_sql_tagmsg,
};

0 comments on commit 9f95594

Please sign in to comment.