/**********************************************************************
 * PTlink IRC Services is (C) CopyRight PTlink IRC Software 1999-2006 *
 *                     http://software.pt-link.net                    *
 * This program is distributed under GNU Public License               *
 * Please read the file COPYING for copyright information.            *
 **********************************************************************

  Description: export users to joomla

*/

#include "module.h"
#include "my_sql.h"
#include "dbconf.h"

#define REG_GROUP 18

SVS_Module mod_info =
 /* module, version, description */
{"joomla_export", "1.0",  "export users to joomla" };

/* Change Log
  1.0 - initial release
*/

/** functions/events we require **/
/* void (*FunctionPointer)(void);*/
int e_nick_register = -1;
int e_nick_delete = -1;

MOD_REQUIRES
  MOD_FUNC(dbconf_get_or_build)
  MOD_FUNC(e_nick_register)
  MOD_FUNC(e_nick_delete)
MOD_END

/** functions/events we provide **/

/** Internal functions declaration **/
/* void internal_function(void); */
int ev_joomla_export_nick_register(IRC_User *u, u_int32_t *snid);
int ev_joomla_export_nick_delete(u_int32_t *snid, void *dummy);
int joomla_db_mysql_open();
int joomla_db_mysql_query(char *sql);
u_int32_t joomla_sql_execute(char *fmt, ...);
MYSQL_RES* joomla_sql_query(char *fmt, ...);
int export_users(void);
int export_groups(void);

extern int sql_debug;

/** Local variables **/
static MYSQL *mysql;                   /* MySQL Handler */

/** Local config **/
static char* DB_Host;
static char* DB_User;
static char* DB_Password;
static char* DB_Name;
static char* DB_Prefix;

DBCONF_PROVIDES
  DBCONF_WORD(DB_Host,"Host", "Joomla MySQL server")
  DBCONF_WORD(DB_User, "User", "Joomla MySQL user")  
  DBCONF_WORD_OPT(DB_Password, "Password", "Joomla MySQL user password")
  DBCONF_WORD(DB_Name, 	"Database", "Joomla MySQL database name")
  DBCONF_WORD(DB_Prefix,"jos_",
    "Set to the $mosConfig_dbprefix from your Joomla configuration.php")
DBCONF_END


int mod_rehash(void)
{
  if(dbconf_get_or_build(mod_info.name, dbconf_provides) < 0 )
  {
    errlog("Error reading dbconf!");
    return -1;
  }
  return 0;
}

static int jo_log;
/** load code **/
int mod_load(void)
{
  MYSQL_RES* res;
  MYSQL_ROW row;
  u_int32_t nickserv_total = 0;
  u_int32_t joomla_total = 0;
  
  jo_log = log_open("joomla","joomla");
    
  /* first lets connect to the joomla db */  
  if(joomla_db_mysql_open() < 0)
  {
    errlog("Unable to connect to the Joomla database !");
    return -1;
  }  
  
  /* now lets check if the dbs are sinchronized */
  res = sql_query("SELECT count(*) FROM nickserv");
  if(res && (row = sql_next_row(res)))
    nickserv_total = atoi(row[0]);
  sql_free(res);

  res = joomla_sql_query("SELECT count(*) FROM %susers", DB_Prefix);
  if(res && (row = sql_next_row(res)))
    joomla_total = atoi(row[0]);    
  sql_free(res);
  
  if(nickserv_total != joomla_total)
  {
    stdlog(L_WARN, "Joomla database is out of sync, exporting full user database");
    if(export_users() < 0)
    {
      errlog("Error exporting to joomla db");
      return -2;
    }
    if(export_groups() < 0)
    {
      errlog("Error exporting groups");
      return -2;
    }    
  }
  
  /* setup the actions for the updates */
  mod_add_event_action(e_nick_register, 
    (ActionHandler) ev_joomla_export_nick_register);
  mod_add_event_action(e_nick_delete, 
    (ActionHandler) ev_joomla_export_nick_delete);
  
  return 0;
}
    
/** unload code **/
void mod_unload(void)
{
  return;
}
    
