"Ilmu pengetahuan Tertinggi adalah ilmu pengetahuan yang tidak bisa dipikirkan oleh otak manusia tapi bisa dirasakan hati manusia"

"Top science is science that can not be considered by the human brain can be felt but the human heart"

"トップ科学人間の脳考えることはできない科学感じることができる、人間のです."

Senin, 08 Agustus 2011

auspice-conf

#
# *+.+**+.+**+.+**+.+**+.+**+.+**+.+*
# *+.+* EasyNets Services *+.+*
# *+.+**+.+**+.+**+.+**+.+**+.+**+.+*
#
# This is EasyNets Services sample config file
# Created By Dj-RuFfy @ EasyNets
# Special Thanks To My Lovely Julia

# Remote Server, the irc server where services would connect to
# ex: 209.20.92.45
S:98.129.237.176
A:Angels3

# Port where Services will connect to
P:6667

# Connect Password where it's place in C/N line in server
# services connect to.
X:services

# Services Server Name
N:services.angels3.com

# Services Describe
D:EasyNets Services IRC Network by Dj-RuFfy N Estrada

# Services Admin Full Name, this will show in /admin sevices.*
# Note: No space allow
ANAME:Dj-RuFfy

# Services Admin E-mail
AMAIL:root@angels3.com

# Services E-mail (show in reply when services send any e-mail to someone)
PMAIL:ruffy@angels3.com

# Services User for NickServ/ChanServ...
U:services

# Services Host for NickServ/ChanServ...
H:easynets.org

# Service Master Nick Name
# This nickname must first register.
M:Dj-RuFfy

# Service Co Master
R:tian

# Define Services Name Follow
MEMOSERV:MemoServ
HELPSERV:HelpServ
OPERSERV:OperServ
ROOTSERV:RootServ
HOSTSERV:HostServ
BOTSERV:BotServ
GLOBAL:Global

# NickServ

# Services Nick Name
NICKSERV:NickServ

# Nickname expire
NICKEXP:21

# Auto set mode on register
# 1= Enable 0= Disable
KILL:0
SECURE:0
PRIVATE:0

# Allow Add channel VOP/HOP/AOP/SOP/CFOUNDER by using access mask
# 0= YES 1= NO
ACCESS:1

# Allow user using ListChans Command
# Default = 0, 1 = Enable
ALLOWCLIST:1

# Maximum permitted mask enteries per nick access list.
# Default: 20; 0 Disables
U_ACC_MAX:20

# Ammount of seconds to automatically release an enforced nick.
# Default: 30
RELEASE:30

# ChanServ

# ChanServ Nick name
CHANSERV:ChanServ

# Define expire data for channel
CHANEXP:21

# Maximum permitted enteries per channel access list.
# Access list = AVOICE+HOP+AOP+SOP+CFOUNDER as a sum.
# Default: 900; 0 Disables
C_ACC_MAX:900

# Changes default #Snoop channel.
SET_SNOOP:1
SNOOPCHAN:#debug

# Maximum channels permitted to be registered per user.
# Default: 20, 0 = Disable
CHANREG:20

# Maximum amount of auto-kick's for a channel.
# Default: 100, 0 = Disable
AKICK:100

# Maximum channel suspensions services will keep.
# Default: 256
SUSPEND:256

# Default: +rtn, Disable: +
MLOCK:+rtn

# Defines how long, in seconds, ChanServ should retain in
# a channel after a masskick or suspension.
# Default: 15
CHANNEL_INHABIT:15

# TOPICFIX This option will prevent
# services from adding duplicate nicks to the topic.
# Enable: 1, Disable: 0;
TOPICFIX:1

# Auto update Database on NickServ/ChanServ/MemoServ/HostServ changed
# Enable: 1, Disable: 0
# Not warranty it's safe for your data in this option
# I haven't test yet if you do it please give me the result
AUTOUP:0

# Number of seconds which database update/expires
# 900 = 15 minutes = 15 * 60
UPDATE:900

# Should not touch, if you running a slow server you may put it to 5
TIMEOUT:3

# Limite badpass identify to Chan/Nick Serv
PW_LIMIT:4

# Number of seconds which services forget the badpass attempts
PW_TIMEOUT:1800

# Number of Memo permit per user
MEMOMAX:20

# Number of seconds that must elapse sending memo
MEMO_WAIT:5

# Nick/Chan/Memo Expire day
MEMOEXP:21

# Max Number of permit Services Root
ROOTS:5

# Max Number of permit Services Admin
ADMINS:30

# Max Number of permit Services Oper
OPERS:40

# Max Number of permit Helper
HELPOPS:20

# Max akill add, 0 disable
AKILLS:128

# Maximum permitted "jupitered" servers. Default: 12; 0 Disables
JUPES:12

# Maximum permitted triggers. Default: 128; 0 Disables
TRIGGERS:128

# Default AKILL expiry time in seconds. Default: 86400 (1 day)
AKILLEXP:86400

# Number of client found before notice as clone
CLONES:6

# Number of seconds between consecutive clone warming from
# the same host. Default: 10
# Note: -It will not keep warming unless more clones ware loaded
CLONE_WARN:10

# Max charaters permit in memo
MEMO_LEN:225

# Enable or Disable sending log files via email
LOGS:0

# Enable Services +a umode flag. With this setting
# enabled, any services admin identifying to their
# nick will have services set umode +a.
# This option also allows services admins to use /samode.
# Enable = 1; Disable = 0; Default = 1
UMODE_a:1

# Maximum permitted Services q:lines. These are
# viewed via /stats q, not /stats Q.
# Default = 64; 0 Disables
QLINES:64

# Maximum permitted Services global z:lines.
# Default: 128, 0 Disables
ZLINES:128

# Allow users to have their memos sent via email.
# Sendmail must be working on the computer services
# are running from. Default = 1; 0 Disables
EMAIL:0

# If you wish to have your own notice when any client
# connects, enable this, and edit "messages.h" where it
# says "CUSTOM_WELCOME". You must recompile in order for
# it to take effect. 1 = Enable, 0 = Disable; Default: 0
CUSTOM:0

# If you want to keep the generic welcome notice each
# unregistered nick receives on connection, enable this.
# 1 = Enable, 0 = Disable; Default: 1
GENERIC:1

# When enabled, users will be /kill'ed off the network with
# the specified AKILL reason the operator gave. When disabled,
# the generic AKILL message will be given. (Found in messages.h)
# 1 = Enable, 0 = Disable. Default: 1
AKILL_REASON:1

# This option is not limited entirely to snoop, but also log files.
# When enabled, extra information will be logged, and if snoop
# is enabled, sent to the snoop channel. On larger networks,
# it may be wise to disable this to save on disk space for logs
# and avoid being flooded in the snoop channel. Only non-essential
# information will be stripped, ie: valid identifies, etc.
# 1 = Enable, 0 = Disable. Default: 1
EXTRA_SNOOP:0


# Number of registrations until services will
# automatically update the databases, regardless
# of next scheduled event. Valid for nicks & channels.
# 0 = Disables, 1 = Enables; Default: 0
REG_SAVES:0

# Enable displaying routine database expire & save
# global notices.
# Default: 1, Disable = 0
DISPLAY_UPDATES:0

# This allows services to display the uptime in the MOTD.
# Enable: 1, Disable: 0; Default: 1
UPTIME:1

# This allows services to display the time time until the next
# database update in the MOTD.
# Enable: 1, Disable: 0; Default: 1
MOTD_UPDATE:1


# Allow flood levels. These are used to warn the network
# of abusive users that are flooding. Services will first
# warn via globops, and notice the user, then warn if
# the user is severely flooding services. Further abuse
# results in the user being killed. Default = 1; 0 Disables
SET_FLOOD:1

# Allow ignore code to be used. When enabled, services
# admins will be able to make use of the OS IGNORE
# command to have services ignore all commands from
# a nick!user@host.
# Default = 1; 0 Disables
SET_IGNORE:1

# Have services set Read Only mode. Any commands
# that may effect databases will not be permitted.
# Default: 0; 1 Enables; 0 Disables;
SET_RO:0

# This setting enables "Real Name Catching". Services
# will match /whois realnames against an internal list
# provided. Whois' which contain words such as "*admin*"
# or "irc*op*" will be triggered and globoped with a
# warning.
# Default: 1; 0 Disables
SET_RN:0

# This feature will allow services to create a duplicate
# back-up database after database updates.
# The backup database will be stored in data/backup.
# Default: 10, 0 Disables
BACKUP:10

# 0 Defualt, 1 Make services do Private message instead of Notice
# It's good for WebTV user
SPRIV:0

# Enable Auto Join Channel
# 1 Enable, 0 Disable
AUTOJOIN:0
AUTOJOINCHANNEL:#3angels

# Enable Auto Join on Oper
# 1 Enable, 0 Disable
OPERJOIN:0

# Show user on register nick/chan, RootServ auto join that channel
# Mark as Official Help Channel
OPERCHAN:#staff

# Enable or Disable Flag JOIN for channel
# Make ChanServ join non 0 user channel when JOIN FLAG set by founder
# 1 Enable, 0 Disable
CJOIN:0

# There address of where your e-mail would go
SENDMAIL_PATH:/usr/sbin/sendmail

# Hide the next database update info
# 0 = Show the info, 1 = Hide it
HIDEUME:1

# Notice IRCop when any nick/chan registered
# 1 = Enable, 0 = Disable
REGNOTICE:1

# Prevent Akill being added if percentage is greater than this setting
PERCENT:50

# Sending E-mail to nearly expire nick.
# 0 = disable, 1 = enable
ALLOWMAIL:0

# Spam Detector
# Spam Nick
SPAMNICK:vitanizer
SPAMUSER:ninche
SPAMHOST:Services.angels3.com

# URL Note all URL must not include http://
# NickServ URL
NSURL:easynets.org/html/ns.htm
# ChanServ URL
CSURL:easynets.org/html/cs.htm
# Being Guest
GUESTURL:easynets.org/html/guest.htm


wimhost

; myndzi / v1.0
;
; whatismyip.com automatic local info configuration
; this my another script by Dj-RuFfy
; Last Edited by Dj-RuFfy
; Thanks To All Friends

on *:start:.disable #wimhost

alias wimip sockclose wimip | sockopen wimip www.whatismyip.com 80

on *:sockopen:wimip:{
if ($sockerr) return
sockwrite -n $sockname GET / HTTP/1.1
sockwrite -n $sockname Host: www.whatismyip.com
sockwrite -n $sockname
}
on *:sockread:wimip:{
if ($sockerr) return
var %t | sockread %t
while ($sockbr) {
if (*** iswm %t) {
var %ip = $gettok(%t,4,32)
localinfo $iif($host == $null,%ip,$host) %ip
sockclose $sockname
.enable #wimhost
.timer 1 0 .dns $ip
return
}
sockread %t
}
}
on *:sockwrite:wimip:if ($sockerr) return
on *:sockclose:wimip:if ($sockerr) return

#wimhost off
on *:dns:{
if ($dns(1).ip == $ip) .disable #wimhost
if ($dns(1).addr != $null) localinfo $dns(%i).addr $ip
echo -st Local host: $host ( $+ $ip $+ )
}
#wimhost end

Anope ns_ajoin

