#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif

#define MSG_VERIFY         "AUTH"
#define TOK_VERIFY         "AUTHH"

typedef struct _VerifyUser VerifyUser;

static char *verifyjoin;

struct _VerifyUser
{
        VerifyUser        *prev, *next;
        aClient                *skyptr;
        int                verified, verifysifresi, verifyexcept;
};

extern void                        sendto_one(aClient *to, char *pattern, ...);
extern void                        sendto_realops(char *pattern, ...);

int verify_kontrol(Cmdoverride *ovr, u_short cmd, aClient *cptr, aClient *sptr, int parc, char *parv[]);
static int m_verify(aClient *cptr, aClient *sptr, int parc, char *parv[]);

static int cb_pre_connect(aClient *);
static int cb_pre_connect2(aClient *);
static int cb_quit(aClient *, char *);
static int cb_rehash();
static int cb_stats(aClient *sptr, char *stats);
static int cb_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
static int cb_conf(ConfigFile *cf, ConfigEntry *ce, int type);
static void InitConf();
static void FreeConf();

static ConfigItem_except        *VerifyExcept = NULL;
static VerifyUser                *VERIFYUSER;

static void free_verify_user();

static void AddVerifyException(char *mask);
static void AddVerifyIdentException(char *mask);
static void AddVerifyPortException(char *mask);
int except_verify_bul(char *host, char *ip);
int except_verifyident_bul(char *ident);
int except_verifyport_bul(u_short port);

static Hook                *HookPreConnect, *HookConnect, *HookQuit, *HookRemoteQuit;
static Hook                *HookConfTest, *HookConfRun, *HookConfRehash;
static Hook                        *HookStats = NULL;

static Command                *AddCommand(Module *module, char *msg, char *token, iFP func, int params);

#define DelOverride(cmd, ovr)        if (ovr && CommandExists(cmd)) CmdoverrideDel(ovr); ovr = NULL
#define DelHook(x)                if (x) HookDel(x); x = NULL
#define OVR_FUNC(x)                int (x)(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
#define DelCommand(x)        if (x) CommandDel(x); x = NULL

#define CMD_PRIVMSG                0
#define CMD_NOTICE                1
#define CMD_JOIN                2

static OVR_FUNC(ovr_Privmsg);
static OVR_FUNC(ovr_Notice);
static OVR_FUNC(ovr_Join);

static Cmdoverride                *AddOverride(char *msg, iFP cb);
static Cmdoverride                *OvrPrivmsg, *OvrNotice, *OvrJoin;

Command                        *CmdVerify;

#ifndef STATIC_LINKING
static ModuleInfo        *MyModInfo;
 #define MyMod                MyModInfo->handle
 #define SAVE_MODINFO        MyModInfo = modinfo;
#else
 #define MyMod                NULL
 #define SAVE_MODINFO
#endif

ModuleHeader MOD_HEADER(m_verify)
  = {
        "webauth",
        "Auth kontrol sistemi(web uyumlu)",
        "User ile botu ayirmak icin auth kod uygulamasi",
        "3.2-b8-1",
        NULL
    };

DLLFUNC int MOD_TEST(m_verify)(ModuleInfo *modinfo)
{
        SAVE_MODINFO
        HookConfTest = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGTEST, cb_test);
    return MOD_SUCCESS;
}

DLLFUNC int MOD_INIT(m_verify)(ModuleInfo *modinfo)
{
        SAVE_MODINFO
        HookConfRun        = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGRUN, cb_conf);
        HookConfRehash        = HookAddEx(modinfo->handle, HOOKTYPE_REHASH, cb_rehash);

        HookStats        = HookAddEx(modinfo->handle, HOOKTYPE_STATS, cb_stats);

        HookPreConnect        = HookAddEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, cb_pre_connect);
        HookConnect        = HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, cb_pre_connect2);
        HookQuit                = HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_QUIT, cb_quit);
        HookRemoteQuit                = HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_QUIT, cb_quit);
        CmdVerify = AddCommand(modinfo->handle, MSG_VERIFY, TOK_VERIFY, m_verify, 2);

        if (!CmdVerify)
                return MOD_FAILED;

    return MOD_SUCCESS;
}

DLLFUNC int MOD_LOAD(m_verify)(int module_load)
{
        int ret = MOD_SUCCESS;

        OvrPrivmsg                = AddOverride("privmsg", ovr_Privmsg);
        OvrNotice                = AddOverride("notice", ovr_Notice);
        OvrJoin                        = AddOverride("join", ovr_Join);

        if (!OvrNotice || !OvrPrivmsg || !OvrJoin)
                ret = MOD_FAILED;

        return ret;
}

