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

  Description: nickserv register command

 *  $Id: ns_register.c,v 1.13 2005/10/18 16:25:06 jpinto Exp $
*/

#include "nickserv.h"
#include "module.h"
#include "dbconf.h"
#include "encrypt.h"
#include "my_sql.h"
#include "email.h"
#include "nsmacros.h"
#include "lang/ns_register.lh"

SVS_Module mod_info =
/* module, version, description */
{"ns_register", "2.3","nickserv register command" };

/* Change Log
  2.3 - #61: MaxTimeForAuth setting to expire unauthenticated nicks
  2.2 - #24 : move e_nick_register event registration to nickserv
  2.1 - 0000340: WelcomeChan option to make new users join a channel
        0000332: ns_register missing call for the e_nick_register event
        0000330: nickserv links exchange option
  2.0 - 0000277: ns_blacklist to support email blacklists
        0000265: remove nickserv cache system
  1.2 - 0000255: new field to store nick expire time
  1.1 - 0000218: NickDefaultOptions to set nick default options
*/
            
/* functions/events we require */
ServiceUser* (*nickserv_suser)(void);
int (*forbidden_email)(char *email);
int mysql_connection;
int ns_log;
int e_nick_register;

MOD_REQUIRES
  MOD_FUNC(dbconf_get)
  MOD_FUNC(dbconf_get_or_build)
  MOD_FUNC(nickserv_suser)
  MOD_FUNC(mysql_connection)  
  MOD_FUNC(e_nick_register)
  EMAIL_FUNCTIONS
MOD_END

MOD_OPTIONS
  MOD_FUNC(forbidden_email)
MOD_END

/* functions and events we provide */

/* internal functions */
void ns_register(IRC_User *s, IRC_User *u);
void parse_nick_def_options(void);

/* Remote config */
static int StrongPasswords;
static int MaxNicksPerEmail;
static int NickSecurityCode;
static int SecurityCodeLenght;
static int ExpireTime;
static char* NickProtectionPrefix;
static int MaxTimeForAuth = 0;

DBCONF_REQUIRES
  DBCONF_GET("nickserv", StrongPasswords)
  DBCONF_GET("nickserv", MaxNicksPerEmail)
  DBCONF_GET("nickserv", NickSecurityCode)
  DBCONF_GET("nickserv", SecurityCodeLenght)
  DBCONF_GET("nickserv", ExpireTime)
  DBCONF_GET("nickserv", NickProtectionPrefix)
  DBCONF_GET("nickserv", MaxTimeForAuth)
DBCONF_END

/* Local config */
static char* NickDefaultOptions;
static int LinkExchange;
static char* WelcomeChan;
DBCONF_PROVIDES
  DBCONF_WORD_OPT(NickDefaultOptions, NULL, 
    "Nick default SET options (value1,value2...")
  DBCONF_SWITCH(LinkExchange, "off",
    "Welcome emails will include favorite links from random users")
  DBCONF_WORD_OPT(WelcomeChan, "#PTlink",
    "New registered users will be joined to this channel")
DBCONF_END

/* this is called before load and at services rehash */
int mod_rehash(void)
{
  if(dbconf_get(dbconf_requires) < 0 )
  {
    errlog("Error reading dbconf!");
    return -1;
  }
  if(dbconf_get_or_build(mod_info.name, dbconf_provides) < 0 )
  {
    errlog("Error reading dbconf!");
    return -1;
  }
  parse_nick_def_options();
  return 0;
}

static ServiceUser* nsu;
u_int32_t nick_def_options = 0;
char* welcome_emails[MAX_LANGS];

int mod_load(void)
{

  ns_log = log_handle("nickserv");
  
  if(email_load("welcome", welcome_emails) < 0)
    return -1;      
    
  nsu = nickserv_suser();
  suser_add_cmd(nsu,
    "REGISTER", ns_register, REGISTER_SUMMARY, REGISTER_HELP);
  return 0;
}

void
mod_unload(void)
{
   suser_del_mod_cmds(nsu, &mod_info);
   email_free(welcome_emails);
}
 
/* s = service the command was sent to
   u = user the command was sent from */