/**
* -----------------------------------------------------------------------------
* Name : ns_ajoin
* Author : Dj-RuFfy ( Founder & CEO EasyNets Corp )
* Date : 23/10/2006
* Version : 4.2.1
* -----------------------------------------------------------------------------
* Limitations: Any IRCd which supports SVSJOIN
* Tested : Anope-1.7.21 + UnrealIRCd 3.2.6
* Requires : Anope-1.7.20
* -----------------------------------------------------------------------------
* This module adds the AJOIN command to nickserv allowing users to maintain
* a server side auto-join list.
* The ajoin settings can be configured for each nick group through SET AJOIN.
*
* This module has been designed and tested for Anope-1.7.21 and will not
* properly work on any versions prior to 1.7.20! Changes have been made to
* SVSJOIN support for both inspircd and UnrealIRCd. Without these users
* may be able to pass through channels bans (insp) or not get into +k chans.
*
* This module requires the IRCd to support SVSJOIN.
* At the time of writing this module will only properly work with following IRCDs:
* - InspIRCd
* - Plexus 3.0 [or later]
* - PTLink
* - UltimateIRCd 2.8.2 [or later] [Excluding 3.x]
* - Unreal 3.1.1 [or later]
* - Unreal 3.2 [or later]
* - ViagraIRCd 1.3.x [or later]
*
* I wrote this module because the other 2 alternatives (addon module by
* DukePyrolator and ns_ajoin by Scott) are outdated and require MySQL, which
* i - like many other people probably - do not use / want to use.
*
* The database subroutines have been ported from swhois by Trystan,
* I wouldn't have been able to pull this off without those...
*
* Note that this module should be placed in ModuleDelayedAutoload.
* -----------------------------------------------------------------------------
* Translations:
*
* - English and Dutch Languages provided and maintained by myself.
* - German translation : SNU.
* - Turkish translation : ice
* - Russian translation : Kein
* -----------------------------------------------------------------------------
*
* Changelog:
*
* 4.2.1 Fixed AJOIN not requiring password identify (Reported by ysfm).
* Fixed ajoining suspended channels on identify.
* Fixed adding forbidden/suspended channels to the ajoin list.
* Fixed ChanServ replying to AJOIN ADD if the channel is not registered.
*
* 4.2.0 Going to next minor version and considering stable.
* Added ability to delete and list entries by number/list.
* Added russian translation (Provided by Kein)
* Fixed a few typos.
* Fixed crashbug when autojoining to dropped/expired channels. (Thanks to "Aded")
* Increased default number of entries allowed in AutoJoin list to 12
*
* 4.1.15 Fixed module causing a crash when ajoin issued by an unregistered user. (Thanks to "aerolife")
*
* 4.1.14 Fixed ajoin failing under several conditions on a channel with +k..
* Added ban testing and unbanning if possible...
* Because UnrealIRCd is the only IRCd supporting SVSJOIN'ing to +k chans
* we now invite before joining on all IRCd's except unreal.
* We no longer unban the user if he is excepted...
* Added hooks for NS ID.
*
* 4.1.13 Limited channels on ajoin list to registered channels only.
* This should resolve issues with invalid channel names. (Reported by "Avenger")
* Added check before executing the SVSJOIN to make sure channel isn't forbidden.
* Fixed bug causing remaining ajoins to be aborted if user is already on a ajoin chan.
*
* 4.1.12 Removed remaining bit of debug code
* Fixed some minor language details (Complained about by "SNU" ;-) )
* Added german translation (Provided by SNU)
*
* 4.1.11 Fixed possible segfault when loading is aborted because of unsupported ircd
* Fixed missing help for SET AJOIN.
*
* 4.1.10 Fixed segfault when saving DB after nick was dropped/expired. (Reported by "hexa")
* (Rewrote part of DB saving routine and the way AjoinEntries are addressed.(ugly!))
* Added InspIRCd as supported IRCd. (Their DOCs say it implements SVSJOIN so..)
* Added turkish translation (Provided by ice)
*
* 4.1.9 Added win32 support
* Fixed segfault when AJOIN is used by an unregistered user
*
* 4.1.8 Fixed vhost being set after ajoining (Reported by "CuttingEdge")
* Now also performing ajoin on UPDATE
*
* 4.1.7 Fixed crashes in ajoin add/del
* Added Anope version check
* Default ajoin flags moved to a const
* No longer storing empty entries with default configuration to the DB
*
* 4.1.6 Added SET AJOIN option
* Changed database scheme to include version info.
* Fixed a memleak in the AjoinEntry handlers.
*
* 4.1.5 Fixed segfaults on load & unload
* AnopeFini now goes over the ajoinTable.. should speed unloading up.
* Anope now also backs the ajoin database up.
*
* 4.1.4 Finished runtime storing and database writing and reading.
* Implemented ajoining on identify.
*
* 4.1.3 Replaced hardcoded replies with langtables.
*
* 4.1.2 Replaced database system
*
* 4.1.1 First 'working' Alpha Version
*
* 4.1 Module Development taken over by me (Dj-RuFfy)
* Beginning with clean development version.
*
* -----------------------------------------------------------------------------
**/

/**
* TODO:
*
* - default entries in ajoin: a /msg nickserv ajoin default (add,del,list,clear)
* which is only available to opers
*
**/


/**
* Configuration directives that should be copy-pasted to services.conf

# AJoinDB [OPTIONAL]
# Module: ns_ajoin
#
# Use the given filename as database to store the AJOINs.
# If not given, the default of "ns_ajoin.db" will be used.
#
#AJoinDB "ns_ajoin.db"

*
**/

/*------------------------------Configuration Block----------------------------*/

/**
* Determines the maximum entries in an ajoin list.
*
* If this value is changed, it will not affect AjoinEntries allready in the
* database, however now ones can't be added if the limit is exceeded.
**/

int NSAjoinMax = 12;


/*-------------------------End of Configuration Block--------------------------*/


#include "module.h"

#define AUTHOR "Dj-RuFfy"
#define VERSION "4.2.1"
#define AJOINDBVERSION 1


/* Language defines */
#define LANG_NUM_STRINGS 29

#define LANG_AJOIN_DESC 0
#define LANG_AJOIN_SYNTAX 1
#define LANG_AJOIN_SYNTAX_EXT 2
#define LANG_AJOIN_DISABLED 3
#define LANG_NO_LOCAL_CHAN 4
#define LANG_CHAN_SYMB_REQUIRED 5
#define LANG_CHAN_UPDATED 6
#define LANG_AJOIN_LIST_FULL 7
#define LANG_CHAN_ADDED 8
#define LANG_NO_AJOINS 9
#define LANG_AJOIN_LIST_EMPTY 10
#define LANG_NO_ENTRY 11
#define LANG_CHAN_DELETED 12
#define LANG_AJOIN_ENTRY 13
#define LANG_AJOIN_ENTRIES 14
#define LANG_AJOIN_LIST_CLEARED 15
#define LANG_UNKWN_AJOIN_OPTION 16
#define LANG_AJOINING 17
#define LANG_AJOINING_FAILED 18
#define LANG_SET_AJOIN_DESC 19
#define LANG_SET_AJOIN_SYNTAX 20
#define LANG_SET_AJOIN_SYNTAX_EXT 21
#define LANG_SET_AJOIN_ON 22
#define LANG_SET_AJOIN_SILENT 23
#define LANG_SET_AJOIN_OFF 24
#define LANG_AJOINING_SUM_SUCCESS 25
#define LANG_AJOINING_SUM_FAILED 26
#define LANG_AJOIN_DELETED_NR_1 27
#define LANG_AJOIN_DELETED_NR 28



/* Flags to set in database */
#define AJOIN_ON (1 << 0)
#define AJOIN_SILENT (1 << 1)

/* Database seperators */
#define SEPARATOR ':' /* End of a key, seperates keys from values */
#define BLOCKEND '\n' /* End of a block, e.g. a whole nick/channel or a subblock */
#define VALUEEND '\000' /* End of a value */
#define SUBSTART '\010' /* Beginning of a new subblock, closed by a BLOCKEND */

/* Database reading return values */
#define DB_READ_SUCCESS 0
#define DB_READ_ERROR 1
#define DB_EOF_ERROR 2
#define DB_VERSION_ERROR 3
#define DB_READ_BLOCKEND 4
#define DB_READ_SUBSTART 5

#define DB_WRITE_SUCCESS 0
#define DB_WRITE_ERROR 1
#define DB_WRITE_NOVAL 2

/* Database Key, Value max length */
#define MAXKEYLEN 128
#define MAXVALLEN 1024


/* Structs */
typedef struct db_file_ DBFile;
typedef struct ajoinchan_ AjoinChan;
typedef struct ajoinentry_ AjoinEntry;

struct db_file_ {
FILE *fptr; /* Pointer to the opened file */
int db_version; /* The db version of the datafiles (only needed for reading) */
int core_db_version; /* The current db version of this anope source */
char service[256]; /* StatServ/etc. */
char filename[256]; /* Filename of the database */
char temp_name[262]; /* Temp filename of the database */
};

struct ajoinchan_ {
AjoinChan *prev, *next;
char *channel;
char *key;
int nr;
};

struct ajoinentry_ {
/* Specifies storage location in ajoinTable */
int row, col;
AjoinEntry *prev, *next;
int ajchannels;
AjoinChan *channels;
/* Flags store AJOIN settings.
* Bits are used as followed:
* User wants to be autojoined {bit 0}
* User wants autojoin to be silent {bit 1}
*/
uint16 flags;
/* Used to check during the cleanup whether the entry is still being used.
* This is always 0 except when the DB saving function has completed going
* over all NickCore's. The ajoin entries with in_use set to 0 at that time
* are no longer used and cleared. In the other entries in_use is reset to 0. */
int in_use;
};


/* Constants */
char *DefAJoinDB = "ns_ajoin.db";
char *ModDataKey = "ajoin";
uint16 DefAjoinFlags = 1;


/* Variables */
char *AJoinDB;

/* This stores the last used row in teh ajoinTable so the module can attempt to
* spread the entries out as evenly as possible... */
int counter;

/* We still need a table cause we won't be able to reach the AjoinEntry if
* the nick is dropped... this sucks i know, but it s just a list of references */
/* Table will be cleaned of invalid entries every time the database is saved */
AjoinEntry *ajoinTable[1024];


/* Functions */
void do_help_list(User *u);
int do_help(User *u);
int add_ajoin_option(User *u);
int do_set_ajoin_help(User *u);

int do_ajoin(User *u);
int do_identify(User *u);
int ns_set(User *u);
int null_func(User *u);
int is_banned(ChannelInfo *ci, User *u);

int new_open_db_read(DBFile *dbptr, char **key, char **value);
int new_open_db_write(DBFile *dbptr);
void new_close_db(FILE *fptr, char **key, char **value);
int new_read_db_entry(char **key, char **value, FILE * fptr);
int new_write_db_entry(const char *key, DBFile *dbptr, const char *fmt, ...);
int new_write_db_endofblock(DBFile *dbptr);
void fill_db_ptr(DBFile *dbptr, int version, int core_version, char service[256], char filename[256]);

static int ajoin_del_callback(User * u, int num, va_list args);
static int ajoin_list_callback(User * u, int num, va_list args);

static AjoinChan *addAjoinChan(AjoinEntry *ae, char *chan, char *key);
AjoinChan *findAjoinChan(AjoinEntry *ae, char *chan);
AjoinChan *findAjoinChanNr(AjoinEntry *ae, int nr);
static int deleteAjoinChan(AjoinEntry *ae, AjoinChan *ac);
static int clearAjoinChans(AjoinEntry *ae);
static int numberAjoinChans(AjoinEntry *ae);

static AjoinEntry *createAjoinEntry(NickCore *nc);
AjoinEntry *getAjoinEntry(NickCore *nc);
static int deleteAjoinEntry(AjoinEntry *ae);
void freeUnusedEntries();

int do_save(int argc, char **argv);
int db_backup(int argc, char **argv);
void load_ajoin_db(void);
void save_ajoin_db(void);
AjoinEntry *go_to_next_entry(uint16 skipped, AjoinEntry *next, AjoinEntry *ae);

int valid_ircd(void);

void load_config(void);
int reload_config(int argc, char **argv);
void add_languages(void);


/* ------------------------------------------------------------------------------- */

/**
* Create the command, and tell anope about it.
* @param argc Argument count
* @param argv Argument list
* @return MOD_CONT to allow the module, MOD_STOP to stop it
**/
int AnopeInit(int argc, char **argv) {
Command *c;
EvtHook *hook;

alog("[\002ns_ajoin\002] Loading module...");

counter = 0;

if (!valid_ircd()) {
alog("[\002ns_ajoin\002] ERROR: IRCd not supported by this module");
alog("[\002ns_ajoin\002] Unloading module...");
return MOD_STOP;
}

if (!moduleMinVersion(1,7,21,1341)) {
alog("[\002ns_ajoin\002] Your version of Anope isn't supported. Please update to a newer release.");
return MOD_STOP;
}


/* Create AJOIN command.. */
c = createCommand("AJOIN", do_ajoin, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV,c,MOD_HEAD) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot create AJOIN command...");
return MOD_STOP;
}
moduleAddHelp(c,do_help);
moduleSetNickHelp(do_help_list);


/* Hook to the IDENTIFY and UPDATE command */
c = createCommand("IDENTIFY", do_identify, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV,c,MOD_TAIL) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot hook to IDENTIFY command...");
return MOD_STOP;
}

c = createCommand("ID", do_identify, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV,c,MOD_TAIL) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot hook to ID command...");
return MOD_STOP;
}

c = createCommand("UPDATE", do_identify, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV,c,MOD_TAIL) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot hook to UPDATE command...");
return MOD_STOP;
}


/* Create the SET AJOIN command, its help and add it to cmd listing.. */
c = createCommand("SET", ns_set, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV, c, MOD_HEAD) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot create SET AJOIN command...");
return MOD_STOP;
}

c = createCommand("SET AJOIN", NULL, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV, c, MOD_TAIL) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot create help for the SET AJOIN command...");
return MOD_STOP;
}
moduleAddHelp(c, do_set_ajoin_help);

