/*
 * Turkish :
 * - Bu Modul Sky-Dancer Tarafindan Yazilmis/Editlenmistir.
 * - Bu Modulu Kullaniyorsaniz Telif Hakki Yazilarini Silemezsiniz.
 * - Bu Modulu Kullanarak LICENSE.UNOFF.TR adli okuma dosyasi icindeki Lisansi
 *   Kabul Etmis Sayiliyorsunuz.
 * - Dagitim Tarihi : 09 / 01 / 2007
 */

/*
 * English :
 * - This Module Codded/Edited By Sky-Dancer.
 * - if you are using this module, you can not delete copyright texts on this module.
 * - if you are using this module, You Are Accepting The License in LICENSE.ENG named file.
 * - Release Date : 09 / 01 / 2007
 */

 /*
  * Desc:
  * Old base + new conf struct & changed pass lookup
  */

  /*
   * Known Bugs:
   * There is no duplicate port control..
   * if there is no NickServ nick online at that time, User can't automatically oper.
   */

#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 _WIN32
#include "version.h"
#endif

// For English Version (ingilizce Versiyon icin)
//#define MODENG
// For Turkish Version (Turkce Versiyon icin)
#undef MODENG 

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

/* Prototypes */
void Delete_Hook(Hook *Dlt);
static int OperTest(aClient *sptr, char *mask);
static void ConfPassEkle(char *mask);
static void ConfOperPortEkle(char *mask);
int ConfItemTest(aClient *sptr);
DLLFUNC int kullanici_girisi(aClient *);
DLLFUNC int kullanici_girisi2(aClient *);
DLLFUNC int Call_LocalNSPass(aClient *, aClient *);
static void SifreGir(aClient *sptr);

// For Config.
DLLFUNC int Call_ConfigRun(ConfigFile *File, ConfigEntry *Entry, int Type);
DLLFUNC int Call_ConfigTest(ConfigFile *File, ConfigEntry *Entry, int Type, int *Error);
DLLFUNC int Call_ConfigRehash();

/* Variables */
static Hook *ConfigTest = NULL, *ConfigRun = NULL, *ConfigRehash = NULL;
static Hook *PreConnect = NULL, *LocalNSPass = NULL;
static ConfigItem_except *PortSifresi = NULL;

/* Conf File Structs */
typedef struct _MyConf MyConf;
struct _MyConf {
	MyConf *prev, *next;
	char *port;
	char *pass;
	int Tip;
};
static MyConf *ConfBuff;

/* Lang Defines; Yes, This is an ugly language switcher but, need a basic language switcher :) */
#ifdef MODENG
#define LANG_MODHEAD "Add Passwords to Specific Ports v1.0.7 (By Sky-Dancer)"
#define LANG_NOPASS "You Must Enter a Password."
#define LANG_PASSTOOLONG "Your Password is Too Long."
#define LANG_WRONGPASS "Your Password is Wrong."
#define LANG_OPERSERVER "This Port for Opers Only."
//#define LANG_CORRECTPASSWORD "Congratulations, Your Password Accepted."
#else
#define LANG_MODHEAD "Belirlenen Port'a Sifre v1.0.7 (By Sky-Dancer)"
#define LANG_NOPASS "Sifre Girmelisiniz."
#define LANG_PASSTOOLONG "Sifreniz Cok Uzun."
#define LANG_WRONGPASS "Sifreniz Yanlis."
#define LANG_OPERSERVER "Bu Port Sadece Operatorler icindir."
//#define LANG_CORRECTPASSWORD "Tebrikler, Sifreniz Kabul Edildi."
#endif

#ifndef STATIC_LINKING
static ModuleInfo	*Mod_PSifresi;
#endif

/* Main Module Header For UnrealIRCd */
ModuleHeader MOD_HEADER(portsifresi) = {
	"portsifresi",
	LANG_MODHEAD,
	LANG_MODHEAD,
	"3.2-b8-1",
	NULL 
};

/* MOD_TEST Function */
DLLFUNC int MOD_TEST(portsifresi)(ModuleInfo *modinfo) {
	ConfigTest	= HookAddEx(modinfo->handle, HOOKTYPE_CONFIGTEST, Call_ConfigTest);
return MOD_SUCCESS;
}

/* MOD_INIT Function */
DLLFUNC int MOD_INIT(portsifresi)(ModuleInfo *modinfo) {
#ifndef STATIC_LINKING
	// Maybe, later uses :)
	Mod_PSifresi = modinfo;
#endif
	ConfBuff=NULL;
	PreConnect		= HookAddEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, kullanici_girisi);
	LocalNSPass		= HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_NICKPASS, Call_LocalNSPass);
	ConfigRun		= HookAddEx(modinfo->handle, HOOKTYPE_CONFIGRUN, Call_ConfigRun);
	ConfigRehash	= HookAddEx(modinfo->handle, HOOKTYPE_REHASH, Call_ConfigRehash);