DLLFUNC int MOD_UNLOAD(m_verify)(int module_unload)
{
        DelOverride("privmsg", OvrPrivmsg);
        DelOverride("notice", OvrNotice);
        DelOverride("join", OvrJoin);
        free_verify_user();
        DelHook(HookPreConnect);
        DelHook(HookRemoteQuit);
        DelHook(HookQuit);
        DelHook(HookConfTest);
        DelHook(HookConfRun);
        DelHook(HookConfRehash);
        DelHook(HookStats);
        DelCommand(CmdVerify);

        return MOD_SUCCESS;
}

static Command *AddCommand(Module *module, char *msg, char *token, iFP func, int params)
{
        Command *cmd;

        if (CommandExists(msg))
            {
                config_error("%s Komutu Zaten Var.", msg);
                return NULL;
            }
            if (CommandExists(token))
        {
                config_error("Token %s Zaten Var.", token);
                return NULL;
            }

        cmd = CommandAdd(module, msg, token, func, params, 0);

#ifndef STATIC_LINKING
        if (ModuleGetError(module) != MODERR_NOERROR || !cmd)
#else
        if (!cmd)
#endif
        {
#ifndef STATIC_LINKING
                config_error("%s Komutu Eklenemedi: %s", msg,
                        ModuleGetErrorStr(module));
#else
                config_error("%s Komutu Eklenemedi", msg);
#endif
                return NULL;
        }

        return cmd;
}

Cmdoverride *AddOverride(char *msg, iFP cb)
{
        Cmdoverride *ovr = CmdoverrideAdd(MyMod, msg, cb);

#ifndef STATIC_LINKING
        if (ModuleGetError(MyMod) != MODERR_NOERROR ||!ovr)
#else
        if (!ovr)
#endif
        {
#ifndef STATIC_LINKING
                config_error("%s modulu yuklenirken, %s komutu konulamadi: %s",
                        MOD_HEADER(m_verify).name, msg, ModuleGetErrorStr(MyMod));
#else
                config_error("%s modulu yuklenirken, %s komutu konulamadi",
                        MOD_HEADER(m_verify).name, msg);
#endif
                return NULL;
        }

        return ovr;
}

static VerifyUser *find_verifyuser(aClient *cptr)
{
        VerifyUser *u;

        for (u = VERIFYUSER; u; u = u->next)
                if (u->skyptr == cptr)
                        break;

        return u;
}

static void add_verifyuser(aClient *cptr)
{
        VerifyUser *u;

        u        = (VerifyUser *) MyMalloc(sizeof(VerifyUser));
        u->skyptr        = cptr;

        AddListItem(u, VERIFYUSER);
}

static void free_verify_user()
{
        VerifyUser        *u;
        ListStruct        *next;

        for (u = VERIFYUSER; u; u = (VerifyUser *) next)
        {
                next = (ListStruct *) u->next;
                DelListItem(u, VERIFYUSER);
        }
}

static int cb_quit(aClient *sptr, char *comment)
{
        VerifyUser *u;
        ListStruct        *next;
        for (u = VERIFYUSER; u; u = u->next)
                if (u->skyptr == sptr)
                        break;

        DelListItem(u, VERIFYUSER);

        return 0;
}

static int cb_pre_connect(aClient *sptr)
{

        VerifyUser *u;

if (!IsULine(sptr) && !IsServer(sptr)) {
        add_verifyuser(sptr);

        if (!(u=find_verifyuser(sptr))) {
                return exit_client(sptr, sptr, &me,        "*** Bir Problem Oluştu. Lütfen Çıkıp Tekar Giriniz.");
        }
                u->skyptr = sptr;
                u->verified = 0;
                u->verifyexcept = 0;
                u->verifysifresi = ((rand() % (int)(((99999)+1) - (10000))) + (10000));
        }

        if (except_verify_bul(sptr->sockhost,sptr->sockhost)) {
                u->verified=1;
                u->verifyexcept=1;
        }

        if (except_verifyident_bul(sptr->user->username)) {
                u->verified=1;
                u->verifyexcept=1;
        }

        if (except_verifyport_bul(sptr->listener->port)) {
                u->verified=1;
                u->verifyexcept=1;
        }

        return 0;
}