c = createCommand("SET", null_func, NULL, -1, -1, -1, -1, -1);
if (moduleAddCommand(NICKSERV, c, MOD_TAIL) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Cannot add AJOIN to SET options...");
return MOD_STOP;
}
moduleAddHelp(c, add_ajoin_option);


/* Hook to some events.. */
hook = createEventHook(EVENT_RELOAD, reload_config);
if (moduleAddEventHook(hook) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Can't hook to EVENT_RELOAD event");
return MOD_STOP;
}

hook = createEventHook(EVENT_DB_SAVING, do_save);
if (moduleAddEventHook(hook) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Can't hook to EVENT_DB_SAVING event");
return MOD_STOP;
}

hook = createEventHook(EVENT_DB_BACKUP, db_backup);
if (moduleAddEventHook(hook) != MOD_ERR_OK) {
alog("[\002ns_ajoin\002] Can't hook to EVENT_DB_BACKUP event");
return MOD_STOP;
}

load_config();
add_languages();
load_ajoin_db();

moduleAddAuthor(AUTHOR);
moduleAddVersion(VERSION);

alog("[\002ns_ajoin\002] Module loaded successfully...");

return MOD_CONT;
}


/**
* Unload the module
**/
void AnopeFini(void) {
AjoinEntry *ae = NULL, *next = NULL;
int i;

if (AJoinDB)
save_ajoin_db();

/* clear the memory.... */
for (i = 0; i < 1024; i++) {
for (ae = ajoinTable[i]; ae; ae = next) {
next = ae->next;
deleteAjoinEntry(ae);
}
}

if (AJoinDB)
free(AJoinDB);

alog("[\002ns_ajoin\002] Unloading module...");
}


/* ------------------------------------------------------------------------------- */


/**
* Add the AJOIN command to the NickServ HELP listing.
**/
void do_help_list(User *u) {
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_DESC);
}


/**
* Show the extended help on the AJOIN command.
**/
int do_help(User *u) {
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_SYNTAX_EXT);
return MOD_CONT;
}


/**
* Add the AJOIN option to the end of the SET options listing.
**/
int add_ajoin_option(User *u) {
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_DESC);
return MOD_CONT;
}


/**
* Show the extended help on the SET AJOIN command.
**/
int do_set_ajoin_help(User *u) {
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_SYNTAX_EXT);
return MOD_CONT;
}


/* ------------------------------------------------------------------------------- */

int do_ajoin(User *u) {
ChannelInfo *ci;
char *buffer, *cmd, *chan, *key;

buffer = moduleGetLastBuffer();
cmd = myStrGetToken(buffer, ' ', 0);
chan = myStrGetToken(buffer, ' ', 1);
key = myStrGetToken(buffer, ' ', 2);

if (!cmd)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_SYNTAX);

else if (stricmp(cmd, "ADD") == 0) {
if (readonly)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_DISABLED);
else if (!u->na)
notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
else if (!nick_identified(u))
notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
else if (!chan)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_SYNTAX);
else if (*chan == '&')
moduleNoticeLang(s_NickServ, u, LANG_NO_LOCAL_CHAN);
else if (*chan != '#')
moduleNoticeLang(s_NickServ, u, LANG_CHAN_SYMB_REQUIRED);
else if (!anope_valid_chan(chan))
notice_lang(s_NickServ, u, CHAN_X_INVALID, chan);
else if (!(ci = cs_findchan(chan)))
notice_lang(s_NickServ, u, CHAN_X_NOT_REGISTERED, chan);
else if (ci->flags & CI_VERBOTEN)
notice_lang(s_NickServ, u, CHAN_X_FORBIDDEN, chan);
else if (ci->flags & CI_SUSPENDED)
notice_lang(s_NickServ, u, CHAN_X_FORBIDDEN, chan);
else {
AjoinEntry *ae = NULL;
AjoinChan *ac = NULL;

ae = getAjoinEntry(u->na->nc);
ac = findAjoinChan(ae, chan);

if (!ae)
ae = createAjoinEntry(u->na->nc);

if (ac) {
/* update existing entry */
if (!key && ac->key) {
free(ac->key);
ac->key = NULL;
} else if (key) {
free(ac->key);
ac->key = sstrdup(key);
}
moduleNoticeLang(s_NickServ, u, LANG_CHAN_UPDATED);
} else {
if (ae->ajchannels == NSAjoinMax)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_LIST_FULL);
else {
addAjoinChan(ae, chan, key);
moduleNoticeLang(s_NickServ, u, LANG_CHAN_ADDED, chan);
}
}
}

} else if (stricmp(cmd, "DEL") == 0) {
AjoinEntry *entry;

if (readonly)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_DISABLED);
else if (!u->na)
notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
else if (!chan)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_SYNTAX);
else if (!(entry = getAjoinEntry(u->na->nc)))
moduleNoticeLang(s_NickServ, u, LANG_NO_AJOINS);
else {
/* we r a valid chan, delete us if we r present... */
if (entry->ajchannels == 0)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_LIST_EMPTY);

else {
/* Check if the given target is a number/list.
* Only search if it isn't. */
if (isdigit(*chan) && strspn(chan, "1234567890,-") == strlen(chan)) {
int deleted, count;
deleted = process_numlist(chan, &count, ajoin_del_callback, u, entry);
numberAjoinChans(entry);

if (deleted == 1)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_DELETED_NR_1, deleted);
else
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_DELETED_NR, deleted);
} else {
if (*chan != '#')
moduleNoticeLang(s_NickServ, u, LANG_CHAN_SYMB_REQUIRED);
else {
AjoinChan *ac = findAjoinChan(entry, chan);

if (!ac)
moduleNoticeLang(s_NickServ, u, LANG_NO_ENTRY, chan);

else {
deleteAjoinChan(entry, ac);
numberAjoinChans(entry);
moduleNoticeLang(s_NickServ, u, LANG_CHAN_DELETED, chan);
}
}
}
}
}

} else if (stricmp(cmd, "LIST") == 0) {
int i = 0;
AjoinEntry *ae = NULL;
AjoinChan *ac = NULL;

if (!u->na) {
notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
} else {
ae = getAjoinEntry(u->na->nc);

if (!ae)
moduleNoticeLang(s_NickServ, u, LANG_NO_AJOINS);

else {
if (ae->ajchannels == 0)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_LIST_EMPTY);

else {
/* Check if the given target is a number/list. */
if (chan && isdigit(*chan) && strspn(chan, "1234567890,-") == strlen(chan)) {
int count, found;
found = process_numlist(chan, &count, ajoin_list_callback, u, ae);
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_ENTRIES, found);
} else {
for (ac = ae->channels; ac; ac = ac->next) {
if (chan && !match_wild_nocase(chan, ac->channel))
continue;
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_ENTRY, ac->nr, ac->channel,
((ac->key) ? ac->key:""));
i++;
}

moduleNoticeLang(s_NickServ, u, LANG_AJOIN_ENTRIES, i);
}
}
}
}

} else if (stricmp(cmd, "CLEAR") == 0) {
AjoinEntry *ae;

if (readonly)
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_DISABLED);
else if (!u->na)
notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
else if (!(ae = getAjoinEntry(u->na->nc)))
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_LIST_EMPTY);
else {
clearAjoinChans(ae);
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_LIST_CLEARED);
}

} else {
moduleNoticeLang(s_NickServ, u, LANG_UNKWN_AJOIN_OPTION);
moduleNoticeLang(s_NickServ, u, LANG_AJOIN_SYNTAX);
}

if (cmd)
free(cmd);
if (chan)
free(chan);
if (key)
free(key);

return MOD_CONT;
}


int do_identify(User *u) {
int i = 0, ok, needinvite, counter_succ = 0, counter_f = 0;

if (nick_identified(u) && u->na->nc) {
AjoinEntry *ae = NULL;

ae = getAjoinEntry(u->na->nc);

if (ae && (ae->flags & AJOIN_ON) && (ae->ajchannels > 0)) {
AjoinChan *ac = NULL;

ac = ae->channels;
for (i = 0; i < ae->ajchannels; i++) {
Channel *c = NULL;
ChannelInfo *ci;
ok = 1, needinvite = 0;

if (!ac)
break;

/* If the channel is no longer registered we won't complain..
* We are sure the name is valid because it was registered once.
* We do complain when the channel is forbidden.. no point in joining. */
/* We do the same when it s suspended. We do NOT automatically remove channels though. */
ci = cs_findchan(ac->channel);
if (ci && (ci->flags & CI_VERBOTEN)) {
notice_lang(s_NickServ, u, CHAN_X_FORBIDDEN, ac->channel);
ok = 0;
}
if (ci && (ci->flags & CI_SUSPENDED)) {
notice_lang(s_NickServ, u, CHAN_X_FORBIDDEN, ac->channel);
ok = 0;
}

/* Check if channel already exists...
* We can't use c->ci here because we don't require the chan to still be registered */
if (ok && ((c = findchan(ac->channel)))) {
if (is_on_chan(c, u)) {
ac = ac->next;
continue;
}

else {
if (c->key) {
if (!ac->key || (stricmp(ac->key, c->key) != 0)) {
if (ci && check_access(u, ci, CA_GETKEY)) {
if (ac->key)
free(ac->key);
ac->key = sstrdup(c->key);

} else
needinvite = 1;
}

/* Any IRCd other then unreal needs invite cause they don't support
* SVSJOIN with a key.. */
if (stricmp(IRCDModule,"unreal32"))
needinvite = 1;
}

/* Check if user is banned and if so, remove is possible.
* If we cannot remove it, try to invite */
if (ci && is_banned(ci, u)) {
if (check_access(u, ci, CA_UNBAN))
common_unban(ci, u->nick);
else
needinvite = 1;
}

if ((c->mode & anope_get_invite_mode()) || needinvite) {
if (ci && check_access(u, ci, CA_INVITE))
anope_cmd_invite(s_NickServ, ac->channel, u->nick);
else
ok = 0;
}
}
}

if (ok) {
if (ae->flags & AJOIN_SILENT)
counter_succ++;
else
moduleNoticeLang(s_NickServ, u, LANG_AJOINING, ac->channel);

anope_cmd_svsjoin(s_NickServ, u->nick, ac->channel, ac->key);
} else {
if (ae->flags & AJOIN_SILENT)
counter_f++;
else
moduleNoticeLang(s_NickServ, u, LANG_AJOINING_FAILED, ac->channel);
}

ac = ac->next;
}

if (ae->flags & AJOIN_SILENT) {
if (counter_succ > 0)
moduleNoticeLang(s_NickServ, u, LANG_AJOINING_SUM_SUCCESS, counter_succ);
if (counter_f > 0)
moduleNoticeLang(s_NickServ, u, LANG_AJOINING_SUM_FAILED, counter_f);
}
}
}


return MOD_CONT;
}


int ns_set(User *u) {
char *args, *cmd, *option;

/* If readonly, let the core ns_set handle it.. */
if (readonly)
return MOD_CONT;

args = moduleGetLastBuffer();
if (!args)
return MOD_CONT;

cmd = myStrGetToken(args, ' ', 0);
option = myStrGetToken(args, ' ', 1);

if (cmd && !stricmp(cmd, "AJOIN")) {
if (!option)
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_SYNTAX);
else if (!u->na)
notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
else if (!nick_identified(u))
notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
else {
AjoinEntry *ae = NULL;
ae = getAjoinEntry(u->na->nc);

if (!ae)
ae = createAjoinEntry(u->na->nc);

if (!stricmp(option, "ON")) {
/* Turn off silent bit */
ae->flags &= ~AJOIN_SILENT;
/* Turn on use autojoin bit */
ae->flags |= AJOIN_ON;
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_ON);

} else if (!stricmp(option, "SILENT")) {
/* Turn on silent bit */
ae->flags |= AJOIN_SILENT;
/* Turn on use autojoin bit */
ae->flags |= AJOIN_ON;
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_SILENT);

} else if (!stricmp(option, "OFF")) {
/* Turn off silent bit */
ae->flags &= ~AJOIN_SILENT;
/* Turn off use autojoin bit */
ae->flags &= ~AJOIN_ON;
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_OFF);

} else
moduleNoticeLang(s_NickServ, u, LANG_SET_AJOIN_SYNTAX);
}

free(cmd);
if (option) free (option);
return MOD_STOP;
}

if (cmd) free(cmd);
if (option) free (option);

return MOD_CONT;
}


int null_func(User *u) {
return MOD_CONT;
}


