#include <mysql/mysql.h>
#include "stralloc.h"
#include "qsutil.h"
#include "mysql_queries.h"

extern int connect_mysql();
extern int disconnect_mysql();

extern MYSQL dbh, *mysql;
extern MYSQL_RES *result;

/* simulate reading a .qmail file from ye olde database */
int dotqmail_mysql(char *username, char *ext, stralloc *sa, int bufsize) {
  int i, len, num;
  MYSQL_ROW row;
  stralloc query = { 0 };
  stralloc user = { 0 };
  stralloc real_ext = { 0 };
#ifdef FUNKY_ALIAS_QUERIES
#ifdef OIL_AND_WATER
  stralloc last1 = { 0 };
  stralloc last2 = { 0 };
#endif
#endif

  /* initialise database handle or signal trouble */
  if (! connect_mysql()) return -1;

  i = str_len(username);
  if (! stralloc_ready(&user, 2 * i + 1)) return zoiks(-1);
  mysql_escape_string(user.s, username, i);

  i = str_len(ext);
  if (! stralloc_ready(&real_ext, 2 * i + 1)) return zoiks(-1);
  mysql_escape_string(real_ext.s, ext, i);

  /* make the query or signal an out of memory exception */
  len = str_len(ALIAS) + real_ext.len + user.len - 3;
  if (! stralloc_ready(&query, len)) return zoiks(-1);
  if (! stralloc_cats(&query, ALIAS1)) return zoiks(-1);
  if (! stralloc_cats(&query, user.s)) return zoiks(-1);
  if (! stralloc_cats(&query, ALIAS2)) return zoiks(-1);
  if (! stralloc_cats(&query, real_ext.s)) return zoiks(-1);
  if (! stralloc_cats(&query, ALIAS3)) return zoiks(-1);
  if (! stralloc_0(&query)) return zoiks(-1);

#ifndef O_NOT_LOG
  tcplog("query: ", query.s, ";\n");
#endif

  /* do the query or signal to use .qmail */
  if (mysql_real_query(mysql, query.s, query.len) < 0) {
    /* bad => log it anyway */
    tcplog("error: ", mysql_error(&dbh), "\n");
    disconnect_mysql();
    return 0;
  }
  result = mysql_store_result(mysql);
  if (!result) return zoiks(-1);

  num = mysql_num_rows(result);

  /* no rows: let's try the default alias - but not if extension was blank */
  if (num == 0 && *ext) {
    mysql_free_result(result);
    query.len = 0;
    len = str_len(ALIAS) + user.len - 2;
    if (! stralloc_ready(&query, len)) return zoiks(-1);
    if (! stralloc_cats(&query, ALIAS1)) return zoiks(-1);
    if (! stralloc_cats(&query, user.s)) return zoiks(-1);
    if (! stralloc_cats(&query, ALIAS2)) return zoiks(-1);
    if (! stralloc_append(&query, "@")) return zoiks(-1);
    if (! stralloc_cats(&query, ALIAS3)) return zoiks(-1);
    if (! stralloc_0(&query)) return zoiks(-1);

#ifndef O_NOT_LOG
    tcplog("query: ", query.s, ";\n");
#endif

    /* hmm, a function would have been nice here */
    if (mysql_real_query(mysql, query.s, query.len) < 0) {
      /* bad => log it anyway */
      tcplog("error: ", mysql_error(&dbh), "\n");
      disconnect_mysql();
      return 0;
    }

    result = mysql_store_result(mysql);
    if (!result) return zoiks(0);

    num = mysql_num_rows(result);
  }

  /* well it looks like there's really no match */
  if (num == 0) return zoiks(0);

#ifdef FUNKY_ALIAS_QUERIES
#ifdef OIL_AND_WATER
  if (! stralloc_ready(&last1, 2)) return zoiks(-1);
  if (! stralloc_append(&last1, "0")) return zoiks(-1);
  if (! stralloc_0(&last1)) return zoiks(-1);
  if (! stralloc_ready(&last2, 2)) return zoiks(-1);
  if (! stralloc_append(&last2, "0")) return zoiks(-1);
  if (! stralloc_0(&last2)) return zoiks(-1);
#endif
#endif

  for (i = 0; i < num; i++) {
    row = mysql_fetch_row(result);
    if (! *(row[0])) {
      tcplog("MySQL misconfiguration: alias_username is blank for username '", user.s, "' in alias table!\n");
      continue;
    }
#ifdef FUNKY_ALIAS_QUERIES
#ifdef OIL_AND_WATER
    /* discard wildcard matches if we already had explicit matches */
    if (i && (str_diff(row[2], last1.s) || str_diff(row[3], last2.s))) break;

    if (! stralloc_ready(&last1, str_len(row[2]) + 1)) return zoiks(-1);
    if (! stralloc_cats(&last1, row[2])) return zoiks(-1);
    if (! stralloc_0(&last1)) return zoiks(-1);
    if (! stralloc_ready(&last2, str_len(row[3]) + 1)) return zoiks(-1);
    if (! stralloc_cats(&last2, row[3])) return zoiks(-1);
    if (! stralloc_0(&last2)) return zoiks(-1);
#endif
#endif
    /* we need space for &blabla@crap\n\0 */
    len = str_len(row[0]) + str_len(row[1]) + 4;
    if (! stralloc_readyplus(sa, len)) return zoiks(-1);
    /* if the result is too big for the buffer we skip it */
    if (len > bufsize) continue;
    /* if the alias username is a | we use the alias host value as the target */
    if (*row[0] == '|') {
      /* skip if the pipe would break */
      if (str_len(row[1]) == 0) continue;
      if (! stralloc_cats(sa, "| ")) return zoiks(-1);
    }
    /* . or / means delivery to a mailbox or maildir */
    else if (*row[0] == '/' || *row[0] == '.') {
      *(row[0] + 1) = '\0';
      if (str_len(row[1]) == 0) continue;
      if (! stralloc_cats(sa, row[0])) return zoiks(-1);
    }
    else {
      if (! stralloc_cats(sa, "&")) return zoiks(-1);
      if (! stralloc_cats(sa, row[0])) return zoiks(-1);
      if (strcmp(row[1], "") && ! stralloc_cats(sa, "@")) return zoiks(-1);
    }
    if (! stralloc_cats(sa, row[1])) return zoiks(-1);
    if (! stralloc_cats(sa, "\n")) return zoiks(-1);
  }

  return zoiks(num);
}

/* free memory used by query, disconnect from database and return */
int zoiks(int ret) {
  mysql_free_result(result);
  disconnect_mysql();
  return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1