static int cb_pre_connect2(aClient *sptr)
{
        VerifyUser        *u;

        if (!IsULine(sptr) && !IsServer(sptr) && MyClient(sptr)) {
        if (!(u=find_verifyuser(sptr))) {
                sendto_one(sptr, ":%s NOTICE %s :Bir Problem Oluştu. Lütfen Çıkıp Tekar Giriniz.", me.name, sptr->name);
        return 0;
        }
        else {
        if (u->verifyexcept==0) {
        sendto_one(sptr, ":%s NOTICE %s :Sistemimize kendinizi tanıtmak zorundasınız. Aksi halde hic bir islem yapamiyacaksiniz.", me.name, sptr->name);
        sendto_one(sptr, ":%s NOTICE %s :Kodunuz icin tiklayin: http://www.eksimuhabbet.com/auth.php?kod=%d", me.name, sptr->name, u->verifysifresi);
        sendto_one(sptr, ":%s NOTICE %s :12Kodunuzu 4/auth <Kod>12 Şeklinde Girebilirsiniz..", me.name, sptr->name);
        }
        }
        }
        return 0;
}


static OVR_FUNC(ovr_Privmsg)
{
        if (!IsAnOper(sptr) && !IsULine(sptr) && !IsServer(sptr) && MyClient(sptr))
        return verify_kontrol(ovr, CMD_NOTICE, cptr, sptr, parc, parv);

return CallCmdoverride(ovr, cptr, sptr, parc, parv);
}

static OVR_FUNC(ovr_Notice)
{
        if (!IsAnOper(sptr) && !IsULine(sptr) && !IsServer(sptr) && MyClient(sptr))
        return verify_kontrol(ovr, CMD_NOTICE, cptr, sptr, parc, parv);

return CallCmdoverride(ovr, cptr, sptr, parc, parv);
}

static OVR_FUNC(ovr_Join)
{
        if (!IsAnOper(sptr) && !IsULine(sptr) && !IsServer(sptr) && MyClient(sptr))
        return verify_kontrol(ovr, CMD_JOIN, cptr, sptr, parc, parv);

return CallCmdoverride(ovr, cptr, sptr, parc, parv);
}

void ban_client(aClient *cptr, char *type, long period, char *reason);
int verify_kontrol(Cmdoverride *ovr, u_short cmd, aClient *cptr, aClient *sptr, int parc, char *parv[])
{
        VerifyUser        *u;

        if (!(u=find_verifyuser(sptr))) {
                sendto_one(sptr, ":%s NOTICE %s :Bir Problem Oluştu. Lütfen Çıkıp Tekar Giriniz.", me.name, sptr->name);
        return 0;
        }
        else {

        if (u->verifyexcept==1 || u->verified==1)
        {
                return CallCmdoverride(ovr, cptr, sptr, parc, parv);
        } else {
                sendto_one(sptr, ":%s NOTICE %s :Merhaba %s, Lütfen auth kodunu giriniz aksi halde hic bir islemi yapamiyacaksiniz..", me.name, sptr->name, sptr->name); 
                static int zaman;
                scanf("%d", &zaman);
                int tut=time(NULL)+zaman;       
                if ((tut%60)==zaman) {
                 place_host_ban(sptr, BAN_ACT_GLINE, "Sunucudan 10 dk uzaklaştırıldınız. Lütfen auth kodu ile kendinizi tanıtınız.", 600);
                }
               sendto_one(sptr, ":%s NOTICE %s :Merhaba %s, Doğrulama Yapmamışsınız. http://www.eksimuhabbet.com/auth.php?kod=%d adresinden dogrulama kodunu alip giriniz..", me.name, sptr->name, u->verifysifresi);
        return 0;
        }

        }

return CallCmdoverride(ovr, cptr, sptr, parc, parv);
}



/*
** m_verify
**      parv[0] = sender prefix
**      parv[1] = nickname
**      parv[2] = password
*/