int is_banned(ChannelInfo *ci, User *u) {
int i, isbanned = 0;
char *host = NULL;

if (!ci->c)
return 0;

host = host_resolve(u->host);

for (i = 0; i < ci->c->bancount; i++) {
if (match_usermask(ci->c->bans[i], u) ||
(host && match_userip(ci->c->bans[i], u, host))) {
isbanned = 1;
break;
}
}

if (host)
free(host);

return isbanned;
}


/* ------------------------------------------------------------------------------- */

/**************************************************************************
* Generic DataBase Functions (Taken from swhois by Trystan)
**************************************************************************/


int new_open_db_read(DBFile *dbptr, char **key, char **value) {
*key = malloc(MAXKEYLEN);
*value = malloc(MAXVALLEN);

if (!(dbptr->fptr = fopen(dbptr->filename, "rb"))) {
if (debug) {
alog("debug: Can't read %s database %s : errno(%d)", dbptr->service,
dbptr->filename, errno);
}
free(*key);
*key = NULL;
free(*value);
*value = NULL;
return DB_READ_ERROR;
}
dbptr->db_version = fgetc(dbptr->fptr) << 24 | fgetc(dbptr->fptr) << 16
| fgetc(dbptr->fptr) << 8 | fgetc(dbptr->fptr);

if (ferror(dbptr->fptr)) {
if (debug) {
alog("debug: Error reading version number on %s", dbptr->filename);
}
free(*key);
*key = NULL;
free(*value);
*value = NULL;
return DB_READ_ERROR;
} else if (feof(dbptr->fptr)) {
if (debug) {
alog("debug: Error reading version number on %s: End of file detected",
dbptr->filename);
}
free(*key);
*key = NULL;
free(*value);
*value = NULL;
return DB_EOF_ERROR;
} else if (dbptr->db_version < 1) {
if (debug) {
alog("debug: Invalid version number (%d) on %s", dbptr->db_version, dbptr->filename);
}
free(*key);
*key = NULL;
free(*value);
*value = NULL;
return DB_VERSION_ERROR;
}
return DB_READ_SUCCESS;
}


int new_open_db_write(DBFile *dbptr) {
if (!(dbptr->fptr = fopen(dbptr->filename, "wb"))) {
if (debug) {
alog("debug: %s Can't open %s database for writing", dbptr->service, dbptr->filename);
}
return DB_WRITE_ERROR;
}

if (fputc(dbptr->core_db_version >> 24 & 0xFF, dbptr->fptr) < 0 ||
fputc(dbptr->core_db_version >> 16 & 0xFF, dbptr->fptr) < 0 ||
fputc(dbptr->core_db_version >> 8 & 0xFF, dbptr->fptr) < 0 ||
fputc(dbptr->core_db_version & 0xFF, dbptr->fptr) < 0) {
if (debug) {
alog("debug: Error writing version number on %s", dbptr->filename);
}
return DB_WRITE_ERROR;
}
return DB_WRITE_SUCCESS;
}


void new_close_db(FILE *fptr, char **key, char **value) {
if (key && *key) {
free(*key);
*key = NULL;
}
if (value && *value) {
free(*value);
*value = NULL;
}

if (fptr) {
fclose(fptr);
}
}


int new_read_db_entry(char **key, char **value, FILE *fptr) {
char *string = *key;
int character;
int i = 0;

**key = '\0';
**value = '\0';

while (1) {
if ((character = fgetc(fptr)) == EOF) { /* a problem occurred reading the file */
if (ferror(fptr)) {
return DB_READ_ERROR; /* error! */
}
return DB_EOF_ERROR; /* end of file */
} else if (character == BLOCKEND) { /* END OF BLOCK */
return DB_READ_BLOCKEND;
} else if (character == VALUEEND) { /* END OF VALUE */
string[i] = '\0'; /* end of value */
return DB_READ_SUCCESS;
} else if (character == SEPARATOR) { /* END OF KEY */
string[i] = '\0'; /* end of key */
string = *value; /* beginning of value */
i = 0; /* start with the first character of our value */
} else {
if ((i == (MAXKEYLEN - 1)) && (string == *key)) { /* max key length reached, continuing with value */
string[i] = '\0'; /* end of key */
string = *value; /* beginning of value */
i = 0; /* start with the first character of our value */
} else if ((i == (MAXVALLEN - 1)) && (string == *value)) { /* max value length reached, returning */
string[i] = '\0';
return DB_READ_SUCCESS;
} else {
string[i] = character; /* read string (key or value) */
i++;
}
}
}
}


int new_write_db_entry(const char *key, DBFile *dbptr, const char *fmt, ...) {
char string[MAXKEYLEN + MAXVALLEN + 2], value[MAXVALLEN]; /* safety byte :P */
va_list ap;
unsigned int length;

if (!dbptr) {
return DB_WRITE_ERROR;
}

va_start(ap, fmt);
vsnprintf(value, MAXVALLEN, fmt, ap);
va_end(ap);

if (!stricmp(value, "(null)")) {
return DB_WRITE_NOVAL;
}
snprintf(string, MAXKEYLEN + MAXVALLEN + 1, "%s%c%s", key, SEPARATOR, value);
length = strlen(string);
string[length] = VALUEEND;
length++;

if (fwrite(string, 1, length, dbptr->fptr) < length) {
if (debug) {
alog("debug: Error writing to %s", dbptr->filename);
}
new_close_db(dbptr->fptr, NULL, NULL);
if (debug) {
alog("debug: Restoring backup.");
}
remove(dbptr->filename);
rename(dbptr->temp_name, dbptr->filename);
free(dbptr);
dbptr = NULL;
return DB_WRITE_ERROR;
}
return DB_WRITE_SUCCESS;
}


int new_write_db_endofblock(DBFile *dbptr) {
if (!dbptr) {
return DB_WRITE_ERROR;
}
if (fputc(BLOCKEND, dbptr->fptr) == EOF) {
if (debug) {
alog("debug: Error writing to %s", dbptr->filename);
}
new_close_db(dbptr->fptr, NULL, NULL);
return DB_WRITE_ERROR;
}
return DB_WRITE_SUCCESS;
}



void fill_db_ptr(DBFile *dbptr, int version, int core_version,
char service[256], char filename[256]) {
dbptr->db_version = version;
dbptr->core_db_version = core_version;
if (!service)
strcpy(dbptr->service, service);
else
strcpy(dbptr->service, "");

strcpy(dbptr->filename, filename);
snprintf(dbptr->temp_name, 261, "%s.temp", filename);
return;
}


/* ------------------------------------------------------------------------------- */

static int ajoin_del_callback(User * u, int num, va_list args) {
AjoinEntry *ae = va_arg(args, AjoinEntry *);
AjoinChan *ac = findAjoinChanNr(ae, num);

if (!ac)
return 0;

moduleNoticeLang(s_NickServ, u, LANG_CHAN_DELETED, ac->channel);
deleteAjoinChan(ae, ac);

return 1;
}

static int ajoin_list_callback(User * u, int num, va_list args) {
AjoinEntry *ae = va_arg(args, AjoinEntry *);
AjoinChan *ac = findAjoinChanNr(ae, num);

if (!ac)
return 0;

moduleNoticeLang(s_NickServ, u, LANG_AJOIN_ENTRY, ac->nr, ac->channel,
((ac->key) ? ac->key:""));

return 1;
}



/* ------------------------------------------------------------------------------- */

/**
* We add an AjoinChan to the list and update the nr of the channels.
**/
static AjoinChan *addAjoinChan(AjoinEntry *ae, char *chan, char *key) {
AjoinChan *ac = NULL, *current = NULL, *previous = NULL;

if (!ae || !chan)
return NULL;

if ((ac = malloc(sizeof(AjoinChan))) == NULL) {
fatal("Out Of Memory!");
}

for (current = ae->channels; current; current = current->next) {
/* search for the position to insert the new channel */
if (stricmp(chan, current->channel) > 0)
previous = current;
else
break;
}

ac->next = current;
ac->prev = previous;

ac->channel = sstrdup(chan);
if (key)
ac->key = sstrdup(key);
else
ac->key = NULL;

if (previous == NULL) {
ae->channels = ac;
ac->nr = 1;
} else {
previous->next = ac;
ac->nr = previous->nr + 1;
}

if (current)
current->prev = ac;

while (current) {
current->nr++;
current = current->next;
}

ae->ajchannels++;

return ac;
}


AjoinChan *findAjoinChan(AjoinEntry *ae, char *chan) {
AjoinChan *current;

if (!ae)
return NULL;

for (current = ae->channels; current; current = current->next) {
if (!stricmp(chan, current->channel))
return current;
}

return NULL;
}


AjoinChan *findAjoinChanNr(AjoinEntry *ae, int nr) {
AjoinChan *current;

if (!nr)
return NULL;

for (current = ae->channels; current; current = current->next) {
if (current->nr == nr)
return current;
}

return NULL;
}

/**
* We delete an AjoinChan from the list, but we do not update the numbering.
* This needs to be done later by calling numberAjoinChans() because numbers shouldn't
* change while deleting ajoinchans by number.
**/
static int deleteAjoinChan(AjoinEntry *ae, AjoinChan *ac) {
if (!ae || !ac)
return 0;

if (ac->prev)
ac->prev->next = ac->next;
else
ae->channels = ac->next;

if (ac->next)
ac->next->prev = ac->prev;

if (ac->channel)
free(ac->channel);
if (ac->key)
free(ac->key);

free(ac);
ae->ajchannels--;

return 1;
}


static int clearAjoinChans(AjoinEntry *ae) {
AjoinChan *ac = NULL, *next = NULL;

if (!ae)
return 0;

for (ac = ae->channels; ac; ac = next) {
if (ac->next)
next = ac->next;
else
next = NULL;

if (ac->channel)
free(ac->channel);
if (ac->key)
free(ac->key);

free(ac);
}

ae->channels = NULL;
ae->ajchannels = 0;

return 1;
}

static int numberAjoinChans(AjoinEntry *ae) {
AjoinChan *current;
int nr = 1;

if (!ae)
return 0;

for (current = ae->channels; current; current = current->next) {
current->nr = nr++;
}

return 1;
}


/* ------------------------------------------------------------------------------- */

static AjoinEntry *createAjoinEntry(NickCore *nc) {
AjoinEntry *ae = NULL;
char buf[BUFSIZE];

if (!nc)
return NULL;

if ((ae = malloc(sizeof(AjoinEntry))) == NULL) {
fatal("Out Of Memory!");
}

ae->prev = NULL;
ae->next = NULL;
ae->row = counter;
ae->ajchannels = 0;
ae->in_use = 0;
ae->flags = DefAjoinFlags;
ae->channels = NULL;

/* add it to the ajoinTable */
if (ajoinTable[counter] == NULL) {
ajoinTable[counter] = ae;
ae->col = 0;
} else {
int i = 0, last = -1;
AjoinEntry *t, *prev = NULL;

for (t = ajoinTable[counter]; t; t = t->next) {
if (t->col != last + 1)
break;

last = t->col;
i++;
prev = t;
}
ae->col = i;

if (prev) {
if (prev->next) {
ae->next = prev->next;
prev->next->prev = ae;
}
prev->next = ae;
}
ae->prev = prev;
}

/* add to the nc, so it can be addressed relative quickly */
snprintf(buf, BUFSIZE, "%d;%d", ae->row, ae->col);
moduleAddData(&nc->moduleData, ModDataKey, buf);

if (counter < 1023)
counter++;
else
counter = 0;

return ae;
}

AjoinEntry *getAjoinEntry(NickCore *nc) {
char *t, *x, *y;
int row, col;
AjoinEntry *ae = NULL;
if (!nc)
return NULL;

t = moduleGetData(&nc->moduleData, ModDataKey);

if (t == NULL) {
return NULL;
}
x = myStrGetToken(t, ';', 0);
y = myStrGetToken(t, ';', 1);

row = atoi(x);
col = atoi(y);

for (ae = ajoinTable[row]; ae; ae = ae->next) {
if (ae->col == col)
break;
}

free(t);
free(x);
free(y);

return ae;
}

static int deleteAjoinEntry(AjoinEntry *ae) {
if (!ae)
return 0;

if (ajoinTable[ae->row] == ae)
ajoinTable[ae->row] = ae->next;

if (ae->prev)
ae->prev->next = ae->next;

if (ae->next)
ae->next->prev = ae->prev;

clearAjoinChans(ae);
ae->prev = NULL;
ae->next = NULL;

free(ae);

return 1;
}

/**
* When we are called, we assume used entries have in_use set to 1 (done while the
* DB is saved) and reset it to 0 for all other entries.
* Entries with in_use to 0 are free()'d and removed from the AjoinTable since we
* assume all other references to it have allready been removed.
**/
void freeUnusedEntries() {
AjoinEntry *next = NULL, *ae = NULL;
int i;

for (i = 0; i < 1024; i++) {
for (ae = ajoinTable[i]; ae; ae = next) {
if (ae->in_use == 1) {
/* Entry is still being used... resetting */
ae->in_use = 0;
next = ae->next;
continue;
}

/* Entry is no longer being used... free it */
next = ae->next;
deleteAjoinEntry(ae);
}
}
}