return MOD_SUCCESS;
}

/* MOD_LOAD Function */
DLLFUNC int MOD_LOAD(portsifresi)(int module_load) {
return MOD_SUCCESS;
}

/* MOD_UNLOAD Function */
DLLFUNC int MOD_UNLOAD(portsifresi)(int module_unload) {
/*	Delete_Hook(ConfigTest);
	Delete_Hook(ConfigRun);
	Delete_Hook(ConfigRehash);
	Delete_Hook(PreConnect);*/
return MOD_SUCCESS;
}

void Delete_Hook(Hook *Dlt) {
	if (Dlt) {
		HookDel(Dlt);
		Dlt = NULL;
	}
}

/* Local User Connect Hook */
DLLFUNC int kullanici_girisi(aClient *sptr) {
	int ret;
	ret = ConfItemTest(sptr);
	switch (ret) {
		case 1:
		return exit_client(sptr, sptr, &me, LANG_NOPASS);
		break;

		case 2:
		return exit_client(sptr, sptr, &me, LANG_PASSTOOLONG);
		break;

		case 3:
		return exit_client(sptr, sptr, &me, LANG_WRONGPASS);
		break;

		case 4:
		return exit_client(sptr, sptr, &me, LANG_OPERSERVER);
		break;

		case 5:
//		sendto_one(sptr, ":%s NOTICE %s :*** "LANG_CORRECTPASSWORD, me.name, sptr->name);
		break;

		default:
		return exit_client(sptr, sptr, &me, "?");
		break;
	}

return 0;
}

// Local Nickserv Pass Hook ;)
// For some reasons, in linked servers there was a kill problem from other links.
// So i used this hook instead of Local Connect Hook.
DLLFUNC int Call_LocalNSPass(aClient *sptr, aClient *NSptr) {
	MyConf *Cnf;
	for (Cnf = ConfBuff; Cnf; Cnf = Cnf->next) {
		if (!Cnf->port)
			continue;
		if (Cnf->Tip == 0)
			continue;
		// user already connected with oper password ;)
		if ((atoi(Cnf->port) == sptr->listener->port))
			SifreGir(sptr);
	}
return HOOK_CONTINUE;
}


static void SifreGir(aClient *sptr) {
	char *mynick = NULL, *mypass = NULL;
	char maxbuff[128];
	char line[128];
	if (sptr->passwd) {
		memset(maxbuff,0,sizeof(maxbuff));
		strncpy(maxbuff,sptr->passwd,128);
		mynick = strtok(maxbuff, ":");
		if (mynick) {
			mypass = strtok(NULL, ":");
			if (mypass) {
				char *OperGir[4] = {
					sptr->name,
					mynick,
					mypass,
					NULL
				};
				do_cmd(sptr, sptr, "OPER", 4, OperGir);
/*				char *NickGir[3] = {
					sptr->name,
					mynick,
					NULL
				};
				do_cmd(sptr, sptr, "NICK", 3, NickGir);*/
			}
		}
	}

}


/* Test for oper nicks & passes from conf variables. */
static int OperTest(aClient *sptr, char *mask) {
	char *mynick = NULL, *mypass = NULL;
	char maxbuff[128];
	char line[128];
	int MyKill = 1, t=0;
	ConfigItem_oper *p;
	if (MyConnect(sptr) && (!IsServer(sptr) && !IsULine(sptr))) {
		if (mask) {
			memset(maxbuff,0,sizeof(maxbuff));
			strncpy(maxbuff,mask,128);
			mynick = strtok(maxbuff, ":");
			if (mynick) {
				mypass = strtok(NULL, ":");
				if (mypass) {
					for (p = conf_oper; p; p = (ConfigItem_oper *) p->next) {
						if (p->name) {
							if (!strcmp(p->name, mynick)) {
								t = Auth_Check(sptr, p->auth, mypass);
								if (t > 1) {
									MyKill = 0;
								break;
								}
							}
						}
					}
				}
			}
		}
	}
return !MyKill;
}

/* Adding passwords to memory from confs reads */
static void ConfPassEkle(char *mask) {
	MyConf *Cnf;
	char *myport = NULL, *mypass = NULL;
	char maxbuff[128];
	char line[128];
	if (mask) {
		memset(maxbuff,0,sizeof(maxbuff));
		strncpy(maxbuff,mask,128);
		myport = strtok(maxbuff, ":");
		if (myport) {
			mypass = strtok(NULL, ":");
			if (mypass) {
				Cnf = (MyConf *) MyMallocEx(sizeof(MyConf));
				Cnf->port=strdup(myport);
				Cnf->pass=strdup(mypass);
				Cnf->Tip=0;
				AddListItem(Cnf, ConfBuff);
			}
		}
	}
}