static int m_verify(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
        VerifyUser        *u;

        if (!(u=find_verifyuser(sptr))) {
                sendto_one(sptr, ":%s NOTICE %s :Bir Problem Oluştu. Lütfen Çıkıp Tekar Giriniz.", me.name, sptr->name);
        return 0;
        }
        else {

        if (parv[1]==NULL)
        {
                sendto_one(sptr, ":%s NOTICE %s :Parametre Yetersiz.", me.name, sptr->name);
        return 0;
        }

        if (u->verified == 1) {
                sendto_one(sptr, ":%s NOTICE %s :Şifreniz Zaten Girilmiş.", me.name, sptr->name);
        return 0;
        }

        if (atoi(parv[1]) == u->verifysifresi) {
                sendto_one(sptr, ":%s NOTICE %s :Şifreniz Kabul Edildi. iyi Sohbetler..", me.name, sptr->name);
                u->verified = 1;
                if (!(verifyjoin == NULL)) {
                char *chans[3] = {
                sptr->name,
                verifyjoin,
                NULL
                };
                do_cmd(sptr, sptr, "JOIN", 3, chans);
                }
        return 0;
        }
        else
        {
                sendto_one(sptr, ":%s NOTICE %s :Şifreniz Yanlış. Lütfen Tekrar Deneyiniz.", me.name, sptr->name);
        return 0;
        }
        }
return 0;
}

static void FreeConf()
{
        ListStruct                *next;
    ConfigItem_except        *e;
        for (e = VerifyExcept; e; e = (ConfigItem_except *) next)
        {
                next = (ListStruct *) e->next;
                DelListItem(e, VerifyExcept);
                MyFree(e->mask);
                MyFree(e);
        }
}

static int cb_rehash()
{
        FreeConf();
        return 1;
}

static int cb_stats(aClient *sptr, char *stats)
{
        if (*stats == 'S')
        {
        sendto_one(sptr, ":%s %i %s :except::verify mask",
                        me.name, RPL_TEXT, sptr->name);
        sendto_one(sptr, ":%s %i %s :except::verifyport port",
                me.name, RPL_TEXT, sptr->name);
        sendto_one(sptr, ":%s %i %s :except::verifyident mask",
                me.name, RPL_TEXT, sptr->name);
        sendto_one(sptr, ":%s %i %s :except::verifyjoin chan",
                me.name, RPL_TEXT, sptr->name);
        }

        return 0;
}