/* ------------------------------------------------------------------------------- */

/**
* When anope saves her databases, we do the same.
**/
int do_save(int argc, char **argv) {
if ((argc >= 1) && (!stricmp(argv[0], EVENT_STOP)))
save_ajoin_db();

return MOD_CONT;
}


/**
* When anope backs her databases up, we do the same.
**/
int db_backup(int argc, char **argv) {
if ((argc >= 1) && (!stricmp(argv[0], EVENT_STOP))) {
alog("[ns_ajoin] Backing up AJOIN database...");
ModuleDatabaseBackup(AJoinDB);

/* When anope backs her databases up, we also clear unused entries from the AjoinTable */
freeUnusedEntries();
}
return MOD_CONT;
}


/**************************************************************************
* DataBase Handling
**************************************************************************/

void load_ajoin_db(void) {
DBFile *dbptr = scalloc(1, sizeof(DBFile));
AjoinEntry *ae = NULL;
NickCore *nc = NULL;
char *key, *value;
int retval = 0;

fill_db_ptr(dbptr, 0, AJOINDBVERSION, s_NickServ, AJoinDB);

/* let's remove existing temp files here, because we only load dbs on startup */
remove(dbptr->temp_name);

/* Open the db, fill the rest of dbptr and allocate memory for key and value */
if (new_open_db_read(dbptr, &key, &value)) {
free(dbptr);
return; /* Bang, an error occurred */
}

while (1) {
/* read a new entry and fill key and value with it -Certus */
retval = new_read_db_entry(&key, &value, dbptr->fptr);

if (retval == DB_READ_ERROR) {
new_close_db(dbptr->fptr, &key, &value);
free(dbptr);
return;

} else if (retval == DB_EOF_ERROR) {
new_close_db(dbptr->fptr, &key, &value);
free(dbptr);
return;
} else if (retval == DB_READ_BLOCKEND) { /* DB_READ_BLOCKEND */
/* prevent chans from one block ending up in another... */
ae = NULL;
} else { /* DB_READ_SUCCESS */
if (!*key || !*value)
continue;

/* nick */
if (!stricmp(key, "ncd")) {
if ((nc = findcore(value))) {
ae = createAjoinEntry(nc);
} else
ae = NULL;

/* flags */
} else if (!stricmp(key, "flgs") && ae) {
ae->flags = (uint16) atoi(value);

/* channel entry */
} else if (!stricmp(key, "che") && ae) {
char *chan = myStrGetToken(value, ' ', 0);
char *chkey = myStrGetToken(value, ' ', 1);

addAjoinChan(ae, chan, chkey);

free(chan);
if (chkey)
free(chkey);
} else if (!stricmp(key, "AJOIN DB VERSION")) {
if ((int)atoi(value) != AJOINDBVERSION) {
alog("[\002ns_ajoin\002] Database version does not match any database versions supported by this module.");
alog("[\002ns_ajoin\002] Continuing with clean database...");
break;
}
}
} /* else */
} /* while */

free(dbptr);
}


void save_ajoin_db(void) {
DBFile *dbptr = scalloc(1, sizeof(DBFile));
NickCore *nc;
int i;

fill_db_ptr(dbptr, 0, AJOINDBVERSION, s_NickServ, AJoinDB);

/* time to backup the old db */
rename(AJoinDB, dbptr->temp_name);

if (new_open_db_write(dbptr)) {
rename(dbptr->temp_name, AJoinDB);
free(dbptr);
return; /* Bang, an error occurred */
}

/* Store the version of the DB in the DB as well...
* This will make stuff a lot easier if the database scheme needs to modified. */
new_write_db_entry("AJOIN DB VERSION", dbptr, "%d", AJOINDBVERSION);
new_write_db_endofblock(dbptr);

/* Go over the entire NickCore list and check whether each one has an ajoin entry */
for (i = 0; i < 1024; i++) {
for (nc = nclists[i]; nc; nc = nc->next) {
AjoinEntry *ae = NULL;
AjoinChan *ac = NULL;

ae = getAjoinEntry(nc);
if (!ae)
continue;

/* If there are no entries in the list and the configuration is set to the default
* value, there is no need to save it to the db. */
if (ae->ajchannels == 0 && ae->flags == DefAjoinFlags) {
/* Delete the entry first since it s just eating up space... */
moduleDelData(&nc->moduleData, ModDataKey);
deleteAjoinEntry(ae);
continue;
}

new_write_db_entry("ncd", dbptr, "%s", nc->display);
new_write_db_entry("flgs", dbptr, "%d", ae->flags);

if (ae->ajchannels > 0) {
for (ac = ae->channels; ac; ac = ac->next) {
new_write_db_entry("che", dbptr, "%s %s", ac->channel, (ac->key ? ac->key : ""));
}
}

new_write_db_endofblock(dbptr);

/* Marking the entry as in use... */
ae->in_use = 1;
}
}

if (dbptr) {
new_close_db(dbptr->fptr, NULL, NULL); /* close file */
remove(dbptr->temp_name); /* saved successfully, no need to keep the old one */
free(dbptr); /* free the db struct */
}
}

/* ------------------------------------------------------------------------------- */

/**
* We check if the ircd is supported
**/
int valid_ircd(void) {
if (!stricmp(IRCDModule, "unreal31"))
return 1;

if (!stricmp(IRCDModule, "unreal32"))
return 1;

if (!stricmp(IRCDModule, "viagra"))
return 1;

if (!stricmp(IRCDModule, "ptlink"))
return 1;

if (!stricmp(IRCDModule, "ultimate2"))
return 1;

if (!stricmp(IRCDModule, "plexus3"))
return 1;

if (!stricmp(IRCDModule, "inspircd10"))
return 1;

if (!stricmp(IRCDModule, "inspircd11"))
return 1;

return 0;
}

/* ------------------------------------------------------------------------------- */

/**
* (Re)Load the configuration directives
**/
void load_config(void) {
int i;

Directive confvalues[][1] = {
{{"AJoinDB", {{PARAM_STRING, PARAM_RELOAD, &AJoinDB}}}},
};

if (AJoinDB)
free(AJoinDB);
AJoinDB = NULL;

for (i = 0; i < 1; i++)
moduleGetConfigDirective(confvalues[i]);

if (!AJoinDB)
AJoinDB = sstrdup(DefAJoinDB);

if (debug)
alog ("[ns_ajoin] debug: AJoinDB set to %s", AJoinDB);
}


/**
* Upon /os reload call the routines for reloading the configuration directives
**/
int reload_config(int argc, char **argv) {
if (argc >= 1) {
if (!stricmp(argv[0], EVENT_START)) {
alog("[ns_ajoin]: Reloading configuration directives...");
load_config();
}
}
return MOD_CONT;
}


/* ------------------------------------------------------------------------------- */