void ns_register(IRC_User *s, IRC_User *u)
{
  
  char *pass = strtok(NULL, " ");    
  char *email = strtok(NULL, " ");
  
  /* syntax validation */
  if((IsNull(pass)) || (IsNull(email)))
    send_lang(u, s, NICK_REGISTER_SYNTAX);    
  /* check requirements */
  else if(!is_email(email)) 
    send_lang(u, s, INVALID_EMAIL);
  else if(StrongPasswords && is_weak_passwd(pass))
    send_lang(u, s, WEAK_PASSWORD);
  else if(NickProtectionPrefix &&
    !strncasecmp(u->nick, NickProtectionPrefix, strlen(NickProtectionPrefix)))
      send_lang(u, s, NICK_CANNOT_BE_REGISTERED, u->nick);
  else if(nick2snid(u->nick) != 0)
    send_lang(u, s, NICK_ALREADY_REGISTERED);
  else if(forbidden_email && (forbidden_email(email) > 0))
    send_lang(u, s, FORBIDDEN_EMAIL);
  else if(MaxNicksPerEmail && (reg_count_for_email(email) >= MaxNicksPerEmail))
    send_lang(u, s, ALREADY_X_WITH_EMAIL, MaxNicksPerEmail);
  else /* execute operation */
    {
      u_int32_t snid = 0;
      char* securitycode;
      sqlb_init("nickserv");
      sqlb_add_str("nick", irc_lower_nick(u->nick));
      sqlb_add_str("email", email);
      sqlb_add_int("flags", nick_def_options);
      sqlb_add_int("status", NST_ONLINE);
      sqlb_add_int("t_reg", irc_CurrentTime);
      sqlb_add_int("t_ident", irc_CurrentTime);
      sqlb_add_int("t_seen", irc_CurrentTime);      
      if(MaxTimeForAuth && NickSecurityCode)
        sqlb_add_int("t_expire", irc_CurrentTime + MaxTimeForAuth);
      else
        sqlb_add_int("t_expire", irc_CurrentTime + ExpireTime);
      sqlb_add_int("lang", u->lang);
      securitycode = malloc(SecurityCodeLenght+1);
      rand_string(securitycode, SecurityCodeLenght, SecurityCodeLenght);

      snid = sql_execute("%s", sqlb_insert());
      if(snid == 0)
      {
        free(securitycode);
        send_lang(u, s, NICK_REGISTER_FAIL);
        return ;
      } 
      else
      {
        sqlb_init("nickserv_security");              
        sqlb_add_int("snid", snid);
        sqlb_add_str("pass", hex_str(encrypted_password(pass),16));
        sqlb_add_str("securitycode", 
          hex_str(encrypted_password(securitycode),16));
        sqlb_add_int("t_lset_pass", (int) irc_CurrentTime);
        sql_execute("%s", sqlb_insert());
      }
      u->snid = snid;
      u->flags = nick_def_options;
      u->status = NST_ONLINE;      
      if(NickSecurityCode)
        {
          email_init_symbols();
          email_add_symbol("nick", u->nick);
          email_add_symbol("email", email);
          email_add_symbol("securitycode", securitycode);
          if(LinkExchange)
          { /* pick a random favorite link */
            sql_singlequery("SELECT nick, favlink FROM nickserv"
              " WHERE favlink IS NOT NULL AND flags & %d "
              " ORDER BY RAND() LIMIT 1", NFL_AUTHENTIC);
            if(sql_field(0) && sql_field(1)) /* just to be safe */
              email_add_symbol("linkexchange", 
                lang_str(u, LINK_EXCHANGE_X_X, sql_field(0), sql_field(1)));
            else
              email_add_symbol("linkexchange", "");
          } else email_add_symbol("linkexchange", "");
          if(email_send(welcome_emails[u->lang]) < 0)
          {
            log_log(ns_log, mod_info.name, "Error sending welcome email to %s by %s",
              email, irc_UserMask(u));
            send_lang(u, s, WELCOME_ERROR);
          }
          else
          {
            log_log(ns_log, mod_info.name, "Welcome email was sent to %s by %s",
              email, irc_UserMask(u));
            send_lang(u, s, WELCOME_SENT);
            if(WelcomeChan)
              irc_SvsJoin(u, s, WelcomeChan);
          }
        }
      else /* no security code required */
        {
          send_lang(u, s, NICK_REGISTER_SUCCESS);
          irc_SvsMode(u, s, "+r");            
          if(WelcomeChan)
            irc_SvsJoin(u, s, WelcomeChan);
        }
      free(securitycode);
      log_log(ns_log, mod_info.name, "Nick %s [%s] registered by %s",
        u->nick, email, irc_UserSMask(u));
      mod_do_event(e_nick_register, u, &snid);
    }
}
/* parse NickDefaultOptions */
void parse_nick_def_options(void)
{
  char* options;
  char* opt;
  
  if(NickDefaultOptions == NULL)
    return;
    
  options = strdup(NickDefaultOptions);  
  opt = strtok(options,",");
  while(opt)
    {
      int i;
      i = mask_value(nick_options_mask, opt);
      if( i == 0)
      	errlog("Unknown NickDefaultOption %s", opt);
      else
      	nick_def_options |= i;
      opt = strtok(NULL,",");
    }
  FREE(options);
}



syntax highlighted by Code2HTML, v. 0.9.1