static int cb_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
{
        ConfigEntry        *cep, *cepp;
        int                errors = 0;

        if (type == CONFIG_EXCEPT)
        {
                if (!strcmp(ce->ce_vardata, "verifyjoin"))
                {
                        if (!config_find_entry(ce->ce_entries, "chan"))
                        {
                                config_error("%s:%i: except verifyjoin without chan item",
                                        ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
                                errors++;
                        }
                        else
                        {
                                for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                {
                        if (!cep->ce_varname)
                        {
                                config_error("%s:%i: blank except verifyjoin::chan item",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum);
                                errors++;
                                continue;
                        }
                        if (!cep->ce_vardata)
                        {
                                config_error("%s:%i: except verifyjoin::%s item without value",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum, cep->ce_varname);
                                errors++;
                                continue;
                        }
                                        if (!strcmp(cep->ce_varname, "chan"))
                                                 ;
                                        else
                                        {
                                                config_error("%s:%i: unknown except verifyjoin directive %s",
                                                        cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
                                                errors++;
                                                continue;
                                        }
                                }
                        }
                        *errs = errors;
                        return errors ? -1 : 1;
                }
                if (!strcmp(ce->ce_vardata, "verify"))
                {
                        if (!config_find_entry(ce->ce_entries, "mask"))
                        {
                                config_error("%s:%i: except verify without mask item",
                                        ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
                                errors++;
                        }
                        else
                        {
                                for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                {
                        if (!cep->ce_varname)
                        {
                                config_error("%s:%i: blank except verify::mask item",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum);
                                errors++;
                                continue;
                        }
                        if (!cep->ce_vardata)
                        {
                                config_error("%s:%i: except verify::%s item without value",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum, cep->ce_varname);
                                errors++;
                                continue;
                        }
                                        if (!strcmp(cep->ce_varname, "mask"))
                                                 ;
                                        else
                                        {
                                                config_error("%s:%i: unknown except verify directive %s",
                                                        cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
                                                errors++;
                                                continue;
                                        }
                                }
                        }
                        *errs = errors;
                        return errors ? -1 : 1;
                }
                if (!strcmp(ce->ce_vardata, "verifyident"))
                {
                        if (!config_find_entry(ce->ce_entries, "mask"))
                        {
                                config_error("%s:%i: except verifyident without mask item",
                                        ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
                                errors++;
                        }
                        else
                        {
                                for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                {
                        if (!cep->ce_varname)
                        {
                                config_error("%s:%i: blank except verifyident::mask item",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum);
                                errors++;
                                continue;
                        }
                        if (!cep->ce_vardata)
                        {
                                config_error("%s:%i: except verifyident::%s item without value",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum, cep->ce_varname);
                                errors++;
                                continue;
                        }
                                        if (!strcmp(cep->ce_varname, "mask"))
                                                 ;
                                        else
                                        {
                                                config_error("%s:%i: unknown except verifyident directive %s",
                                                        cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
                                                errors++;
                                                continue;
                                        }
                                }
                        }
                        *errs = errors;
                        return errors ? -1 : 1;
                }
                if (!strcmp(ce->ce_vardata, "verifyport"))
                {
                        if (!config_find_entry(ce->ce_entries, "port"))
                        {
                                config_error("%s:%i: except verifyport without port item",
                                        ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
                                errors++;
                        }
                        else
                        {
                                for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                {
                        if (!cep->ce_varname)
                        {
                                config_error("%s:%i: blank except verifyport::port item",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum);
                                errors++;
                                continue;
                        }
                        if (!cep->ce_vardata)
                        {
                                config_error("%s:%i: except verifyport::%s item without value",
                                        cep->ce_fileptr->cf_filename,
                                        cep->ce_varlinenum, cep->ce_varname);
                                errors++;
                                continue;
                        }
                                        if (!strcmp(cep->ce_varname, "port"))
                                                 ;
                                        else
                                        {
                                                config_error("%s:%i: unknown except verifyport directive %s",
                                                        cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
                                                errors++;
                                                continue;
                                        }
                                }
                        }
                        *errs = errors;
                        return errors ? -1 : 1;
                }
        }

        return 0;
}

static int cb_conf(ConfigFile *cf, ConfigEntry *ce, int type)
{
        ConfigEntry        *cep, *cepp;

        if (type == CONFIG_EXCEPT)
        {
                if (!strcmp(ce->ce_vardata, "verifyjoin"))
                {
                        for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                if (!strcmp(cep->ce_varname, "chan"))
                                        verifyjoin=strdup(cep->ce_vardata);
                        return 1;
                }
                if (!strcmp(ce->ce_vardata, "verify"))
                {
                        for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                if (!strcmp(cep->ce_varname, "mask"))
                                        AddVerifyException(cep->ce_vardata);
                        return 1;
                }
                if (!strcmp(ce->ce_vardata, "verifyident"))
                {
                        for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                if (!strcmp(cep->ce_varname, "mask"))
                                        AddVerifyIdentException(cep->ce_vardata);
                        return 1;
                }
                if (!strcmp(ce->ce_vardata, "verifyport"))
                {
                        for (cep = ce->ce_entries; cep; cep = cep->ce_next)
                                if (!strcmp(cep->ce_varname, "port"))
                                        AddVerifyPortException(cep->ce_vardata);
                        return 1;
                }

        }

        return 0;
}

static void AddVerifyException(char *mask)
{
        ConfigItem_except *e;

        e = (ConfigItem_except *) MyMallocEx(sizeof(ConfigItem_except));
        e->mask = strdup(mask);
        e->type = 50;

        AddListItem(e, VerifyExcept);
}

int except_verify_bul(char *host, char *ip)
{
        ConfigItem_except *e;

        for (e = VerifyExcept; e; e = (ConfigItem_except *) e->next)
                if ((!match(e->mask, host) || !match(e->mask, ip)) && (e->type == 50)) {
                return 1;
        }
                else {
                return 0;
        }
        return 0;
}

static void AddVerifyIdentException(char *mask)
{
        ConfigItem_except *e;

        e = (ConfigItem_except *) MyMallocEx(sizeof(ConfigItem_except));
        e->mask = strdup(mask);
        e->type = 51;

        AddListItem(e, VerifyExcept);
}

int except_verifyident_bul(char *ident)
{
        ConfigItem_except *e;

        for (e = VerifyExcept; e; e = (ConfigItem_except *) e->next)
                if (!match(e->mask, ident) && (e->type == 51)) {
                return 1;
        }
                else {
                return 0;
        }
        return 0;
}

static void AddVerifyPortException(char *mask)
{
        ConfigItem_except *e;

        e = (ConfigItem_except *) MyMallocEx(sizeof(ConfigItem_except));
        e->mask = strdup(mask);
        e->type = 52;

        AddListItem(e, VerifyExcept);
}

int except_verifyport_bul(u_short port)
{
        ConfigItem_except *e;
        for (e = VerifyExcept; e; e = (ConfigItem_except *) e->next)
                if ((atoi(e->mask) == port) && (e->type == 52)) {
                return 1;
        }
                else {
                return 0;
        }
        return 0;
}