/**
* Add language strings to the module's language db.
**/
void add_languages(void) {
char *langtable_en_us[] = {
/* LANG_AJOIN_DESC */
" AJOIN Manipulate the AutoJoin list.",
/* LANG_AJOIN_SYNTAX */
" Syntax: AJOIN { ADD | DEL | LIST | CLEAR } [\037channel\037 | \037entry-list\037] [\037key\037]",
/* LANG_AJOIN_SYNTAX_EXT */
" Syntax: \002AJOIN ADD \037channel\037 \037key\037\002 \n"
" \002AJOIN DEL {\037channel\037 | \037entry-nr\037 | \037list\037}\002\n"
" \002AJOIN LIST [\037mask\037 | \037list\037]\002 \n"
" \002AJOIN CLEAR\002 \n"
" \n"
" Maintains the \002AutoJoin list\002 for nick group. \n"
" If a user identifies to his nickname, he will \n"
" automatically join the listed channels. \n"
" \n"
" The \002AJOIN ADD\002 command adds the given channel\n"
" to the AutoJoin list or updates the existing entry, \n"
" if it is allready present on the AutoJoin list. \n"
" If no key is given and an entry for the channel is already\n"
" present, the key allready set (if any) will be unset. \n"
" Only \002registered channels\002 are accepted! \n"
" \n"
" The \002AJOIN DEL\002 command removes the given channel \n"
" from the AutoJoin list. If a list of entry numbers is given,\n"
" those entries are deleted.\n"
" \n"
" The \002AJOIN LIST\002 command displays the AutoJoin list.\n"
" If a wildcard mask is given, only those entries matching the\n"
" mask are displayed. If a list of entry numbers is given, only\n"
" those entries are shown.\n"
" \n"
" The \002AJOIN CLEAR\002 command clears all entries on the \n"
" AutoJoin list.",
/* LANG_AJOIN_DISABLED */
" Sorry, AutoJoin list modification is temporarily disabled.",
/* LANG_NO_LOCAL_CHAN */
" Cannot add local channels to ajoin list.",
/* LANG_CHAN_SYMB_REQUIRED */
" The channel symbol '\002#\002' is required.",
/* LANG_CHAN_UPDATED */
" Ajoin entry updated.",
/* LANG_AJOIN_LIST_FULL */
" The AutoJoin list is full.",
/* LANG_CHAN_ADDED */
" \002%s\002 has been added to the ajoin list.",
/* LANG_NO_AJOINS */
" No AutoJoins have been set.",
/* LANG_AJOIN_LIST_EMPTY */
" The AutoJoins list is empty.",
/* LANG_NO_ENTRY */
" \002%s\002 is not in the AutoJoin list.",
/* LANG_CHAN_DELETED */
" \002%s\002 has been deleted from the AutoJoin list.",
/* LANG_AJOIN_ENTRY */
" %d - Channel: %s - Key: %s",
/* LANG_AJOIN_ENTRIES */
" Found %d entries",
/* LANG_AJOIN_LIST_CLEARED */
" AJOIN list cleared.",
/* LANG_UNKWN_AJOIN_OPTION */
" Unknown AJOIN option.",
/* LANG_AJOINING */
" Automatically joining %s .",
/* LANG_AJOINING_FAILED */
" Could not automatically join %s .",
/* LANG_SET_AJOIN_DESC */
" \n"
" Commands Provided by module ns_ajoin: \n"
" AJOIN Change your autojoin settings.",
/* LANG_SET_AJOIN_SYNTAX */
" Syntax: SET AJOIN { ON | OFF | SILENT }",
/* LANG_SET_AJOIN_SYNTAX_EXT */
" Syntax: \002SET AJOIN { ON | OFF | SILENT }\002 \n"
" \n"
" Toggles whether or not your AutoJoin list is performed when \n"
" you IDENTIFY or UPDATE.\n"
" When set to ON, you will receive a notification for each channel\n"
" you are automatically joined to. When set to SILENT, you will receive\n"
" one message indicating you are automatically joining channels. \n"
" When set to OFF, you will not join any channels upon identifying.\n"
" \n"
" The default setting is \002ON\002.",
/* LANG_SET_AJOIN_ON */
" AutoJoin is now \002ON\002.",
/* LANG_SET_AJOIN_SILENT */
" AutoJoin is now \002ON\002 and set to \002SILENT\002 mode.",
/* LANG_SET_AJOIN_OFF */
" AutoJoin is now \002OFF\002.",
/* LANG_AJOINING_SUM_SUCCESS */
" Successfully joined %d channel(s).",
/* LANG_AJOINING_SUM_FAILED */
" Failed joining %d channel(s).",
/* LANG_AJOIN_DELETED_NR_1 */
" Deleted %d entry from the AutoJoin list.",
/* LANG_AJOIN_DELETED_NR */
" Deleted %d entries from the AutoJoin list.",
};

char *langtable_nl[] = {
/* LANG_AJOIN_DESC */
" AJOIN Beheer de autojoin lijst.",
/* LANG_AJOIN_SYNTAX */
" Gebruik: AJOIN {ADD | DEL | LIST | CLEAR} [\037kanaal\037 | \037lijst\037] [\037wachtwoord\037]",
/* LANG_AJOIN_SYNTAX_EXT */
" Gebruik: \002AJOIN ADD \037kanaal\037 \037wachtwoord\037\002 \n"
" \002AJOIN DEL {\037kanaal\037 | \037nummer\037 | \037lijst\037}\002 \n"
" \002AJOIN LIST [\037mask\037 | \037lijst\037]\002 \n"
" \002AJOIN CLEAR\002 \n"
" \n"
" Onderhoud de \002AutoJoin lijst\002 voor een nick groep. \n"
" Als een gebruiker zich voor zijn nickname identificeerd,\n"
" zal hij automatisch de kanalen in de lijst joinen.\n"
" \n"
" Het \002AJOIN ADD\002 commando voegt het gegeven kanaal toe \n"
" aan de AutoJoin lijst of werkt de bestaande entry bij, \n"
" indien het kanaal reeds aanwezig is op de AutoJoin lijst. \n"
" Als er geen wachtwoord is opgegeven en het kanaal reeds \n"
" aanwezig is op de lijst, zal het wachtwoord dat reeds is \n"
" ingesteld (indien aanwezig) verwijderd worden. \n"
" Enkel \002geregistreerde kanalen\002 worden aanvaard!. \n"
" \n"
" Het \002AJOIN DEL\002 commando verwiderd het gegeven kanaal \n"
" van de AutoJoin lijst. Als een lijst met entry-nummers is\n"
" gegeven, worden deze verwijderd.\n"
" \n"
" Het \002AJOIN LIST\002 commando geeft de AutoJoin lijst weer.\n"
" Als een wildcard mask is opgegeven worden alleen de overeenkomsten\n"
" weergegeven. Als een lijst van entry-nummers in gegeven wordt,\n"
" worden alleen die weergegeven\n"
" \n"
" Het \002AJOIN CLEAR\002 commando maakt de AutoJoin lilst leeg.",
/* LANG_AJOIN_DISABLED */
" Sorry,het wijzigen van de AutoJoin lijst is tijdelijk uitgeschakeld.",
/* LANG_NO_LOCAL_CHAN */
" Kan geen lokale kanalen toevoegen aan de ajoin list.",
/* LANG_CHAN_SYMB_REQUIRED */
" Het kanaal symbool '\002#\002' is vereist.",
/* LANG_CHAN_UPDATED */
" AutoJoin entry bijgewerkt.",
/* LANG_AJOIN_LIST_FULL */
" De AutoJoin lijst is vol.",
/* LANG_CHAN_ADDED */
" \002%s\002 is aan de autojoin lijst toegevoegd.",
/* LANG_NO_AJOINS */
" Er zijn geen AutoJoins ingesteld.",
/* LANG_AJOIN_LIST_EMPTY */
" De AutoJoin lijst is leeg.",
/* LANG_NO_ENTRY */
" \002%s\002 bestaat niet in de AutoJoin lijst.",
/* LANG_CHAN_DELETED */
" \002%s\002 is van de AutoJoin lijst verwijderd.",
/* LANG_AJOIN_ENTRY */
" %d - Kanaal: %s - Wachtwoord: %s",
/* LANG_AJOIN_ENTRIES */
" %d plaatsen gevonden.",
/* LANG_AJOIN_LIST_CLEARED */
" AutoJoin lijst is leeggemaakt.",
/* LANG_UNKWN_AJOIN_OPTION */
" Onbekende AJOIN parameter.",
/* LANG_AJOINING */
" Automatisch %s joinen",
/* LANG_AJOINING_FAILED */
" Kon %s niet automatisch joinen.",
/* LANG_SET_AJOIN_DESC */
" \n"
" Commandos toegevoegd door module ns_ajoin: \n"
" AJOIN Wijzig de instellingen van je autojoin.",
/* LANG_SET_AJOIN_SYNTAX */
" Gebruik: SET AJOIN { ON | OFF | SILENT }",
/* LANG_SET_AJOIN_SYNTAX_EXT */
" Gebruik: \002SET AJOIN { ON | OFF | SILENT }\002 \n"
" \n"
" Configureert of je AutoJoin lijst al dan niet wordt uitgevoerd bij \n"
" een nickserv IDENTIFY of UPDATE.\n"
" Wanneer deze optie op ON staat zal je een melding krijgen voor elk kanaal\n"
" dat je automatisch joint. Wanneer het op SILENT staat, krijg je één melding\n"
" die aangeeft dat je automatisch kanalen joint. \n"
" Wanneer deze optie op OFF staat zal je niet automatisch kanalen joinen.\n"
" \n"
" De standaard waarde is \002ON\002.",
/* LANG_SET_AJOIN_ON */
" AutoJoin staat nu \002OAAN\002.",
/* LANG_SET_AJOIN_SILENT */
" AutoJoin staat nu \002AAN\002 in \002STILLE\002 modus.",
/* LANG_SET_AJOIN_OFF */
" AutoJoin staat nu \002UIT\002.",
/* LANG_AJOINING_SUM_SUCCESS */
" Succesvol %d kanaal/kanalen gejoint.",
/* LANG_AJOINING_SUM_FAILED */
" Kon %d kanaal/kanalen niet joinen.",
/* LANG_AJOIN_DELETED_NR_1 */
" %d kanaal uit de AutoJoin lijst verwijderd.",
/* LANG_AJOIN_DELETED_NR */
" %d kanalen uit de AutoJoin lijst verwijderd.",
};

char *langtable_de[] = {
/* LANG_AJOIN_DESC */
" AJOIN AutoJoin-Liste bearbeiten.",
/* LANG_AJOIN_SYNTAX */
" Syntax: AJOIN { ADD | DEL | LIST | CLEAR } [\037channel\037 | \037entry-list\037] [\037key\037]",
/* LANG_AJOIN_SYNTAX_EXT */
" Syntax: \002AJOIN ADD \037channel\037 \037key\037\002 \n"
" \002AJOIN DEL {\037channel\037 | \037entry-nr\037 | \037list\037}\002 \n"
" \002AJOIN LIST [\037mask\037 | \037list\037]\002 \n"
" \002AJOIN CLEAR\002 \n"
" \n"
" Verwaltet die \002AutoJoin Liste\002 für eine Nick-Gruppe. \n"
" Wenn ein user sich mit seinem Nicknamen identifiziert, so \n"
" betritt er automatisch die Räume aus der Liste. \n"
" \n"
" \002AJOIN ADD\002 fügt den angegebenen Raum \n"
" der AutoJoin-Liste hinzu oder aktualisiert den \n"
" Eintrag, wenn der angegebene Raum schon vorhanden ist. \n"
" Wenn kein Raum-Schlüssel angegeben wird und es bereits \n"
" einen Listeneintrag für diesen Raum gibt, wo ein Schlüssel \n"
" angegeben wurde, dann wird dieser Schlüssel zurückgesetzt. \n"
" Nur \002registrierte Räume\002 sind erlaubt! \n"
" \n"
" \002AJOIN DEL\002 entfernt den angegebenen Raum \n"
" aus der AutoJoin-Liste. Wurden die Nummern der Einträge angegeben,\n"
" werden die dazugehörigen Einträge gelöscht.\n"
" \n"
" \002AJOIN LIST\002 zeigt die AutoJoin-liste.\n"
" If a wildcard mask is given, only those entries matching the\n"
" mask are displayed. Wurden die Nummern der Listeneinträge angegeben,\n"
" werden nur diese Einträge angezeigt.\n"
" \n"
" \002AJOIN CLEAR\002 löscht alle Einträge aus der \n"
" AutoJoin-Liste.",
/* LANG_AJOIN_DISABLED */
" Sorry, das Bearbeiten der AutoJoin-Liste ist vorrübergehend deaktiviert.",
/* LANG_NO_LOCAL_CHAN */
" Kann keine lokalen Räume zur AutoJoin-Liste hinzufügen.",
/* LANG_CHAN_SYMB_REQUIRED */
" Das Raumsymbol '\002#\002' wird benötigt.",
/* LANG_CHAN_UPDATED */
" AutoJoin Eintrag aktualisiert.",
/* LANG_AJOIN_LIST_FULL */
" Die AutoJoin-Liste ist voll.",
/* LANG_CHAN_ADDED */
" \002%s\002 wurde zur AutoJoin-Liste hinzugefügt.",
/* LANG_NO_AJOINS */
" Es wurden noch keine AutoJoins festgelegt.",
/* LANG_AJOIN_LIST_EMPTY */
" Die AutoJoin-Liste ist leer.",
/* LANG_NO_ENTRY */
" \002%s\002 ist nicht in der AutoJoin-liste.",
/* LANG_CHAN_DELETED */
" \002%s\002 wurde aus der AutoJoin-Liste gelöscht.",
/* LANG_AJOIN_ENTRY */
" %d - Channel: %s - Key: %s",
/* LANG_AJOIN_ENTRIES */
" Habe %d Einträge gefunden ",
/* LANG_AJOIN_LIST_CLEARED */
" AutoJoin-Liste gesäubert.",
/* LANG_UNKWN_AJOIN_OPTION */
" Unbekannte AutoJoin-Option.",
/* LANG_AJOINING */
" AutoJoining %s .",
/* LANG_AJOINING_FAILED */
" Konnte %s nicht AutoJoinen .",
/* LANG_SET_AJOIN_DESC */
" \n"
" Unterstützte Kommandos von Modul ns_ajoin: \n"
" AJOIN AutoJoin-Settings ändern.",
/* LANG_SET_AJOIN_SYNTAX */
" Syntax: SET AJOIN { ON | OFF | SILENT }",
/* LANG_SET_AJOIN_SYNTAX_EXT */
" Syntax: \002SET AJOIN { ON | OFF | SILENT }\002 \n"
" \n"
" Stellt ein, ob die AutoJoin-Liste abgearbeitet wird, wenn \n"
" IDENTIFY oder UPDATE ausgeführt wird.\n"
" Wenn ON eingestellt wird, bekommst du für jeden Raum, den du AutoJoinst \n"
" eine Nachricht. Bei Einstellung SILENT, bekommst du \n"
" eine Nachricht, welche dir mitteilt, dass du AutoJoinst. \n"
" Die Einstellung OFF bewirkt, dass du keinen Raum beim IDENTIFY Befehl betrittst. \n"
" \n"
" Voreinstellung ist: \002ON\002.",
/* LANG_SET_AJOIN_ON */
" AutoJoin ist jetzt \002ON\002.",
/* LANG_SET_AJOIN_SILENT */
" AutoJoin ist jetzt \002ON\002 und auf \002SILENT\002 eingestellt.",
/* LANG_SET_AJOIN_OFF */
" AutoJoin ist jetzt \002OFF\002.",
/* LANG_AJOINING_SUM_SUCCESS */
" Erfolgreich %d Channel(s) automatisch betreten.",
/* LANG_AJOINING_SUM_FAILED */
" Fehler beim AutoJoinen von %d channel(s).",
/* LANG_AJOIN_DELETED_NR_1 */
" %d Eintrag wurde aus der AutoJoin-Liste entfernt.",
/* LANG_AJOIN_DELETED_NR */
" %d Einträge wurden aus der AutoJoin-Liste entfernt.",
};

char *langtable_tr[] = {
/* LANG_AJOIN_DESC */
" AJOIN Otojoin listesinizi yönetebilirsiniz.",
/* LANG_AJOIN_SYNTAX */
" Kullanýmý: AJOIN { ADD | DEL | LIST | CLEAR } [\037#kanaladi\037 | \037entry-list\037] [\037anahtar\037]",
/* LANG_AJOIN_SYNTAX_EXT */
" Kullanýmý: \002AJOIN ADD \037#kanaladi\037 \037anahtar\037\002 \n"
" \002AJOIN DEL {\037#kanaladi\037 | \037entry-nr\037 | \037list\037}\002 \n"
" \002AJOIN LIST [\037mask\037 | \037list\037]\002 \n"
" \002AJOIN CLEAR\002 \n"
" \n"
" Nick grubunuzun \002otojoin list\002 düzenini görüntüler. \n"
" Nickinizi identify ettikten sonra, otomatik \n"
" olarak eklediðiniz kanallara giriþ yaparsýnýz. \n"
" \n"
" Otojoin listeniz hazýrda var ise \002AJOIN ADD\002 komutu\n"
" ile kanal ekleyebilir veya otojoin \n"
" listesini düzenlersiniz. \n"
" Eðer kanal eklerken anahtar belirtilmediyse ve kanalda \n"
" anahtar var ise, kanala girmek için anahtar olmucak.\n"
" Sadece \002kayýtlý kanal\002 kabul edilir! \n"
" \n"
" \002AJOIN DEL\002 komutu eklediðiniz kanalý otojoin \n"
" listesinden çýkartýr. Eðerki listede ki giriþ numaralarý verilirse,\n"
" bu giriþler silinir.\n"
" \n"
" \002AJOIN LIST\002 komutu otojoin listenizi görüntüler.\n"
" Eðerki mask belirtilirse, sadece belirtrilen bu masklar\n"
" görüntülenir. Eðerki sadece listede ki giriþ numaralarý belirtilirse, sadece\n"
" bunlar gözükür.\n"
" \n"
" \002AJOIN CLEAR\002 komutu bütün ekli olan kanallarýnýzý \n"
" otojoin listenizden siler.",
/* LANG_AJOIN_DISABLED */
" Üzgünüm, ajoin komutu kullaným dýþý býrakýlmýþtýr.",
/* LANG_NO_LOCAL_CHAN */
" Lokal kanal ekleyemezsiniz.",
/* LANG_CHAN_SYMB_REQUIRED */
" '\002#\002' iþaretini kulanmanýz gerekmektedir.",
/* LANG_CHAN_UPDATED */
" Otojoin giriþleriniz güncellendi.",
/* LANG_AJOIN_LIST_FULL */
" Otojoin listiniz dolmuþtur.",
/* LANG_CHAN_ADDED */
" \002%s\002 kanali otojoin listenize eklendi.",
/* LANG_NO_AJOINS */
" Herhangi bir otojoin kullanýlmadý.",
/* LANG_AJOIN_LIST_EMPTY */
" Otojoin listiniz boþ.",
/* LANG_NO_ENTRY */
" \002%s\002 kanali otojoin listenizde deðildir.",
/* LANG_CHAN_DELETED */
" \002%s\002 kanali otojoin listenizden silindi.",
/* LANG_AJOIN_ENTRY */
" %d - Kanaladi: %s - Anahtar: %s",
/* LANG_AJOIN_ENTRIES */
" %d giriþ bulundu",
/* LANG_AJOIN_LIST_CLEARED */
" Otojoin listeniz temizlendi.",
/* LANG_UNKWN_AJOIN_OPTION */
" Bilinmeyen otojoin komutu.",
/* LANG_AJOINING */
" %s kanalýna otomatik olarak giriþ yaptýnýz .",
/* LANG_AJOINING_FAILED */
" %s kanalýna otomatik giriþ yapamadýnýz .",
/* LANG_SET_AJOIN_DESC */
" \n"
" ns_ajoin modulu hakkýnda: \n"
" AJOIN Otojoin ayarlarýnýzý düzenler.",
/* LANG_SET_AJOIN_SYNTAX */
" Kullanýmý: SET AJOIN { ON | OFF | SILENT }",
/* LANG_SET_AJOIN_SYNTAX_EXT */
" Kullanýmý: \002SET AJOIN { ON | OFF | SILENT }\002 \n"
" \n"
" Otojoin listiniz hakkýnda IDENTIFY ve UPDATE edildiginde \n"
" geniþ bilgi sunar.\n"
" ON olduðunda otojoin listesinizdeki kanallara giriþ\n"
" yapmanýzý saðlar. Bu ayar SILENT olduðunda, sadece bir tane\n"
" otomatik giriþ yaptýðýnýz kanallardan giriþ mesajýnýz alýrsýnýz. \n"
" Bu ayar OFF olduðunda, hiçbir kanala otojoin yapamazsýnýz.\n"
" \n"
" Belirlenmiþ ayar \002ON\002.",
/* LANG_SET_AJOIN_ON */
" Þuan otojoin \002ON\002.",
/* LANG_SET_AJOIN_SILENT */
" Otojoin þuan \002ON\002 ve \002SILENT\002 modundadýr.",
/* LANG_SET_AJOIN_OFF */
" Otojoin þuan \002OFF\002.",
/* LANG_AJOINING_SUM_SUCCESS */
" %d kanallarýna baþarýlý þekilde giriþ yaptýnýz.",
/* LANG_AJOINING_SUM_FAILED */
" %d kanallarýna giriþ yapamadýnýz.",
/* LANG_AJOIN_DELETED_NR_1 */
" %d giriþ otojoin listesinden silindi.",
/* LANG_AJOIN_DELETED_NR */
" %d giriþler otojoin listesinden silindi.",
};

char *langtable_ru[] = {
/* LANG_AJOIN_DESC */
" AJOIN Óïðàâëÿåò AJOIN-ñïèñêîì (àâòîçàõîä).",
/* LANG_AJOIN_SYNTAX */
"Ñèíòàêñèñ: AJOIN { ADD | DEL | LIST | CLEAR } [\037#êàíàë\037 | \037ñïèñîê_çàïèñåé\037] [\037êëþ÷\037]",
/* LANG_AJOIN_SYNTAX_EXT */
"Ñèíòàêñèñ: \002AJOIN ADD \037#êàíàë\037 \037êëþ÷\037\002 \n"
" \002AJOIN DEL {\037#êàíàë\037 | \037íîìåð_çàïèñè\037 | \037ñïèñîê_çàïèñåé\037}\002\n"
" \002AJOIN LIST [\037ìàñêà\037 | \037ñïèñîê\037]\002 \n"
" \002AJOIN CLEAR\002 \n"
" \n"
"Ïîçâîëÿåò óïðàâëÿòü ñïèñêîì \002àâòîçàõîäà\002 íà êàíàëû. \n"
"Êàê òîëüêî ïîëüçîâàòåëü èäåíòèôèöèðóåòñÿ ê ñâîåìó íèêó, îí áóäåò \n"
"àâòîìàòè÷åñêè ïðèñîåäèíåí ê óêàçàííûì â ñïèñêå êàíàëàì. \n"
" \n"
"Êîìàíäà \002AJOIN ADD\002 ïîçâîëÿåò äîáàâèòü êàíàë â ñïèñîê \n"
"àâòîçàõîäà èëè îáíîâèòü èíôîðìàöèþ äëÿ óæå ñóùåñòâóþùåãî â \n"
"â ñïèñêå êàíàëà. \n"
"Åñëè ïðè îáíîâëåíèè çàïèñè äëÿ êàêîãî ëèáî êàíàëà, âû íå óêàæåòå \n"
"äîïîëíèòåëüíûé ïàðàìåòð 'êëþ÷' - òåêóùèé óñòàíîâëåííûé äëÿ êàíàëà \n"
"êëþ÷ áóäåò óäàëåí (ïðè óñëîâèè ÷òî îí ñòîÿë, êîíå÷íî) \n"
"Ñïèñîê àâòîçàõîäà ìîæåò ñîäåðæàòü òîëüêî \002çàðåãèñòðèðîâàííûå êàíàëû\002 \n"
" \n"
"Êîìàíäà \002AJOIN DEL\002 ïîçâîëÿåò óäàëèòü óêàçàííûé êàíàë èç \n"
"ñïèñêà àâòîçàõîäà.  êà÷åñòâå ïàðàìåòðà âû ìîæåòå óêàçàòü ñïèñîê \n"
"çàïèñåé èëè êîíêðåòíûé íîìåð çàïèñè ajoin-ñïèñêà \n"
" \n"
"Êîìàíäà \002AJOIN LIST\002 îòîáðàæàåò òåêóùèé ñïèñîê àâòîçàõîäà.\n"
"Äîïóñòèìî èñïîëüçîâàíèå ïîäñòàíîâî÷íûõ ñèìâîëîâ (ãëîáàëüíûõ ìàñîê)\n"
"â êà÷åñòâå äîïîëíèòåëüíîãî ïàðàìåòðà. Òàê æå, â êà÷åñòâå óëîâèÿ ëèñòèíãà\n"
"êàíàëîâ, âû ìîæåòå óêàçàòü ñïèñîê çàïèñåé.\n"
" \n"
"Êîìàíäà \002AJOIN CLEAR\002 ïîëíîñòüþ óäàëÿåò \002âñå\002 çàïèñè èç \n"
"ñïèñêà àâòîçàõîäà.",
/* LANG_AJOIN_DISABLED */
"Èçâèíèòå, íî ìîäèôèêàöèÿ ñïèñêà àâòîçàõîäà âðåìåííî íåäîñòóïíà.",
/* LANG_NO_LOCAL_CHAN */
"Âû íå ìîæåòå äîáàâèòü ëîêàëüíûå êàíàëû â ñïèñîê àâòîçàõîäà.",
/* LANG_CHAN_SYMB_REQUIRED */
"Âû äîëæíû óêàçàòü ñèìâîë êàíàëà: '\002#\002' .",
/* LANG_CHAN_UPDATED */
"Îáíîâëåíà îäíà çàïèñü â ñïèñêå àâòîçàõîäà.",
/* LANG_AJOIN_LIST_FULL */
"Ñïèñîê àâòîçàõîäà ïåðåïîëíåí.",
/* LANG_CHAN_ADDED */
"Êàíàë \002%s\002 óñïåøíî äîáàâëåí â ñïèñîê àâòîçàõîäà.",
/* LANG_NO_AJOINS */
"Ñïèñîê àâòîçàõîäà äëÿ âàøåãî íèêà íå íàñòðîåí.",
/* LANG_AJOIN_LIST_EMPTY */
"Ñïèñîê àâòîçàõîäà ïóñò.",
/* LANG_NO_ENTRY */
"Êàíàë \002%s\002 íå ïðèñóòñòâóåò â ñïèñêå àâòîçàõîäà.",
/* LANG_CHAN_DELETED */
"Êàíàë \002%s\002 óñïåøíî óäàëåí èç ñïèñêà àâòîçàõîäà.",
/* LANG_AJOIN_ENTRY */
" %d - Êàíàë: %s - Êëþ÷: %s",
/* LANG_AJOIN_ENTRIES */
"Âñåãî çàïèñåé: %d",
/* LANG_AJOIN_LIST_CLEARED */
"Ñïèñîê àâòîçàõîäà ïîëíîñòüþ î÷èùåí.",
/* LANG_UNKWN_AJOIN_OPTION */
"Íåèçâåñòíàÿ AJOIN-îïöèÿ.",
/* LANG_AJOINING */
"Óñïåøíûé àâòîçàõîä íà %s .",
/* LANG_AJOINING_FAILED */
"Íåóäà÷íûé àâòîçàõîä íà %s .",
/* LANG_SET_AJOIN_DESC */
" \n"
"Êîìàíäû, ïðåäîñòàâëÿåìûå ìîäóëåì ns_ajoin: \n"
" AJOIN Ïîçâîëÿåò íàñòðîèòü ðåæèì àâòîçàõîäà.",
/* LANG_SET_AJOIN_SYNTAX */
"Ñèíòàêñèñ: SET AJOIN { ON | OFF | SILENT }",
/* LANG_SET_AJOIN_SYNTAX_EXT */
"Ñèíòàêñèñ: \002SET AJOIN { ON | OFF | SILENT }\002 \n"
" \n"
"Ïîçâîëÿåò âêëþ÷èòü èëè âûêëþ÷èòü àâòîçàõîä íà êàíàëû êàê òîëüêî \n"
"âû èäåíòèôèöèðóåòåñü ê íèêó èëè èñïîëüçóåòå êîìàíäó UPDATE. \n"
"Óñòàíîâêà â ON àêòèâèðóåò àâòîìàòè÷åñêîå óâåäîìëåíèå îá àâòîçàõîäå íà \n"
"êàæäûé êàíàë èç âàøåãî ñïèñêà àâòîçàõîäà. Óñòàíîâêà â SILENT àêòèâèðóåò \n"
"ëèøü åäèíñòâåííîå óâåäîìëåíèå î òîì, ê êàêîìó êîëè÷åñòâó êàíàëîâ èç âàøåãî \n"
"ñïèñêà àâòîçàõîäà âû óñïåøíî/íåóñïåøíî ïðèñîåäèíåíû. \n"
"Óñòàíîâêà îïöèè â OFF îòêëþ÷èò âîçìîæíîñòü àâòîçàõîäà âîîáùå. \n"
" \n"
"Óñòàíîâêà ïî-óìîë÷àíèþ: \002ON\002.",
/* LANG_SET_AJOIN_ON */
"Ðåæèì àâòîçàõîäà \002ÂÊËÞ×ÅÍ\002.",
/* LANG_SET_AJOIN_SILENT */
"Ðåæèì àâòîçàõîäà \002ÂÊËÞ×ÅÍ\002, áóäåò èñïîëüçîâàí \002SILENT\002-ðåæèì (ìèíèìóì óâåäîìëåíèé).",
/* LANG_SET_AJOIN_OFF */
"Ðåæèì àâòîçàõîäà \002ÂÛÊËÞ×ÅÍ\002.",
/* LANG_AJOINING_SUM_SUCCESS */
"Óñïåøíûé àâòîçàõîä íà %d êàíàë(à/îâ).",
/* LANG_AJOINING_SUM_FAILED */
"Íåóäà÷íûé àâòîçàõîä íà %d êàíàë(à/îâ).",
/* LANG_AJOIN_DELETED_NR_1 */
"Çàïèñü ïîä íîìåðîì %d óäàëåíà èç ñïèñêà àâòîçàõîäà.",
/* LANG_AJOIN_DELETED_NR */
"Èç ñïèñêà àâòîçàõîäà óñïåøíî óäàëåíû %d çàïèñåé.",
};

moduleInsertLanguage(LANG_EN_US, LANG_NUM_STRINGS, langtable_en_us);
moduleInsertLanguage(LANG_NL, LANG_NUM_STRINGS, langtable_nl);
moduleInsertLanguage(LANG_DE, LANG_NUM_STRINGS, langtable_de);
moduleInsertLanguage(LANG_TR, LANG_NUM_STRINGS, langtable_tr);
moduleInsertLanguage(LANG_RU, LANG_NUM_STRINGS, langtable_ru);
}