int ev_joomla_export_nick_register(IRC_User *u, u_int32_t *snid)
{
  MYSQL_RES *res;
  MYSQL_ROW row;    
  res = sql_query("SELECT n.snid, n.nick, n.email, ns.pass"
    " FROM nickserv n, nickserv_security ns"
    " WHERE ns.snid=n.snid AND n.snid=%d", *snid);
  if(res && (row = sql_next_row(res)))
  {
    u_int32_t aro_id = 0;
    if(joomla_sql_execute("INSERT INTO %susers "
      "VALUES (%s, %s, %s, %s, %s, 'Registered',"
      "0, 1, %d, 0, 0, '', '')", DB_Prefix,
      sql_str(row[0]), sql_str(row[1]), sql_str(row[1])
      , sql_str(row[2]), sql_str(row[3]), REG_GROUP) == 0)
        return 0;
    aro_id = joomla_sql_execute("INSERT INTO %score_acl_aro "
      "VALUES (%s, 'users', %s, 0, %s, 0)", 
      DB_Prefix, sql_str(row[0]), sql_str(row[0]), sql_str(row[1]));
    if(aro_id == 0)
        return 0;
    if(joomla_sql_execute("INSERT INTO %score_acl_groups_aro_map"
      " VALUES(%d, '', %d)", DB_Prefix, REG_GROUP, aro_id) == 0)
        return 0;  
  }
  return 0;
}

int ev_joomla_export_nick_delete(u_int32_t *snid, void *dummy)
{  
  joomla_sql_execute("DELETE FROM %susers WHERE id=%d", DB_Prefix, *snid); 
  joomla_sql_execute("DELETE FROM %score_acl_aro WHERE aro_id=%d", 
    DB_Prefix, *snid);
  joomla_sql_execute("DELETE FROM %score_acl_groups_aro_map"
    " WHERE aro_id=%d", DB_Prefix, *snid);    
  return 0;
}

int export_users(void)
{
  MYSQL_RES *res;
  MYSQL_ROW row;

  /* delete the existing users and acls */
  joomla_sql_execute("DELETE FROM %susers", DB_Prefix); 
  joomla_sql_execute("DELETE FROM %score_acl_aro", DB_Prefix);
  joomla_sql_execute("DELETE FROM %score_acl_groups_aro_map", DB_Prefix);  
  
  /* insert the new users */
  res = sql_query("SELECT n.snid, n.nick, n.email, ns.pass"
    " FROM nickserv n, nickserv_security ns"
    " WHERE ns.snid=n.snid");      
  while((row = sql_next_row(res)))
  {
    u_int32_t aro_id;

    /* joomla does not accept null emails or fields */
    if(row[2] == NULL)
      row[2] = "";
    if(row[3] == NULL)
      row[3] = "";
    if(joomla_sql_execute("INSERT INTO %susers "
      "VALUES (%s, %s, %s, %s, %s, 'Registered',"
      "0, 1, %d, 0, 0, '', '')", DB_Prefix,
      sql_str(row[0]), sql_str(row[1]), sql_str(row[1])
      , sql_str(row[2]), sql_str(row[3]), REG_GROUP) == 0)
        return -1;
    
    aro_id = joomla_sql_execute("INSERT INTO %score_acl_aro "
      "VALUES (%s, 'users', %s, 0, %s, 0)", 
      DB_Prefix, sql_str(row[0]), sql_str(row[0]), sql_str(row[1]));
    if(aro_id == 0)
        return -1;
    if(joomla_sql_execute("INSERT INTO %score_acl_groups_aro_map"
      " VALUES(%d, '', %d)", DB_Prefix, REG_GROUP, aro_id) == 0)
        return -1;
  }
  sql_free(res);
  return 0;
}