/* Adding Oper Port(s).. */
static void ConfOperPortEkle(char *mask) {
	MyConf *Cnf;
	if (mask) {
		Cnf = (MyConf *) MyMallocEx(sizeof(MyConf));
		Cnf->port=strdup(mask);
		Cnf->pass=strdup(" ");
		Cnf->Tip=1;
		AddListItem(Cnf, ConfBuff);
	}
}

/* Test Password with our config values (psifre::...) */
int ConfItemTest(aClient *sptr) {
	MyConf *Cnf;
	int ret = 5;

	for (Cnf = ConfBuff; Cnf; Cnf = Cnf->next) {
		// Maybe Not Needed..
		if (!Cnf->port || !Cnf->pass)
			continue;

		if ((atoi(Cnf->port) == sptr->listener->port)) {
			if (sptr->passwd==NULL) {
				ret = 1;
			break;
			}

			if (strlen(sptr->passwd) > 128){
				ret = 2;
			break;
			}
			if (Cnf->Tip == 0) {
				if (!strcmp(Cnf->pass,sptr->passwd)) {
					ret = 5;
				break;
				}
				else ret = 3;
			} else {
				if (OperTest(sptr, sptr->passwd) == 1) {
					ret = 5;
				break;
				}
				else ret = 4;
			}
		}
	}

return (ret);
}

/* On Rehash Hook? :) */
DLLFUNC int Call_ConfigRehash() {
	MyConf *Cnf;
	ListStruct *next;

	for (Cnf = ConfBuff; Cnf; Cnf = (MyConf *) next) {
		next = (ListStruct *) Cnf->next;
		if (Cnf->port) MyFree(Cnf->port);
			Cnf->port = NULL;
		if (Cnf->pass) MyFree(Cnf->pass);
			Cnf->pass = NULL;
		DelListItem(Cnf, ConfBuff);
	}
return 1;
}

/* On Conf Test Hook. */
DLLFUNC int Call_ConfigTest(ConfigFile *File, ConfigEntry *Entry, int Type, int *Error) {
	int ErrorTemp = 0;
	ConfigEntry	*EntryTemp;

	if (Type != CONFIG_MAIN)
		return 0;

	if (!Entry || !Entry->ce_varname || strcmp(Entry->ce_varname, "psifre"))
		return 0;

	for (EntryTemp = Entry->ce_entries; EntryTemp; EntryTemp = EntryTemp->ce_next)	{
		if (!EntryTemp->ce_varname) {
			config_error("%s:%i: psifre is empty.",
				EntryTemp->ce_fileptr->cf_filename, EntryTemp->ce_varlinenum);
			ErrorTemp++;
			continue;
		}
		else if (!strcmp(EntryTemp->ce_varname, "pass")) { 
			if (strlen(EntryTemp->ce_vardata)==0) {
				config_error("%s:%i: psifre::pass is empty.",
					EntryTemp->ce_fileptr->cf_filename, EntryTemp->ce_varlinenum);
				ErrorTemp++;
			continue;
			}
			else {
				if (!strstr(EntryTemp->ce_vardata, ":")) {
					config_error("%s:%i: psifre::pass line must be \"port:pass\"",
						EntryTemp->ce_fileptr->cf_filename, EntryTemp->ce_varlinenum);
					ErrorTemp++;
				continue;
				}
			}
		}
		else if (!strcmp(EntryTemp->ce_varname, "operport")) { 
			if (strlen(EntryTemp->ce_vardata)==0) {
				config_error("%s:%i: psifre::operport is empty.",
					EntryTemp->ce_fileptr->cf_filename, EntryTemp->ce_varlinenum);
				ErrorTemp++;
			continue;
			}
		}
		else {
			config_error("%s:%i: Unknown Directive psifre::%s",
				EntryTemp->ce_fileptr->cf_filename, EntryTemp->ce_varlinenum, EntryTemp->ce_varname);
			ErrorTemp++;
			continue;
		}
	}
	*Error = ErrorTemp;
return ErrorTemp ? -1 : 1;
}

/* On Conf Run Hook. */
DLLFUNC int Call_ConfigRun(ConfigFile *File, ConfigEntry *Entry, int Type) {
	ConfigEntry	*EntryTemp;

	if (Type != CONFIG_MAIN)
		return 0;

	if (!Entry || !Entry->ce_varname || strcmp(Entry->ce_varname, "psifre"))
		return 0;

	for (EntryTemp = Entry->ce_entries; EntryTemp; EntryTemp = EntryTemp->ce_next) {
		if (!strcmp(EntryTemp->ce_varname, "pass"))
			ConfPassEkle(EntryTemp->ce_vardata);
		if (!strcmp(EntryTemp->ce_varname, "operport"))
			ConfOperPortEkle(EntryTemp->ce_vardata);
	}
return 1;
}