/* EOF */

anope services.conf

# Anope 1.7.18

IRCDModule "unreal32"
EncModule "enc_none"
HostCoreModules "hs_help hs_on hs_off hs_group hs_list hs_set hs_setall hs_del hs_delall"
MemoCoreModules "ms_send ms_cancel ms_list ms_read ms_del ms_set ms_info ms_rsend ms_check ms_staff ms_sendall ms_help"
HelpCoreModules "he_help"
BotCoreModules "bs_gseen bs_massassign bs_autoassign bs_help bs_botlist bs_assign bs_set bs_kick bs_badwords bs_act bs_info bs_say bs_unassign bs_bot bs_fantasy bs_fantasy_kick bs_fantasy_kickban bs_fantasy_owner bs_fantasy_seen bs_fantasy_unban"
OperCoreModules "os_notinchanlist os_svsjoinpart os_set_sa os_autologchan os_forceid os_help os_global os_stats os_oper os_admin os_staff os_mode os_kick os_clearmodes os_killclones os_akill os_sgline os_sqline os_szline os_chanlist os_userlist os_logonnews os_randomnews os_opernews os_session os_noop os_jupe os_ignore os_set os_reload os_update os_restart os_quit os_shutdown os_defcon os_chankill os_svsnick os_oline os_umode os_modload os_modunload os_modlist os_modinfo"
NickCoreModules "ns_ghost ns_ajoin ns_vhostongroup ns_help ns_register ns_group ns_identify ns_access ns_set ns_saset ns_drop ns_recover ns_release ns_sendpass ns_ghost ns_alist ns_info ns_list ns_logout ns_status ns_update ns_getpass ns_getemail ns_forbid ns_suspend"
ChanCoreModules "cs_join cs_help cs_register cs_identify cs_set cs_xop cs_access cs_akick cs_drop cs_sendpass cs_ban cs_clear cs_modes cs_getkey cs_invite cs_kick cs_list cs_logout cs_topic cs_info cs_getpass cs_forbid cs_suspend cs_status"
RemoteServer 67.205.67.205 6667 "services"
#LocalAddress nowhere. 0
ServerName "services.easynets.org"
ServerDesc "Services for IRC Networks"
ServiceUser "services@easynets.org"
NickServName "NickServ" "Nickname Server"
ChanServName "ChanServ" "Channel Server"
MemoServName "MemoServ" "Memo Server"
BotServName "BotServ" "Bot Server"
HelpServName "HelpServ" "Help Server"
OperServName "OperServ" "Operator Server"
GlobalName "Global" "Global Noticer"
#DevNullName "DevNull" "/dev/null -- message sink"
HostServName "HostServ" "vHost Server"
#NickServAlias "NickServ2" "Nickname Server Forwarder"
#ChanServAlias "ChanServ2" "Channel Server Forwarder"
#MemoServAlias "MemoServ2" "Memo Server Forwarder"
#BotServAlias "BotServ2" "Bot Server Forwarder"
#HelpServAlias "HelpServ2" "Help Server Forwarder"
#OperServAlias "OperServ2" "Operator Server Forwarder"
#GlobalAlias "Global2" "Global Noticer Forwarder"
#DevNullAlias "DevNull2" "/dev/null -- message sink Forwarder"
#HostServAlias "HostServ2" "vHost Server Forwarder"
PIDFile services.pid
MOTDFile services.motd
NickServDB nick.db
#PreNickServDB prenick.db
ChanServDB chan.db
BotServDB bot.db
OperServDB oper.db
NewsDB news.db
ExceptionDB exception.db
HostServDB hosts.db
AutokillDB akill.db
HelpChannel "#help"
LogChannel "#staff"
LogBot
NetworkName "easynets.org"
#Numeric "64"
NickLen 31
UserKey1 93486623
UserKey2 86363013
UserKey3 36212456
#NoBackupOkay
StrictPasswords
BadPassLimit 50
BadPassTimeout 1h
UpdateTimeout 5m
ExpireTimeout 30m
ReadTimeout 5s
WarningTimeout 4h
TimeoutCheck 3s
KeepLogs 70
KeepBackups 30
ForceForbidReason
#UsePrivmsg
#DumpCore
LogUsers
#HideStatsO
#GlobalOnCycle
GlobalOnCycleMessage "Services are restarting, they will be back shortly - please be good while we're gone"
GlobalOnCycleUP "Services are now back online - have a nice day"
#AnonymousGlobal
NickRegDelay 30
#UseSVSHOLD
#RestrictOperNicks
#UseTokens
#UseSVS2MODE
#NewsCount 30
#UnRestrictSAdmin
UlineServers "stats.easynets.org proxy.easynets.org"
#UseTS6
UseMail
SendMailPath "anopesmtp 127.0.0.1"
SendFrom services@easynets.org
RestrictMail
MailDelay 5m
#DontQuoteAddresses
NSForceEmail
#NSEmailReg
#NSDefNone
NSDefKill
#NSDefKillQuick
NSDefSecure
#NSDefPrivate
#NSDefHideEmail
#NSDefHideUsermask
#NSDefHideQuit
#NSDefMsg
NSDefMemoSignon
NSDefMemoReceive
NSDefLanguage 2
NSRegDelay 30s
NSExpire 31d
#NSRExpire 1d
NSMaxAliases 16
NSAccessMax 32
NSEnforcerUser enforcer@easynets.org
NSReleaseTimeout 30m
#NSAllowKillImmed
#NSNoGroupChange
#NSListOpersOnly
NSListMax 50
NSGuestNickPrefix "EasyNets"
NSSecureAdmins
NSStrictPrivileges
#NSModeOnID
#NSRestrictGetPass
#NSNickTracking
#NSAddAccessOnReg
#CSDefNone
CSDefKeepTopic
#CSDefOpNotice
CSDefPeace
#CSDefPrivate
#CSDefRestricted
CSDefSecure
#CSDefSecureOps
CSDefSecureFounder
CSDefSignKick
#CSDefSignKickLevel
#CSDefTopicLock
CSDefXOP
CSMaxReg 20
CSExpire 31d
CSDefBantype 2
CSAccessMax 1024
CSAutokickMax 32
CSAutokickReason "User has been banned from the channel"
CSInhabit 15s
#CSListOpersOnly
CSListMax 50
#CSRestrictGetPass
#CSOpersOnly
MSMaxMemos 20
MSSendDelay 3s
MSNotifyAll
#MSMemoReceipt 1
#BSDefDontKickOps
#BSDefDontKickVoices
BSDefGreet
BSDefFantasy
BSDefSymbiosis
BSMinUsers 10
BSBadWordsMax 32
BSKeepData 10m
#BSSmartJoin
BSGentleBWReason
#BSCaseSensitive
#BSFantasyCharacter "!"
#HostSetters "rob dengel certus"
ServicesRoot "Dj-RuFfy"
SuperAdmin "Dj-RuFfy"
LogMaxUsers
AutoKillExpiry 30d
ChanKillExpiry 30d
SGLineExpiry 30d
SQLineExpiry 30d
SZLineExpiry 30d
#AkillOnAdd
#KillOnSGline
#KillOnSQline
KillClonesAkillExpire 30m
DisableRaw
#WallOper
#WallBadOS
WallOSGlobal
WallOSMode
WallOSClearmodes
WallOSKick
WallOSAkill
WallOSSGLine
WallOSSQLine
WallOSSZLine
WallOSNoOp
WallOSJupe
WallOSRaw
#WallAkillExpire
#WallSGLineExpire
#WallSQLineExpire
#WallSZLineExpire
#WallExceptionExpire
WallGetpass
WallSetpass
WallForbid
WallDrop
LimitSessions
DefSessionLimit 70
MaxSessionLimit 100
ExceptionExpiry 1d
SessionLimitExceeded "The session limit for your host %s has been exceeded."
#SessionLimitDetailsLoc "Please visit http://your.website.url/ for more information about session limits."
MaxSessionKill 15
SessionAutoKillExpiry 30m
#CheckClones 5 10s 30s
#KillClones
AddAkiller
OSOpersOnly
#DefConLevel 50
#DefCon4 23
#DefCon3 31
#DefCon2 159
#DefCon1 415
#DefConSessionLimit 20
#DefConAkillExpire 5m
#DefConChanModes "+R"
#DefConTimeOut 15m
#GlobalOnDefcon
#GlobalOnDefconMore
#DefconMessage "Put your message to send your users here. Dont forget to uncomment GlobalOnDefconMore"
#DefConOffMessage "Services are now back to normal, sorry for any inconvenience"
#DefConAkillReason "This network is currently not accepting connections, please try again later"
#MysqlHost "localhost"
#MysqlUser "Anonymous"
#MysqlPass ""
#MysqlName "anope"
#MysqlSock "/tmp/mysql.sock"
#MysqlPort 3306
#MysqlSecure ""
#MysqlRetries 10
#MysqlRetryGap 1
#UseRDB
#ModuleAutoload "hs_moo ircd_defizzer"
ModuleDelayedAutoload "cs_appendtopic cs_enforce ns_maxemail ns_noop os_info hs_request"
#NSEmailMax 1
#NSAutoOPDBName autoop.db
#OSInfoDBName os_info.db
#HSRequestMemoUser
#HSRequestMemoOper
#HSRequestMemoSetters
#HSRequestDBName hs_request.db