int export_groups(void)
{
  MYSQL_RES *res;
  MYSQL_ROW row;

  /* inser the new users */
  res = sql_query("SELECT ng.name, ngu.snid"
    " FROM ns_group ng, ns_group_users ngu"
    " WHERE ng.sgid=ngu.sgid");      
  while((row = sql_next_row(res)))
  {
    int new_gid = 0;
    if(strcasecmp(row[0], "Root") == 0)
      new_gid = 25; /* Super Admin */
    else
    if(strcasecmp(row[0], "Admin") == 0)    
      new_gid = 24; /* Admin */
    else
    if(strcasecmp(row[0], "Admin") == 0)    
      new_gid = 23; /* Manager */
    else
      continue;
    if(joomla_sql_execute("UPDATE %susers SET gid=%d WHERE id=%s"
      , DB_Prefix, new_gid, row[1]) == 0)
      return -1;
    joomla_sql_execute("UPDATE %score_acl_groups_aro_map "
      "SET group_id=%d WHERE aro_id=%s", DB_Prefix, new_gid, row[1]);
  }
  sql_free(res);
  return 0;
}

int joomla_db_mysql_open()
{
  mysql = mysql_init(NULL);
  
  if ((!mysql_real_connect
      (mysql, DB_Host, DB_User, DB_Password, DB_Name, 0, NULL, 0)))
      {
        printf("MySQL ErrNo: %d\n", mysql_errno(mysql));
        errlog("Cant connect to MySQL: %s\n", mysql_error(mysql));
        return -1;
      }
      
  log_log(jo_log, "Connect", "MySQL connected to %s", DB_Host);

  return 1;
}

/*************************************************************************/

int joomla_db_mysql_query(char *sql)
{

    int result, lcv;
    /* slog(L_INFO,"%s", sql); */
    result = mysql_query(mysql, sql);

    if (result) {
        switch (mysql_errno(mysql)) {
        case CR_SERVER_GONE_ERROR:
        case CR_SERVER_LOST:
            /* Reconnect -> 5 tries (need to move to config file) */
            for (lcv = 0; lcv < 5; lcv++) {
                if (db_mysql_open()>0) {
                    result = mysql_query(mysql, sql);
                    return (result);
                }
                sleep(1);
            }

            /* If we get here, we could not connect. */
            slog(L_ERROR, "Unable to reconnect to database: %s\n",
                       mysql_error(mysql));
            db_mysql_error(MYSQL_ERROR, "connect");
            exit(-5);
            /* Never reached. */
            break;

        default:
            /* Unhandled error. */
            return (result);
        }
    }

    return (0);

}    

/* execute an sql query (for insert/deletes/updates
  returns
  ANY ACTION
    0 means ERROR
  INSERT
    mysql_insert_id if there is some autoincrement field
    or affected rows otherwise
  DELETE/UPDATES
    number of affected rows
*/
u_int32_t joomla_sql_execute(char *fmt, ...)
{
  static char buf[4096];
  va_list args;
  
  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);

  if(sql_debug)
    stdlog(L_INFO, "%s", buf);    

  if (joomla_db_mysql_query(buf)) 
    {
      /* slog(L_ERROR, "Can't create sql query: %s", buf);*/
      log_log(jo_log, "ERROR", "sql_execute() %s", buf);
      db_mysql_error(MYSQL_WARNING, "query");
      return 0;
    }    
    
  if(strncasecmp(buf,"INSERT",6) == 0)
    {
      u_int32_t id;
      id = mysql_insert_id(mysql);
      if(id == 0) /* only tables without id return 0 */
        return mysql_affected_rows(mysql);
      return id;
    }

  return  mysql_affected_rows(mysql);  
}

/* */
MYSQL_RES* joomla_sql_query(char *fmt, ...)
{
  static char buf[4096];
  va_list args;
  
  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);

  if(sql_debug)
    stdlog(L_INFO, "%s", buf);  
  if (joomla_db_mysql_query(buf)) 
    {
      log_log(jo_log, "ERROR", "sql_query() %s", buf);
      /* slog(L_ERROR, "Can't create sql query: %s", buf); */
      db_mysql_error(MYSQL_WARNING, "query");
      return NULL;
    }
    
  return mysql_store_result(mysql);
}


/* End of module */


syntax highlighted by Code2HTML, v. 0.9.1