#EOF

ircd_vhostserv

#include "module.h"
#define AUTHOR "Dj-RuFfy"
#define VERSION "$Id: ircd_vhostserv.c v2.0.2 04-03-2008 Dj-RuFfy $"

/* ------------------------------------------------------------------------------------
* Name : ircd_vhostserv.c
* Author : Dj-RuFfy [Dj-RuFfy@easynets.com]
* Version : 2.0.2
* Date : 2nd October, 2006
* Update : 23th March, 2008
* ------------------------------------------------------------------------------------
* Description:
*
* This module create a new services client/bot. The bot have its own fantasy command
* !vhost and !groupvhost. The bot will answer the fantasy commands ONLY on its own channel.
* ------------------------------------------------------------------------------------
* Providing Fantasy Commands:
*
* !vhost some.vhost.here - set a vhost for users
* !groupvhost group.vhost.here - set vhost for all users in group
* !vhost restricted - list all restricted vhosts
* ------------------------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ------------------------------------------------------------------------------------
* Change Log:
* v1.0.0 - First Public Release
*
* v1.0.1 -
* a) Fixed a few mem leaks
* b) Fixed a bug on vIdent
*
* v1.0.2 -
* a) Minor code update
* b) Added modload prevention for unsupported IRCd's. The module will not load on
* unsupported IRCd's (bahamut, dreamforge, hybrid, ratbox).
* c) Added Tokens support
* d) Added checked for vHost channel before modload. If the vHost channel is not
* registered, the module will not load.
*
* v2.0.0 - Fixed a crash bug when the line starts with a space in it.
*
* v2.0.1 -
* a) Added !groupvhost fantasy command for setting all users vhost in a group
* b) Added configuration directive support
* c) Added vhost flood protection; will now kick/ban users after a vhost is set
* d) Remove !hs on|off fantasy command
* e) Module will not load on version less than 1.7.21
*
* v2.0.2 -
* a) Added check for unallowed vhosts.
* b) Added options to kick-ban users who request unallowed vhosts.
* c) Added fantasy command "!vhost restricted" to list all restricted hosts so that
* a user can be warned first before kickban.
* ------------------------------------------------------------------------------------
* Module made possible using vhost fantasy module by Trystan
* ------------------------------------------------------------------------------------
* This module have 10 configurable options.
*
* Copy/Paste below on services.conf

# BotNick [REQUIRED]
# Module: ircd_vhostserv
# Define what nick the bot will have.
#
BotNick "vHostServ"

# BotIdent [REQUIRED]
# Define the bot identd.
#
BotIdent "Bot"

# BotHost [REQUIRED]
# Define the bot hostname or vhost.
#
BotHost "LocalHost-IRC.Host.Bot"

# BotReal [REQUIRED]
# Define the bot realname.
#
BotReal "/msg vHostServ Help"

# vHostChannel [REQUIRED]
# Define your network vhost channel.
#
vHostChannel "#vHost"

# BanClearTime