1
0
mirror of https://github.com/anope/anope.git synced 2026-06-30 00:36:37 +02:00

Initial Anope Import

git-svn-id: svn://svn.anope.org/anope/trunk@1 31f1291d-b8d6-0310-a050-a5561fc1590b


git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1 5417fbe8-f217-4b02-8779-1006273d7864
This commit is contained in:
svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b
2004-03-28 21:59:56 +00:00
commit 55bf4dbcab
103 changed files with 119474 additions and 0 deletions
Vendored
+1
View File
@@ -0,0 +1 @@
-kr -nut
+1299
View File
File diff suppressed because it is too large Load Diff
+428
View File
@@ -0,0 +1,428 @@
Anope Version 1.6.0
--------------------
** ADDED CONFIGURATION DIRECTIVES **
###########################################################################
#
# DefCon configuration
#
###########################################################################
# DefConLevel <level> [OPTIONAL]
# Default defcon level (1-5) to use when starting services up, level 5
# instructs services to run as normal.
#DefConLevel 5
# DefCon1-4 <numeric> [REQUIRED if Defcon is activated]
# These numercics determine which of the following operations take place
# at each level, the correct numeric can be found by adding together the
# number for each restriction you wish to place at a level.
# No new channel registrations 1
# No New Nick Registrations 2
# No MLOCK changes 4
# Force Chan Mode 8
# Use Reduced Session Limit 16
# KILL any new clients trying to connect 32
# Services will ignore everyone but opers 64
# Services will silently ignore everyone but opers 128
# AKILL all new clients trying to connect 256
# No new memos sent to block memoserv attacks 512
#DefCon4 23
# No channel reg + No Nick Reg + No MLOCK changes + Use Reduced Session Limit
# 1 + 2 + 4 + 16
#DefCon3 31
# As DefCon4 + Services will Force Chan Mode's on channels
# 23 + 8
#DefCon2 159
# As DefCon3 + Services will silently ignore everyone but opers
# 32 + 128
#DefCon1 415
# As DefCon2 + AKILL all new clients trying to connect
# 159 + 256
# DefConSessionLimit <limit> [REQUIRED if DefCon is activated]
# New session limit to use when a defcon level is using "reduced"
# session limiting.
# NOTE: When using DefCon this value needs to be defined
#DefConSessionLimit 2
# DefConAkillExpire <time> [REQUIRED if DefCon is activated]
# Length of time to add the AKILL for when DEFCON is preventing
# all new clients from connecting to the network
#
# NOTE: As with all expire times, the expirey check will only be
# carried out once every "ExpireTimeout" so if this setting is
# 30m the the akill could last for 30m regardless of this setting.
#
# NOTE: When using DefCon this value needs to be defined
#DefConAkillExpire 5m
# DefConChanModes <modes> [REQUIRED if DefCon is activated]
# The channel modes to set on all channel's when the DefCon channel
# mode system is in use.
#
# NOTE: Choose these modes carefully, because when defcon switches to
# a level which does NOT have the mode setting selected, services will
# set the reverse on all channel's, e.g. if this setting is +RN
# when defcon is used all channel's will be set to +RN, when
# defcon is removed, channels will all be set to -RN. You don't
# want to set this to +k for example because when defcon is removed all
# channels will -k.
# NOTE: mlock'ed modes will not be lost
#DefConChanModes "+R"
# DefConTimeOut <time> [OPTIONAL]
# This value can be used to automaticaly return the network to
# defcon 5 after the specified time period - just in case any opers
# forget to remove a defcon setting.
#DefConTimeOut 15m
# GlobalOnDefcon [OPTIONAL]
#
# Setting this directive will make Services send a global message on
# Defcon Level changes.
#GlobalOnDefcon
# GlobalOnDefconMore [OPTIONAL]
#
# Setting this directive will make Services send a global message on
# Defcon Level changes. Uncommenting this will allow you to send along
# with the new level, the DefconMessage.
#GlobalOnDefconMore
#DefconMessage "Put your message to send your users here. Dont forget to uncomment GlobalOnDefconMore"
# DefConOffMessage [OPTIONAL]
#
# If this is defined, it will be used in place of GlobalOnDefcon and
# GlobalOnDefconMore when defcon is returned to level 5
#DefConOffMessage "Services are now back to normal, sorry for any inconvenience"
# DefConAkillReason <text> [REQUIRED if DefCon is activated]
#
# When using DEFCON this setting will be used when any clients are killed
# or akilled from the network by defcon
#
#DefConAkillReason "This network is currently not accepting connections, please try again later"
###########################################################################
#
# MySQL configuration
#
###########################################################################
#
# Mysql [OPTIONAL]
#
# Your MySQL configuration for use with Anope.
# To disable MySQL functionality, just comment out this block.
# To make use of MySQL use these directives and change their
# setting to the appropiate values.
#
# MysqlHost defines the Mysql server hostname.
# MysqlUser defines the Mysql user to log in with.
# MysqlPass defines the Mysql pass required for the specified user to log in.
# MysqlName defines the Mysql database name Anope uses
# MysqlSock defines the Mysql UNIX socket
# MysqlPort defines the Mysql TCP port
#
#MysqlHost "localhost"
#MysqlUser "Anonymous"
#MysqlPass ""
#MysqlName "anope"
#MysqlSock "/tmp/mysql.sock"
#MysqlPort 3306
# MysqlSecure "<des>|<md5>|<sha>|<key>" [OPTIONAL]
#
# Method for storing passwords on MySQL. Available methods are:
# Empty or not set will save your passwords as clear text.
# des : Encrypt using a simple DES algorithm.
# md5 : Produces the md5 hash for the password.
# sha : Calculates the checksum using a Secure Hash Algorithm.
# key : Encodes using "key" as password.
# Please read docs/MYSQL file for more info and details.
#
#MysqlSecure ""
# MysqlRetries <value> [OPTIONAL]
# MysqlRetryGap <value> [OPTIONAL]
#
# These values let you define how often and with how much interruption Anope
# shall retry to open a connection when losing the contact to the mysql db.
# The product of these values must be between 1 and 60.
#
#MysqlRetries 10
#MysqlRetryGap 1
###########################################################################
#
# Module configuration
#
###########################################################################
#
# ModuleAutoload [OPTIONAL]
#
# When compiled with module support, this contains a space seperated list
# of modules to automaticaly load as soon as possible, e.g. IRCD support modules.
#
#ModuleAutoload "hs_moo ircd_defizzer"
# ModuleDelayedAutoload [OPTIONAL]
#
# When compiled with module support, this contains a space seperated list
# of modules to automaticaly load when services are ready for new clients.
# e.g. new pesudo clients such as CatServ :-) *meow*
#
#ModuleDelayedAutoload "ircd_catserv"
###########################################################################
#
# Misc configuration
#
###########################################################################
# AnonymousGlobal [OPTIONAL]
# hides the oper's nick in a globalmsg
#AnonymousGlobal
# DontQuoteAddresses [OPTIONAL]
#
# When enabled, services will not attempt to "" the TO: fields in mails
#
# So far we only know of ESMTP which needs this set.
#
#DontQuoteAddresses
# If services can't connect to the RemoteServer, they will try
# RemoteServer2 (if defined). If they can't connect to RemoteServer2,
# they will use RemoteServer3 (if defined).
RemoteServer localhost 6667 "mypass"
#RemoteServer2 localhost 6667 "mypass"
#RemoteServer3 localhost 6667 "mypass"
# NSRestrictGetPass [OPTIONAL]
#
# When enabled, services will only allow Services Root to use the getpass
# command on a nick.
#
#NSRestrictGetPass
# CSRestrictGetPass [OPTIONAL]
#
# When enabled, services will only allow Services Root to use the getpass
# command on a channel.
#
#CSRestrictGetPass
# CSOpersOnly [OPTIONAL]
# If this is defined, only IRC Operators will be permitted to use ChanServ.
#CSOpersOnly
# GlobalOnCycleMessage <text> [OPTIONAL]
#
# This is the message to global when using GlobalOnCycle
#GlobalOnCycleMEssage "Services are restarting, they will be back shortley - please be good while were gone"
# GlobalOnCycleUP <text> [OPTIONAL]
#
# if defined, this string will be globaled when services join the network
#GlobalOnCycleUP "Services are now back online - have a nice day"
# ChanKillExpiry <time> [REQUIRED]
# Default /OS CHANKILL expire time
ChanKillExpiry 7d
# HostSetters <nicks> [DISCOURAGED]
# Specifies the nicks of NON-OPERS allowed to Set/Remove vHosts using
# HostServ. Can be re-loaded with /msg operserv reload
# You can specify more than one nick by separating each one by a space.
#
# make sure you insert the correct nick(s) here..
#HostSetters "rob dengel certus"
Anope Version 1.4.18
--------------------
** ADDED CONFIGURATION DIRECTIVES **
# PreNickServDB prenick.db
# NSEmailReg [OPTIONAL]
# This option splits the nick registration into 2 steps, the first
# after registering a email with a passcode is sent to the supplied
# email address, this passcode needs to be entered with a confirm
# command before the nick registration will be completed.
#
# You must have mail / forcemail set for this to work correctly.
# It is also recommended that MailDelay be set to a sensible value
# to prevent mail flooding
# NSEmailReg
# NSRExpire <time> [OPTIONAL]
# Sets the length of time a user gets to enter the confirmation code
# which has been e-mailed to them before the nick will be relased
# for general use again
# NSRExpire 1d
# NSModeOnID [OPTIONAL]
#
# When enabled, services will set channel modes a user has when they identify
#
# NSModeOnID
# HideStatsO [OPTIONAL]
#
# Setting this directive will make Services only show Stats O to
# IRC Operators.
#HideStatsO
# GlobalOnCycle [OPTIONAL]
#
# Setting this directive will make Services send global messages on
# starting up and shuting down/restarting.
#GlobalOnCycle
** MODIFIED CONFIGURATION DIRECTIVES **
# NetworkDomain <name> [OPTIONAL]
#
# If your network has a common domain name, specify it there (for
# example, all IRCZONE servers have a name ending in ".irczone.cl",
# so "irczone.cl" would be set there. It will be used by the OperServ
# GLOBAL command, and if you don't have a common domain name, this
# command may just not work.
#
# You can specify more than one Network Domain by separating each one by
# a space: NetworkDomain "localnet.net localnet.com"
NetworkDomain "localnet.com"
AnopeVersion 1.4.26
--------------------------
** ADDED CONFIGURATION DIRECTIVES **
# DontQuoteAddresses [OPTIONAL]
#
# When enabled, services will not attempt to "" the to fields in mails
#
# So far we only know of ESMTP which needs this set.
#
#DontQuoteAddresses
Anope Version 1.4.18
--------------------
** ADDED CONFIGURATION DIRECTIVES **
# PreNickServDB prenick.db
# NSEmailReg [OPTIONAL]
# This option splits the nick registration into 2 steps, the first
# after registering a email with a passcode is sent to the supplied
# email address, this passcode needs to be entered with a confirm
# command before the nick registration will be completed.
#
# You must have mail / forcemail set for this to work correctly.
# It is also recommended that MailDelay be set to a sensible value
# to prevent mail flooding
# NSEmailReg
# NSRExpire <time> [OPTIONAL]
# Sets the length of time a user gets to enter the confirmation code
# which has been e-mailed to them before the nick will be relased
# for general use again
# NSRExpire 1d
# NSModeOnID [OPTIONAL]
#
# When enabled, services will set channel modes a user has when they identify
#
# NSModeOnID
# HideStatsO [OPTIONAL]
#
# Setting this directive will make Services only show Stats O to
# IRC Operators.
#HideStatsO
# GlobalOnCycle [OPTIONAL]
#
# Setting this directive will make Services send global messages on
# starting up and shuting down/restarting.
#GlobalOnCycle
Anope Version 1.4.16
--------------------
** ADDED CONFIGURATION DIRECTIVES **
HostServName "HostServ" "vHost Server"
HostServDB hosts.db
HostServAlias "HostServ2" "Vhostname Server Forwarder"
** MODIFIED CONFIGURATION DIRECTIVES **
# ForceForbidReason [OPTIONAL]
#
# If set, Services will require a reason when a forbid is added, else
# the reason is optional. This directive also applies to SUSPENDed
# channels as well.
ForceForbidReason
** DELETED CONFIGURATION DIRECTIVES **
Anope Version 1.4.15
--------------------
** ADDED CONFIGURATION DIRECTIVES **
# ...Alias <nick> <string> [OPTIONAL]
# Specify alternate nicknames for services. When a user will /msg
# NickServAlias sthing, it will be forwarded to NickServName, and
# NickServName will answer. This can be used to ease the migration
# from another network, for example if your services are called
# NickKeeper, ChanKeeper, etc ... and the other network calls them
# NickServ, ChanServ, etc ...
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"
#DevNullName "DevNull2" "/dev/null -- message sink Forwarder"
# LogChannel <channel> [OPTIONAL]
#
# When defined, services will output log messages to this channel.
# IMPORTANT: This can be a security risk so make certain this channel
# is sufficiently protected from normal access.
#LogChannel "#services"
# LogChannel [OPTIONAL]
#
# When defined, services will output all BotServ chatter to the defined
# LogChan above. It shows all uses of BotServ ACT and SAY commands. Note
# that there is no logging to the log file. Only works is LogChannel is
# also defined.
#LogBot
# SuperAdmin [OPTIONAL]
# Having this flag enabled will turn all Services Admin to have Founder
# level on *all* registered channels.
#SuperAdmin
# AddAkiller [OPTIONAL]
# Adds the nickname of the Operator issuing an AKILL to the kill reason.
#
AddAkiller
+963
View File
@@ -0,0 +1,963 @@
Anope Version 1.6.0
--------------------
New Strings:
CHAN_HELP_ULTIMATE3
DEFCON_GLOBAL
END_OF_ANY_LIST
HELP_HELP_HOST
HOST_DELALL
HOST_DELALL_SYNTAX
HOST_HELP_DELALL
HOST_LIST_FOOTER
HOST_LIST_KEY_FOOTER
HOST_LIST_RANGE_FOOTER
HOST_OPER_HELP
MEMO_HELP_ADMIN
MEMO_HELP_FOOTER
MEMO_HELP_OPER
MEMO_HELP_SENDALL
MEMO_HELP_STAFF
MEMO_MASS_SENT
MODULE_HELP_HEADER
NICK_ALREADY_IDENTIFIED
NICK_GETEMAIL_EMAILS_ARE
NICK_GETEMAIL_NOT_USED
NICK_GETEMAIL_SYNTAX
NICK_HELP_UPDATE
NICK_LOGOUT_SERVICESADMIN
NICK_SERVADMIN_HELP_GETEMAIL
NICK_UPDATE_SUCCESS
NICK_X_ILLEGAL
NICK_X_IN_USE
NICK_X_TRUNCATED
OPER_CHANKILL_SYNTAX
OPER_DEFCON_CHANGED
OPER_DEFCON_DENIED
OPER_DEFCON_NO_CONF
OPER_DEFCON_SYNTAX
OPER_DEFCON_WALL
OPER_HELP_ADMIN_CMD
OPER_HELP_CHANKILL
OPER_HELP_DEFCON
OPER_HELP_DEFCON_AKILL_NEW_CLIENTS
OPER_HELP_DEFCON_FORCE_CHAN_MODES
OPER_HELP_DEFCON_NO_MLOCK_CHANGE
OPER_HELP_DEFCON_NO_NEW_CHANNELS
OPER_HELP_DEFCON_NO_NEW_CLIENTS
OPER_HELP_DEFCON_NO_NEW_MEMOS
OPER_HELP_DEFCON_NO_NEW_NICKS
OPER_HELP_DEFCON_OPER_ONLY
OPER_HELP_DEFCON_REDUCE_SESSION
OPER_HELP_DEFCON_SILENT_OPER_ONLY
OPER_HELP_LOGGED
OPER_HELP_MODINFO
OPER_HELP_MODLIST
OPER_HELP_MODLOAD
OPER_HELP_MODUNLOAD
OPER_HELP_OPER_CMD
OPER_HELP_ROOT_CMD
OPER_HELP_SVSNICK
OPER_MODULE_CMD_LIST
OPER_MODULE_INFO_LIST
OPER_MODULE_INFO_SYNTAX
OPER_MODULE_LIST
OPER_MODULE_LOADED
OPER_MODULE_LOAD_FAIL
OPER_MODULE_LOAD_SYNTAX
OPER_MODULE_MSG_LIST
OPER_MODULE_NO_INFO
OPER_MODULE_NO_LIST
OPER_MODULE_REMOVE_FAIL
OPER_MODULE_UNLOADED
OPER_MODULE_UNLOAD_SYNTAX
OPER_STAFF_AFORMAT
OPER_STAFF_FORMAT
OPER_STAFF_LIST_HEADER
OPER_SVSNICK_NEWNICK
OPER_SVSNICK_SYNTAX
Modified strings (need to be re-translated):
BOT_ASSIGN_ALREADY
CHAN_HELP_LOGOUT
CHAN_HELP_ULTIMATE
CHAN_SERVADMIN_HELP_LOGOUT
HOST_ENTRY
HOST_HELP_DEL
HOST_HELP_LIST
HOST_HELP_SET
HOST_IDENT_ENTRY
HOST_OPER_HELP
MEMO_HELP
NICK_HELP_DROP
OPER_HELP
OPER_HELP_ADMIN
OPER_HELP_UMODE
Anope Version 1.4.22
--------------------
New strings:
OPER_JUPE_HOST_ERROR
CHAN_UNSUSPEND_ERROR
Anope Version 1.4.21
--------------------
New strings:
BOT_BAD_NICK
BOT_BAD_HOST
BOT_BAD_IDENT
HOST_SET_IDENT_ERROR
Modified strings (need to be re-translated):
HOST_SET_ERROR
Anope Version 1.4.18
--------------------
New strings:
MEMO_X_MANY_NOTICE
MEMO_X_ONE_NOTICE
MEMO_NEW_X_MEMO_ARRIVED
MEMO_CHAN_DELETED_ALL
NICK_REQUESTED
NICK_IS_PREREG
NICK_ENTER_REG_CODE
NICK_CONFIRM_NOT_FOUND
NICK_CONFIRM_INVALID
NICK_REG_MAIL_SUBJECT
NICK_REG_MAIL_HEAD
NICK_REG_MAIL_LINE_1
NICK_REG_MAIL_LINE_2
NICK_REG_MAIL_LINE_3
NICK_REG_MAIL_LINE_4
NICK_REG_MAIL_LINE_5
HOST_HELP_GROUP
HOST_IDENT_GROUP
HOST_GROUP
NICK_REG_RESENT
NICK_REG_UNABLE
NICK_GETPASS_PASSCODE_IS
NICK_FORCE_REG
BOT_EXCEPT
OPER_IGNORE_SYNTAX
OPER_IGNORE_VALID_TIME
OPER_IGNORE_TIME_DONE
OPER_IGNORE_PERM_DONE
OPER_IGNORE_DEL_DONE
OPER_IGNORE_LIST_NOMATCH
OPER_IGNORE_LIST_CLEARED
OPER_HELP_IGNORE
OPER_HELP_UMODE
OPER_HELP_OLINE
OPER_UMODE_SYNTAX
OPER_OLINE_SYNTAX
OPER_OLINE_SUCCESS
OPER_SUPER_ADMIN_ON
OPER_SUPER_ADMIN_OFF
OPER_SUPER_ADMIN_SYNTAX
OPER_SUPER_ADMIN_WALL_ON
OPER_SUPER_ADMIN_WALL_OFF
OPER_UMODE_SUCCESS
OPER_UMODE_CHANGED
OPER_SUPER_ADMIN_ONLY
OPER_HELP_SET_SUPERADMIN
OPER_OLINE_IRCOP
Modified strings (need to be re-translated):
HOST_HELP
NICK_LIST_SERVADMIN_SYNTAX
MEMO_HELP_DEL
OPER_HELP
OPER_HELP_SET
Deleted strings:
Anope Version 1.4.17
--------------------
New strings:
NICK_INFO_VHOST
HOST_SET_ERROR
HOST_SET_TOOLONG
NICK_ALIST_SYNTAX
NICK_ALIST_HEADER
NICK_ALIST_HEADER_X
NICK_ALIST_XOP_FORMAT
NICK_ALIST_ACCESS_FORMAT
NICK_ALIST_FOOTER
NICK_HELP_ALIST
NICK_SERVADMIN_HELP_ALIST
HOST_IDENT_SET
HOST_IDENT_SETALL
HOST_SET_IDENTTOOLONG
HOST_IDENT_ACTIVATED
HOST_NO_VIDENT
Modified strings (need to be re-translated):
RAW_DISABLED
HOST_OFF_UNREAL
HOST_HELP_SET
HOST_HELP_SETALL
Deleted strings:
CHAN_CLIST_SYNTAX
CHAN_CLIST_HEADER
CHAN_CLIST_FORMAT
CHAN_CLIST_FOOTER
CHAN_ALIST_SYNTAX
CHAN_ALIST_HEADER
CHAN_ALIST_XOP_FORMAT
CHAN_ALIST_AXS_FORMAT
CHAN_ALIST_FOOTER
CHAN_HELP_CLIST
CHAN_HELP_ALIST
Anope Version 1.4.16
--------------------
New strings:
CHAN_X_SUSPENDED
CHAN_AOP_MOVED
CHAN_HOP_MOVED
CHAN_SOP_MOVED
CHAN_VOP_MOVED
CHAN_ACCESS_LIST_XOP_FORMAT
CHAN_ACCESS_LIST_AXS_FORMAT
CHAN_ALIST_SYNTAX
CHAN_ALIST_HEADER
CHAN_ALIST_XOP_FORMAT
CHAN_ALIST_AXS_FORMAT
CHAN_ALIST_FOOTER
CHAN_CLEARED_EXCEPTS
CHAN_FORBID_REASON
CHAN_SUSPEND_SYNTAX
CHAN_SUSPEND_SYNTAX_REASON
CHAN_SUSPEND_SUCCEEDED
CHAN_SUSPEND_FAILED
CHAN_SUSPEND_REASON
CHAN_UNSUSPEND_SYNTAX
CHAN_UNSUSPEND_SUCCEEDED
CHAN_UNSUSPEND_FAILED
CHAN_EXCEPTED
CHAN_HELP_CLIST
CHAN_HELP_ALIST
CHAN_SERVADMIN_HELP_SUSPEND
CHAN_SERVADMIN_HELP_UNSUSPEND
HOST_EMPTY
HOST_ENTRY
HOST_SET
HOST_SETALL
HOST_NOREG
HOST_SET_SYNTAX
HOST_SETALL_SYNTAX
HOST_DENIED
HOST_NOT_ASSIGNED
HOST_ACTIVATED
HOST_ID
HOST_NOT_REGED
HOST_DEL
HOST_DEL_SYNTAX
HOST_OFF_UNREAL
HOST_HELP
HOST_OPER_HELP
HOST_ADMIN_HELP
HOST_HELP_ON
HOST_HELP_SET
HOST_HELP_SETALL
HOST_HELP_OFF
HOST_HELP_DEL
HOST_HELP_LIST
Modified strings:
CHAN_HELP
CHAN_CLIST_HEADER
CHAN_CLIST_FORMAT
CHAN_SERVADMIN_HELP
CHAN_SERVADMIN_HELP_LIST
CHAN_LIST_SERVADMIN_SYNTAX
CHAN_HELP_SET
CHAN_SERVADMIN_HELP
Deleted strings:
CHAN_SERVADMIN_HELP_CLIST
CHAN_ACCESS_LIST_FORMAT
CHAN_XOP_ALREADY_EXISTS
Anope Version 1.4.15
--------------------
New strings:
RAW_DISABLED
CHAN_ACCESS_LIST_FOOTER
OPER_SET_LOGCHAN_ON
OPER_SET_LOGCHAN_OFF
OPER_SET_LOGCHAN_ERROR
OPER_HELP_SET_LOGCHAN
Modified strings:
OPER_HELP_SET
Epona Version 1.4.0
-------------------
New strings:
BOT_BOTLIST_FOOTER
BOT_BOTLIST_PRIVATE_HEADER
BOT_INFO_BOT_OPTIONS
BOT_INFO_OPT_PRIVATE
BOT_SERVADMIN_HELP_SET_PRIVATE
BOT_SET_PRIVATE_...
CHAN_ACCESS_XOP
CHAN_AKICK_STUCK
CHAN_AKICK_UNSTUCK
CHAN_AKICK_VIEW_FORMAT_STUCK
CHAN_AOP_...
CHAN_HELP_AOP
CHAN_HELP_BAN
CHAN_HELP_DEOWNER
CHAN_HELP_HOP
CHAN_HELP_OWNER
CHAN_HELP_SET_PEACE
CHAN_HELP_SET_XOP
CHAN_HELP_SOP
CHAN_HELP_VOP
CHAN_HELP_TOPIC
CHAN_HOP_...
CHAN_INFO_OPT_OPNOTICE
CHAN_INFO_OPT_PEACE
CHAN_INFO_OPT_XOP
CHAN_LEVEL_BANME
CHAN_LEVEL_BAN
CHAN_LEVEL_INFO
CHAN_LEVEL_TOPIC
CHAN_LEVELS_XOP
CHAN_SET_MLOCK_IMPOSSIBLE_CHAR
CHAN_SET_MLOCK_K_REQUIRED
CHAN_SET_PEACE_...
CHAN_SET_XOP_...
CHAN_SOP_...
CHAN_TOPIC_SYNTAX
CHAN_VOP_...
CHAN_XOP_...
NEWS_HELP_RANDOM
NEWS_RANDOM_...
NEWS_RANDOM_TEXT
NICK_GROUP_TOO_MANY
NICK_X_NOT_ON_CHAN
OPER_CACHE_...
OPER_HELP_CACHE
OPER_HELP_SQLINE
OPER_SQLINE_...
OPER_STATS_PROXY_MEM
OPER_STATS_SQLINE_...
Modified strings:
BOT_HELP_INFO
BOT_HELP_SET_SYMBIOSIS
BOT_SERVADMIN_HELP_SET
CHAN_AKICK_SYNTAX
CHAN_AKICK_LIST_FORMAT
CHAN_HELP
CHAN_HELP_AKICK
CHAN_HELP_CLEAR
CHAN_HELP_DEHALFOP
CHAN_HELP_DEOP
CHAN_HELP_DEPROTECT
CHAN_HELP_DEVOICE
CHAN_HELP_HALFOP
CHAN_HELP_INFO
CHAN_HELP_INVITE
CHAN_HELP_KICK
CHAN_HELP_OP
CHAN_HELP_PROTECT
CHAN_HELP_SET
CHAN_HELP_SET_MLOCK
CHAN_HELP_VOICE
CHAN_HELP_ULTIMATE
CHAN_HELP_UNREAL
CHAN_HELP_UNBAN
NO_REASON
OPER_CHANLIST_HEADER
OPER_CHANLIST_HEADER_USER
OPER_CHANLIST_RECORD
OPER_HELP
OPER_HELP_KILLCLONES
OPER_HELP_JUPE
Deleted strings:
CHAN_HELP_ADMIN
CHAN_HELP_DEADMIN
CHAN_HELP_SET_TOPIC
CHAN_LEVEL_ADMIN
CHAN_LEVEL_ADMINME
CHAN_LEVEL_AUTOADMIN
CHAN_MLOCK_REMOVED
CHAN_NO_AOP_SOP
CHAN_SET_MLOCK_FLOOD_REQUIRED
CHAN_SET_MLOCK_KEY_REQUIRED
CHAN_SET_MLOCK_LIMIT_POSITIVE
CHAN_SET_MLOCK_LIMIT_REQUIRED
CHAN_SET_MLOCK_REDIRECT_REQUIRED
CHAN_SET_TOPIC_FAILED
NICK_INFO_LINKED_TO
Epona Version 1.3.0
-------------------
New strings:
CHAN_LEVEL_ADMIN
CHAN_LEVEL_ADMINME
CHAN_LEVEL_AUTOADMIN
BOT_REASON_BADWORD_GENTLE
CHAN_CLIST_...
CHAN_HELP_ADMIN
CHAN_HELP_DEADMIN
CHAN_HELP_ULTIMATE
CHAN_SERVADMIN_HELP_CLIST
EXPIRES_...
MAIL_X_INVALID
NICK_HELP_GLIST
NICK_HELP_GROUP
NICK_HELP_SET_DISPLAY
NICK_HELP_SET_MSG
NICK_IDENTIFY_EMAIL_HOWTO
NICK_INFO_OPT_MSG
NICK_GLIST_...
NICK_GROUP_...
NICK_SERVADMIN_HELP_GLIST
NICK_SET_DISPLAY_...
NICK_SET_MSG_...
NICK_SET_OPTION_DISABLED
OBSOLETE_COMMAND
OPER_AKILL_EXISTS
OPER_AKILL_ALREADY_COVERED
OPER_AKILL_REACHED_LIMIT
OPER_AKILL_CHANGED
OPER_AKILL_NO_MATCH
OPER_AKILL_DELETED
OPER_AKILL_DELETED_ONE
OPER_AKILL_DELETED_SEVERAL
OPER_AKILL_LIST_EMPTY
OPER_AKILL_VIEW_HEADER
OPER_AKILL_CLEAR
OPER_HELP_NOOP
OPER_HELP_SGLINE
OPER_HELP_SZLINE
OPER_NOOP_...
OPER_SGLINE_...
OPER_STATS_ALIASES_MEM
OPER_STATS_GROUPS_MEM
OPER_STATS_SGLINE_...
OPER_STATS_SZLINE_...
OPER_SZLINE_...
Modified strings:
CHAN_HELP
CHAN_ACCESS_LIST_FORMAT
CHAN_SERVADMIN_HELP
NICK_HELP
NICK_HELP_DROP
NICK_HELP_EXPIRES
NICK_HELP_GHOST
NICK_HELP_RECOVER
NICK_HELP_REGISTER
NICK_HELP_RELEASE
NICK_HELP_SET
NICK_IDENTIFY_EMAIL_REQUIRED
NICK_SERVADMIN_HELP
NICK_SERVADMIN_HELP_DROP
OPER_ADMIN_LIST_FORMAT
OPER_AKILL_SYNTAX
OPER_AKILL_ADDED
OPER_AKILL_NOT_FOUND
OPER_AKILL_LIST_HEADER
OPER_AKILL_LIST_FORMAT
OPER_AKILL_VIEW_FORMAT
OPER_OPER_LIST_FORMAT
OPER_HELP
OPER_HELP_AKILL
Deleted strings:
CHAN_HELP_SET_LEAVEOPS
CHAN_INFO_OPT_LEAVEOPS
CHAN_SET_LEAVEOPS_...
NICK_DROP_SYNTAX
NICK_HELP_LINK
NICK_HELP_UNLINK
NICK_LINK_SYNTAX
NICK_LINK_DISABLED
NICK_LINK_FAILED
NICK_LINK_CIRCULAR
NICK_LINKED
NICK_LISTLINKS_SYNTAX
NICK_LISTLINKS_HEADER
NICK_LISTLINKS_FOOTER
NICK_NO_LINK_SAME
NICK_NOT_LINKED
NICK_SERVADMIN_HELP_LISTLINKS
NICK_SERVADMIN_HELP_UNLINK
NICK_UNLINK_SYNTAX
NICK_UNLINK_FAILED
NICK_UNLINKED
NICK_X_NOT_LINKED
NICK_X_UNLINKED
OPER_AKILL_ADD_SYNTAX
OPER_AKILL_DEL_SYNTAX
OPER_AKILL_REMOVED
OPER_AKILL_NO_EXPIRE
OPER_AKILL_EXPIRES_SOON
OPER_AKILL_EXPIRES_M
OPER_AKILL_EXPIRES_1M
OPER_AKILL_EXPIRES_HM
OPER_AKILL_EXPIRES_H1M
OPER_AKILL_EXPIRES_1HM
OPER_AKILL_EXPIRES_1H1M
OPER_AKILL_EXPIRES_D
OPER_AKILL_EXPIRES_1D
OPER_STATS_NICKSERV_MEM
OPER_TOO_MANY_AKILLS
Epona Version 1.2.3
-------------------
New strings:
HELP_HELP_BOT
Epona Version 1.2.0
-------------------
New strings:
BOT_INFO_OPT_NOBOT
BOT_SEEN_BOT
BOT_SEEN_YOU
BOT_SEEN_ON_CHANNEL
BOT_SEEN_ON_CHANNEL_AS
BOT_SEEN_ON
BOT_SEEN_NEVER
BOT_SEEN_UNKNOWN
BOT_SERVADMIN_HELP_SET
BOT_SERVADMIN_HELP_SET_NOBOT
BOT_SET_NOBOT_SYNTAX
BOT_SET_NOBOT_ON
BOT_SET_NOBOT_OFF
CHAN_HELP_KICK
CHAN_HELP_LOGOUT
CHAN_HELP_SET_SIGNKICK
CHAN_INFO_OPT_SIGNKICK
CHAN_LEVEL_KICKME
CHAN_LEVEL_KICK
CHAN_LOGOUT_SYNTAX
CHAN_LOGOUT_SERVADMIN_SYNTAX
CHAN_LOGOUT_SUCCEEDED
CHAN_LOGOUT_ALL_SUCCEEDED
CHAN_SERVADMIN_HELP_LOGOUT
CHAN_SET_SIGNKICK_SYNTAX
CHAN_SET_SIGNKICK_ON
CHAN_SET_SIGNKICK_LEVEL
CHAN_SET_SIGNKICK_OFF
CHAN_SUCCESSOR_IS_FOUNDER
DURATION_DAY
DURATION_DAYS
DURATION_HOUR
DURATION_HOURS
DURATION_MINUTE
DURATION_MINUTES
DURATION_SECOND
DURATION_SECONDS
MEMO_INFO_NOTIFY_OFF
MEMO_INFO_NOTIFY_ON
MEMO_INFO_NOTIFY_RECEIVE
MEMO_INFO_NOTIFY_SIGNON
MEMO_INFO_X_NOTIFY_OFF
MEMO_INFO_X_NOTIFY_ON
MEMO_INFO_X_NOTIFY_RECEIVE
MEMO_INFO_X_NOTIFY_SIGNON
NICK_HELP_EXPIRES
NICK_HELP_LOGOUT
NICK_HELP_SET_ICQ
NICK_INFO_ICQ
NICK_INFO_SERVICES_ADMIN
NICK_INFO_SERVICES_OPER
NICK_LOGOUT_SYNTAX
NICK_LOGOUT_SUCCEEDED
NICK_LOGOUT_X_SUCCEEDED
NICK_SERVADMIN_HELP_LOGOUT
NICK_SET_ICQ_CHANGED
NICK_SET_ICQ_UNSET
NICK_SET_ICQ_INVALID
OPER_ADMIN_CLEAR
OPER_ADMIN_DELETED
OPER_ADMIN_DELETED_ONE
OPER_ADMIN_DELETED_SEVERAL
OPER_ADMIN_LIST_EMPTY
OPER_ADMIN_LIST_FORMAT
OPER_ADMIN_NO_MATCH
OPER_ADMIN_REACHED_LIMIT
OPER_HELP_RELOAD
OPER_OPER_CLEAR
OPER_OPER_DELETED
OPER_OPER_DELETED_ONE
OPER_OPER_DELETED_SEVERAL
OPER_OPER_LIST_EMPTY
OPER_OPER_LIST_FORMAT
OPER_OPER_NO_MATCH
OPER_OPER_REACHED_LIMIT
OPER_RELOAD
USERHOST_MASK_TOO_WIDE
Modified strings:
BOT_HELP_SET_FANTASY
CHAN_HELP
CHAN_HELP_SET
MEMO_INFO_X_HARD_LIMIT
NICK_HELP
NICK_HELP_SET
NICK_SERVADMIN_HELP
OPER_ADMIN_LIST_HEADER
OPER_HELP
OPER_HELP_ADMIN
OPER_HELP_OPER
OPER_OPER_LIST_HEADER
Deleted strings:
BOT_KICK_NO_COLORS
NICK_HELP_EXPIRE_ZERO
OPER_ADMIN_ADD_SYNTAX
OPER_ADMIN_DEL_SYNTAX
OPER_ADMIN_REMOVED
OPER_ADMIN_TOO_MANY
OPER_OPER_ADD_SYNTAX
OPER_OPER_DEL_SYNTAX
OPER_OPER_REMOVED
OPER_OPER_TOO_MANY
Epona Version 1.1.x
-------------------
New strings:
BOT_BADWORDS_CLEAR
BOT_HELP_SET_GREET
BOT_INFO_OPT_GREET
CHAN_ACCESS_CLEAR
CHAN_AKICK_VIEW_FORMAT
CHAN_AKICK_CLEAR
CHAN_FORBID_SYNTAX_REASON
CHAN_HELP
CHAN_HELP_DEVOICE
CHAN_HELP_DEHALFOP
CHAN_HELP_DEPROTECT
CHAN_HELP_GETKEY
CHAN_HELP_HALFOP
CHAN_HELP_PROTECT
CHAN_HELP_SET_BANTYPE
CHAN_HELP_SET_SECUREFOUNDER
CHAN_HELP_UNREAL
CHAN_HELP_VOICE
CHAN_INFO_BANTYPE
CHAN_INFO_OPT_SECUREFOUNDER
CHAN_LEVEL_AUTOHALFOP
CHAN_LEVEL_AUTOPROTECT
CHAN_LEVEL_GETKEY
CHAN_LEVEL_GREET
CHAN_LEVEL_HALFOPME
CHAN_LEVEL_HALFOP
CHAN_LEVEL_OPDEOPME
CHAN_LEVEL_PROTECTME
CHAN_LEVEL_PROTECT
CHAN_LEVEL_VOICEME
CHAN_LEVEL_VOICE
CHAN_LIST_SERVADMIN_SYNTAX
CHAN_SET_BANTYPE_INVALID
CHAN_SET_BANTYPE_CHANGED
CHAN_SET_MLOCK_FLOOD_REQUIRED
CHAN_SET_MLOCK_REDIRECT_REQUIRED
CHAN_SET_MLOCK_L_REQUIRED
CHAN_SET_SECUREFOUNDER_SYNTAX
CHAN_SET_SECUREFOUNDER_ON
CHAN_SET_SECUREFOUNDER_OFF
CHAN_X_FORBIDDEN_OPER
MEMO_HELP_CANCEL
MEMO_CANCEL_SYNTAX
MEMO_CANCEL_DISABLED
MEMO_CANCEL_NONE
MEMO_CANCELLED
NICK_FORBID_SYNTAX_REASON
NICK_HELP_SET_GREET
NICK_INFO_GREET
NICK_INFO_LINKED_TO
NICK_SET_GREET_CHANGED
NICK_SET_GREET_UNSET
NICK_X_FORBIDDEN_OPER
NO_REASON
OPER_HELP_SET_NOEXPIRE
OPER_SET_READONLY_ON
OPER_SET_READONLY_OFF
OPER_SET_READONLY_ERROR
OPER_STATS_RESET
UNKNOWN
Modified strings:
BOT_BADWORDS_SYNTAX
BOT_BADWORDS_LIST_FORMAT
BOT_HELP_BADWORDS
BOT_HELP_SET
CHAN_ACCESS_SYNTAX
CHAN_AKICK_SYNTAX
CHAN_FORBID_SYNTAX
CHAN_HELP
CHAN_HELP_ACCESS
CHAN_HELP_AKICK
CHAN_HELP_FORBID
CHAN_HELP_SET
CHAN_SERVADMIN_HELP_LIST
MEMO_HELP
NICK_FORBID_SYNTAX
NICK_HELP_FORBID
NICK_HELP_SET
OPER_HELP_SET
OPER_HELP_STATS
NICK_LIST_SERVADMIN_SYNTAX
Deleted strings:
OPER_HELP_ROTATELOG
OPER_ROTATELOG_*
Epona Version 1.0x
------------------
Deleted strings:
CHAN_OP_SYNTAX
CHAN_DEOP_SYNTAX
DISCONNECT_IN_1_MINUTE
DISCONNECT_IN_20_SECONDS
DISCONNECT_NOW
Modified strings:
CHAN_HELP_OP
CHAN_HELP_DEOP
NICK_HELP_REGISTER
NICK_HELP_SET
NICK_HELP_SET_KILL
NICK_INFO_OPT_KILL
NICK_REGISTER_SYNTAX
NICK_SET_KILL_ON
NICK_SET_KILL_QUICK
NICK_SET_KILL_IMMED
NICK_SET_KILL_OFF
New strings:
BOT_DOES_NOT_EXIST
BOT_NOT_ASSIGNED
BOT_NOT_ON_CHANNEL
BOT_REASON_BADWORD
BOT_REASON_BOLD
BOT_REASON_CAPS
BOT_REASON_COLOR
BOT_REASON_FLOOD
BOT_REASON_REPEAT
BOT_REASON_REVERSE
BOT_REASON_UNDERLINE
BOT_BOT_SYNTAX
BOT_BOT_ALREADY_EXISTS
BOT_BOT_CREATION_FAILED
BOT_BOT_READONLY
BOT_BOT_ADDED
BOT_BOT_ANY_CHANGES
BOT_BOT_CHANGED
BOT_BOT_DELETED
BOT_BOTLIST_HEADER
BOT_BOTLIST_EMPTY
BOT_ASSIGN_SYNTAX
BOT_ASSIGN_READONLY
BOT_ASSIGN_ALREADY
BOT_ASSIGN_ASSIGNED
BOT_UNASSIGN_SYNTAX
BOT_UNASSIGN_UNASSIGNED
BOT_INFO_SYNTAX
BOT_INFO_NOT_FOUND
BOT_INFO_BOT_HEADER
BOT_INFO_BOT_MASK
BOT_INFO_BOT_REALNAME
BOT_INFO_BOT_CREATED
BOT_INFO_BOT_USAGE
BOT_INFO_CHAN_HEADER
BOT_INFO_CHAN_BOT
BOT_INFO_CHAN_BOT_NONE
BOT_INFO_CHAN_KICK_BADWORDS
BOT_INFO_CHAN_KICK_BOLDS
BOT_INFO_CHAN_KICK_CAPS_ON
BOT_INFO_CHAN_KICK_CAPS_OFF
BOT_INFO_CHAN_KICK_COLORS
BOT_INFO_CHAN_KICK_FLOOD_ON
BOT_INFO_CHAN_KICK_FLOOD_OFF
BOT_INFO_CHAN_KICK_REPEAT_ON
BOT_INFO_CHAN_KICK_REPEAT_OFF
BOT_INFO_CHAN_KICK_REVERSES
BOT_INFO_CHAN_KICK_UNDERLINES
BOT_INFO_CHAN_KICK_BADWORDS_BAN
BOT_INFO_CHAN_KICK_BOLDS_BAN
BOT_INFO_CHAN_KICK_CAPS_BAN
BOT_INFO_CHAN_KICK_COLORS_BAN
BOT_INFO_CHAN_KICK_FLOOD_BAN
BOT_INFO_CHAN_KICK_REPEAT_BAN
BOT_INFO_CHAN_KICK_REVERSES_BAN
BOT_INFO_CHAN_KICK_UNDERLINES_BAN
BOT_INFO_ACTIVE
BOT_INFO_INACTIVE
BOT_INFO_CHAN_OPTIONS
BOT_INFO_OPT_DONTKICKOPS
BOT_INFO_OPT_DONTKICKVOICES
BOT_INFO_OPT_FANTASY
BOT_INFO_OPT_SYMBIOSIS
BOT_INFO_OPT_NONE
BOT_SET_SYNTAX
BOT_SET_DISABLED
BOT_SET_UNKNOWN
BOT_SET_DONTKICKOPS_SYNTAX
BOT_SET_DONTKICKOPS_ON
BOT_SET_DONTKICKOPS_OFF
BOT_SET_DONTKICKVOICES_SYNTAX
BOT_SET_DONTKICKVOICES_ON
BOT_SET_DONTKICKVOICES_OFF
BOT_SET_FANTASY_SYNTAX
BOT_SET_FANTASY_ON
BOT_SET_FANTASY_OFF
BOT_SET_SYMBIOSIS_SYNTAX
BOT_SET_SYMBIOSIS_ON
BOT_SET_SYMBIOSIS_OFF
BOT_KICK_SYNTAX
BOT_KICK_DISABLED
BOT_KICK_UNKNOWN
BOT_KICK_NO_COLORS
BOT_KICK_BAD_TTB
BOT_KICK_BADWORDS_ON
BOT_KICK_BADWORDS_ON_BAN
BOT_KICK_BADWORDS_OFF
BOT_KICK_BOLDS_ON
BOT_KICK_BOLDS_ON_BAN
BOT_KICK_BOLDS_OFF
BOT_KICK_CAPS_ON
BOT_KICK_CAPS_ON_BAN
BOT_KICK_CAPS_OFF
BOT_KICK_COLORS_ON
BOT_KICK_COLORS_ON_BAN
BOT_KICK_COLORS_OFF
BOT_KICK_FLOOD_ON
BOT_KICK_FLOOD_ON_BAN
BOT_KICK_FLOOD_OFF
BOT_KICK_REPEAT_ON
BOT_KICK_REPEAT_ON_BAN
BOT_KICK_REPEAT_OFF
BOT_KICK_REVERSES_ON
BOT_KICK_REVERSES_ON_BAN
BOT_KICK_REVERSES_OFF
BOT_KICK_UNDERLINES_ON
BOT_KICK_UNDERLINES_ON_BAN
BOT_KICK_UNDERLINES_OFF
BOT_BADWORDS_SYNTAX
BOT_BADWORDS_DISABLED
BOT_BADWORDS_REACHED_LIMIT
BOT_BADWORDS_ALREADY_EXISTS
BOT_BADWORDS_ADDED
BOT_BADWORDS_NO_SUCH_ENTRY
BOT_BADWORDS_NOT_FOUND
BOT_BADWORDS_NO_MATCH
BOT_BADWORDS_DELETED
BOT_BADWORDS_DELETED_ONE
BOT_BADWORDS_DELETED_SEVERAL
BOT_BADWORDS_LIST_EMPTY
BOT_BADWORDS_LIST_HEADER
BOT_BADWORDS_LIST_FORMAT
BOT_SAY_SYNTAX
BOT_ACT_SYNTAX
BOT_HELP
BOT_HELP_BOTLIST
BOT_HELP_ASSIGN
BOT_HELP_UNASSIGN
BOT_HELP_INFO
BOT_HELP_SET
BOT_HELP_SET_DONTKICKOPS
BOT_HELP_SET_DONTKICKVOICES
BOT_HELP_SET_FANTASY
BOT_HELP_SET_SYMBIOSIS
BOT_HELP_KICK
BOT_HELP_KICK_BADWORDS
BOT_HELP_KICK_BOLDS
BOT_HELP_KICK_CAPS
BOT_HELP_KICK_COLORS
BOT_HELP_KICK_FLOOD
BOT_HELP_KICK_REPEAT
BOT_HELP_KICK_REVERSES
BOT_HELP_KICK_UNDERLINES
BOT_HELP_BADWORDS
BOT_HELP_SAY
BOT_HELP_ACT
BOT_SERVADMIN_HELP
BOT_SERVADMIN_HELP_BOT
CHAN_LEVEL_ASSIGN
CHAN_LEVEL_BADWORDS
CHAN_LEVEL_FANTASIA
CHAN_LEVEL_NOKICK
CHAN_SENDPASS_SYNTAX
CHAN_SENDPASS_UNAVAILABLE
CHAN_SENDPASS_SUBJECT
CHAN_SENDPASS_HEAD
CHAN_SENDPASS_LINE_1
CHAN_SENDPASS_LINE_2
CHAN_SENDPASS_LINE_3
CHAN_SENDPASS_LINE_4
CHAN_SENDPASS_LINE_5
CHAN_SENDPASS_OK
HELP_HELP
MAIL_DISABLED
MAIL_INVALID
MAIL_LATER
NICK_REGISTER_SYNTAX_EMAIL
NICK_IDENTIFY_EMAIL_REQUIRED
NICK_SET_EMAIL_UNSET_IMPOSSIBLE
NICK_SENDPASS_SYNTAX
NICK_SENDPASS_UNAVAILABLE
NICK_SENDPASS_SUBJECT
NICK_SENDPASS_HEAD
NICK_SENDPASS_LINE_1
NICK_SENDPASS_LINE_2
NICK_SENDPASS_LINE_3
NICK_SENDPASS_LINE_4
NICK_SENDPASS_LINE_5
NICK_SENDPASS_OK
OPER_STATS_BOTSERV_MEM
OPER_CHANLIST_HEADER
OPER_CHANLIST_RECORD
OPER_CHANLIST_END
OPER_USERLIST_HEADER
OPER_USERLIST_HEADER_CHAN
OPER_USERLIST_RECORD
OPER_USERLIST_END
OPER_HELP_CHANLIST
OPER_HELP_USERLIST
Version 4.3
-----------
Modified strings:
DISCONNECT_NOW
NICK_INFO_SYNTAX
CHAN_AKICK_SYNTAX
CHAN_INFO_SYNTAX
NICK_HELP_INFO
CHAN_HELP_SET
CHAN_HELP_AKICK
CHAN_HELP_INFO
OPER_HELP
New strings:
BAD_EXPIRY_TIME
FORCENICKCHANGE_...
NICK_INFO_ADDRESS_ONLINE...
CHAN_AKICK_ENFORCE_DONE
CHAN_INFO_SUCCESSOR
CHAN_INFO_NO_SUCCESSOR
CHAN_INFO_ENTRYMSG
CHAN_INFO_NO_EXPIRE
OPER_STATS_BYTES_...
OPER_STATS_SESSIONS_MEM
OPER_KILLCLONES_...
OPER_ROTATELOG_...
OPER_EXCEPTION_...
OPER_SESSION_...
OPER_HELP_EXCEPTION
OPER_HELP_SESSION
NICK_SERVADMIN_HELP_INFO
CHAN_SERVADMIN_HELP_INFO
OPER_HELP_KILLCLONES
OPER_HELP_ROTATELOG
+174
View File
@@ -0,0 +1,174 @@
# Makefile for Epona.
#
# Epona (c) 2000-2002 PegSoft
# Contact us at epona@pegsoft.net
#
# This program is free but copyrighted software; see the file COPYING for
# details.
#
# Based on the original code of Services by Andy Church.
include Makefile.inc
###########################################################################
########################## Configuration section ##########################
# Note that changing any of these options (or, in fact, anything in this
# file) will automatically cause a full rebuild of Services.
# Compilation options:
# -DCLEAN_COMPILE Attempt to compile without any warnings (note that
# this may reduce performance)
# -DSTREAMLINED Leave out "fancy" options to enhance performance
CDEFS =
# Add any extra flags you want here. The default line enables warnings and
# debugging symbols on GCC. If you have a non-GCC compiler, you may want
# to comment it out or change it.
MORE_CFLAGS = -Wall -g
######################## End configuration section ########################
###########################################################################
CFLAGS = $(CDEFS) $(BASE_CFLAGS) $(MORE_CFLAGS)
OBJS = actions.o botserv.o channels.o chanserv.o commands.o compat.o converter.o \
config.o datafiles.o encrypt.o helpserv.o hostserv.o init.o language.o list.o log.o mail.o main.o \
memory.o memoserv.o messages.o misc.o modules.o news.o nickserv.o operserv.o \
process.o protocol.o proxy.o send.o sessions.o slist.o sockutil.o \
timeout.o users.o \
$(VSNPRINTF_O) $(RDB_O) $(MYSQL_O)
SRCS = actions.c botserv.c channels.c chanserv.c commands.c compat.c converter.c \
config.c datafiles.c encrypt.c helpserv.c hostserv.c init.c language.c list.c log.c mail.c main.c \
memory.c memoserv.c messages.c misc.c modules.c news.c nickserv.c operserv.c \
process.c protocol.c proxy.c send.c sessions.c slist.c sockutil.c \
timeout.c users.c \
$(VSNPRINTF_C) $(RDB_C) $(MYSQL_C)
.c.o:
$(CC) $(CFLAGS) -c $<
all: $(PROGRAM) languages modules
@echo Now run \"$(MAKE) install\" to install Services.
myclean:
rm -f *.o $(PROGRAM) a.out
clean: myclean
(cd lang ; $(MAKE) spotless)
rm -f language.h
(cd modules ; $(MAKE) clean)
spotless: myclean
(cd lang ; $(MAKE) spotless)
(cd modules ; rm -f *.so Makefile.inc)
rm -f config.cache configure.log sysconf.h Makefile.inc language.h version.h *~
distclean: spotless
install: $(PROGRAM) languages
$(INSTALL) services $(BINDEST)/services
rm -f $(BINDEST)/listnicks $(BINDEST)/listchans
ln $(BINDEST)/services $(BINDEST)/listnicks
ln $(BINDEST)/services $(BINDEST)/listchans
(cd lang ; $(MAKE) install)
$(CP_ALL) data/* $(DATDEST)
test -d $(DATDEST)/backups || mkdir $(DATDEST)/backups
test -d $(DATDEST)/logs || mkdir $(DATDEST)/logs
@if [ "$(MODULE_PATH)" ] ; then \
(cd modules ; $(MAKE) install) ; \
fi
@if [ "$(RUNGROUP)" ] ; then \
echo chgrp -R $(RUNGROUP) $(DATDEST) ; \
chgrp -R $(RUNGROUP) $(DATDEST) ; \
echo chmod -R g+rw $(DATDEST) ; \
chmod -R g+rw $(DATDEST) ; \
echo find $(DATDEST) -type d -exec chmod g+xs \'\{\}\' \\\; ; \
find $(DATDEST) -type d -exec chmod g+xs '{}' \; ; \
fi
@echo ""
@echo "Don't forget to create/update your services.conf file! See"
@echo "the README for details."
@echo ""
###########################################################################
$(PROGRAM): version.h $(OBJS)
$(CC) $(LFLAGS) $(OBJS) $(LIBS) $(MLIBS) -o $@ $(ELIBS)
languages: FRC
(cd lang ; $(MAKE) CFLAGS="$(CFLAGS)")
modules: FRC
@if [ "$(MODULE_PATH)" ] ; then \
(cd modules ; ./configure ; $(MAKE) CFLAGS="$(CFLAGS)") \
fi
# Catch any changes in compilation options at the top of this file
$(OBJS): Makefile
actions.o: actions.c services.h
botserv.o: botserv.c services.h pseudo.h
channels.o: channels.c services.h
chanserv.o: chanserv.c services.h pseudo.h
commands.o: commands.c services.h commands.h language.h
compat.o: compat.c services.h
config.o: config.c services.h
converter.o: converter.c services.h datafiles.h
datafiles.o: datafiles.c services.h datafiles.h
encrypt.o: encrypt.c encrypt.h sysconf.h
init.o: init.c services.h
hostserv.o: hostserv.c services.h pseudo.h
language.o: language.c services.h language.h
list.o: list.c services.h
log.o: log.c services.h pseudo.h
mail.o: mail.c services.h language.h
main.o: main.c services.h timeout.h version.h
memory.o: memory.c services.h
memoserv.o: memoserv.c services.h pseudo.h
messages.o: messages.c services.h messages.h language.h
misc.o: misc.c services.h language.h
news.o: news.c services.h pseudo.h
nickserv.o: nickserv.c services.h pseudo.h
operserv.o: operserv.c services.h pseudo.h
process.o: process.c services.h messages.h
protocol.o: protocol.c services.h
proxy.o: proxy.c services.h pseudo.h
send.o: send.c services.h
sessions.o: sessions.c services.h pseudo.h
slist.o: slist.c services.h slist.h
sockutil.o: sockutil.c services.h
timeout.o: timeout.c services.h timeout.h
users.o: users.c services.h
vsnprintf.o: vsnprintf.c
services.h: sysconf.h config.h extern.h
touch $@
extern.h: slist.h
touch $@
pseudo.h: commands.h language.h timeout.h encrypt.h datafiles.h slist.h
touch $@
version.h: Makefile version.sh version.log services.h pseudo.h messages.h $(SRCS)
sh version.sh
language.h: lang/language.h
cp -p lang/language.h .
lang/language.h: lang/Makefile lang/index
(cd lang ; $(MAKE) language.h)
###########################################################################
FRC:
+93
View File
@@ -0,0 +1,93 @@
/* Various routines to perform simple actions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: actions.c,v 1.6 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
/* Note a bad password attempt for the given user. If they've used up
* their limit, toss them off.
*/
void bad_password(User * u)
{
time_t now = time(NULL);
if (!BadPassLimit)
return;
if (BadPassTimeout > 0 && u->invalid_pw_time > 0
&& u->invalid_pw_time < now - BadPassTimeout)
u->invalid_pw_count = 0;
u->invalid_pw_count++;
u->invalid_pw_time = now;
if (u->invalid_pw_count >= BadPassLimit)
#ifdef IRC_BAHAMUT
send_cmd(NULL, "SVSKILL %s :%s", u->nick,
"Too many invalid passwords");
#else
kill_user(NULL, u->nick, "Too many invalid passwords");
#endif
}
/*************************************************************************/
void change_user_mode(User * u, char *modes, char *arg)
{
#ifndef IRC_HYBRID
int ac = 1;
char *av[2];
av[0] = modes;
if (arg) {
av[1] = arg;
ac++;
}
#ifdef IRC_BAHAMUT
send_cmd(ServerName, "SVSMODE %s %ld %s%s%s", u->nick, u->timestamp,
av[0], (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
#else
send_cmd(ServerName, "SVSMODE %s %s%s%s", u->nick, av[0],
(ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
#endif
set_umode(u, ac, av);
#endif
}
/*************************************************************************/
/* Remove a user from the IRC network. `source' is the nick which should
* generate the kill, or NULL for a server-generated kill.
*/
void kill_user(const char *source, const char *user, const char *reason)
{
char *av[2];
char buf[BUFSIZE];
if (!user || !*user)
return;
if (!source || !*source)
source = ServerName;
if (!reason)
reason = "";
snprintf(buf, sizeof(buf), "%s (%s)", source, reason);
av[0] = sstrdup(user);
av[1] = buf;
send_cmd(source, "KILL %s :%s", user, av[1]);
do_kill(source, 2, av);
free(av[0]);
}
/*************************************************************************/
Executable
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
#
# $Id: checklang,v 1.1 2003/07/16 04:34:04 dane Exp $
#
if [ ! -f en_us.l ]; then
echo "*** You must run this script on the lang directory."
echo ""
exit 1
fi
for lang in $(ls *.l)
do
echo "*** CHECKING $lang ***"
./obs.pl $lang
done
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
if [ $1 = "-t" ] ; then
shift
fi
if [ ! "$2" ] ; then
echo >&2 Usage: $0 '<sourcedir> <targetdir>'
exit 1
fi
if [ -d "$1" ] ; then
dir="$1"
else
dir="`echo $1 | sed 's#\(.*\)/.*#\1#'`"
fi
while [ "$2" ] ; do
shift
done
if [ ! -d $1 ] ; then
mkdir -p $1 || exit 1
fi
/bin/tar -Ccf $dir - . | /bin/tar -Cxf $1 -
Executable
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
#
# $Id: fixlang,v 1.1 2003/07/16 04:34:04 dane Exp $
#
if [ ! -f en_us.l ]; then
echo "*** You must run this script on the lang directory."
echo ""
exit 1
fi
for lang in $(ls *.l)
do
echo "*** CHECKING $lang ***"
./fixlang.pl $lang
mv fixed.l $lang
done
Executable
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
#
# $Id: getanope,v 1.2 2003/11/24 20:23:28 dane Exp $
#
MODULE="anope-dev"
BRANCH=""
if [ "$1" == "" ]; then
DST="$MODULE"
else
DST="$1"
fi
let cnt="$(echo $CVSROOT | grep anope | wc -l)"
if [ $cnt -eq 0 ]; then
echo "*** Environment variable CVSROOT is not set. Please set it"
echo "*** if you have a developer account with write access."
echo ""
echo "*** Assuming anonymous access. If prompted for a password,"
echo "*** just press RETURN to continue."
echo ""
export CVSROOT=":pserver:pubcvs@zero.org:/home/cvs/anope"
let login="$(grep "pubcvs@zero.org" ~/.cvspass 2> /dev/null | grep anope | wc -l)"
if [ $login -eq 0 ]; then
cvs -d$CVSROOT login
fi
fi
echo "Checking out $MODULE"
if [ "$BRANCH" == "" ]; then
cvs -z3 -d$CVSROOT checkout -d$DST $MODULE
else
cvs -z3 -d$CVSROOT checkout -r$BRANCH -d$DST $MODULE
fi
echo "*** All done!"
exit 0
+239
View File
@@ -0,0 +1,239 @@
#!/usr/bin/perl
#
# Ribosome's all in one language tool
# 1) Compares to check for missing lines
# 2) Compares to check for equal lines
# 3) Fixes (on request) missing lines
# 4) Checks for errors in lines
# 5) Checks for long lines (>60 characters)
#
# Check to see if we have received arguments
if (!$ARGV[0]) {
print "Usage: $0 [language file]\n";
exit;
}
# If yes, set $sourcefile to the language filename
$testagainst = $ARGV[0];
# Set $sourcefile to en_us language file
$sourcefile = "en_us.l";
# Number of Keys in File, Number of Equal Lines, Number of Missing Lines
# Fixed Lines (optional) and Number of Format Error Lines, Number of Long Lines
my $numberlines = 0;
my $equallines = 0;
my $missinglines = 0;
my $fixedlines = 0;
my $errorline = 0;
my $longlines = 0;
# Array to hold the lines from the source file and explosion array for long line check
my @sourcearray;
my @explosion;
# Create associative arrays which will contain keys and definitions
# One for the control source and one for what is being tested against
my %sourcehash= ();
my %testhash= ();
# Check if Files Exist
if (! -f $sourcefile) {
print "Critical Error: The source file does not exist or is unreadable.\nNote: This tool must be run from the language directory.\n";
exit;
}
if (! -f $testagainst) {
print "Critical Error: The language file does not exist or is unreadable\n";
exit;
}
###########################################
# Function to load sourcefile into memory #
###########################################
sub load_sourcefile {
my $_key; # This variable will hold the key
my $_def; # This variable will hold the definition
my $line; # This variable will hold the current line
open (SOURCEFILE, "< $sourcefile"); # Open the source file
while (<SOURCEFILE>) { # For each line the source file
$line = $_; # $line is set to the line in the source file
# Skip comments
if (/^#/) { # This checks for # which indicates comment
next; # If detected, the next line is skipped to
}
# Start of a key
if (/^[A-Z]/) { # Checks to see if the line is a key
chomp($line); # Removes things that shouldn't be at the end
push (@sourcearray, $line); # Puts the line into the source array
# If a key is defined, load definition into the hash
if ($_key ne undef) { # If the key is defined
$sourcehash{$_key} = $_def; # Add the definition to the associative array
}
$_key=$line; # Set the key to the line
$_def=""; # Reset the definition
next; # Move onto the next line
}
if ($_key ne undef) { # If the key is set already
$_def.=$line; # The definition is the current line
}
$sourcehash{$_key} = $_def; # Load the definition into the associative array
} # End of while which reads lines
close (SOURCEFILE); # Close the source file
} # End of load_sourcefile function
#################################################
# Function to load testagainst file into memory #
#################################################
sub load_testagainst {
my $_key; # This variable will hold the key
my $_def; # This variable will hold the definition
my $line; # This variable will hold the current line
open (TESTAGAINSTFILE, "< $testagainst"); # Open the file containing the control lines
while (<TESTAGAINSTFILE>) { # For each line in the file
$line = $_; # $line is set to the lines value
# Skip comments
if (/^#/) { # This checks for # which indicates comment
next; # If detected, the next line is skipped to
}
# Start of a key
if (/^[A-Z]/) { # Checks to see if the line is a key
chomp($line); # Removes things that shouldn't be at the end
if ($_key ne undef) { # If the key is defined
$testhash{$_key} = $_def; # Add the definition to the associative array
}
$_key=$line; # Set the key to the line
$_def=""; # Reset the definition
next; # Move onto the next line
}
if ($_key ne undef) { # If the key is set already
$_def.=$line; # The definition is the current line
}
$testhash{$_key} = $_def; # Load the definition into the associative array
} # End of while which reads lines
close (TESTAGAINSTFILE); # Close the source file
}
sub get_format { # Function to get the formatting from a string
my $fmt="";
my $str=shift; # Get the input
while ($str =~ m/%\w/g) {
$fmt .= $&;
}
return $fmt; # Return the formatting
}
load_sourcefile; # Call function to load the source file
load_testagainst; # Call function to load the test file
if (!grep(/^LANG_NAME/,%testhash)) {
print "Critical Error: $ARGV[0] is not a valid language file!\n";
exit;
}
open (LOG,"> langcheck.log"); # Open logfile for writing
foreach $sourcearray (@sourcearray) { # For each key stored in the source array
my $_key=$_; # Store key from source array in $_key
if ((get_format($sourcehash{$sourcearray})) ne (get_format($testhash{$sourcearray}))) {
if ($sourcearray !~ STRFTIME ) {
$errorline++;
print LOG "FORMAT: $sourcearray - (expecting '".get_format($sourcehash{$sourcearray})."' and got '".get_format($testhash{$sourcearray})."')\n";
} }
if ($testhash{$sourcearray} eq $sourcehash{$sourcearray} ) {
# If the definitions between the source and the test are equal
$equallines++; # Number of equal lines increases
print LOG "EQUAL: $sourcearray\n"; # Line is written to logfile
}
if (!grep(/^$sourcearray/,%testhash)) { # If the key is found in the testhash associative array
$missinglines++; # Increase missing lines
print LOG "MISSING: $sourcearray\n"; # Line is written to logfile
}
@explosion = split(/\n/, $testhash{$sourcearray});
foreach $explosion (@explosion) {
$explosion =~ s/\002//g;
$explosion =~ s/\037//g;
if (length($explosion) > 61) {
print LOG "LONGLINE: $sourcearray (".substr($explosion,1,30)."...)\n";
$longlines++;
}
}
$numberlines++; # Increase the number of lines tested by 1
}
close (LOG); # Close the logfile
#########################
# Show the test results #
#########################
print "Calculation Results:\n";
print "----------------------------------\n";
print "[$numberlines] line(s) were compared\n";
print "[$equallines] line(s) were found to equal their $sourcefile counterpart(s)\n";
print "[$missinglines] line(s) were found to be missing\n";
print "[$longlines] line(s) were found to be long (>60 chars)\n";
print "[$errorline] line(s) were found to have formatting errors\n";
print "The specific details of the test have been saved in langcheck.log\n";
if ($missinglines) { # If missing lines exist
print "----------------------------------\n";
print "Missing line(s) have been detected in this test, would you like to fix the file?\n";
print "This automatically inserts values from the control file ($sourcefile) for the missing values\n";
print "y/N? (Default: No) ";
my $input = <STDIN>; # Ask if the file should be fixed
if ((substr($input,0,1) eq "y") || (substr($input,0,1) eq "Y")) { # If Yes...
open (FIX, ">> $testagainst"); # Open the file and append changes
foreach $sourcearray (@sourcearray) { # For each key stored in the source array
my $_key=$_; # Store key from source array in $_key
if (!grep(/^$sourcearray/,%testhash)) { # If the key is not found in the testhash associative array
print FIX "$sourcearray\n$sourcehash{$sourcearray}"; # Add the line(s) to the language file
$fixedlines++; # Increase the fixed line count
}
}
close (FIX); # Close file after fixing
print "Fixing Compete. [$fixedlines] line(s) fixed.\n";
exit; # And Exit!
}
# Otherwise, quit without fixing
print "Exiting. The language file has NOT been fixed.\n";
}
Executable
+83
View File
@@ -0,0 +1,83 @@
#!/bin/bash
# Daniel Engel (dane@zero.org)
#
# Creates a patch from any version of Anope to another within the
# same CVS module (in this case, anope-rel). Usage:
#
# ./anope-mkpatch 1.5.1 1.5.5
#
# The earliest version you can use is 1.5.1 (the first CVS tag)
#
# Feel free to improve this script at will.
#
CVSROOT=":pserver:pubcvs@zero.org:/home/cvs/anope"
MODULE="anope-dev"
OLD="$1"
NEW="$2"
NAME="$1-$2.diff"
echo "*** Note: This script is able to create patches from one version of 1.5.x"
echo "*** to anoter. The earliest valid version is 1.5.1, and you can only make"
echo "*** a patch between two released versions (i.e. no -rnum versions)"
echo ""
if [[ $OLD == "" ]]; then
echo "*** Usage: $0 [OLD] [NEW]"
exit 0
fi
if [[ $NEW == "" ]]; then
echo "*** Usage: $0 [OLD] [NEW]"
exit 0
fi
OLD="anope-$OLD"
NEW="anope-$NEW"
if [[ -d $OLD ]]; then
echo "*** Directory $OLD already exists... aborting."
exit 0
fi
if [[ -d $NEW ]]; then
echo "*** Directory $OLD already exists... aborting."
exit 0
fi
echo "*** Issuing the CVS login, when prompted for a password, just press RETURN..."
cvs -d $CVSROOT login
if [[ $? -ne 0 ]]; then
echo "*** ERROR: CVS login failed... aborting."
exit 0
fi
TOLD="$(echo $OLD | sed 's/\./_/g')"
TNEW="$(echo $NEW | sed 's/\./_/g')"
echo "*** Cheking out $MODULE ($TOLD)"
cvs -d $CVSROOT checkout -r $TOLD -d $OLD $MODULE > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "*** ERROR: Unable to checkout $MODULE ($TNEW)... aborting."
exit 0
fi
echo "*** Cheking out $MODULE ($TNEW)"
cvs -d $CVSROOT checkout -r $TNEW -d $NEW $MODULE > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "*** ERROR: Unable to checkout $MODULE ($TNEW)... aborting."
exit 0
fi
# I wish i could use cvsrmadm here, but not everybody has it :(
echo "*** Removing CVS control files"
find $OLD -name CVS -exec rm -rf {} \; > /dev/null 2>&1
find $NEW -name CVS -exec rm -rf {} \; > /dev/null 2>&1
echo "*** Creating the patch..."
diff -urN $OLD $NEW > $NAME
echo "*** Done! The patch is $NAME";
echo "*** You might want to clean things up with:"
echo "*** rm -rf $OLD $NEW"
Executable
+194
View File
@@ -0,0 +1,194 @@
#!/bin/sh
#
# Location of the .sql file with the schema
DBFILE="data/tables.sql"
# Schema Version
SVER="1"
# Local Version, defaults to 0
LVER="0"
TFILE="/tmp/.anopedb.$$"
if [ "`eval echo -n 'a'`" = "-n a" ] ; then
c="\c"
else
n="-n"
fi
if [ ! -f $DBFILE ] ; then
echo "Error: Required file $DBFILE is inaccessible!";
exit
fi
echo ""
echo "This script will guide you through the process of configuring your Anope"
echo "installation to make use of MySQL support. This script must be used for both"
echo "new installs as well as for upgrading for users who have a previous version"
echo "of Anope installed"
while [ -z "$SQLHOST" ] ; do
echo ""
echo "What is the hostname of your MySQL server?"
echo $n "-> $c"
read cc
if [ ! -z "$cc" ] ; then
SQLHOST=$cc
fi
done
while [ -z "$SQLUSER" ] ; do
echo ""
echo "What is your MySQL username?"
echo $n "-> $c"
read cc
if [ ! -z "$cc" ] ; then
SQLUSER=$cc
fi
done
OLD_TTY=`stty -g`
echo ""
echo "What is your MySQL password?"
echo $n "-> $c"
stty -echo echonl
read cc
if [ ! -z "$cc" ] ; then
SQLPASS=$cc
fi
stty $OLD_TTY
mysqlshow -h$SQLHOST -u$SQLUSER -p$SQLPASS >/dev/null 2>&1
if test "$?" = "1" ; then
echo "Error: Unable to login, verify your login/password and hostname"
exit
fi
while [ -z "$SQLDB" ] ; do
echo ""
echo "What is the name of the Anope SQL database?"
echo $n "-> $c"
read cc
if [ ! -z "$cc" ] ; then
SQLDB=$cc
fi
done
MYSQLSHOW="mysqlshow -h$SQLHOST -u$SQLUSER -p$SQLPASS $SQLDB"
MYSQL="mysql -h$SQLHOST -u$SQLUSER -p$SQLPASS $SQLDB"
echo ""
$MYSQLHOW >/dev/null 2>&1
if test "$?" = "1" ; then
echo "It appears that database does not exist. Or that you don't have the"
echo "correct credentials to access it. Please verify that you have entered"
echo "the correct values."
exit
fi
res="$($MYSQL -Bs -e "show tables like 'anope_os_core'" | wc -l)"
if test "$res" = "0" ; then
echo -n "Unable to find Anope schema, creating... "
mysql -h$SQLHOST -u$SQLUSER -p$SQLPASS $SQLDB < $DBFILE
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'schema creation'"
fi
else
# Introduced on Anope 1.6.0 -> Table anope_info
res="$($MYSQL -Bs -e "show tables like 'anope_info'" | wc -l)"
if test "$res" = "0" ; then
echo -n "Unable to find Anope info table, creating... "
echo "CREATE TABLE anope_info (version int, date datetime) TYPE=MyISAM" > $TFILE
mysql -h$SQLHOST -u$SQLUSER -p$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'anope_info table'"
fi
else
LVER="$($MYSQL -sB -e "select version from anope_info")"
if test "x$LVER" = "x" ; then
LVER=0
fi
fi
# Introduced on Anope 1.5.14.5 -> anope_cs_info.memomax
res="$($MYSQL -Bs -e "describe anope_cs_info memomax" 2> /dev/null | wc -l)"
if test "$res" = "0" ; then
echo -n "Unable to find anope_cs_info.memomax, altering... "
echo "ALTER TABLE anope_cs_info ADD memomax smallint unsigned NOT NULL default 0" > $TFILE
mysql -h$SQLHOST -u$SQLUSER -p$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'anope_cs_info.ttb alter'"
fi
fi
# Introduced on Anope 1.5.14.5 -> anope_cs_info.ttb
res="$($MYSQL -Bs -e "describe anope_cs_info ttb" | wc -l)"
if test "$res" = "0" ; then
echo -n "Unable to find anope_cs_info.ttb, altering... "
echo "ALTER TABLE anope_cs_info ADD ttb smallint NOT NULL default 0" > $TFILE
mysql -h$SQLHOST -u$SQLUSER -p$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'anope_cs_info.ttb alter'"
fi
fi
fi
# Insert initial version number. This will have to be redesigned for 1.7
if [ $LVER -ne $SVER ]; then
echo -n "Inserting initial version number... "
$MYSQL -Bs -e "delete from anope_info"
echo "INSERT INTO anope_info (version, date) VALUES ($SVER, now())" > $TFILE
$MYSQL < $TFILE >/dev/null 2>&1
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'version insert'"
fi
fi
rm -f $TFILE
if test "x$FAILED" = "x" ; then
# Try to find out more about this installation
SQLSOCK="$(mysql_config --socket 2> /dev/null)"
SQLPORT="$(mysql_config --port 2> /dev/null)"
echo ""
echo "Your MySQL setup is complete and your Anope schema is up to date. Make"
echo "sure you configure MySQL on your services.conf file prior to launching"
echo "Anope with MySQL support. Your configuration values are:"
echo ""
echo "MysqlHost \"$SQLHOST\""
echo "MysqlUser \"$SQLUSER\""
echo "MysqlPass \"$SQLPASS\""
echo "MysqlName \"$SQLDB\""
echo "MysqlSock \"$SQLSOCK\""
echo "MysqlPort \"$SQLPORT\""
echo ""
else
echo "The following operations failed:"
echo "$FAILED"
fi
exit
Executable
+104
View File
@@ -0,0 +1,104 @@
#!/bin/sh
#
# $Id: putanope,v 1.14 2003/12/02 23:02:28 joris Exp $
#
CTRL="version.log"
MODULE="anope-dev"
TMP="/tmp/putanope.$$"
TMP2="/tmp/putanope2.$$"
# We need an editor for the log entry
if [ "$EDITOR" == "" ]; then
EDITOR="vi"
fi
# Use default target, or provided?
if [ "$1" == "" ]; then
DST="$MODULE"
else
DST="$1"
fi
# Find where to run the rest of the script from.
if [ ! -d $DST ]; then
cd ..
if [ ! -d $DST ]; then
cd ..
if [ ! -d $DST ]; then
echo "*** Directory $DST does not exist, what's going on?"
echo ""
exit 1
fi
fi
fi
# CVSROOT dosnt need to be set, just read it form the CVS file :-)
CVSROOT=`cat ${DST}/CVS/Root`
cd $DST
# source control file
. $CTRL
# Version arithmetics
CVER="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_BUILD}"
let minor="$(echo $VERSION_BUILD)"
let new="$minor + 1"
NVER="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${new}"
# Greet the developer
echo ""
echo "*** Using CVSROOT: $CVSROOT"
echo "*** Using module : $MODULE"
echo "*** Current ver : $CVER"
echo "*** Updated ver : $NVER"
echo ""
echo "*** Make sure you have updated Changes, Changes.conf, and"
echo "*** Changes.lang acordingly before you proceed."
echo -n "*** Ready to continue? (RETURN if so, CTRL-C otherwise) "
read FOO
cat > $TMP2 <<EOF
# Anope commit utility. Please use this template for your commits.
# Add Mantis bugs separated by spaces. The note part is free form.
BUILD : $NVER
BUGS :
NOTES :
EOF
$EDITOR $TMP2
echo "*** Ready to commit, please verify:"
echo ""
grep -v "^#" $TMP2
echo ""
echo -n "*** Perform commit? (RETURN if so, CTRL-C otherwise) "
read FOO
echo "*** Running indent..."
for source in *.c
do
indent -kr -nut $source
done
# Clean up indent backup files
rm -f *~
echo "*** Bumping the version number..."
sed "s/VERSION_BUILD=\"$VERSION_BUILD\"/VERSION_BUILD=\"$new\"/" $CTRL > $TMP
cat $TMP > $CTRL
TS="$(date '+%F %R')"
grep -v "^#" $TMP2 > $TMP
echo "VTAG : cvs checkout -D \"$TS\" $MODULE" >> $TMP
cd ..
cvs -d$CVSROOT commit -F $TMP $DST
rm -f $TMP $TMP2
echo "*** Done!"
exit 0
+2512
View File
File diff suppressed because it is too large Load Diff
+1595
View File
File diff suppressed because it is too large Load Diff
+6187
View File
File diff suppressed because it is too large Load Diff
+178
View File
@@ -0,0 +1,178 @@
/* Routines for looking up commands in a *Serv command list.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: commands.c,v 1.13 2003/09/22 21:40:23 rob Exp $
*
*/
#include "services.h"
#include "commands.h"
#include "language.h"
/*************************************************************************/
/* Return the Command corresponding to the given name, or NULL if no such
* command exists.
*/
Command *lookup_cmd(Command * list, const char *cmd)
{
Command *c;
for (c = list; c->name; c++) {
if (stricmp(c->name, cmd) == 0)
return c;
}
return NULL;
}
/*************************************************************************/
/* Run the routine for the given command, if it exists and the user has
* privilege to do so; if not, print an appropriate error message.
*/
void run_cmd(const char *service, User * u, Command * list,
const char *cmd)
{
Command *c = lookup_cmd(list, cmd);
do_run_cmd(service, u, c, cmd);
}
void mod_run_cmd(const char *service, User * u, CommandHash * cmdTable[],
const char *cmd)
{
Command *c = findCommand(cmdTable, cmd);
do_run_cmd(service, u, c, cmd);
}
void do_run_cmd(const char *service, User * u, Command * c,
const char *cmd)
{
int retVal = 0;
Command *current;
if (c && c->routine) {
if ((checkDefCon(DEFCON_OPER_ONLY)
|| checkDefCon(DEFCON_SILENT_OPER_ONLY)) && !is_oper(u)) {
if (!checkDefCon(DEFCON_SILENT_OPER_ONLY)) {
notice_lang(service, u, OPER_DEFCON_DENIED);
}
} else {
if ((c->has_priv == NULL) || c->has_priv(u)) {
mod_current_module_name = c->mod_name;
retVal = c->routine(u);
mod_current_module_name = NULL;
if (retVal == MOD_CONT) {
current = c->next;
while (current && retVal == MOD_CONT) {
mod_current_module_name = c->mod_name;
retVal = current->routine(u);
mod_current_module_name = NULL;
current = current->next;
}
}
}
else {
notice_lang(service, u, ACCESS_DENIED);
alog("Access denied for %s with service %s and command %s",
u->nick, service, cmd);
}
}
} else {
if ((!checkDefCon(DEFCON_SILENT_OPER_ONLY)) || is_oper(u))
notice_lang(service, u, UNKNOWN_COMMAND_HELP, cmd, service);
}
}
/*************************************************************************/
/* Print a help message for the given command. */
void do_help_cmd(const char *service, User * u, Command * c,
const char *cmd)
{
Command *current;
int has_had_help = 0;
int cont = MOD_CONT;
const char *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
for (current = c; (current) && (cont == MOD_CONT);
current = current->next) {
p1 = current->help_param1;
p2 = current->help_param2;
p3 = current->help_param3;
p4 = current->help_param4;
if (current->helpmsg_all >= 0) {
notice_help(service, u, current->helpmsg_all, p1, p2, p3, p4);
has_had_help = 1;
} else if (current->all_help) {
cont = current->all_help(u);
has_had_help = 1;
}
if (is_services_root(u)) {
if (current->helpmsg_root >= 0) {
notice_help(service, u, current->helpmsg_root, p1, p2, p3,
p4);
has_had_help = 1;
} else if (current->root_help) {
cont = current->root_help(u);
has_had_help = 1;
}
} else if (is_services_admin(u)) {
if (current->helpmsg_admin >= 0) {
notice_help(service, u, current->helpmsg_admin, p1, p2, p3,
p4);
has_had_help = 1;
} else if (current->admin_help) {
cont = current->admin_help(u);
has_had_help = 1;
}
} else if (is_services_oper(u)) {
if (current->helpmsg_oper >= 0) {
notice_help(service, u, current->helpmsg_oper, p1, p2, p3,
p4);
has_had_help = 1;
} else if (current->oper_help) {
cont = current->oper_help(u);
has_had_help = 1;
}
} else {
if (current->helpmsg_reg >= 0) {
notice_help(service, u, current->helpmsg_reg, p1, p2, p3,
p4);
has_had_help = 1;
} else if (current->regular_help) {
cont = current->regular_help(u);
has_had_help = 1;
}
}
}
if (has_had_help == 0) {
notice_lang(service, u, NO_HELP_AVAILABLE, cmd);
}
}
void help_cmd(const char *service, User * u, Command * list,
const char *cmd)
{
Command *c = lookup_cmd(list, cmd);
do_help_cmd(service, u, c, cmd);
}
void mod_help_cmd(const char *service, User * u, CommandHash * cmdTable[],
const char *cmd)
{
Command *c = findCommand(cmdTable, cmd);
do_help_cmd(service, u, c, cmd);
}
/*************************************************************************/
+34
View File
@@ -0,0 +1,34 @@
/* Declarations for command data.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: commands.h,v 1.6 2003/08/16 22:13:47 rob Exp $
*
*/
#include "modules.h"
/*************************************************************************/
/* Routines for looking up commands. Command lists are arrays that must be
* terminated with a NULL name.
*/
extern Command *lookup_cmd(Command *list, const char *name);
extern void run_cmd(const char *service, User *u, Command *list,
const char *name);
extern void help_cmd(const char *service, User *u, Command *list,
const char *name);
extern void do_run_cmd(const char *service, User * u, Command *c,const char *cmd);
extern void do_help_cmd(const char *service, User * u, Command *c,const char *cmd);
extern void mod_help_cmd(const char *service, User *u, CommandHash *cmdTable[],const char *cmd);
extern void mod_run_cmd(const char *service, User *u, CommandHash *cmdTable[],const char *cmd);
extern char *mod_current_module_name;
/*************************************************************************/
+212
View File
@@ -0,0 +1,212 @@
/* Compatibility routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: compat.c,v 1.5 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
#if !HAVE_SNPRINTF
/* [v]snprintf: Like [v]sprintf, but don't write more than len bytes
* (including null terminator). Return the number of bytes
* written.
*/
#if BAD_SNPRINTF
int vsnprintf(char *buf, size_t len, const char *fmt, va_list args)
{
if (len <= 0)
return 0;
*buf = 0;
#undef vsnprintf
vsnprintf(buf, len, fmt, args);
#define vsnprintf my_vsnprintf
buf[len - 1] = 0;
return strlen(buf);
}
#endif /* BAD_SNPRINTF */
int snprintf(char *buf, size_t len, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
return vsnprintf(buf, len, fmt, args);
}
#endif /* !HAVE_SNPRINTF */
/*************************************************************************/
#if !HAVE_STRICMP && !HAVE_STRCASECMP
/* stricmp, strnicmp: Case-insensitive versions of strcmp() and
* strncmp().
*/
int stricmp(const char *s1, const char *s2)
{
register int c;
while ((c = tolower(*s1)) == tolower(*s2)) {
if (c == 0)
return 0;
s1++;
s2++;
}
if (c < tolower(*s2))
return -1;
return 1;
}
int strnicmp(const char *s1, const char *s2, size_t len)
{
register int c;
if (!len)
return 0;
while ((c = tolower(*s1)) == tolower(*s2) && len > 0) {
if (c == 0 || --len == 0)
return 0;
s1++;
s2++;
}
if (c < tolower(*s2))
return -1;
return 1;
}
#endif
/*************************************************************************/
#if !HAVE_STRDUP
char *strdup(const char *s)
{
char *new = calloc(strlen(s) + 1, 1);
if (new)
strcpy(new, s);
return new;
}
#endif
/*************************************************************************/
#if !HAVE_STRSPN
size_t strspn(const char *s, const char *accept)
{
size_t i = 0;
while (*s && strchr(accept, *s))
++i, ++s;
return i;
}
#endif
/*************************************************************************/
#if !HAVE_STRERROR
# if HAVE_SYS_ERRLIST
extern char *sys_errlist[];
# endif
char *strerror(int errnum)
{
# if HAVE_SYS_ERRLIST
return sys_errlist[errnum];
# else
static char buf[20];
snprintf(buf, sizeof(buf), "Error %d", errnum);
return buf;
# endif
}
#endif
/*************************************************************************/
#if !HAVE_STRSIGNAL
char *strsignal(int signum)
{
static char buf[32];
switch (signum) {
case SIGHUP:
strscpy(buf, "Hangup", sizeof(buf));
break;
case SIGINT:
strscpy(buf, "Interrupt", sizeof(buf));
break;
case SIGQUIT:
strscpy(buf, "Quit", sizeof(buf));
break;
#ifdef SIGILL
case SIGILL:
strscpy(buf, "Illegal instruction", sizeof(buf));
break;
#endif
#ifdef SIGABRT
case SIGABRT:
strscpy(buf, "Abort", sizeof(buf));
break;
#endif
#if defined(SIGIOT) && (!defined(SIGABRT) || SIGIOT != SIGABRT)
case SIGIOT:
strscpy(buf, "IOT trap", sizeof(buf));
break;
#endif
#ifdef SIGBUS
case SIGBUS:
strscpy(buf, "Bus error", sizeof(buf));
break;
#endif
case SIGFPE:
strscpy(buf, "Floating point exception", sizeof(buf));
break;
case SIGKILL:
strscpy(buf, "Killed", sizeof(buf));
break;
case SIGUSR1:
strscpy(buf, "User signal 1", sizeof(buf));
break;
case SIGSEGV:
strscpy(buf, "Segmentation fault", sizeof(buf));
break;
case SIGUSR2:
strscpy(buf, "User signal 2", sizeof(buf));
break;
case SIGPIPE:
strscpy(buf, "Broken pipe", sizeof(buf));
break;
case SIGALRM:
strscpy(buf, "Alarm clock", sizeof(buf));
break;
case SIGTERM:
strscpy(buf, "Terminated", sizeof(buf));
break;
case SIGSTOP:
strscpy(buf, "Suspended (signal)", sizeof(buf));
break;
case SIGTSTP:
strscpy(buf, "Suspended", sizeof(buf));
break;
case SIGIO:
strscpy(buf, "I/O error", sizeof(buf));
break;
default:
snprintf(buf, sizeof(buf), "Signal %d\n", signum);
break;
}
return buf;
}
#endif
/*************************************************************************/
+1283
View File
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
/* Services configuration.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: config.h,v 1.7 2003/09/04 18:55:34 rob Exp $
*
*/
#ifndef CONFIG_H
#define CONFIG_H
/* Note that most of the options which used to be here have been moved to
* services.conf. */
/*************************************************************************/
/******* General configuration *******/
/* Name of configuration file (in Services directory) */
#define SERVICES_CONF "services.conf"
/* Name of log file (in Services directory) */
#define LOG_FILENAME "services.log"
/* Maximum amount of data from/to the network to buffer (bytes). */
#define NET_BUFSIZE 65536
/******* OperServ configuration *******/
/* How big a hostname list do we keep for clone detection? On large nets
* (over 500 simultaneous users or so), you may want to increase this if
* you want a good chance of catching clones. */
#define CLONE_DETECT_SIZE 16
/* Define this to enable OperServ's svs commands (superadmin only). */
#define USE_OSSVS
/* Define this to enable OperServ's debugging commands (Services root
* only). These commands are undocumented; "use the source, Luke!" */
/* #define DEBUG_COMMANDS */
/******************* END OF USER-CONFIGURABLE SECTION ********************/
/* Size of input buffer (note: this is different from BUFSIZ)
* This must be big enough to hold at least one full IRC message, or messy
* things will happen. */
#define BUFSIZE 1024
/* Extra warning: If you change CHANMAX, your ChanServ database will be
* unusable.
*/
/* Maximum length of a channel name, including the trailing null. Any
* channels with a length longer than (CHANMAX-1) including the leading #
* will not be usable with ChanServ. */
#define CHANMAX 64
/* Maximum length of a nickname, including the trailing null. This MUST be
* at least one greater than the maximum allowable nickname length on your
* network, or people will run into problems using Services! The default
* (32) works with all servers I know of. */
#define NICKMAX 32
/* Maximum length of a password */
#define PASSMAX 32
/* Maximum length of a username */
#define USERMAX 10
/* Maximum length of a domain */
#define HOSTMAX 64
/**************************************************************************/
#endif /* CONFIG_H */
Vendored Executable
+1858
View File
File diff suppressed because it is too large Load Diff
+398
View File
@@ -0,0 +1,398 @@
/* Database converters.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: converter.c,v 1.5 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
#include "datafiles.h"
/* Each converter will try to convert the databases to the format used
* by ircservices-4.3 (that is compatible with Epona).
*/
#ifdef USE_CONVERTER
/*************************************************************************/
#define IS43_VERSION 7
#define SAFER(x) do { \
if ((x) < 0) { \
fatal("Read error on %s", rdb); \
return 0; \
} \
} while (0)
#define SAFEW(x) do { \
if ((x) < 0) { \
fatal("Write error on %s", wdb); \
return 0; \
} \
} while (0)
/*************************************************************************/
/*****************************ircservices-4.4*****************************/
/*************************************************************************/
#ifdef IS44_CONVERTER
#define IS44_VERSION 8
#define IS44_CA_SIZE 13
int convert_ircservices_44(void)
{
dbFILE *f, *g; /* f for reading, g for writing */
int c, i, j;
char *rdb, *wdb;
char *tmp;
int16 tmp16;
int32 tmp32;
char nick[NICKMAX];
char pass[PASSMAX];
char chan[CHANMAX];
/* NickServ database */
if (rename("nick.db", "nick.db.old") == -1) {
fatal("Converter: unable to rename nick.db to nick.db.old: %s",
strerror(errno));
return 0;
}
if (!(f = open_db(s_NickServ, "nick.db.old", "r", IS44_VERSION))) {
fatal("Converter: unable to open nick.db.old in read access: %s",
strerror(errno));
return 0;
}
if (!(g = open_db(s_NickServ, NickDBName, "w", IS43_VERSION))) {
fatal("Converter: unable to open %s in write access: %s",
NickDBName, strerror(errno));
return 0;
}
rdb = sstrdup("nick.db.old");
wdb = sstrdup(NickDBName);
get_file_version(f);
for (i = 0; i < 256; i++) {
while ((c = getc_db(f)) == 1) {
if (c != 1)
fatal("Invalid format in %s", wdb);
SAFEW(write_int8(1, g));
SAFER(read_buffer(nick, f));
SAFEW(write_buffer(nick, g));
SAFER(read_buffer(pass, f));
SAFEW(write_buffer(pass, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
if (tmp) {
if (tmp)
free(tmp);
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
} else {
int32 flags;
int16 memocount, accesscount;
SAFER(read_int32(&flags, f));
tmp32 = (flags & ~0x10000000);
SAFEW(write_int32(tmp32, g));
/* Suspend stuff that we don't convert */
if (flags & 0x10000000) {
SAFER(read_buffer(nick, f));
SAFER(read_string(&tmp, f));
if (tmp)
free(tmp);
SAFER(read_int32(&tmp32, f));
SAFER(read_int32(&tmp32, f));
}
SAFER(read_int16(&tmp16, f));
accesscount = tmp16;
SAFEW(write_int16(tmp16, g));
if (accesscount) {
for (j = 0; j < accesscount; j++) {
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
}
}
SAFER(read_int16(&memocount, f));
SAFEW(write_int16(memocount, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
if (memocount) {
for (j = 0; j < memocount; j++) {
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_buffer(nick, f));
SAFEW(write_buffer(nick, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
}
}
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
}
} /* while (getc_db(f) != 0) */
SAFEW(write_int8(0, g));
} /* for (i) */
close_db(f);
close_db(g);
free(rdb);
free(wdb);
/* ChanServ */
rdb = sstrdup("chan.db.old");
wdb = sstrdup(ChanDBName);
if (rename("chan.db", rdb) == -1) {
fatal("Converter: unable to rename chan.db to %s: %s", rdb,
strerror(errno));
return 0;
}
if (!(f = open_db(s_ChanServ, rdb, "r", IS44_VERSION))) {
fatal("Converter: unable to open %s in read access: %s", rdb,
strerror(errno));
return 0;
}
if (!(g = open_db(s_ChanServ, wdb, "w", IS43_VERSION))) {
fatal("Converter: unable to open %s in write access: %s", wdb,
strerror(errno));
return 0;
}
get_file_version(f);
for (i = 0; i < 256; i++) {
while ((c = getc_db(f)) != 0) {
int16 n_levels, accesscount, akickcount, memocount;
if (c != 1)
fatal("Invalid format in %s", wdb);
SAFEW(write_int8(1, g));
SAFER(read_buffer(chan, f));
SAFEW(write_buffer(chan, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_buffer(pass, f));
SAFEW(write_buffer(pass, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_buffer(nick, f));
SAFEW(write_buffer(nick, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int16(&n_levels, f));
SAFEW(write_int16(n_levels, g));
for (j = 0; j < n_levels; j++) {
SAFER(read_int16(&tmp16, f));
if (j < IS44_CA_SIZE)
SAFEW(write_int16(tmp16, g));
}
SAFER(read_int16(&accesscount, f));
SAFEW(write_int16(accesscount, g));
if (accesscount) {
for (j = 0; j < accesscount; j++) {
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
if (tmp16) {
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
}
}
}
SAFER(read_int16(&akickcount, f));
SAFEW(write_int16(akickcount, g));
if (akickcount) {
for (j = 0; j < akickcount; j++) {
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
if (tmp16) {
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_buffer(nick, f));
}
}
}
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
SAFER(read_int16(&memocount, f));
SAFEW(write_int16(memocount, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
if (memocount) {
for (j = 0; j < memocount; j++) {
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_int16(&tmp16, f));
SAFEW(write_int16(tmp16, g));
SAFER(read_int32(&tmp32, f));
SAFEW(write_int32(tmp32, g));
SAFER(read_buffer(nick, f));
SAFER(write_buffer(nick, g));
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
}
}
SAFER(read_string(&tmp, f));
SAFEW(write_string(tmp, g));
if (tmp)
free(tmp);
} /* while (getc_db(f) != 0) */
SAFEW(write_int8(0, g));
} /* for (i) */
close_db(f);
close_db(g);
free(rdb);
free(wdb);
return 1;
}
#endif
/*************************************************************************/
#endif
/*************************************************************************/
+44
View File
@@ -0,0 +1,44 @@
#!/bin/sh
# Crontab script for Anope
#
# To know how to install the crontab, read the INSTALL file.
###############################################################
# CONFIGURATION
###############################################################
# Anope binary directory
ANOPATH=/home/ircd/services/
# Name of the pid file
ANOPIDF=services.pid
# Name of the executable
ANOPROG=services
# Parameters to pass to the executable
ANOARGS=""
#ANOARGS="-debug"
###############################################################
# DON'T EDIT ANYTHING BELOW #
###############################################################
PATH=/bin:/usr/bin:/usr/local/bin
ANOPID=
cd $ANOPATH
if [ -f $ANOPIDF ]
then
ANOPID=`cat $ANOPIDF`
if [ `ps ux| grep $ANOPROG | grep $ANOPID | grep -v -c grep` = 1 ]
then
exit
fi
rm -f $ANOPIDF
fi
./$ANOPROG $ANOARGS
+1450
View File
File diff suppressed because it is too large Load Diff
+470
View File
@@ -0,0 +1,470 @@
-- If you need to create your db, uncomment the following lines.
-- create database anope;
-- use anope;
--
-- Table structure for table `anope_info`
--
DROP TABLE IF EXISTS anope_info;
CREATE TABLE anope_info (
version int(11) default NULL,
date datetime default NULL
) TYPE=MyISAM;
--
-- Table structure for table `anope_bs_core`
--
DROP TABLE IF EXISTS anope_bs_core;
CREATE TABLE anope_bs_core (
bs_id int(11) NOT NULL auto_increment,
nick varchar(255) NOT NULL default '',
user text NOT NULL,
host text NOT NULL,
rname text NOT NULL,
flags int(11) NOT NULL default '0',
created int(11) NOT NULL default '0',
chancount int(11) NOT NULL default '0',
PRIMARY KEY (bs_id),
UNIQUE KEY nick (nick),
KEY nick_index (nick(10))
) TYPE=MyISAM;
--
-- Table structure for table `anope_cs_access`
--
DROP TABLE IF EXISTS anope_cs_access;
CREATE TABLE anope_cs_access (
ca_id int(11) NOT NULL auto_increment,
in_use int(11) NOT NULL default '0',
level int(11) NOT NULL default '0',
display varchar(255) NOT NULL default '',
channel varchar(255) NOT NULL default '',
last_seen int(11) NOT NULL default '0',
PRIMARY KEY (ca_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_cs_akicks`
--
DROP TABLE IF EXISTS anope_cs_akicks;
CREATE TABLE anope_cs_akicks (
ck_id int(11) NOT NULL auto_increment,
channel varchar(255) NOT NULL default '',
flags int(11) NOT NULL default '0',
dmask text NOT NULL,
reason text NOT NULL,
creator text NOT NULL,
addtime int(11) NOT NULL default '0',
PRIMARY KEY (ck_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_cs_badwords`
--
DROP TABLE IF EXISTS anope_cs_badwords;
CREATE TABLE anope_cs_badwords (
cw_id int(11) NOT NULL auto_increment,
channel varchar(255) NOT NULL default '',
word text NOT NULL,
type int(11) NOT NULL default '0',
PRIMARY KEY (cw_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_cs_info`
--
DROP TABLE IF EXISTS anope_cs_info;
CREATE TABLE anope_cs_info (
ci_id int(11) NOT NULL auto_increment,
name varchar(255) NOT NULL default '',
founder text NOT NULL,
successor text NOT NULL,
founderpass tinyblob NOT NULL,
descr text NOT NULL,
url text NOT NULL,
email text NOT NULL,
time_registered int(10) unsigned NOT NULL default '0',
last_used int(10) unsigned NOT NULL default '0',
last_topic text NOT NULL,
last_topic_setter text NOT NULL,
last_topic_time int(10) unsigned NOT NULL default '0',
flags int(10) unsigned NOT NULL default '0',
forbidby text NOT NULL,
forbidreason text NOT NULL,
bantype smallint(6) NOT NULL default '0',
accesscount smallint(6) NOT NULL default '0',
akickcount smallint(6) NOT NULL default '0',
mlock_on int(10) unsigned NOT NULL default '0',
mlock_off int(10) unsigned NOT NULL default '0',
mlock_limit int(10) unsigned NOT NULL default '0',
mlock_key text NOT NULL,
mlock_flood text NOT NULL,
mlock_redirect text NOT NULL,
entry_message text NOT NULL,
memomax smallint(5) unsigned NOT NULL default '0',
botnick varchar(255) NOT NULL default '',
botflags int(10) unsigned NOT NULL default '0',
ttb smallint(6) NOT NULL default '0',
bwcount smallint(6) NOT NULL default '0',
capsmin smallint(6) NOT NULL default '0',
capspercent smallint(6) NOT NULL default '0',
floodlines smallint(6) NOT NULL default '0',
floodsecs smallint(6) NOT NULL default '0',
repeattimes smallint(6) NOT NULL default '0',
active tinyint(1) NOT NULL default '1',
PRIMARY KEY (ci_id),
UNIQUE KEY name (name),
KEY name_index (name(10))
) TYPE=MyISAM;
--
-- Table structure for table `anope_cs_levels`
--
DROP TABLE IF EXISTS anope_cs_levels;
CREATE TABLE anope_cs_levels (
cl_id int(11) NOT NULL auto_increment,
channel varchar(255) NOT NULL default '',
position int(11) NOT NULL default '0',
level int(11) NOT NULL default '0',
PRIMARY KEY (cl_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_hs_core`
--
DROP TABLE IF EXISTS anope_hs_core;
CREATE TABLE anope_hs_core (
bs_id int(11) NOT NULL auto_increment,
nick varchar(255) NOT NULL default '',
vident text NOT NULL,
vhost text NOT NULL,
creator text NOT NULL,
time int(11) NOT NULL default '0',
PRIMARY KEY (bs_id),
UNIQUE KEY nick (nick),
KEY nick_index (nick(10))
) TYPE=MyISAM;
--
-- Table structure for table `anope_ms_info`
--
DROP TABLE IF EXISTS anope_ms_info;
CREATE TABLE anope_ms_info (
nm_id int(11) NOT NULL auto_increment,
receiver text NOT NULL,
number int(11) NOT NULL default '0',
flags int(11) NOT NULL default '0',
time int(11) NOT NULL default '0',
sender text NOT NULL,
text blob NOT NULL,
serv enum('NICK','CHAN') NOT NULL default 'NICK',
PRIMARY KEY (nm_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_ns_access`
--
DROP TABLE IF EXISTS anope_ns_access;
CREATE TABLE anope_ns_access (
na_id int(11) NOT NULL auto_increment,
display varchar(255) NOT NULL default '',
access text NOT NULL,
PRIMARY KEY (na_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_ns_alias`
--
DROP TABLE IF EXISTS anope_ns_alias;
CREATE TABLE anope_ns_alias (
na_id int(11) NOT NULL auto_increment,
display varchar(255) NOT NULL default '',
nick varchar(255) NOT NULL default '',
time_registered int(10) unsigned NOT NULL default '0',
last_seen int(10) unsigned NOT NULL default '0',
status smallint(6) NOT NULL default '0',
last_usermask text NOT NULL,
last_realname text NOT NULL,
last_quit text NOT NULL,
active tinyint(1) NOT NULL default '1',
PRIMARY KEY (na_id),
UNIQUE KEY nick (nick),
KEY nick_index (nick(10))
) TYPE=MyISAM;
--
-- Table structure for table `anope_ns_core`
--
DROP TABLE IF EXISTS anope_ns_core;
CREATE TABLE anope_ns_core (
nc_id int(11) NOT NULL auto_increment,
display varchar(255) NOT NULL default '',
pass tinyblob NOT NULL,
email text NOT NULL,
icq int(10) unsigned NOT NULL default '0',
url text NOT NULL,
flags int(11) NOT NULL default '0',
language smallint(5) unsigned NOT NULL default '0',
accesscount smallint(6) NOT NULL default '0',
memocount smallint(5) unsigned NOT NULL default '0',
memomax smallint(5) unsigned NOT NULL default '0',
channelcount smallint(5) unsigned NOT NULL default '0',
channelmax smallint(5) unsigned NOT NULL default '0',
greet text NOT NULL,
active tinyint(1) NOT NULL default '1',
PRIMARY KEY (nc_id),
UNIQUE KEY display (display),
KEY display_index (display(10))
) TYPE=MyISAM;
--
-- Table structure for table `anope_ns_request`
--
DROP TABLE IF EXISTS anope_ns_request;
CREATE TABLE anope_ns_request (
nr_id int(11) NOT NULL auto_increment,
nick varchar(255) NOT NULL default '',
passcode text NOT NULL,
password tinyblob NOT NULL,
email text NOT NULL,
requested int(11) NOT NULL default '0',
active int(1) NOT NULL default '1',
PRIMARY KEY (nr_id),
UNIQUE KEY nick (nick),
KEY nick_index (nick(10))
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_akills`
--
DROP TABLE IF EXISTS anope_os_akills;
CREATE TABLE anope_os_akills (
ok_id int(11) NOT NULL auto_increment,
user text NOT NULL,
host text NOT NULL,
xby text NOT NULL,
reason text NOT NULL,
seton int(11) NOT NULL default '0',
expire int(11) NOT NULL default '0',
PRIMARY KEY (ok_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_core`
--
DROP TABLE IF EXISTS anope_os_core;
CREATE TABLE anope_os_core (
oc_id int(11) NOT NULL auto_increment,
maxusercnt int(11) NOT NULL default '0',
maxusertime int(11) NOT NULL default '0',
akills_count int(11) NOT NULL default '0',
sglines_count int(11) NOT NULL default '0',
sqlines_count int(11) NOT NULL default '0',
szlines_count int(11) NOT NULL default '0',
PRIMARY KEY (oc_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_exceptions`
--
DROP TABLE IF EXISTS anope_os_exceptions;
CREATE TABLE anope_os_exceptions (
oe_id int(11) NOT NULL auto_increment,
mask text NOT NULL,
lim int(11) NOT NULL default '0',
who text NOT NULL,
reason text NOT NULL,
time int(11) NOT NULL default '0',
expires int(11) NOT NULL default '0',
PRIMARY KEY (oe_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_hcache`
--
DROP TABLE IF EXISTS anope_os_hcache;
CREATE TABLE anope_os_hcache (
oh_id int(11) NOT NULL auto_increment,
mask text NOT NULL,
status int(11) NOT NULL default '0',
used int(11) NOT NULL default '0',
PRIMARY KEY (oh_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_news`
--
DROP TABLE IF EXISTS anope_os_news;
CREATE TABLE anope_os_news (
on_id int(11) NOT NULL auto_increment,
type int(11) NOT NULL default '0',
num int(11) NOT NULL default '0',
ntext text NOT NULL,
who text NOT NULL,
time int(11) NOT NULL default '0',
PRIMARY KEY (on_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_sglines`
--
DROP TABLE IF EXISTS anope_os_sglines;
CREATE TABLE anope_os_sglines (
og_id int(11) NOT NULL auto_increment,
mask text NOT NULL,
xby text NOT NULL,
reason text NOT NULL,
seton int(11) NOT NULL default '0',
expire int(11) NOT NULL default '0',
PRIMARY KEY (og_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_sqlines`
--
DROP TABLE IF EXISTS anope_os_sqlines;
CREATE TABLE anope_os_sqlines (
og_id int(11) NOT NULL auto_increment,
mask text NOT NULL,
xby text NOT NULL,
reason text NOT NULL,
seton int(11) NOT NULL default '0',
expire int(11) NOT NULL default '0',
PRIMARY KEY (og_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_status`
--
DROP TABLE IF EXISTS anope_os_status;
CREATE TABLE anope_os_status (
os_id int(11) NOT NULL auto_increment,
host text NOT NULL,
status int(11) NOT NULL default '0',
used int(11) NOT NULL default '0',
PRIMARY KEY (os_id)
) TYPE=MyISAM;
--
-- Table structure for table `anope_os_szlines`
--
DROP TABLE IF EXISTS anope_os_szlines;
CREATE TABLE anope_os_szlines (
og_id int(11) NOT NULL auto_increment,
mask text NOT NULL,
xby text NOT NULL,
reason text NOT NULL,
seton int(11) NOT NULL default '0',
expire int(11) NOT NULL default '0',
PRIMARY KEY (og_id)
) TYPE=MyISAM;
--
-- Table structure for table `bugs`
--
DROP TABLE IF EXISTS bugs;
CREATE TABLE bugs (
b_id int(9) NOT NULL auto_increment,
b_moduleid int(9) NOT NULL default '0',
b_title varchar(40) NOT NULL default '',
b_desc text NOT NULL,
b_reporter varchar(15) NOT NULL default '',
PRIMARY KEY (b_id)
) TYPE=MyISAM;
--
-- Table structure for table `modules`
--
DROP TABLE IF EXISTS modules;
CREATE TABLE modules (
m_id int(9) NOT NULL auto_increment,
m_name varchar(30) NOT NULL default '',
m_category enum('OperServ','NickServ','MemoServ','ChanServ','BotServ','HostServ','HelpServ','Misc') NOT NULL default 'Misc',
m_description longtext NOT NULL,
m_activated enum('0','1') NOT NULL default '0',
m_owner varchar(15) NOT NULL default '',
m_path varchar(40) NOT NULL default '',
m_updated date NOT NULL default '0000-00-00',
m_official enum('0','1') NOT NULL default '0',
m_version varchar(5) NOT NULL default '',
PRIMARY KEY (m_id)
) TYPE=MyISAM PACK_KEYS=0;
--
-- Table structure for table `requests`
--
DROP TABLE IF EXISTS requests;
CREATE TABLE requests (
r_id int(3) NOT NULL auto_increment,
r_title varchar(30) NOT NULL default '',
r_category enum('OperServ','NickServ','MemoServ','ChanServ','BotServ','HostServ','HelpServ','Misc') NOT NULL default 'Misc',
r_description longtext NOT NULL,
r_owner varchar(15) NOT NULL default 'Anonymous',
r_assigned varchar(15) NOT NULL default '',
PRIMARY KEY (r_id)
) TYPE=MyISAM;
--
-- Table structure for table `uploaded`
--
DROP TABLE IF EXISTS uploaded;
CREATE TABLE uploaded (
mu_id int(9) NOT NULL auto_increment,
mu_name varchar(30) NOT NULL default '',
mu_category enum('OperServ','NickServ','MemoServ','ChanServ','BotServ','HostServ','HelpServ','Misc') NOT NULL default 'Misc',
mu_description longtext NOT NULL,
mu_activated enum('0','1') NOT NULL default '0',
mu_owner varchar(15) NOT NULL default '',
mu_path varchar(40) NOT NULL default '',
mu_updated date NOT NULL default '0000-00-00',
mu_official enum('0','1') NOT NULL default '0',
mu_version varchar(5) NOT NULL default '',
PRIMARY KEY (mu_id)
) TYPE=MyISAM;
--
-- Table structure for table `users`
--
DROP TABLE IF EXISTS users;
CREATE TABLE users (
u_id int(9) NOT NULL auto_increment,
u_username varchar(15) NOT NULL default '',
u_password varchar(32) NOT NULL default '',
u_email varchar(40) NOT NULL default '',
u_location varchar(40) NOT NULL default '',
u_status enum('normal','coder','admin','root') NOT NULL default 'normal',
u_confirmed enum('0','1') NOT NULL default '1',
u_registered date NOT NULL default '0000-00-00',
u_lastvisit date NOT NULL default '0000-00-00',
u_hideemail enum('0','1') NOT NULL default '0',
PRIMARY KEY (u_id)
) TYPE=MyISAM PACK_KEYS=0;
+507
View File
@@ -0,0 +1,507 @@
/* Database file handling routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: datafiles.c,v 1.8 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
#include "datafiles.h"
#include <fcntl.h>
static int curday = 0;
/*************************************************************************/
/*************************************************************************/
/* Return the version number on the file. Return 0 if there is no version
* number or the number doesn't make sense (i.e. less than 1 or greater
* than FILE_VERSION).
*/
int get_file_version(dbFILE * f)
{
FILE *fp = f->fp;
int version =
fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
if (ferror(fp)) {
#ifndef NOT_MAIN
log_perror("Error reading version number on %s", f->filename);
#endif
return 0;
} else if (feof(fp)) {
#ifndef NOT_MAIN
alog("Error reading version number on %s: End of file detected",
f->filename);
#endif
return 0;
} else if (version < 1) {
#ifndef NOT_MAIN
alog("Invalid version number (%d) on %s", version, f->filename);
#endif
return 0;
}
return version;
}
/*************************************************************************/
/* Write the current version number to the file. Return 0 on error, 1 on
* success.
*/
int write_file_version(dbFILE * f, uint32 version)
{
FILE *fp = f->fp;
if (fputc(version >> 24 & 0xFF, fp) < 0 ||
fputc(version >> 16 & 0xFF, fp) < 0 ||
fputc(version >> 8 & 0xFF, fp) < 0 ||
fputc(version & 0xFF, fp) < 0) {
#ifndef NOT_MAIN
log_perror("Error writing version number on %s", f->filename);
#endif
return 0;
}
return 1;
}
/*************************************************************************/
/*************************************************************************/
static dbFILE *open_db_read(const char *service, const char *filename)
{
dbFILE *f;
FILE *fp;
f = scalloc(sizeof(*f), 1);
if (!f) {
#ifndef NOT_MAIN
log_perror("Can't read %s database %s", service, filename);
#endif
return NULL;
}
strscpy(f->filename, filename, sizeof(f->filename));
f->mode = 'r';
fp = fopen(f->filename, "rb");
if (!fp) {
int errno_save = errno;
#ifndef NOT_MAIN
if (errno != ENOENT)
log_perror("Can't read %s database %s", service, f->filename);
#endif
free(f);
errno = errno_save;
return NULL;
}
f->fp = fp;
f->backupfp = NULL;
return f;
}
/*************************************************************************/
static dbFILE *open_db_write(const char *service, const char *filename,
uint32 version)
{
dbFILE *f;
int fd;
f = scalloc(sizeof(*f), 1);
if (!f) {
#ifndef NOT_MAIN
log_perror("Can't read %s database %s", service, filename);
#endif
return NULL;
}
strscpy(f->filename, filename, sizeof(f->filename));
filename = f->filename;
f->mode = 'w';
*f->backupname = 0;
snprintf(f->backupname, sizeof(f->backupname), "%s.save", filename);
if (!*f->backupname || strcmp(f->backupname, filename) == 0) {
int errno_save = errno;
#ifndef NOT_MAIN
alog("Opening %s database %s for write: Filename too long",
service, filename);
#endif
free(f);
errno = errno_save;
return NULL;
}
unlink(f->backupname);
f->backupfp = fopen(filename, "rb");
if (rename(filename, f->backupname) < 0 && errno != ENOENT) {
int errno_save = errno;
#ifndef NOT_MAIN
static int walloped = 0;
if (!walloped) {
walloped++;
wallops(NULL, "Can't back up %s database %s", service,
filename);
}
errno = errno_save;
log_perror("Can't back up %s database %s", service, filename);
if (!NoBackupOkay) {
#endif
if (f->backupfp)
fclose(f->backupfp);
free(f);
errno = errno_save;
return NULL;
#ifndef NOT_MAIN
}
#endif
*f->backupname = 0;
}
unlink(filename);
/* Use open() to avoid people sneaking a new file in under us */
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
f->fp = fdopen(fd, "wb"); /* will fail and return NULL if fd < 0 */
if (!f->fp || !write_file_version(f, version)) {
int errno_save = errno;
#ifndef NOT_MAIN
static int walloped = 0;
if (!walloped) {
walloped++;
wallops(NULL, "Can't write to %s database %s", service,
filename);
}
errno = errno_save;
log_perror("Can't write to %s database %s", service, filename);
#endif
if (f->fp) {
fclose(f->fp);
unlink(filename);
}
if (*f->backupname && rename(f->backupname, filename) < 0)
#ifndef NOT_MAIN
log_perror("Cannot restore backup copy of %s", filename);
#else
;
#endif
errno = errno_save;
return NULL;
}
return f;
}
/*************************************************************************/
/* Open a database file for reading (*mode == 'r') or writing (*mode == 'w').
* Return the stream pointer, or NULL on error. When opening for write, it
* is an error for rename() to return an error (when backing up the original
* file) other than ENOENT, if NO_BACKUP_OKAY is not defined; it is an error
* if the version number cannot be written to the file; and it is a fatal
* error if opening the file for write fails and the backup was successfully
* made but cannot be restored.
*/
dbFILE *open_db(const char *service, const char *filename,
const char *mode, uint32 version)
{
if (*mode == 'r') {
return open_db_read(service, filename);
} else if (*mode == 'w') {
return open_db_write(service, filename, version);
} else {
errno = EINVAL;
return NULL;
}
}
/*************************************************************************/
/* Restore the database file to its condition before open_db(). This is
* identical to close_db() for files open for reading; however, for files
* open for writing, we first attempt to restore any backup file before
* closing files.
*/
void restore_db(dbFILE * f)
{
int errno_save = errno;
if (f->mode == 'w') {
int ok = 0; /* Did we manage to restore the old file? */
errno = errno_save = 0;
if (*f->backupname && strcmp(f->backupname, f->filename) != 0) {
if (rename(f->backupname, f->filename) == 0)
ok = 1;
}
if (!ok && f->backupfp) {
char buf[1024];
int i;
ok = 1;
if (fseek(f->fp, 0, SEEK_SET) < 0)
ok = 0;
while (ok && (i = fread(buf, 1, sizeof(buf), f->backupfp)) > 0) {
if (fwrite(buf, 1, i, f->fp) != i)
ok = 0;
}
if (ok) {
fflush(f->fp);
ftruncate(fileno(f->fp), ftell(f->fp));
}
}
#ifndef NOT_MAIN
if (!ok && errno > 0)
log_perror("Unable to restore backup of %s", f->filename);
#endif
errno_save = errno;
if (f->backupfp)
fclose(f->backupfp);
if (*f->backupname)
unlink(f->backupname);
}
fclose(f->fp);
if (!errno_save)
errno_save = errno;
free(f);
errno = errno_save;
}
/*************************************************************************/
/* Close a database file. If the file was opened for write, remove the
* backup we (may have) created earlier.
*/
void close_db(dbFILE * f)
{
if (f->mode == 'w' && *f->backupname
&& strcmp(f->backupname, f->filename) != 0) {
if (f->backupfp)
fclose(f->backupfp);
unlink(f->backupname);
}
fclose(f->fp);
free(f);
}
/*************************************************************************/
/*************************************************************************/
/* Read and write 2- and 4-byte quantities, pointers, and strings. All
* multibyte values are stored in big-endian order (most significant byte
* first). A pointer is stored as a byte, either 0 if NULL or 1 if not,
* and read pointers are returned as either (void *)0 or (void *)1. A
* string is stored with a 2-byte unsigned length (including the trailing
* \0) first; a length of 0 indicates that the string pointer is NULL.
* Written strings are truncated silently at 65534 bytes, and are always
* null-terminated.
*
* All routines return -1 on error, 0 otherwise.
*/
int read_int16(uint16 * ret, dbFILE * f)
{
int c1, c2;
c1 = fgetc(f->fp);
c2 = fgetc(f->fp);
if (c1 == EOF || c2 == EOF)
return -1;
*ret = c1 << 8 | c2;
return 0;
}
int write_int16(uint16 val, dbFILE * f)
{
if (fputc((val >> 8) & 0xFF, f->fp) == EOF
|| fputc(val & 0xFF, f->fp) == EOF)
return -1;
return 0;
}
int read_int32(uint32 * ret, dbFILE * f)
{
int c1, c2, c3, c4;
c1 = fgetc(f->fp);
c2 = fgetc(f->fp);
c3 = fgetc(f->fp);
c4 = fgetc(f->fp);
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
return -1;
*ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
return 0;
}
int write_int32(uint32 val, dbFILE * f)
{
if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
return -1;
if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
return -1;
if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
return -1;
if (fputc((val) & 0xFF, f->fp) == EOF)
return -1;
return 0;
}
int read_ptr(void **ret, dbFILE * f)
{
int c;
c = fgetc(f->fp);
if (c == EOF)
return -1;
*ret = (c ? (void *) 1 : (void *) 0);
return 0;
}
int write_ptr(const void *ptr, dbFILE * f)
{
if (fputc(ptr ? 1 : 0, f->fp) == EOF)
return -1;
return 0;
}
int read_string(char **ret, dbFILE * f)
{
char *s;
uint16 len;
if (read_int16(&len, f) < 0)
return -1;
if (len == 0) {
*ret = NULL;
return 0;
}
s = scalloc(len, 1);
if (len != fread(s, 1, len, f->fp)) {
free(s);
return -1;
}
*ret = s;
return 0;
}
int write_string(const char *s, dbFILE * f)
{
uint32 len;
if (!s)
return write_int16(0, f);
len = strlen(s);
if (len > 65534)
len = 65534;
if (write_int16((uint16) (len + 1), f) < 0)
return -1;
if (len > 0 && fwrite(s, 1, len, f->fp) != len)
return -1;
if (fputc(0, f->fp) == EOF)
return -1;
return 0;
}
/*************************************************************************/
/*************************************************************************/
/* Renames a database */
static void rename_database(char *name, char *ext)
{
char destpath[PATH_MAX];
snprintf(destpath, sizeof(destpath), "backups/%s.%s", name, ext);
if (rename(name, destpath) != 0) {
alog("Backup of %s failed.", name);
wallops(s_OperServ, "WARNING! Backup of %s failed.", name);
}
}
/*************************************************************************/
/* Removes old databases */
static void remove_backups(void)
{
char ext[9];
char path[PATH_MAX];
time_t t;
struct tm tm;
time(&t);
t -= (60 * 60 * 24 * KeepBackups);
tm = *localtime(&t);
strftime(ext, sizeof(ext), "%Y%m%d", &tm);
snprintf(path, sizeof(path), "backups/%s.%s", NickDBName, ext);
unlink(path);
snprintf(path, sizeof(path), "backups/%s.%s", BotDBName, ext);
unlink(path);
snprintf(path, sizeof(path), "backups/%s.%s", ChanDBName, ext);
unlink(path);
snprintf(path, sizeof(path), "backups/%s.%s", OperDBName, ext);
unlink(path);
snprintf(path, sizeof(path), "backups/%s.%s", NewsDBName, ext);
unlink(path);
snprintf(path, sizeof(path), "backups/%s.%s", ExceptionDBName, ext);
unlink(path);
snprintf(path, sizeof(path), "backups/%s.%s", HostDBName, ext);
unlink(path);
}
/*************************************************************************/
/* Handles database backups. */
void backup_databases(void)
{
time_t t;
struct tm tm;
if (!KeepBackups)
return;
time(&t);
tm = *localtime(&t);
if (!curday) {
curday = tm.tm_yday;
return;
}
if (curday != tm.tm_yday) {
char ext[9];
alog("Backing up databases");
remove_backups();
curday = tm.tm_yday;
strftime(ext, sizeof(ext), "%Y%m%d", &tm);
if (!skeleton) {
rename_database(NickDBName, ext);
if (s_BotServ)
rename_database(BotDBName, ext);
rename_database(ChanDBName, ext);
if (s_HostServ)
rename_database(HostDBName, ext);
}
rename_database(OperDBName, ext);
rename_database(NewsDBName, ext);
rename_database(ExceptionDBName, ext);
}
}
+67
View File
@@ -0,0 +1,67 @@
/* Database file descriptor structure and file handling routine prototypes.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: datafiles.h,v 1.4 2003/07/20 01:15:49 dane Exp $
*
*/
#ifndef DATAFILES_H
#define DATAFILES_H
/*************************************************************************/
typedef struct dbFILE_ dbFILE;
struct dbFILE_ {
int mode; /* 'r' for reading, 'w' for writing */
FILE *fp; /* The normal file descriptor */
FILE *backupfp; /* Open file pointer to a backup copy of
* the database file (if non-NULL) */
char filename[PATH_MAX]; /* Name of the database file */
char backupname[PATH_MAX]; /* Name of the backup file */
};
/*************************************************************************/
/* Prototypes and macros: */
E void check_file_version(dbFILE *f);
E int get_file_version(dbFILE *f);
E int write_file_version(dbFILE *f, uint32 version);
E dbFILE *open_db(const char *service, const char *filename, const char *mode, uint32 version);
E void restore_db(dbFILE *f); /* Restore to state before open_db() */
E void close_db(dbFILE *f);
E void backup_databases(void);
#define read_db(f,buf,len) (fread((buf),1,(len),(f)->fp))
#define write_db(f,buf,len) (fwrite((buf),1,(len),(f)->fp))
#define getc_db(f) (fgetc((f)->fp))
E int read_int16(uint16 *ret, dbFILE *f);
E int write_int16(uint16 val, dbFILE *f);
E int read_int32(uint32 *ret, dbFILE *f);
E int write_int32(uint32 val, dbFILE *f);
E int read_ptr(void **ret, dbFILE *f);
E int write_ptr(const void *ptr, dbFILE *f);
E int read_string(char **ret, dbFILE *f);
E int write_string(const char *s, dbFILE *f);
#define read_int8(ret,f) ((*(ret)=fgetc((f)->fp))==EOF ? -1 : 0)
#define write_int8(val,f) (fputc((val),(f)->fp)==EOF ? -1 : 0)
#define read_buffer(buf,f) (read_db((f),(buf),sizeof(buf)) == sizeof(buf))
#define write_buffer(buf,f) (write_db((f),(buf),sizeof(buf)) == sizeof(buf))
#define read_buflen(buf,len,f) (read_db((f),(buf),(len)) == (len))
#define write_buflen(buf,len,f) (write_db((f),(buf),(len)) == (len))
#define read_variable(var,f) (read_db((f),&(var),sizeof(var)) == sizeof(var))
#define write_variable(var,f) (write_db((f),&(var),sizeof(var)) == sizeof(var))
/*************************************************************************/
#endif /* DATAFILES_H */
+40
View File
@@ -0,0 +1,40 @@
/* Set default values for any constants that should be in include files but
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
*
* $Id: defs.h,v 1.4 2003/07/20 01:15:49 dane Exp $
*
*/
/*************************************************************************/
#ifndef NAME_MAX
# define NAME_MAX 255
#endif
#ifndef BUFSIZ
# define BUFSIZ 256
#else
# if BUFSIZ < 256
# define BUFSIZ 256
# endif
#endif
/* Length of an array: */
#define lenof(a) (sizeof(a) / sizeof(*(a)))
/* Telling compilers about printf()-like functions: */
#ifdef __GNUC__
# define FORMAT(type,fmt,start) __attribute__((format(type,fmt,start)))
#else
# define FORMAT(type,fmt,start)
#endif
/*************************************************************************/
+17
View File
@@ -0,0 +1,17 @@
Reported Bugs from Mantis: http://www.anope.org/bug
===================================================
.- Strange Segfault on expiring nicknames. Almost arbitrary, very hard
to reproduce.
.- Clone detection can give false warnings if a user connects and then
signs off several times in rapid succession. Clone detection also
goes off wrongly if a server links and has a number of clients from
the same hostname.
.- If there is absolutely no activity on your network, Services may delay
timed events (nick kills, database saving, etc.) until the next message
comes in from Services' uplink server.
.- Modules will not work on OpenBSD machines, due to limitations on libdl.
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+111
View File
@@ -0,0 +1,111 @@
Anope DefCon
------------
Introduction:
Anope 1.6 onwards supports a unique protection mechanism based on the
military "Defense Readiness Condition" (DefCon) system. It is based on
5 levels of defense readiness defined as:
DEFCON5 Normal peacetime readiness
DEFCON4 Increased intelligence and security readiness
DEFCON3 Increase in force readiness
DEFCON2 Further increase in force readiness
DEFCON1 Maximum force readiness.
These are configurable levels that mandates what actions Anope should
take in case of emergency and change in readiness status.
It is used to prevent abuse to both Services, and the ircd on which they
are running. Also to protect the users, primarily in the event of Clones
and/or FloodBOT attacks.
Installation:
The DefCon system is part of Anope's core,
The DefCon system has to be configured on your services.conf file to
be enabled. All directives are optional unless they depend on what
options you enable for each level. Look for the "DefCon configuration"
section on your services.conf file for more information.
Make sure you restart Anope after changing the DefCon configuration
directives.
Configuration:
Pre-defined DefCon actions:
No new channel registrations 1
No New Nick Registrations 2
No MLOCK changes 4
Force Chan Mode 8
Use Reduced Session Limit 16
KILL any new clients trying to connect 32
Services will ignore everyone but opers 64
Services will silently ignore everyone but opers 128
AKILL all new clients trying to connect 256
No new memos sent to block memoserv attacks 512
These are the values used to determine each defcon setting, are set via:
DefCon1 XX
DefCon2 XX
DefCon3 XX
DefCon4 XX
To set the desired value, you simply add the value of the numbers together
and place that as your DefCon# setting. For instance:
Say you wish to set:
No Channel Registrations, No Nickname Registrations and Services Ignoring
everyone except for Operators. You would do this by:
1 + 2 + 128 (Each value listed above is added together)
Giving: 131
You would then place this as which ever Defcon setting you want:
DefCon1 131
The recommended default values are safe to use on any network.
Usage:
Anope starts up in DEFCON5 (normal readiness). To change the Defcon level
in action use:
/msg OperServ DEFCON 1|2|3|4|5
Example:
Place the network on DEFCON4:
/msg OperServ DEFCON 4
*** Global -- from OperServ: dengel Changed the DEFCON level to 4
-OperServ- Services are now at DEFCON 4
-OperServ- * No new channel registrations
-OperServ- * No new nick registrations
-OperServ- * No MLOCK changes
-OperServ- * Use the reduced session limit of 5
-Global- The Defcon Level is now at Level: 4
Restore normal readiness:
/msg OperServ DEFCON 5
*** Global -- from OperServ: dengel Changed the DEFCON level to 5
-OperServ- Services are now at DEFCON 5
-Global- Services are now back to normal, sorry for any inconvenience
Support:
You might get DefCon support by posting on our online forum, or maybe on
our #anope channel at /server irc.anope.org.
+423
View File
@@ -0,0 +1,423 @@
Frequently Asked Questions (FAQ) concerning Anope
=================================================
Index:
1. What is Anope?
2. Where can I find Anope?
3. Does Anope run under Windows?
4. Can I send you questions without reading the FAQ, INSTALL or
README files?
5. When I run "make", I get an error message like "missing separator",
"Unassociated shell command", "Unexpected end of line seen", etc.
6. I get an error like "Makefile.inc not found".
7. I typed "./services" at the command line, but nothing happened!
8. I need support for the XYZ protocol.
9. Whenever I start Anope, I get a message on my IRC server saying
"connection refused" or something similar, and Anope gives an error
message from the server saying "Closing Link: ...".
10. My IRC server is giving me messages like "Connection to
services.whatever.net[127.0.0.1] activated" and then "Access denied --
no N line". Why?
11. When I say "/connect services.*", it doesn't work!
12. Anope complains in the logfile about being unable to load the
default language.
13. Anope always dies after about five minutes, saying "FATAL ERROR!
Can't back up nick.db".
14. Anope starts up okay, but if I try to register a nickname, it comes
back with "Sorry, registration failed."
15. Anope crashed with a segmentation fault.
16. Anope's channel mode setting doesn't work. I can't set modes with
OperServ, and every time ChanServ tries to set a mode, my server
reverses the change.
17. Using the OperServ JUPE command results in server messages like
"Server juped.server introduced by non-hub server services.my.net".
18. I can't use the ADMIN command to add Services admins--it tells me
"Permission denied."
19. When I add an AKILL, the users matching it don't get killed.
20. Anope reports (via /stats u or /msg OperServ STATS) a different
number of users online than I get from doing /lusers.
21. Anope ignored the SET SUCCESSOR setting and deleted a channel when
the founder expired.
22. Trying to use OperServ gives me "Access denied", but my nick is in the
ServicesRoot directive and is registered, and I've identified for my
nick.
23. Anope spricht kein Deutsch!, etc. (Anope doesn't speak my
language!)
24. I selected a language other than English, but sometimes Anope sends
responses in English instead.
25. I've found a bug that's not mentioned here or in the
BUGS files. What should I do?
26. Your Services program doesn't do XYZ like DALnet Services. What's
wrong?
27. I've got a great new idea for Anope. Do you want it?
28. Examples of features I have been asked about and why we won't add (or
haven't yet added) them--so don't ask us about them.
29. How do I add bots to BotServ?
30. When I used the OperServ RAW command, Anope and/or my network
crashed, or did weird things! Please fix this bug!
31. I would like to have the list of the differents RAW on operserv
32. I can't get /OS UMODES and /OS SVSNICK do not work!
33. What is a Super-Admin? How does it work? Why might it not work?
---------------------------------------------------------------------------
1. What is Anope?
Anope is a set of services for IRC networks. See the README
file for more information. And in case you were wondering,
Anope is Epona spelt backwards :)
2. Where can I find Anope?
The latest version can always be found at the official Anope
distribution site:
http://www.anope.org/
New version announcements can also be found at http://anope.zero.org/
in the Announcement section.
3. Does Anope run under Windows?
Well... not officialy. Bu there is a cygwin based patch that makes
Anope work on Windows. Note, however, that some features might not
work, and you should take that into consideration when answering
the questions of ./configure (i.e. MySQL, Modules).
You can obtain a pre-build copy of Anope for Windoes from
http://www.wircds.net/ although we have "blessed" that port,
we do not provide support for it. If you can't get it work,
go to wIRCds.net forum.
If you feel capable of taking ownership of an official windows
port, and to keep it current, please let the current Development
team know.
4. Can I send you questions without reading the FAQ, INSTALL or README
files?
No. If you don't read those files, your messages will most probably
be ignored. We don't mean to be rude, but if we took the time
to write down some documentation, we'd expect you to take some
time to read it.
5. When I run "make", I get an error message like "missing separator",
"Unassociated shell command", "Unexpected end of line seen", etc.
Your make program isn't compatible with the Makefile for Anope.
The Makefile was designed to work with GNU make, and as such may
not work on other systems' "make" programs. If you get an error
from "make", obtain GNU make from ftp://prep.ai.mit.edu/pub/gnu/
(or wherever you prefer) and use it instead of your system's
default "make". Note that GNU make may already be installed on
your system; try using the command "gmake" instead of "make".
The make programs bundled with SunOS/Solaris and FreeBSD have been
reported not to work; you will need to use GNU make on these
systems.
6. I get an error like "Makefile.inc not found".
You forgot to run the configure script first. See the INSTALL file
for compilation instructions.
7. I typed "./services" at the command line, but nothing happened!
Anope puts itself in the background when it starts, so you get
your shell prompt right back. Meanwhile, Anope will continue
setting up, then connect to the IRC server specified in
services.conf (or on the command line). If it doesn't connect, you
probably specified the wrong server type when running the configure
script. (Also make sure that you are actually running one of the
supported servers. There are a gazillion different variations on
the basic IRC protocol out there, and I have neither the time nor
the desire to add support for them.)
The recommended server, under which Epona (the original code base
used by Anope) was developed, is Bahamut. DreamForge 4.6.7 will also
work fine, but it's a bit obsolete nowadays. Derivatives of Bahamut
and DreamForge may also work, if they don't change the server<->server
protocol too much; contact their authors for more information.
Most people, though, are running Anope with UnrealIRCd, UltimateIRCd
or Bahamut.
As always, you can check the log file (services.log by default) for
error messages.
8. I need support for the XYZ protocol.
Hang in there! We are working on making Anope protocol independent.
It should show up sometime soon... more details to follow.
9. Whenever I start Anope, I get a message on my IRC server saying
"connection refused" or something similar, and Anope gives an error
message from the server saying "Closing Link: ...".
See seection 3 of the INSTALL file.
10. My IRC server is giving me messages like "Connection to
services.whatever.net[127.0.0.1] activated" and then "Access denied --
no N line". Why?
This is typically caused by including a port number in the C:line
for services, which tells your server to try to autoconnect to it
(depending on the class (Y:line) settings). This is not what you
want, because Anope will connect to the server itself, but does
not listen for servers to connect to it. The solution is to remove
the port number from the C:line.
11. When I say "/connect services.*", it doesn't work!
Of course not. RTFM (Read The Fine Manual), and see the previous
answer.
12. Anope complains in the logfile about being unable to load the
default language.
You forgot to run "make install".
13. Anope always dies after about five minutes, saying "FATAL ERROR!
Can't back up nick.db".
Make sure that the user Anope runs as has write access to the
data directory, and that the data directory actually exists (the
latter shouldn't be a problem if you ran the configure script).
This means Anope needs write and execute permission on the data
directory itself and execute permission on every parent directory
of the data directory.
14. Anope starts up okay, but if I try to register a nickname, it comes
back with "Sorry, registration failed."
Make sure you've selected the correct IRC server type in the
configure script; see question 9 for details.
15. Anope crashed with a segmentation fault.
See if you can reproduce this by doing a certain sequence of
things. If so, please report it to us (see part 6 of README file). If
not, you're probably out of luck; if you like, you can report it to
us anyway, but chances are it won't get fixed if we don't have
instructions on reproducing it. If you do have such a problem, you
may find the crontab utility useful for dealing with it.
Also, see the DumpCore directive in the configuration file. It allows
Anope to dump its core whenever it's segfaulting, usually calling it
core and placing it into Anope's main directory.
Open up gdb by issuing the following command at your shell:
gdb services core
(of course replacing 'core' with the name of the core if different)
and type 'bt' at the gdb prompt. After that, send us the output you
got and keep the core file in a safe place, in case we need it to
dig deeper into the problem.
16. Anope's channel mode setting doesn't work. I can't set modes with
OperServ, and every time ChanServ tries to set a mode, my server
reverses the change.
Make sure EVERY servers on your network has a U: line for Services in
ircd.conf, for example:
U:services.whatever.net:*:*
17. Using the OperServ JUPE command results in server messages like
"Server juped.server introduced by non-hub server services.my.net".
Services' uplink must have an H: line for Services in the
ircd.conf file, which looks something like:
H:*::services.whatever.net
18. I can't use the ADMIN command to add Services admins--it tells me
"Permission denied."
Did you define yourself as the Services root? You need to insert
your nickname in the ServicesRoot directive in services.conf.
19. When I add an AKILL, the users matching it don't get killed.
Use the AkillOnAdd configuration directive.
20. Anope reports (via /stats u or /msg OperServ STATS) a different
number of users online than I get from doing /lusers.
Anope doesn't count its own pseudo-clients (NickServ, ChanServ,
etc.) in its user count.
21. Anope ignored the SET SUCCESSOR setting and deleted a channel when
the founder expired.
Normally, this is because the successor had too many channels
registered; in this case, you will see an entry in the log file
like the following:
[date] Successor (SuccessorNick) of channel #somechannel owns too
many channels, deleting channel #somechannel
If you don't get a message like this or you can verify that the
successor wasn't running into the channel limit, please report it
using the bug-reporting procedure below (see section 6 of the
README file).
22. Trying to use OperServ gives me "Access denied", but my nick is in the
ServicesRoot directive and is registered, and I've identified for my
nick.
You need to be opered (i.e. user mode +o) to access OperServ.
23. Anope spricht kein Deutsch!, etc. (Anope doesn't speak my
language!)
See section 5 of the README file.
24. I selected a language other than English, but sometimes Anope sends
responses in English instead.
Some language files are not complete--in other words, they don't
have a translation of every message Anope uses, but only some of
them. In this case, the missing messages will be displayed in
English. You can either wait for the primary translator to provide
us with a translation, or do the translation yourself and send us
the messages translated into your language.
25. I've found a bug that's not mentioned here or in the README or
BUGS files. What should I do?
See section 6 of the README file.
26. Your Services program doesn't do XYZ like DALnet (or other) Services.
What's wrong?
Nothing is wrong, except your expectations. Anope is a
completely different program from that used on DALnet; they are
similar in concept only.
27. I've got a great new idea for Services. Do you want it?
We are always interested in hearing new ideas. HOWEVER, do not
expect your proposal to be in the next Anope release for sure.
As a rule, we usually don't add anything that can be equivalently
done by other means, or that we consider totally useless; see below
for examples of things we don't plan to add.
Our general intent is for Anope to provide as much functionality
as possible--while staying as lean as possible. So features which
are arguably beneficial will tend to be added, while features of
limited or no benefit or which can be equally provided by something
else already in use will tend to be passed over.
If you'd like to give us your idea, you can go to our website at
http://www.anope.org/ and add it as a Feature Request on our Bug
Tracking System. Or, if unsure, you can discuss it on our online
Forum, in the Ideas and Suggestions section.
28. Examples of features we have been asked about and why we won't add (or
haven't yet added) them--so don't ask us about them:
- An option to make ChanServ stay in some/all registered channels:
we see absolutely no necessity for this feature, since BotServ
already does this anyway.
- A "current time" field in NickServ and ChanServ INFO displays:
Most people have clocks of some sort either on their computer
screens or on their walls (or both), and all IRC servers, as well
as Services, have a command to return the server's current time.
Thus a current-time field in INFO displays would simply take up
extra space for no reason.
29. How do I add bots to BotServ?
Read /msg BotServ HELP and /msg BotServ HELP BOT.
30. When I used the OperServ RAW command, Anope and/or my network
crashed, or did weird things! Please fix this bug!
"That's not a bug, it's a feature."
Have you ever typed /msg OperServ HELP RAW? It's clearly stated
there that this command is dangerous and that its use may result
in very bad things.
And that's why this command has been disabled by default. If you
enabled and used it, YOU'RE ON YOUR OWN. All help requests will
be ignored, even if the problem happens not immediately.
31. I would like to have the list of the differents RAW on operserv
If you have to ask, you should not be messing with RAW :)
32. I can't get /OS UMODES and /OS SVSNICK do not work!
Make sure you the USE_OSSVS is defined on config.h. Since these
are very controversial commands, they are turned off by default.
Then, make clean ; make ; make install
33. What is a Super-Admin? How does it work? Why might it not work?
Super-Admin's have extra privileges, including being founder on
all channels. It must be activated on a per user basis and is
only available to Services Admins and Services Roots.
It is set using OperServ and is not persistent.
It only works if SuperAdmin is uncommented in the services
configuration file. This is commented by default.
Read /msg OperServ HELP SET SUPERADMIN for further help.
+177
View File
@@ -0,0 +1,177 @@
ANOPE INSTALLATION INSTRUCTIONS
===============================
Table of contents
-----------------
1. Installing Anope
2. Upgrading Anope
3. Setting up the IRCd
4. Starting Anope
5. Setting up a crontab
You should also read the README and FAQ files!
1. Installing Anope
-------------------
IMPORTANT NOTE: it is not recommended to use (and therefore install)
Anope as root. Use an unprivileged user instead -- the one you're
using for the ircd or a dedicated one will be good enough.
The very first thing you need to do is to get the Anope package
(if not already done). You can find it at the following place:
http://www.anope.org/
Next, unpack the package in your home directory, and go into the
created directory.
Now type ./configure to start the configuration script. It will
ask you a few questions, and figure out how to compile Anope on
your system. If you are unsure about the answer to a question,
use the default value.
NOTE: although you may specify different binary and data paths,
it is RECOMMENDED that you use the same value for both.
You can now type make to compile Anope. If there are errors in the
Makefile, *try to use gmake* instead. If it still doesn't work, you
(or the system administrator if it's a shell) must install GNU
make. You may find it at ftp://prep.ai.mit.edu/pub/gnu/.
Now type make install (or gmake install; see above). This will
install all the needed files in the paths you specified with the
configure script, and setup file permissions. You should ensure
that the data directory is not accessible by other users, as malicious
users may cause troubles on your network if passwords are not
encrypted, or read the memos of any user.
If you see errors during this process, please mail us with the
*complete* error output, and don't forget to mention your OS,
compiler and C library versions.
Now go into the data directory (by default, ~/services). Copy the
example.conf file to services.conf, and open the latter with your
favourite text editor. It contains all the configuration
directives Anope will use at startup. Read the instructions contained
in the file carefully. Using the default values is NOT a good idea,
and will most likely not work!
If you need help, you should subscribe to the Anope mailing list and
mail there to get help from other users. See the README file for more
information.
2. Upgrading Anope
------------------
If you got a .diff file and want to patch the old Anope sources with it, do
the following:
* Copy the .diff file into the root Anope sources directory.
* Type patch -p1 <file.diff
To upgrade Anope, just follow the installation instructions described in
section 1. There are however a few specific guidelines:
* IMPORTANT: Back up your old databases!
* If you are upgrading to a new major release, ALWAYS restart a
fresh configuration file from example.conf.
3. Setting up the IRCd
----------------------
Services acts as an IRC server with pseudo-clients on it. To link
them to your network, you'll need to add some lines in the ircd.conf
of their hub server (as stated in the RemoteServer configuration
directive).
For samples below we'll take Services.LocalHost.Net as the name of
the Services (as stated in the ServerName configuration directive).
First, the C/N lines, that allow Services to link. They also need a
Y:line to work correctly.
Y:27:180:0:0:4000000
C:127.0.0.1:mypass:Services.LocalHost.Net::30
N:127.0.0.1:mypass:Services.LocalHost.Net::30
mypass is the same password you mentionned in the RemoteServer
configuration directive. 127.0.0.1 is the IP from which Services
connect from (linking in localhost is the most efficient way
to run Services).
Then, you have to set-up an U:line, that will allow Services to
change channel modes, topics, and much more without being opped
in the channel.
U:Services.LocalHost.Net:*:*
NOTE: if you have more than one server in your network, this line
MUST be added on ALL servers, or things won't work.
Finally, you'll need to add an H:line, to make the OperServ JUPE
command work correctly.
H:*::Services.LocalHost.Net
Don't forget to /rehash to apply changes.
A new trend in ircd configuration is popping all over the place,
good examples are the latest Hybrid and Unreal, which use a more
"readable" for of configuration. For those, use something like:
link Services.LocalHost.Net
{
username *;
hostname localhost;
bind-ip *;
port 6667;
hub *;
password-connect "mypass";
password-receive "mypass";
class servers;
};
4. Starting Anope
-----------------
Go into the directory where binaries were installed (by default,
~/services). Type ./services to launch Anope.
If there are syntax errors in the configuration file they will be
displayed on the screen. Correct them until there are no errors
anymore. A successful startup won't generate any message.
Give to Services at least one minute to link to your network, as
certain IRCds on some OSes may be really slow for the link process.
If nothing happens then, it is probably a configuration problem.
Try to launch Anope with ./services -debug -nofork to see any errors
that it encounters, and try to correct them.
If you need help to solve errors, feel free to subscribe to the
Anope mailing list and ask there. See the README file for details.
5. Setting up a crontab
-----------------------
A crontab entry will allow you to check periodically whether Anope
is still running, and restart it if not. You'll need to have
Anope binaries and data installed in the same directory for this to
work without modification.
First rename the example.chk script that is in Anope path (by default,
~/services) to services.chk and edit it. You'll need to modify the
CONFIGURATION part of the file. Then ensure that the file is marked as
executable by typing chmod +x services.chk, and try to launch the script
to see if it works (Anope must not be running when you do this ;).
When this is done, you'll have to add the crontab entry. Type crontab -e.
This will open the default text editor with the crontab file. Enter the
following (with correct path):
*/5 * * * * /home/ircd/services/services.chk >/dev/null 2>&1
The */5 at the beginning means "check every 5 minutes". You may replace
the 5 with other another number if you want (but less than 60).
Save and exit, and it's installed.
+110
View File
@@ -0,0 +1,110 @@
Anope Modules
-------------
Introduction:
Anope 1.6 onwards supports external modules. External modules are pieces
of code that can be attached to a running Anope process dynamically. These
modules can serve several purposes, and perform all kind of operations to
enhance your network.
Installation:
1. You need to configure Anope to be compiled with module support. To
do so you must run ./configure and answer "Yes" when asked for
Module Support, and selecting a folder where your modules will live
in (the default path is safe for most people).
Notes:
* Modules are not supported on the following platforms: OpenBSD, Windows.
* You might need to run "make distclean" prior to running ./configure
2. Compile Anope as usual. The gmake process will now compile module
support into Anope, and compile the default sample modules, and/or
any other module located on the "modules" folder.
3. Install Anope as usual. The install process will place the compiled
modules in their runtime location, making them available for loading.
4. Start or restart services to make use of the new Anope executable.
Usage:
All module manipulation commands are done through OperServ. These are:
MODLOAD Load a module
MODUNLOAD Un-Load a module
MODLIST List loaded modules
MODINFO Info about a loaded module
These commands available to Service Roots only.
You can also load (and pre-load) Modules automatically by loading them
on startup. To do so, edit your services.conf file and change the values
of "ModuleAutoload" and "ModuleDelayedAutoload" to include the modules
you want to load every time Anope starts.
Example:
/msg OperServ modload hs_moo
*** Global -- from OperServ: dengel loaded module hs_moo
-OperServ- Module hs_moo loaded
/msg OperServ modinfo hs_moo
-OperServ- Module: hs_moo Version: 1.1 Author: Anope loaded: Mar 21 10:54:37 2004 CLT
-OperServ- Providing command: /msg HostServ moo
/msg HostServ moo
-HostServ- MOO! - This command was loaded via a module!
/msg OperServ modunload hs_moo
*** Global -- from OperServ: dengel unloaded module hs_moo
-OperServ- Module hs_moo unloaded
/msg HostServ moo
-HostServ- Unknown command moo. "/msg HostServ HELP" for help.
* Note that the name of the module file is "hs_moo.c", yet we load
and reference the module as "hs_moo" only. By naming convention
modules have an abreviated service name they attach to (hs_ for
HostServ, cs_ for ChanServ, etc) followed by a descriptive keyword.
More Modules:
Anope ships with two sample modules that only ilustrates some of the
implemented module capabilities. They don't really do much or anything
useful.
You can download more useful modules from http://www.anope.org/ or from
our interim modules development website http://modules.anope.org/. Just
grab the module file (usualy with a .c extension). Place the module
file on your compile "modules" folder. The same folder that contain both
hs_moo.c and catserv.c module files.
The new modules need to be compiled and installed before you can make
use of them:
1. Change directories to your compile "modules" folder.
2. Run ./configure
3. Run make
4. Run make install
You can now use /msg OperServ MODLOAD to load the new modules.
Support:
The Anope team is not responsible or liable for any unofficial module
(i.e. anything other than what was released with the Anope package).
Use modules at your own risk, and make sure you get them from a
reputable source. You might get module support by contacting the module
author, posting on our online forum, or maybe on our #anope channel
at /server irc.anope.org.
Developers:
Please take a look at:
* http://geniusdex.dezeserver.nl/anope
+97
View File
@@ -0,0 +1,97 @@
Anope MySQL Support
-------------------
Introduction:
Anope 1.6 onwards supports MySQL databases. On Anope 1.6.0 only PHASE 1
has been implemented. Since the next phases require major changes in the
core, we decided to save it for 2.0. However, having your db's easily
accessible on your website is still a great feature.
PHASE 1:Anope will be able to save all it's databases to MySQL. It will
happen in conjuction with the current FFF databases. This first step is
nothing more than a MySQL dump of the databases (i.e. read-only), since
Anope will not (for now) read from Mysql. (COMPLETED)
PHASE 2:The next step is load the databases from mysql, being able to
replace the FFF completely as an archive method (since all changes to
the mysql db would be lost on the next Services save). All, while keeping
FFF intact. This is still not the final goal, but it's a milestone.
PHASE 3:The next step, and most convoluted of all (since we'll need to
modify pretty much all the source) is to load/save (SELECT/INSERT) data
in realtime. That way the mysql db could be modified externaly (web?).
Again, the FFF will be kept intact.
Requirements:
1. MySQL server version 3.23.32 or greater
2. MySQL libs and development files (usualy called mysql-dev).
3. A MySQL user account
4. A MySQL database
Installation:
1. You need to configure Anope to be compiled with MySQL support. To
do so you must run ./configure and answer "Yes" when asked for
MySQL Support.
Notes:
* MySQL is not supported on the following platforms: Windows.
* You might need to run "make distclean" prior to running ./configure
2. Compile Anope as usual. The gmake process will now compile MySQL
support into Anope.
3. Install Anope as usual.
Configuration:
1. Run bin/mydbgen to help on the schema creation and adjustments.
2. Edit services.conf and add your mysql data to the MySQL configuration
block.
3. Start or restart services to make use of the new Anope executable.
Security:
To add a layer of security you have the option of encrypting or encoding
all passwords for nicks and chans. Use the "MysqlSecure" directive on your
services.conf file to enable it. The availabe storage methods are:
#MysqlSecure "" or MysqlSecure ""
Disables security. All passwords will be saved on the MySQL database
as clear text, with no encryption or encoding. FASTEST
MysqlSecure "des"
Encrypts all passwords using a unix DES encription. This is a one way
encryption algorithm. You can only validate it agains another DES
encrypted string, using the same "salt" (the first two characters of
the encrypted string). FAST
MysqlSecure "md5"
Calculates an MD5 128-bit checksum for the password. The value is
returned as a 32-digit hex number that may be used as a hash key.
SLOW
MysqlSecure "sha"
Calculates an SHA 160-bit checksum for the password. The value is
returned as a 40-digit hex number. SLOWEST
MysqlSecure "mykey"
Encodes the passwords using "mykey" as the encryption password. It
produces a binary string and can be decoded using the MySQL builtit
function DECODE(crypt_str,mykey). VARIABLE
Caveat: Keep in mind that this if you use any method other than clear
text, services will need to encrypt/encode every single password on
every database save. On large networks, it may impact responsiveness
during the saves.
+92
View File
@@ -0,0 +1,92 @@
Highlighted News in Anope 1.6
=============================
* Fixed various exploits and vulverabilities.
* Fixed various language typos and inconsistencies.
* Improved ignore system.
* Improved ./configure script.
* Removed all compile warning fixed.
* Converted HelpServ into a proper service.
* Added external module support.
* Added Defense Condition (DEFCON) System.
* Added MySQL support for mirroring databases.
* Added multi-server configuration.
* Added multi-domain /OS GLOBAL support.
* Added combined +oq +oa +ha +va on net-joins.
* Added support for ircd changes and upgrades.
* Added HostSetters configuration directive.
* Added /OS STAFF command.
* Added /OS SVSNICK command.
* Added /OS CHANKILL command.
* Added /MS STAFF command.
* Added /NS UPDATE command.
* Added /MS SENDALL command.
* Added /NS GETMAIL command.
* Added /HS DELALL command.
* Added /HS LIST command with pattern matching.
* New support scripts and tools.
* New ircd support, complete list: DreamForge 4.6.7, Bahamut 1.4.27,
UnrealIRCd 3.1.1, UltimateIRCd 2.8.2,
UltimateIRCd 3.0.0, Hybrid IRCd 7.0
ViagraIRCd 1.3.x, PTlink 6.15.0
* New Language files, complete list: cat.l, de.l, en_us.l, es.l, fr.l,
gr.l, it.l, nl.l, pt.l, ru.l, tr.l
Highlighted News in Anope 1.4
=============================
After the change from Epona to Anope
------------------------------------
* New Italian Language file
* Added support for UltimateIRCd 3.0 and later
* Services realtime logging to a channel
* SuperAdmin directive for access to "super" commands.
* Ban system is now exception aware.
* HostServ for hostname masquarading.
* Smarter XOP System.
* Email verification/handshake upon registration.
* Services can now /ignore users.
* Smarter memo notification for channels.
* Channel can be SUSPENDed instead of FORBIDen.
Before the change from Epona to Anope
-------------------------------------
* HostServ for networks that support them.
* UnrealIRCd support has been rewritten, it is now fully
working (hopefully) and officially supported again.
* Added support for UltimateIRCd 2.8.2 and later.
* A multi-threaded proxy detector that can scan Wingates,
SOCKS 4/5 and HTTP proxies on ports 3128 and 8080. Don't use
it if you have not been authorized to use it by your system
administrator!
* The ChanServ AOP/SOP/VOP commands, and, on networks that
support halfops, the HOP command, have been added. They
allow a more user-friendly control of channel privileges.
* Use of services IDs that allow an user to be automatically
identified after a split (if he was identified before the split)
in a secure way. This also saves lots of bandwidth.
* Services' default language can now be set in services.conf.
* The OperServ RANDOMNEWS command provides an easy way to show
network news in a random manner without flooding your users
with them (one news per connection).
* The BotServ SET PRIVATE option allows services admins to
make the bot usable by IRC operators only.
* The OperServ SQLINE command allows you to forbid nick masks
and even channel masks with the latest Bahamut.
* The ChanServ AKICK STICK command allows akicks to be permanently
kept on channel.
* The ChanServ SET TOPIC command has been renamed to TOPIC, and
a new BAN command has been added. They both have their own
associated levels.
* A SET PEACE command has been added to ChanServ. It prevents
users to use pejorative services commands (DEOP, KICK, ...)
on users with greater or equal levels.
Networks using Bahamut must upgrade to Bahamut 1.4.27 or later,
while networks using UnrealIRCd must upgrade to Unreal 3.1.1.
For the full changes, see the Changes file.
For announcements and discussions about Anope, subscribe to the mailing
list by sending an e-mail to epona-request@epona.org with "subscribe"
in the body (quotes excluded). You can then post to the mailing list
by sending an e-mail to epona@epona.org.
+307
View File
@@ -0,0 +1,307 @@
Anope -- a set of IRC services for IRC networks
===============================================
Anope is 2003-2004 Anope Team <info@anope.org>
Based on Epona 2000-2002 PegSoft <epona@pegsoft.net>.
Based on Services 1996-1999 Andrew Church <achurch@dragonfire.net>.
This program is free but copyrighted software; see the file COPYING for
details.
Information about Anope may be found at http://www.anope.org/
Information about Epona may be found at http://www.epona.org/
Information about Services may be found at http://www.ircservices.za.net/
TABLE OF CONTENTS
-----------------
1. Credits
2. Presentation
3. Installation
4. Command line options
5. Messages translation
6. Contact and mailing list
1. CREDITS
----------
Anope is based on Lara's Epona version 1.4.14.
Epona is based on Andy Church's IRC Services version 4.3.3.
The original credits:
Mauritz Antunes -- Portuguese translation
Jose R. Holzmann, Raul S. Villarreal -- Spanish translation
Andrew Kempe <theshadow@shadowfire.org> -- news system
<d.duca@eurcom.net> -- Italian translation
<mikado@holyfire.com> -- Turkish translation
Andrew Kempe <theshadow@shadowfire.org> -- session limiting
Epona credits:
lara <lara@pegsoft.net> -- Main coding
CafeiN <oytuny@yahoo.com> -- Turkish translation
Sylvain Cresto aka tost <scresto@netsante.fr> -- FreeBSD 5 patch
Marcelo Conde Foscarini aka Bras <ircadmin@brmarket.net> -- Portuguese translation
Alvaro Toledo aka POLLITO <atoledo@keldon.org> -- Spanish translation
chemical <chemical@musicplay.de> -- German translation
shine <dh@shinewelt.de> -- German translation
Guven Guzelbey aka MeShGuL <guzelbey@cs.utk.edu> -- Turkish translation
Jordi Pujol <jordi.pujol@aujac.org> -- Catalan translation
Eva Dachs <evadachs@terra.es> -- Catalan translation
Toni Perez <toni.perez@aujac.org> -- Catalan translation
Sergios Karalis <sergios_k@hotmail.com> -- Greek translation
Thomas J. Stensas aka ShadowMaster <shadowmaster@shadow-realm.org> -- Ultimate 3.x support
Anope credits:
Adam Kramer <ribosome@anope.org>
Alvaro Toledo <atoledo@keldon.org>
Björn Stiddien <keeper@anope.org>
Daniel Engel <dane@zero.org>
David <dv@diboo.net>
David Narayan <jester@phrixus.net>
David Robson <rob@anope.org>
Daniele Nicolucci <jollino@sogno.net>
Florian Schulze <certus@anope.org>
JH <jh@irc-chat.net>
Joris Vink <joris@anope.org>
Lucas Nussbaum <lucas@lucas-nussbaum.net>
Thomas Juberg Stensås <ShadowMaster@Shadow-Realm.org>
Trystan .S Lee <trystan@anope.org>
openglx <openglx@brasnerd.com.br>
Anope Translations:
GeniousDex (nl.l)
Oleg Nikolaev aka Isot <isot@complife.ru> (ru.l)
Stuff <the.stuff@gmx.de> (de.l)
DrStein (es.l)
2. PRESENTATION
---------------
Anope is a set of Services for IRC networks that allows users to
manage their nicks and channels in a secure and efficient way, and
administrators to manage their network with powerful tools.
Currently available services are:
* NickServ, a powerful nickname manager that users can use to
protect themselves against nick stealing. Each user has its
own nickname group, that allows him to register as many nicks as
he needs while still being able to take profit of his privileges
and to modify his nick configuration. NickServ also has an optional
password retrieval feature.
* ChanServ, a powerful channel manager that helps users to administer
their channels in a totally customizable way. ChanServ has an internal
list of privilegied users and banned users that controls accesses
on a per-channel basis. It eliminates all takeover problems,
because of its powerful op/unban/invite and even mass deop and mass
kick functions.
* MemoServ, an helpful companion that allows sending short messages
to offline users, that they can then read when they come online
later.
* BotServ, an original service that allows users to get a permanent,
friendly bot on their channels in an easy way. Each bot can be
configured to monitor the channels against floods, repetitions,
caps writing, swear, and take appropriate actions. It also can
handle user-friendly commands (!op,!deop,!voice,!devoice,!kick,...),
say a short greet message when an user joins a channel, and even
"take over" ChanServ actions such as auto-opping users, saying the
entry notice, and so on. This service can be disabled if you
want to save some bandwidth.
* OperServ, the IRCops' and IRC admins' black box, that allows them
to manage the list of network bans (also known as AKILL (DALnet) or
GLINE (Undernet)), to configure messages displayed to users when
they log on, to set modes and to kick users from any channel,
to send notices quickly to the entire network, and much more!
* HostServ, a neat service that allows users to show custom
vHosts (virtual hosts) instead of their real IP address; this only
works on deamons supporting ip cloaking, such as UnrealIRCd and
UltimateIRCd.
* HelpServ, a skeleton service used to serve help files.
Anope currently works with:
- DreamForge 4.6.7
- Bahamut 1.4.27 or later
- UnrealIRCd 3.1.1 or later (including 3.2)
- UltimateIRCd 2.8.2 or later (including 3.0.0)
- ViagraIRCd 1.3 or later
- Hybrid 7 or later
- PTlink 6.15 or later
Anope could also work with some of the deamons derivated by the ones
listed above.
3. INSTALLATION
---------------
See the INSTALL file.
4. COMMAND LINE OPTIONS
-----------------------
Normally, Anope can be run simply by invoking the "services"
executable. Anope will then use the defaults specified in the
services.conf file, and connect to the specified uplink server.
Alternatively, any of the following command-line options can be specified
to change the default values:
-remote server[:port] Connect to the specified server
-local host -or- Connect from the specified address (e.g.
[host]:[port] for multihomed servers)
-name servername Our server name (e.g. services.some.net)
-desc string Description of us (e.g. SomeNet Services)
-user username Username for Services' nicks (e.g. services)
-host hostname Hostname for Services' nicks (e.g. esper.net)
-dir directory Directory containing Services' data files
(e.g. /usr/local/lib/services)
-log filename Services log filename (e.g. services.log)
-update secs How often to update databases (in seconds)
-expire secs How often to check for nick/channel
expiration (in seconds)
Additionally, the following command-line options can be used to modify
the behavior of Anope:
-debug Enable debugging mode--more info sent to log
(give option more times for more info)
-readonly Enable read-only mode--no changes to
databases allowed, .db files and log
not written
-skeleton Enable skeleton mode--like read-only mode,
but only OperServ is available
-nofork Do not fork after startup; log messages will
be written to terminal (as well as to
the log file if not in read-only mode)
-forceload Try to load as much of the databases as
possible, even if errors are encountered
-noexpire Expiration routines won't be run at all
-logchan Startup with logchan enabled
Upon starting, Anope will parse its command-line parameters, open
its logfile, then (assuming the -nofork option is not given) detach itself
and run in the background. If Anope encounters a problem reading the
database files or cannot connect to its uplink server, it will terminate
immediately; otherwise, it will run until the connection is terminated (or
a QUIT, SHUTDOWN, or RESTART command is sent--see OperServ's help). In the
case of an error, an appropriate error message will be written to the log
file.
If Anope is run with the "-readonly" command-line option, it can
serve as a "backup" to the full version of services. A "full" version of
services (run without -readonly) will automatically reintroduce its
pseudo-clients (NickServ, ChanServ, etc.), while a "backup" services will
not, thus allowing full services to be brought up at any time without
disrupting the network (and without having to take backup services down
beforehand).
If Anope is run with the "-skeleton" command-line option, it will
not try to load the nickname or channel databases, and will respond with
"service is inactive" messages to any commands sent to NickServ, ChanServ,
MemoServ or BotServ. This can be useful as an emergency stopgap measure
when the main copy of Anope cannot be started.
The "-debug" option is useful if you find or suspect a problem in
Anope. Giving it once on the command line will cause all traffic to and
from services as well as some other debugging information to be recorded in
the log file; if you send a bug report, PLEASE include an excerpt from the
log file WITH DEBUGGING ACTIVE--I cannot emphasize enough how important
this is to tracking down problems. (You can also enable debugging while
Services is running using OperServ's SET DEBUG command.) If you repeat the
-debug option more than once, the debugging level will be increased, which
provides more detailed information but may also slow Anope down
considerably and make the log file grow dramatically faster (in particular,
at debug level 4 a message is written to the log for every character
received from the server). In general, a debug level of 1 is sufficient
for the coding team to be able to trace a problem, because all network
traffic is included and we can usually reproduce the problem.
The "-forceload" option is provided to attempt recovery of data from
corrupted or truncated databases. Normally, if Anope encounters an
error writing to a database file, it will attempt to restore the original
version of the file and report an error to the logfile and through WALLOPS.
However, if this should fail (which normally should not happen), or if
Anope is terminated abruptly e.g. by kill -9 or a power failure, then
one or more of the databases may be corrupt. Normally, this will cause
Anope to abort the next time you try to run it; however, if you give
the -forceload option to Anope, it will instead read as much as it can,
then skip to the next database. For obvious reasons, it's recommended to
keep backup copies of your databases in case something does happen (since
Anope will stop at the first error even with -forceload, meaning you
lose any data after that).
5. MESSAGES TRANSLATIONS
------------------------
Anope has a powerful option in NickServ allowing users to choose what
language it must use when sending messages to users. Messages
are stored in language files (located in the lang directory).
Anope is currently provided with eleven languages: Catalan, Dutch, English,
French, German, Greek, Italian, Portuguese, Russian, Spanish and
Turkish. If you want to translate Anope messages into another language,
follow the following instructions:
* Copy the lang/en_us.l file to a meaningful name (for example, if
you would like to translate messages in Spanish, you would
rename it to es.l).
* Edit the file with your favourite text editor. Carefully read
the instructions given at the top of the file, and start
translating the whole file. The file is big so make sure you have
some coffee available. ;) Try to avoid the use of English words
as much as possible. If the new language contains only a few 'special'
characters, try and use latin representations of it, if possible.
Remember that most clients are only capable of handling the
ISO-8859-1 charset. Of course, if you are translating Anope to a
language with a totally different charset, such as Russian, feel free
to use the one that suites it best (and the one that is in use by
most speakers of that language ;).
* When this is done, you have two solutions: either patch Services
source code so they take in account the new language file (basically,
you'll have to modify lang/Makefile, language.c and maybe services.h),
or send us the translated file so we can make the patch and
include your language in the next Anope release.
* Note that there is a language tool on bin/langtool.pl that can aid
the verification process on newly created language files. Try to use
it before you submit a language file.
When new major releases come out, you'll not have to retranslate the whole
file; the Changes.lang file will help you to know which messages were
added, modified or deleted.
If you did a language file translation, and want to let others use it,
please send it to dev@anope.org (don't forget to mention clearly your
(nick)name, your e-mail and the language name). You'll of course get full
credit for it, and will even get future final major releases before anyone
else to complete the translation!... ;)
6. CONTACT
---------------------------
* For announcements and discussions about Anope, please visit our Portal
and Forums at http://www.anope.org/ make sure you register yourself and
your netowrk to get full benefits.
* If you read the documentation carefully, and didn't find the answer
to your question, feel free to post on the website forums or join our
irc channel (irc.anope.org #anope). Once you join our Support channel,
just type "? report" for instructions on how to report a Bug. Be as
precise as possible when asking a question, because we have no extraordinary
powers and can't guess things if they aren't provided. The more precise you
are, the sooner you'll be likely to get an answer.
* If you think you found a bug, add it to the bug tracking system on our
website (http://www.anope.org) and - again - be as precise as possible. Also
say whether the bug happens always or under what circumstances, and anything
that could be useful to track your bug down. If you wrote a patch, send it
over. :)
* We do *not* support Windows versions of Anope. You must seek support from
the website you downloaded the Windows port from. Anope Services was never
meant to run on Windows... it might in the future, but for the time being
you are on your own. And for Mac fans... Anope runs like a champ on OSX.
+434
View File
@@ -0,0 +1,434 @@
/* Include file for high-level encryption routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: encrypt.c,v 1.5 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
#include "encrypt.h"
#ifdef USE_ENCRYPTION
/*************************************************************************/
/******** Code specific to the type of encryption. ********/
#ifdef /********/ ENCRYPT_MD5 /********/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include <string.h>
typedef unsigned int UINT4;
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
typedef void *POINTER;
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform(UINT4[4], unsigned char[64]);
static void Encode(unsigned char *, UINT4 *, unsigned int);
static void Decode(UINT4 *, unsigned char *, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
static void MD5Init(context)
MD5_CTX *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
static void MD5Update(context, input, inputLen)
MD5_CTX *context; /* context */
unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4) inputLen << 3))
< ((UINT4) inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4) inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
memcpy
((POINTER) & context->buffer[index], (POINTER) input, partLen);
MD5Transform(context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform(context->state, &input[i]);
index = 0;
} else
i = 0;
/* Buffer remaining input */
memcpy
((POINTER) & context->buffer[index], (POINTER) & input[i],
inputLen - i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
static void MD5Final(digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode(bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update(context, PADDING, padLen);
/* Append length (before padding) */
MD5Update(context, bits, 8);
/* Store state in digest */
Encode(digest, context->state, 16);
/* Zeroize sensitive information.
*/
memset((POINTER) context, 0, sizeof(*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform(state, block)
UINT4 state[4];
unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode(x, block, 64);
/* Round 1 */
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
memset((POINTER) x, 0, sizeof(x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode(output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char) (input[i] & 0xff);
output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode(output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
(((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) <<
24);
}
#endif /******** ENCRYPT_MD5 ********/
/*************************************************************************/
/******** Our own high-level routines. ********/
#define XTOI(c) ((c)>9 ? (c)-'A'+10 : (c)-'0')
/* Encrypt `src' of length `len' and store the result in `dest'. If the
* resulting string would be longer than `size', return -1 and leave `dest'
* unchanged; else return 0.
*/
int encrypt(const char *src, int len, char *dest, int size)
{
#ifdef ENCRYPT_MD5
MD5_CTX context;
char digest[33];
int i;
if (size < 16)
return -1;
memset(&context, 0, sizeof(context));
memset(&digest, 0, sizeof(digest));
MD5Init(&context);
MD5Update(&context, src, len);
MD5Final(digest, &context);
for (i = 0; i < 32; i += 2)
dest[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]);
return 0;
#endif
return -1; /* unknown encryption algorithm */
}
/* Shortcut for encrypting a null-terminated string in place. */
int encrypt_in_place(char *buf, int size)
{
return encrypt(buf, strlen(buf), buf, size);
}
/* Compare a plaintext string against an encrypted password. Return 1 if
* they match, 0 if not, and -1 if something went wrong. */
int check_password(const char *plaintext, const char *password)
{
char buf[BUFSIZE];
if (encrypt(plaintext, strlen(plaintext), buf, sizeof(buf)) < 0)
return -1;
#ifdef ENCRYPT_MD5
if (memcmp(buf, password, 16) == 0)
#else
if (0)
#endif
return 1;
else
return 0;
}
/*************************************************************************/
#else /* !USE_ENCRYPTION */
int encrypt(const char *src, int len, char *dest, int size)
{
if (size < len)
return -1;
memcpy(dest, src, len);
return 0;
}
int encrypt_in_place(char *buf, int size)
{
return 0;
}
int check_password(const char *plaintext, const char *password)
{
if (strcmp(plaintext, password) == 0)
return 1;
else
return 0;
}
#endif /* USE_ENCRYPTION */
/*************************************************************************/
+17
View File
@@ -0,0 +1,17 @@
/* Include file for high-level encryption routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: encrypt.h,v 1.4 2003/07/20 01:15:49 dane Exp $
*
*/
extern int encrypt(const char *src, int len, char *dest, int size);
extern int encrypt_in_place(char *buf, int size);
extern int check_password(const char *plaintext, const char *password);
+838
View File
@@ -0,0 +1,838 @@
/* Prototypes and external variable declarations.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: extern.h,v 1.65 2004/03/13 13:55:59 dane Exp $
*
*/
#ifndef EXTERN_H
#define EXTERN_H
#include "slist.h"
#define E extern
/**** modules.c ****/
E void moduleCallBackRun(void);
/**** actions.c ****/
E void change_user_mode(User *u, char *modes, char *arg);
E void kill_user(const char *source, const char *user, const char *reason);
E void bad_password(User *u);
/**** botserv.c ****/
E BotInfo *botlists[256];
E void get_botserv_stats(long *nrec, long *memuse);
E void bs_init(void);
E void botserv(User *u, char *buf);
E void botmsgs(User *u, BotInfo *bi, char *buf);
E void botchanmsgs(User *u, ChannelInfo *ci, char *buf);
E void load_bs_dbase(void);
E void save_bs_dbase(void);
E void save_bs_rdb_dbase(void);
E BotInfo *findbot(char *nick);
E void bot_join(ChannelInfo *ci);
E void bot_rejoin_all(BotInfo *bi);
/**** channels.c ****/
E Channel *chanlist[1024];
E CBMode cbmodes[128];
E CBModeInfo cbmodeinfos[];
E void get_channel_stats(long *nrec, long *memuse);
E Channel *findchan(const char *chan);
E Channel *firstchan(void);
E Channel *nextchan(void);
E void chan_deluser(User *user, Channel *c);
E int is_on_chan(Channel *c, User *u);
E User *nc_on_chan(Channel *c, NickCore *nc);
E char *chan_get_modes(Channel *chan, int complete, int plus);
E void chan_set_modes(const char *source, Channel *chan, int ac, char **av, int check);
E int chan_get_user_status(Channel *chan, User *user);
E int chan_has_user_status(Channel *chan, User *user, int16 status);
E void chan_remove_user_status(Channel *chan, User *user, int16 status);
E void chan_set_user_status(Channel *chan, User *user, int16 status);
E int get_access_level(ChannelInfo *ci, NickAlias *na);
E char *get_xop_level(int level);
E void do_cmode(const char *source, int ac, char **av);
E void do_join(const char *source, int ac, char **av);
E void do_kick(const char *source, int ac, char **av);
E void do_part(const char *source, int ac, char **av);
E void do_sjoin(const char *source, int ac, char **av);
E void do_topic(const char *source, int ac, char **av);
E void do_mass_mode(char *modes);
#define whosends(ci) ((!(ci) || !((ci)->botflags & BS_SYMBIOSIS) || !(ci)->bi || !(ci)->c || (ci)->c->usercount < BSMinUsers) ? s_ChanServ : (ci)->bi->nick)
/**** chanserv.c ****/
E ChannelInfo *chanlists[256];
E CSModeUtil csmodeutils[];
E void listchans(int count_only, const char *chan);
E void get_chanserv_stats(long *nrec, long *memuse);
E void cs_init(void);
E void chanserv(User *u, char *buf);
E void load_cs_dbase(void);
E void save_cs_dbase(void);
E void save_cs_rdb_dbase(void);
E void expire_chans(void);
E void cs_remove_nick(const NickCore *nc);
E void cs_remove_bot(const BotInfo *bi);
E void check_modes(Channel *c);
#ifdef IRC_ULTIMATE3
E int check_valid_admin(User *user, Channel *chan, int servermode);
#endif
E int check_valid_op(User *user, Channel *chan, int servermode);
E int check_should_op(User *user, const char *chan);
E int check_should_voice(User *user, const char *chan);
#ifdef HAS_HALFOP
E int check_should_halfop(User *user, const char *chan);
#endif
#if defined(IRC_UNREAL) || defined(IRC_VIAGRA)
E int check_should_owner(User *user, const char *chan);
E int check_should_protect(User *user, const char *chan);
#endif
#ifdef IRC_ULTIMATE3
E int check_should_protect(User *user, const char *chan);
#endif
E int check_kick(User *user, char *chan);
E void record_topic(const char *chan);
E void restore_topic(const char *chan);
E int check_topiclock(Channel *c, time_t topic_time);
E ChannelInfo *cs_findchan(const char *chan);
E int check_access(User *user, ChannelInfo *ci, int what);
E int is_founder(User *user, ChannelInfo *ci);
E int get_access(User *user, ChannelInfo *ci);
E ChanAccess *get_access_entry(NickCore *nc, ChannelInfo *ci);
E void update_cs_lastseen(User *user, ChannelInfo *ci);
E int get_idealban(ChannelInfo *ci, User *u, char *ret, int retlen);
E AutoKick *is_stuck(ChannelInfo *ci, char *mask);
E void stick_mask(ChannelInfo *ci, AutoKick *akick);
E void stick_all(ChannelInfo *ci);
#ifdef HAS_FMODE
E char *cs_get_flood(ChannelInfo *ci);
E void cs_set_flood(ChannelInfo *ci, char *value);
#endif
E char *cs_get_key(ChannelInfo *ci);
E void cs_set_key(ChannelInfo *ci, char *value);
E char *cs_get_limit(ChannelInfo *ci);
E void cs_set_limit(ChannelInfo *ci, char *value);
#ifdef HAS_LMODE
E char *cs_get_redirect(ChannelInfo *ci);
E void cs_set_redirect(ChannelInfo *ci, char *value);
#endif
/**** compat.c ****/
#if !HAVE_SNPRINTF
# if BAD_SNPRINTF
# define snprintf my_snprintf
# endif
# define vsnprintf my_vsnprintf
E int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
E int snprintf(char *buf, size_t size, const char *fmt, ...);
#endif
#if !HAVE_STRICMP && !HAVE_STRCASECMP
E int stricmp(const char *s1, const char *s2);
E int strnicmp(const char *s1, const char *s2, size_t len);
#endif
#if !HAVE_STRDUP
E char *strdup(const char *s);
#endif
#if !HAVE_STRSPN
E size_t strspn(const char *s, const char *accept);
#endif
#if !HAVE_STRERROR
E char *strerror(int errnum);
#endif
#if !HAVE_STRSIGNAL
char *strsignal(int signum);
#endif
/**** config.c ****/
E char *RemoteServer;
E int RemotePort;
E char *RemotePassword;
E char *RemoteServer2;
E int RemotePort2;
E char *RemotePassword2;
E char *RemoteServer3;
E int RemotePort3;
E char *RemotePassword3;
E char *LocalHost;
E int LocalPort;
E char *ServerName;
E char *ServerDesc;
E char *ServiceUser;
E char *ServiceHost;
E char *HelpChannel;
E char *LogChannel;
E char **NetworkDomains;
E int DomainNumber;
E char *NetworkName;
E char *s_NickServ;
E char *s_ChanServ;
E char *s_MemoServ;
E char *s_BotServ;
E char *s_HelpServ;
E char *s_OperServ;
E char *s_GlobalNoticer;
E char *s_IrcIIHelp;
E char *s_DevNull;
E char *desc_NickServ;
E char *desc_ChanServ;
E char *desc_MemoServ;
E char *desc_BotServ;
E char *desc_HelpServ;
E char *desc_OperServ;
E char *desc_GlobalNoticer;
E char *desc_IrcIIHelp;
E char *desc_DevNull;
E char *HostDBName;
E char *desc_HostServ;
E char *s_HostServ;
E void load_hs_dbase(void);
E void save_hs_dbase(void);
E void save_hs_rdb_dbase(void);
E int do_on_id(User *u);
E void delHostCore(char *nick);
E void hostserv(User *u, char *buf);
E char *s_NickServAlias;
E char *s_ChanServAlias;
E char *s_MemoServAlias;
E char *s_BotServAlias;
E char *s_HelpServAlias;
E char *s_OperServAlias;
E char *s_GlobalNoticerAlias;
E char *s_DevNullAlias;
E char *s_HostServAlias;
E char *desc_NickServAlias;
E char *desc_ChanServAlias;
E char *desc_MemoServAlias;
E char *desc_BotServAlias;
E char *desc_HelpServAlias;
E char *desc_OperServAlias;
E char *desc_GlobalNoticerAlias;
E char *desc_DevNullAlias;
E char *desc_HostServAlias;
E char *PIDFilename;
E char *MOTDFilename;
E char *NickDBName;
E char *PreNickDBName;
E char *ChanDBName;
E char *BotDBName;
E char *OperDBName;
E char *AutokillDBName;
E char *NewsDBName;
E int NoBackupOkay;
E int StrictPasswords;
E int BadPassLimit;
E int BadPassTimeout;
E int UpdateTimeout;
E int ExpireTimeout;
E int ReadTimeout;
E int WarningTimeout;
E int TimeoutCheck;
E int KeepLogs;
E int KeepBackups;
E int ForceForbidReason;
E int UsePrivmsg;
E int DumpCore;
E int LogUsers;
E char **HostSetters;
E int HostNumber;
E int UseMail;
E char *SendMailPath;
E char *SendFrom;
E int RestrictMail;
E int MailDelay;
E int DontQuoteAddresses;
E int ProxyDetect;
E int ProxyThreads;
E char *ProxyMessage[8];
E int ProxyCheckWingate;
E int ProxyCheckSocks4;
E int ProxyCheckSocks5;
E int ProxyCheckHTTP1;
E int ProxyCheckHTTP2;
E int ProxyCheckHTTP3;
E int ProxyTimeout;
E char *ProxyTestServer;
E int ProxyTestPort;
E int ProxyExpire;
E int ProxyCacheExpire;
E char *ProxyAkillReason;
E int WallProxy;
E int ProxyMax;
E int NSDefFlags;
E int NSDefLanguage;
E int NSRegDelay;
E int NSExpire;
E int NSRExpire;
E int NSForceEmail;
E int NSMaxAliases;
E int NSAccessMax;
E char *NSEnforcerUser;
E char *NSEnforcerHost;
E int NSReleaseTimeout;
E int NSAllowKillImmed;
E int NSNoGroupChange;
E int NSListOpersOnly;
E int NSListMax;
E char *NSGuestNickPrefix;
E int NSSecureAdmins;
E int NSStrictPrivileges;
E int NSEmailReg;
E int NSModeOnID;
E int NSRestrictGetPass;
E int CSDefFlags;
E int CSMaxReg;
E int CSExpire;
E int CSDefBantype;
E int CSAccessMax;
E int CSAutokickMax;
E char *CSAutokickReason;
E int CSInhabit;
E int CSListOpersOnly;
E int CSListMax;
E int CSRestrictGetPass;
E int CSOpersOnly;
E int MSMaxMemos;
E int MSSendDelay;
E int MSNotifyAll;
E int BSDefFlags;
E int BSKeepData;
E int BSMinUsers;
E int BSBadWordsMax;
E int BSSmartJoin;
E int BSGentleBWReason;
E int HideStatsO;
E int GlobalOnCycle;
E int AnonymousGlobal;
E char *GlobalOnCycleMessage;
E char *GlobalOnCycleUP;
E char **ServicesRoots;
E int RootNumber;
E int LogMaxUsers;
E int SuperAdmin;
E int LogBot;
E int AutokillExpiry;
E int ChankillExpiry;
E int SGLineExpiry;
E int SQLineExpiry;
E int SZLineExpiry;
E int AkillOnAdd;
E int DisableRaw;
E int WallOper;
E int WallBadOS;
E int WallOSGlobal;
E int WallOSMode;
E int WallOSClearmodes;
E int WallOSKick;
E int WallOSAkill;
E int WallOSSGLine;
E int WallOSSQLine;
E int WallOSSZLine;
E int WallOSNoOp;
E int WallOSJupe;
E int WallOSRaw;
E int WallAkillExpire;
E int WallSGLineExpire;
E int WallSQLineExpire;
E int WallSZLineExpire;
E int WallExceptionExpire;
E int WallDrop;
E int WallForbid;
E int WallGetpass;
E int WallSetpass;
E int CheckClones;
E int CloneMinUsers;
E int CloneMaxDelay;
E int CloneWarningDelay;
E int KillClones;
E int AddAkiller;
E char **ModulesAutoload;
E int ModulesNumber;
E char **ModulesDelayedAutoload;
E int ModulesDelayedNumber;
E int KillClonesAkillExpire;
E int LimitSessions;
E int DefSessionLimit;
E int ExceptionExpiry;
E int MaxSessionKill;
E int MaxSessionLimit;
E int SessionAutoKillExpiry;
E char *ExceptionDBName;
E char *SessionLimitDetailsLoc;
E char *SessionLimitExceeded;
#ifdef USE_RDB
E int rdb_init();
E int rdb_open();
E int rdb_close();
E int rdb_tag_table(char *table);
E int rdb_tag_table(char *table);
E int rdb_clear_table(char *table);
E int rdb_scrub_table(char *table, char *clause);
E int rdb_direct_query(char *query);
E int rdb_ns_set_display(char *newnick, char *oldnick);
E int rdb_cs_set_founder(char *channel, char *founder);
E int rdb_cs_deluser(char *nick);
E int rdb_cs_delchan(ChannelInfo * ci);
E void rdb_save_ns_core(NickCore * nc);
E void rdb_save_ns_alias(NickAlias * na);
E void rdb_save_ns_req(NickRequest * nr);
E void rdb_save_cs_info(ChannelInfo * ci);
E void rdb_save_bs_core(BotInfo * bi);
E void rdb_save_bs_rdb_core(BotInfo * bi);
E void rdb_save_hs_core(HostCore * hc);
E void rdb_save_os_db(unsigned int maxucnt, unsigned int maxutime,
SList * ak, SList * sgl, SList * sql, SList * szl,
HostCache * hc);
E void rdb_save_news(NewsItem * ni);
E void rdb_save_exceptions(Exception * e);
#endif
#ifdef USE_MYSQL
E char *MysqlHost;
E char *MysqlUser;
E char *MysqlPass;
E char *MysqlName;
E int MysqlPort;
E char *MysqlSock;
E char *MysqlSecure;
E int MysqlRetries;
E int MysqlRetryGap;
#endif
E int read_config(int reload);
E int DefConLevel;
E int DefCon[6];
E int checkDefCon(int level);
E void resetDefCon(int level);
E int DefConSessionLimit;
E char *DefConTimeOut;
E char *DefConAKILL;
E char *DefConChanModes;
E int GlobalOnDefcon;
E int GlobalOnDefconMore;
E char *DefconMessage;
E char *DefConAkillReason;
E char *DefConOffMessage;
/**** converter.c ****/
E int convert_ircservices_44(void);
/**** init.c ****/
E void introduce_user(const char *user);
E int init(int ac, char **av);
E int servernum;
/**** language.c ****/
E char **langtexts[NUM_LANGS];
E char *langnames[NUM_LANGS];
E int langlist[NUM_LANGS];
E void lang_init(void);
#define getstring(na,index) \
(langtexts[((na)&&((NickAlias*)na)->nc&&!(((NickAlias*)na)->status & NS_VERBOTEN)?((NickAlias*)na)->nc->language:NSDefLanguage)][(index)])
#define getstring2(nc,index) \
(langtexts[((nc)?((NickCore*)nc)->language:NSDefLanguage)][(index)])
E int strftime_lang(char *buf, int size, User *u, int format, struct tm *tm);
E void syntax_error(const char *service, User *u, const char *command, int msgnum);
/**** list.c ****/
E void do_listnicks(int ac, char **av);
E void do_listchans(int ac, char **av);
/**** log.c ****/
E int open_log(void);
E void close_log(void);
E void alog(const char *fmt, ...) FORMAT(printf,1,2);
E void log_perror(const char *fmt, ...) FORMAT(printf,1,2);
E void fatal(const char *fmt, ...) FORMAT(printf,1,2);
E void fatal_perror(const char *fmt, ...) FORMAT(printf,1,2);
/**** mail.c ****/
E MailInfo *MailBegin(User *u, NickCore *nc, char *subject, char *service);
E MailInfo *MailRegBegin(User *u, NickRequest *nr, char *subject, char *service);
E void MailEnd(MailInfo *mail);
E void MailReset(User *u, NickCore *nc);
E int MailValidate(const char *email);
/**** main.c ****/
E const char version_number[];
E const char version_build[];
E const char version_protocol[];
E const char version_flags[];
E char *services_dir;
E char *log_filename;
E int debug;
E int readonly;
E int logchan;
E int skeleton;
E int nofork;
E int forceload;
E int noexpire;
#ifdef USE_RDB
E int do_mysql;
#endif
E int is44;
E int quitting;
E int delayed_quit;
E char *quitmsg;
E char inbuf[BUFSIZE];
E int servsock;
E int save_data;
E int got_alarm;
E time_t start_time;
E void save_databases(void);
/**** memory.c ****/
E void *smalloc(long size);
E void *scalloc(long elsize, long els);
E void *srealloc(void *oldptr, long newsize);
E char *sstrdup(const char *s);
/**** memoserv.c ****/
E void ms_init(void);
E void memoserv(User *u, char *buf);
E void check_memos(User *u);
/**** misc.c ****/
E char *strscpy(char *d, const char *s, size_t len);
E char *stristr(char *s1, char *s2);
E char *strnrepl(char *s, int32 size, const char *old, const char *new);
E char *merge_args(int argc, char **argv);
E int match_wild(const char *pattern, const char *str);
E int match_wild_nocase(const char *pattern, const char *str);
E int dotime(const char *s);
E char *duration(NickAlias *na, char *buf, int bufsize, time_t seconds);
E char *expire_left(NickAlias *na, char *buf, int len, time_t expires);
typedef int (*range_callback_t)(User *u, int num, va_list args);
E int process_numlist(const char *numstr, int *count_ret,
range_callback_t callback, User *u, ...);
E int isValidHost(const char *host, int type);
E int isvalidchar(char c);
E char *myStrGetToken(const char *str, const char dilim, int token_number);
E char *myStrGetOnlyToken(const char *str, const char dilim,
int token_number);
E char *myStrSubString(const char *src, int start, int end);
E char *myStrGetTokenRemainder(const char *str, const char dilim,
int token_number);
E void doCleanBuffer(char *str);
/**** news.c ****/
E void get_news_stats(long *nrec, long *memuse);
E void load_news(void);
E void save_news(void);
E void save_rdb_news(void);
E void display_news(User *u, int16 type);
E int do_logonnews(User *u);
E int do_opernews(User *u);
E int do_randomnews(User *u);
/**** nickserv.c ****/
E NickAlias *nalists[1024];
E NickCore *nclists[1024];
E NickRequest *nrlists[1024];
E void listnicks(int count_only, const char *nick);
E void get_aliases_stats(long *nrec, long *memuse);
E void get_core_stats(long *nrec, long *memuse);
E void ns_init(void);
E void nickserv(User *u, char *buf);
E void load_ns_dbase(void);
E void load_ns_req_db(void);
E void save_ns_dbase(void);
E void save_ns_req_dbase(void);
E void save_ns_rdb_dbase(void);
E void save_ns_req_rdb_dbase(void);
E int validate_user(User *u);
E void cancel_user(User *u);
E int nick_identified(User *u);
E int nick_recognized(User *u);
E void expire_nicks(void);
E void expire_requests(void);
E int ns_do_register(User * u);
E int delnick(NickAlias *na);
E NickAlias *findnick(const char *nick);
E NickCore *findcore(const char *nick);
E void clean_ns_timeouts(NickAlias *na);
/**** helpserv.c ****/
E void helpserv(User *u, char *buf);
E void helpserv_init(void);
/**** hostserv.c ****/
E void hostserv_init(void);
/**** operserv.c ****/
E SList servadmins;
E SList servopers;
E void operserv(User *u, char *buf);
E void os_init(void);
E void load_os_dbase(void);
E void save_os_dbase(void);
E void save_os_rdb_dbase(void);
E void os_remove_nick(NickCore *nc);
E int is_services_root(User *u);
E int is_services_admin(User *u);
E int is_services_oper(User *u);
E int nick_is_services_admin(NickCore *nc);
E int nick_is_services_oper(NickCore *nc);
E int add_akill(User *u, char *mask, const char *by, const time_t expires, const char *reason);
E int check_akill(const char *nick, const char *username, const char *host, const char *vhost, const char *ip);
E void expire_akills(void);
E void oper_global(char *nick, char *fmt, ...);
#ifdef IRC_BAHAMUT
E int add_sgline(User *u, char *mask, const char *by, const time_t expires, const char *reason);
E int check_sgline(const char *nick, const char *realname);
E void expire_sglines(void);
#endif
E int add_sqline(User *u, char *mask, const char *by, const time_t expires, const char *reason);
E int check_sqline(const char *nick, int nick_change);
#ifdef IRC_BAHAMUT
E int check_chan_sqline(const char *chan);
#endif
E void expire_sqlines(void);
#ifdef IRC_BAHAMUT
E int add_szline(User *u, char *mask, const char *by, const time_t expires, const char *reason);
E void expire_szlines(void);
#endif
E void check_clones(User *user);
E void delete_ignore(const char *nick);
/**** process.c ****/
E int allow_ignore;
E IgnoreData *ignore[];
E void add_ignore(const char *nick, time_t delta);
E IgnoreData *get_ignore(const char *nick);
E int split_buf(char *buf, char ***argv, int colon_special);
E void process(void);
/**** protocol.c ****/
E void s_akill(char *user, char *host, char *who, time_t when, time_t expires, char *reason);
E void s_rakill(char *user, char *host);
E void s_sgline(char *mask, char *reason);
E void s_sqline(char *mask, char *reason);
E void s_svsnoop(char *server, int set);
E void s_szline(char *mask, char *reason);
E void s_unsgline(char *mask);
E void s_unsqline(char *mask);
E void s_unszline(char *mask);
/**** proxy.c ****/
E HostCache *hcache[1024];
E void get_proxy_stats(long *nrec, long *memuse);
E void ntoa(struct in_addr addr, char *ipaddr, int len);
E int proxy_check(char *nick, char *host, uint32 ip);
E void proxy_expire();
E int proxy_init(void);
E int do_cache(User *u);
/**** send.c ****/
E void send_cmd(const char *source, const char *fmt, ...)
FORMAT(printf,2,3);
E void vsend_cmd(const char *source, const char *fmt, va_list args)
FORMAT(printf,2,0);
E void wallops(const char *source, const char *fmt, ...)
FORMAT(printf,2,3);
E void notice(const char *source, const char *dest, const char *fmt, ...)
FORMAT(printf,3,4);
E void notice_user(const char *source, User *u, const char *fmt, ...)
FORMAT(printf,3,4);
E void notice_list(const char *source, const char *dest, const char **text);
E void notice_lang(const char *source, User *dest, int message, ...);
E void notice_help(const char *source, User *dest, int message, ...);
E void privmsg(const char *source, const char *dest, const char *fmt, ...)
FORMAT(printf,3,4);
/**** sessions.c ****/
E void get_session_stats(long *nrec, long *memuse);
E void get_exception_stats(long *nrec, long *memuse);
E int do_session(User *u);
E int add_session(const char *nick, const char *host);
E void del_session(const char *host);
E void load_exceptions(void);
E void save_exceptions(void);
E void save_rdb_exceptions(void);
E int do_exception(User *u);
E void expire_exceptions(void);
/**** sockutil.c ****/
E int32 total_read, total_written;
E int32 read_buffer_len(void);
E int32 write_buffer_len(void);
E int sgetc(int s);
E char *sgets(char *buf, int len, int s);
E char *sgets2(char *buf, int len, int s);
E int sread(int s, char *buf, int len);
E int sputs(char *str, int s);
E int sockprintf(int s, char *fmt,...);
E int conn(const char *host, int port, const char *lhost, int lport);
E void disconn(int s);
/**** users.c ****/
E User *userlist[1024];
E int32 usercnt, opcnt, maxusercnt;
E time_t maxusertime;
E void set_umode(User *user, int ac, char **av);
E void get_user_stats(long *nusers, long *memuse);
E User *finduser(const char *nick);
E User *firstuser(void);
E User *nextuser(void);
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_PTLINK)
E void change_user_host(User *user, const char *host);
E void change_user_username(User *user, const char *username);
E void change_user_realname(User *user, const char *realname);
#endif
E User *do_nick(const char *source, char *nick, char *username, char *host, char *server, char *realname, time_t ts, uint32 svid, ...);
E void do_umode(const char *source, int ac, char **av);
E void do_quit(const char *source, int ac, char **av);
E void do_kill(const char *source, int ac, char **av);
E int is_oper(User *user);
E int is_protected(User *user);
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_HYBRID)
E int is_excepted(ChannelInfo *ci, User *user);
E int is_excepted_mask(ChannelInfo *ci, char *mask);
#endif
E int match_usermask(const char *mask, User *user);
E void split_usermask(const char *mask, char **nick, char **user, char **host);
E char *create_mask(User *u);
#ifdef USE_MYSQL
/**** mysql.c ****/
E MYSQL *mysql;
E MYSQL_RES *mysql_res;
E MYSQL_FIELD *mysql_fields;
E MYSQL_ROW mysql_row;
E int db_mysql_init();
E int db_mysql_open();
E int db_mysql_close();
E int db_mysql_query(char *sql);
E char *db_mysql_quote(char *sql);
E void db_mysql_save_ns_core(NickCore * nc);
E void db_mysql_save_ns_alias(NickAlias * na);
E void db_mysql_save_ns_req(NickRequest * nr);
E void db_mysql_save_cs_info(ChannelInfo * ci);
E void db_mysql_save_os_db(unsigned int maxucnt, unsigned int maxutime, SList *ak, SList *sgl, SList *sql, SList *szl, HostCache *hc);
E void db_mysql_save_news(NewsItem * ni);
E void db_mysql_save_exceptions(Exception * e);
E void db_mysql_save_hs_core(HostCore * hc);
E void db_mysql_save_bs_core(BotInfo * bi);
#endif
#endif /* EXTERN_H */
+83
View File
@@ -0,0 +1,83 @@
/* HelpServ functions
*
* (C) 2003 Anope Team / GeniusDex
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: helpserv.c,v 1.2 2004/01/18 04:33:25 dane Exp $
*
*/
/*************************************************************************/
#include "services.h"
#include "pseudo.h"
#define HELP_VERSION 1
void helpserv_init(void);
static int do_help(User * u);
void moduleAddHelpServCmds(void);
/*************************************************************************/
void moduleAddHelpServCmds(void)
{
Command *c;
c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
addCoreCommand(HELPSERV, c);
}
/*************************************************************************/
/*************************************************************************/
/* HelpServ initialization. */
void helpserv_init(void)
{
moduleAddHelpServCmds();
}
/*************************************************************************/
/* Main HelpServ routine. */
void helpserv(User * u, char *buf)
{
char *cmd, *s;
cmd = strtok(buf, " ");
if (!cmd) {
return;
} else if (stricmp(cmd, "\1PING") == 0) {
if (!(s = strtok(NULL, "")))
s = "\1";
notice(s_HelpServ, u->nick, "\1PING %s", s);
} else {
mod_run_cmd(s_HelpServ, u, HELPSERV, cmd);
}
}
/*************************************************************************/
/* Display the HelpServ help. */
/* This core function has been embed in the source for a long time, but */
/* it moved into it's own file so we now all can enjoy the joy of */
/* modules for HelpServ. */
static int do_help(User * u)
{
char *cmd = strtok(NULL, "");
if (!cmd) {
notice_help(s_HelpServ, u, HELP_HELP, s_NickServ, s_ChanServ,
s_MemoServ);
if (s_BotServ)
notice_help(s_HelpServ, u, HELP_HELP_BOT, s_BotServ);
if (s_HostServ)
notice_help(s_HelpServ, u, HELP_HELP_HOST, s_HostServ);
moduleDisplayHelp(7, u);
} else {
mod_help_cmd(s_HelpServ, u, HELPSERV, cmd);
}
return MOD_CONT;
}
+1108
View File
File diff suppressed because it is too large Load Diff
+807
View File
@@ -0,0 +1,807 @@
/* Initalization and related routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: init.c,v 1.40 2004/03/13 13:55:59 dane Exp $
*
*/
#include "services.h"
#include "pseudo.h"
int servernum = 0;
extern void moduleAddMsgs(void);
/*************************************************************************/
/* Send a NICK command for the given pseudo-client. If `user' is NULL,
* send NICK commands for all the pseudo-clients.
*
* Now also sends MODE and SQLINE */
#if defined(IRC_HYBRID)
# define NICK(nick,name,modes) \
do { \
kill_user(NULL, (nick), "Nick used by Services"); \
send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", (nick), time(NULL), (modes), \
ServiceUser, ServiceHost, ServerName, (name)); \
} while (0)
#elif defined(IRC_ULTIMATE3)
# define NICK(nick,name,modes) \
do { \
send_cmd(NULL, "CLIENT %s 1 %ld %s + %s %s * %s 0 0 :%s", (nick), time(NULL), (modes), \
ServiceUser, ServiceHost, ServerName, (name)); \
send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
} while (0)
#elif defined(IRC_BAHAMUT)
# define NICK(nick,name,modes) \
do { \
send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", (nick), time(NULL), (modes), \
ServiceUser, ServiceHost, ServerName, (name)); \
send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
} while (0)
#elif defined(IRC_UNREAL)
# define NICK(nick,name,modes) \
do { \
send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 %s * :%s", (nick), time(NULL), \
ServiceUser, ServiceHost, ServerName, (modes), (name)); \
send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
} while (0)
#elif defined(IRC_DREAMFORGE)
# define NICK(nick,name,modes) \
do { \
send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", (nick), time(NULL), \
ServiceUser, ServiceHost, ServerName, (name)); \
if (strcmp(modes, "+")) send_cmd((nick), "MODE %s %s", (nick), (modes)); \
send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
} while (0)
#elif defined(IRC_PTLINK)
# define NICK(nick,name,modes) \
do { \
send_cmd(NULL, "NICK %s 1 %lu %s %s %s %s %s :%s", (nick), time(NULL), \
(modes), ServiceUser, ServiceHost, ServiceHost, ServerName, (name)); \
} while (0)
#endif
void introduce_user(const char *user)
{
/* Watch out for infinite loops... */
#define LTSIZE 20
static int lasttimes[LTSIZE];
if (lasttimes[0] >= time(NULL) - 3)
fatal("introduce_user() loop detected");
memmove(lasttimes, lasttimes + 1, sizeof(lasttimes) - sizeof(int));
lasttimes[LTSIZE - 1] = time(NULL);
#undef LTSIZE
if (!user || stricmp(user, s_NickServ) == 0)
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_NickServ, desc_NickServ, "+S");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_NickServ, desc_NickServ, "+oS");
#else
NICK(s_NickServ, desc_NickServ, "+o");
#endif
if (!user || stricmp(user, s_ChanServ) == 0)
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_ChanServ, desc_ChanServ, "+S");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_ChanServ, desc_ChanServ, "+oS");
#else
NICK(s_ChanServ, desc_ChanServ, "+o");
#endif
#ifdef HAS_VHOST
if (s_HostServ && (!user || stricmp(user, s_HostServ) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_HostServ, desc_HostServ, "+oS");
#else
NICK(s_HostServ, desc_HostServ, "+o");
#endif
#endif
if (!user || stricmp(user, s_MemoServ) == 0)
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_MemoServ, desc_MemoServ, "+S");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_MemoServ, desc_MemoServ, "+oS");
#else
NICK(s_MemoServ, desc_MemoServ, "+o");
#endif
if (s_BotServ && (!user || stricmp(user, s_BotServ) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_BotServ, desc_BotServ, "+S");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_BotServ, desc_BotServ, "+oS");
#else
NICK(s_BotServ, desc_BotServ, "+o");
#endif
if (!user || stricmp(user, s_HelpServ) == 0)
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_HelpServ, desc_HelpServ, "+Sh");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_HelpServ, desc_HelpServ, "+oS");
#else
NICK(s_HelpServ, desc_HelpServ, "+h");
#endif
if (!user || stricmp(user, s_OperServ) == 0)
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_OperServ, desc_OperServ, "+iS");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_OperServ, desc_OperServ, "+ioS");
#else
NICK(s_OperServ, desc_OperServ, "+io");
#endif
if (s_DevNull && (!user || stricmp(user, s_DevNull) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3)
NICK(s_DevNull, desc_DevNull, "+iS");
#else
NICK(s_DevNull, desc_DevNull, "+i");
#endif
if (!user || stricmp(user, s_GlobalNoticer) == 0)
#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
NICK(s_GlobalNoticer, desc_GlobalNoticer, "+iS");
#elif defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_GlobalNoticer, desc_GlobalNoticer, "+ioS");
#else
NICK(s_GlobalNoticer, desc_GlobalNoticer, "+io");
#endif
/* We make aliases go online */
if (s_NickServAlias && (!user || stricmp(user, s_NickServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_NickServAlias, desc_NickServAlias, "+oS");
#else
NICK(s_NickServAlias, desc_NickServAlias, "+o");
#endif
if (s_ChanServAlias && (!user || stricmp(user, s_ChanServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_ChanServAlias, desc_ChanServAlias, "+oS");
#else
NICK(s_ChanServAlias, desc_ChanServAlias, "+o");
#endif
if (s_MemoServAlias && (!user || stricmp(user, s_MemoServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_MemoServAlias, desc_MemoServAlias, "+oS");
#else
NICK(s_MemoServAlias, desc_MemoServAlias, "+o");
#endif
if (s_BotServAlias && (!user || stricmp(user, s_BotServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_BotServAlias, desc_BotServAlias, "+oS");
#else
NICK(s_BotServAlias, desc_BotServAlias, "+o");
#endif
if (s_HelpServAlias && (!user || stricmp(user, s_HelpServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_HelpServAlias, desc_HelpServAlias, "+oS");
#else
NICK(s_HelpServAlias, desc_HelpServAlias, "+h");
#endif
if (s_OperServAlias && (!user || stricmp(user, s_OperServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_OperServAlias, desc_OperServAlias, "+ioS");
#else
NICK(s_OperServAlias, desc_OperServAlias, "+io");
#endif
if (s_DevNullAlias && (!user || stricmp(user, s_DevNullAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_DevNullAlias, desc_DevNullAlias, "+iS");
#else
NICK(s_DevNullAlias, desc_DevNullAlias, "+i");
#endif
if (s_HostServAlias && (!user || stricmp(user, s_HostServAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NICK(s_HostServAlias, desc_HostServAlias, "+ioS");
#else
NICK(s_HostServAlias, desc_HostServAlias, "+io");
#endif
if (s_GlobalNoticerAlias
&& (!user || stricmp(user, s_GlobalNoticerAlias) == 0))
#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL)
NICK(s_GlobalNoticerAlias, desc_GlobalNoticerAlias, "+ioS");
#else
NICK(s_GlobalNoticerAlias, desc_GlobalNoticerAlias, "+io");
#endif
/* We make the bots go online */
if (s_BotServ) {
BotInfo *bi;
int i;
for (i = 0; i < 256; i++)
for (bi = botlists[i]; bi; bi = bi->next)
if (!user || !stricmp(user, bi->nick))
#if defined(IRC_UNREAL) || defined(IRC_VIAGRA)
NEWNICK(bi->nick, bi->user, bi->host, bi->real, "+qS",
1);
#elif defined(IRC_ULTIMATE)
NEWNICK(bi->nick, bi->user, bi->host, bi->real, "+pS",
1);
#elif defined(IRC_ULTIMATE3)
NEWNICK(bi->nick, bi->user, bi->host, bi->real, "+S",
1);
#else
NEWNICK(bi->nick, bi->user, bi->host, bi->real, "+",
1);
#endif
}
}
#undef NICK
/*************************************************************************/
/* Set GID if necessary. Return 0 if successful (or if RUNGROUP not
* defined), else print an error message to logfile and return -1.
*/
static int set_group(void)
{
#if defined(RUNGROUP) && defined(HAVE_SETGRENT)
struct group *gr;
setgrent();
while ((gr = getgrent()) != NULL) {
if (strcmp(gr->gr_name, RUNGROUP) == 0)
break;
}
endgrent();
if (gr) {
setgid(gr->gr_gid);
return 0;
} else {
alog("Unknown group `%s'\n", RUNGROUP);
return -1;
}
#else
return 0;
#endif
}
/*************************************************************************/
/* Parse command-line options for the "-dir" option only. Return 0 if all
* went well or -1 for a syntax error.
*/
/* XXX this could fail if we have "-some-option-taking-an-argument -dir" */
static int parse_dir_options(int ac, char **av)
{
int i;
char *s;
for (i = 1; i < ac; i++) {
s = av[i];
if (*s == '-') {
s++;
if (strcmp(s, "dir") == 0) {
if (++i >= ac) {
fprintf(stderr, "-dir requires a parameter\n");
return -1;
}
services_dir = av[i];
} else if (strcmp(s, "log") == 0) {
if (++i >= ac) {
fprintf(stderr, "-log requires a parameter\n");
return -1;
}
log_filename = av[i];
}
}
}
return 0;
}
/*************************************************************************/
/* Parse command-line options. Return 0 if all went well, -1 for an error
* with an option, or 1 for -help.
*/
static int parse_options(int ac, char **av)
{
int i;
char *s, *t;
for (i = 1; i < ac; i++) {
s = av[i];
if (*s == '-') {
s++;
if (strcmp(s, "remote") == 0) {
if (++i >= ac) {
fprintf(stderr, "-remote requires hostname[:port]\n");
return -1;
}
s = av[i];
t = strchr(s, ':');
if (t) {
*t++ = 0;
if (atoi(t) > 0)
RemotePort = atoi(t);
else {
fprintf(stderr,
"-remote: port number must be a positive integer. Using default.");
return -1;
}
}
RemoteServer = s;
} else if (strcmp(s, "local") == 0) {
if (++i >= ac) {
fprintf(stderr,
"-local requires hostname or [hostname]:[port]\n");
return -1;
}
s = av[i];
t = strchr(s, ':');
if (t) {
*t++ = 0;
if (atoi(t) >= 0)
LocalPort = atoi(t);
else {
fprintf(stderr,
"-local: port number must be a positive integer or 0. Using default.");
return -1;
}
}
LocalHost = s;
} else if (strcmp(s, "name") == 0) {
if (++i >= ac) {
fprintf(stderr, "-name requires a parameter\n");
return -1;
}
ServerName = av[i];
} else if (strcmp(s, "desc") == 0) {
if (++i >= ac) {
fprintf(stderr, "-desc requires a parameter\n");
return -1;
}
ServerDesc = av[i];
} else if (strcmp(s, "user") == 0) {
if (++i >= ac) {
fprintf(stderr, "-user requires a parameter\n");
return -1;
}
ServiceUser = av[i];
} else if (strcmp(s, "host") == 0) {
if (++i >= ac) {
fprintf(stderr, "-host requires a parameter\n");
return -1;
}
ServiceHost = av[i];
} else if (strcmp(s, "dir") == 0) {
/* Handled by parse_dir_options() */
i++; /* Skip parameter */
} else if (strcmp(s, "log") == 0) {
/* Handled by parse_dir_options(), too */
i++; /* Skip parameter */
} else if (strcmp(s, "update") == 0) {
if (++i >= ac) {
fprintf(stderr, "-update requires a parameter\n");
return -1;
}
s = av[i];
if (atoi(s) <= 0) {
fprintf(stderr,
"-update: number of seconds must be positive");
return -1;
} else
UpdateTimeout = atol(s);
} else if (strcmp(s, "expire") == 0) {
if (++i >= ac) {
fprintf(stderr, "-expire requires a parameter\n");
return -1;
}
s = av[i];
if (atoi(s) <= 0) {
fprintf(stderr,
"-expire: number of seconds must be positive");
return -1;
} else
ExpireTimeout = atol(s);
} else if (strcmp(s, "debug") == 0) {
debug++;
} else if (strcmp(s, "readonly") == 0) {
readonly = 1;
skeleton = 0;
} else if (strcmp(s, "skeleton") == 0) {
readonly = 0;
skeleton = 1;
} else if (strcmp(s, "nofork") == 0) {
nofork = 1;
} else if (strcmp(s, "logchan") == 0) {
logchan = 1;
#ifdef IRC_HYBRID
fprintf(stderr,
"LogChan will only work if your logchannel is not set to +n\n");
#endif
} else if (strcmp(s, "forceload") == 0) {
forceload = 1;
} else if (!strcmp(s, "noexpire")) {
noexpire = 1;
#ifdef IS44_CONVERTER
} else if (!strcmp(s, "is44")) {
is44 = 1;
#endif
} else {
fprintf(stderr, "Unknown option -%s\n", s);
return -1;
}
} else {
fprintf(stderr, "Non-option arguments not allowed\n");
return -1;
}
}
return 0;
}
/*************************************************************************/
/* Remove our PID file. Done at exit. */
static void remove_pidfile(void)
{
remove(PIDFilename);
}
/*************************************************************************/
/* Create our PID file and write the PID to it. */
static void write_pidfile(void)
{
FILE *pidfile;
pidfile = fopen(PIDFilename, "w");
if (pidfile) {
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
atexit(remove_pidfile);
} else {
log_perror("Warning: cannot write to PID file %s", PIDFilename);
}
}
/*************************************************************************/
/* Overall initialization routine. Returns 0 on success, -1 on failure. */
int init(int ac, char **av)
{
int i;
int openlog_failed = 0, openlog_errno = 0;
int started_from_term = isatty(0) && isatty(1) && isatty(2);
/* Imported from main.c */
extern void sighandler(int signum);
/* Set file creation mask and group ID. */
#if defined(DEFUMASK) && HAVE_UMASK
umask(DEFUMASK);
#endif
if (set_group() < 0)
return -1;
/* Parse command line for -dir option. */
parse_dir_options(ac, av);
/* Chdir to Services data directory. */
if (chdir(services_dir) < 0) {
fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
return -1;
}
/* Open logfile, and complain if we didn't. */
if (open_log() < 0) {
openlog_errno = errno;
if (started_from_term) {
fprintf(stderr, "Warning: unable to open log file %s: %s\n",
log_filename, strerror(errno));
} else {
openlog_failed = 1;
}
}
/* Read configuration file; exit if there are problems. */
if (!read_config(0))
return -1;
/* Add Core MSG handles */
moduleAddMsgs();
/* Parse all remaining command-line options. */
parse_options(ac, av);
/* Detach ourselves if requested. */
if (!nofork) {
if ((i = fork()) < 0) {
perror("fork()");
return -1;
} else if (i != 0) {
exit(0);
}
if (started_from_term) {
close(0);
close(1);
close(2);
}
if (setpgid(0, 0) < 0) {
perror("setpgid()");
return -1;
}
}
/* Write our PID to the PID file. */
write_pidfile();
/* Announce ourselves to the logfile. */
if (debug || readonly || skeleton) {
alog("Anope %s (compiled for %s) starting up (options:%s%s%s)",
version_number, version_protocol,
debug ? " debug" : "", readonly ? " readonly" : "",
skeleton ? " skeleton" : "");
} else {
alog("Anope %s (compiled for %s) starting up",
version_number, version_protocol);
}
start_time = time(NULL);
/* If in read-only mode, close the logfile again. */
if (readonly)
close_log();
/* Set signal handlers. Catch certain signals to let us do things or
* panic as necessary, and ignore all others.
*/
#if defined(NSIG) && !defined(LINUX20) && !defined(LINUX22)
for (i = 1; i <= NSIG - 1; i++) {
#else
for (i = 1; i <= 31; i++) {
#endif
#if defined(USE_THREADS) && defined(LINUX20)
if (i != SIGUSR1 && i != SIGUSR2)
#endif
signal(i, SIG_IGN);
}
#ifndef USE_THREADS
signal(SIGINT, sighandler);
#else
signal(SIGINT, SIG_DFL);
#endif
signal(SIGTERM, sighandler);
signal(SIGQUIT, sighandler);
if (!DumpCore) {
signal(SIGSEGV, sighandler);
signal(SIGBUS, sighandler);
signal(SIGILL, sighandler);
signal(SIGTRAP, sighandler);
} else {
signal(SIGSEGV, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGTRAP, SIG_DFL);
}
signal(SIGQUIT, sighandler);
signal(SIGHUP, sighandler);
#ifdef SIGIOT
signal(SIGIOT, sighandler);
#endif
signal(SIGFPE, sighandler);
#if !defined(USE_THREADS) || !defined(LINUX20)
signal(SIGUSR1, sighandler); /* This is our "out-of-memory" panic switch */
#endif
/* Initialize multi-language support */
lang_init();
if (debug)
alog("debug: Loaded languages");
/* Initialize subservices */
ns_init();
cs_init();
ms_init();
bs_init();
os_init();
hostserv_init();
helpserv_init();
#ifdef USE_RDB
db_mysql_init();
#endif
/* Initialize proxy detection */
#ifdef USE_THREADS
if (ProxyDetect && !proxy_init()) {
perror("proxy_init()");
return -1;
}
#endif
/* load any custom modules */
modules_init();
#ifdef USE_CONVERTER
/* Convert the databases NOW! */
# ifdef IS44_CONVERTER
if (is44) {
convert_ircservices_44();
alog("debug: Databases converted");
}
# endif
#endif
/* Load up databases */
if (!skeleton) {
load_ns_dbase();
if (debug)
alog("debug: Loaded %s database (1/9)", s_NickServ);
if (s_HostServ) {
load_hs_dbase();
if (debug)
alog("debug: Loaded %s database (2/9)", s_HostServ);
}
if (s_BotServ) {
load_bs_dbase();
if (debug)
alog("debug: Loaded %s database (3/9)", s_BotServ);
} else if (debug)
alog("debug: BotServ database (4/9) not loaded because BotServ is disabled");
load_cs_dbase();
if (debug)
alog("debug: Loaded %s database (5/9)", s_ChanServ);
}
load_os_dbase();
if (debug)
alog("debug: Loaded %s database (6/9)", s_OperServ);
load_news();
if (debug)
alog("debug: Loaded news database (7/9)");
load_exceptions();
if (debug)
alog("debug: Loaded exception database (8/9)");
if (PreNickDBName) {
load_ns_req_db();
if (debug)
alog("debug: Loaded PreNick database (9/9)");
}
alog("Databases loaded");
/* Save the databases back to file/mysql to reflect any changes */
save_databases();
/* Connect to the remote server */
servsock = conn(RemoteServer, RemotePort, LocalHost, LocalPort);
if (servsock < 0 && RemoteServer2) {
servsock = conn(RemoteServer2, RemotePort2, LocalHost, LocalPort);
if (servsock < 0 && RemoteServer3) {
servsock =
conn(RemoteServer3, RemotePort3, LocalHost, LocalPort);
if (servsock < 0) {
fatal_perror("Can't connect to server");
} else {
servernum = 3;
alog("Connected to Server %d (%s:%d)", servernum,
RemoteServer3, RemotePort3);
}
} else {
if (servsock < 0) {
fatal_perror("Can't connect to server");
}
servernum = 2;
alog("Connected to Server %d (%s:%d)", servernum,
RemoteServer2, RemotePort2);
}
} else {
if (servsock < 0) {
fatal_perror("Can't connect to server");
}
servernum = 1;
alog("Connected to Server %d (%s:%d)", servernum, RemoteServer,
RemotePort);
}
#ifdef IRC_UNREAL
send_cmd(NULL, "PROTOCTL NICKv2 VHP");
#endif
#if defined(IRC_ULTIMATE3)
if (servernum == 1)
send_cmd(NULL, "PASS %s :TS", RemotePassword);
else if (servernum == 2)
send_cmd(NULL, "PASS %s :TS", RemotePassword2);
else if (servernum == 3)
send_cmd(NULL, "PASS %s :TS", RemotePassword3);
send_cmd(NULL, "CAPAB NICKIP SSJ5 TS5 CLIENT");
#elif defined(IRC_BAHAMUT)
if (servernum == 1)
send_cmd(NULL, "PASS %s :TS", RemotePassword);
else if (servernum == 2)
send_cmd(NULL, "PASS %s :TS", RemotePassword2);
else if (servernum == 3)
send_cmd(NULL, "PASS %s :TS", RemotePassword3);
send_cmd(NULL, "CAPAB NICKIP SSJOIN TS3");
#elif defined(IRC_HYBRID)
if (servernum == 1)
send_cmd(NULL, "PASS %s :TS", RemotePassword);
else if (servernum == 2)
send_cmd(NULL, "PASS %s :TS", RemotePassword2);
else if (servernum == 3)
send_cmd(NULL, "PASS %s :TS", RemotePassword3);
send_cmd(NULL, "CAPAB TS5 EX IE HOPS HUB AOPS");
#elif defined(IRC_PTLINK)
if (servernum == 1)
send_cmd(NULL, "PASS %s :TS", RemotePassword);
else if (servernum == 2)
send_cmd(NULL, "PASS %s :TS", RemotePassword2);
else if (servernum == 3)
send_cmd(NULL, "PASS %s :TS", RemotePassword3);
#else
if (servernum == 1)
send_cmd(NULL, "PASS :%s", RemotePassword);
if (servernum == 2)
send_cmd(NULL, "PASS :%s", RemotePassword2);
if (servernum == 3)
send_cmd(NULL, "PASS :%s", RemotePassword3);
#endif
#ifdef IRC_PTLINK
send_cmd(NULL, "SERVER %s 1 Anope.Services%s :%s",
ServerName, version_number, ServerDesc);
#else
send_cmd(NULL, "SERVER %s 1 :%s", ServerName, ServerDesc);
#endif
#ifdef IRC_BAHAMUT
send_cmd(NULL, "SVINFO 3 1 0 :%ld", time(NULL));
#endif
#ifdef IRC_HYBRID
send_cmd(NULL, "SVSINFO 5 5 0 :%ld", time(NULL));
#endif
#ifdef IRC_PTLINK
send_cmd(NULL, "SVINFO 3 6 %lu", time(NULL));
send_cmd(NULL, "SVSINFO %lu %d", time(NULL), maxusercnt);
#endif
sgets2(inbuf, sizeof(inbuf), servsock);
if (strnicmp(inbuf, "ERROR", 5) == 0) {
/* Close server socket first to stop wallops, since the other
* server doesn't want to listen to us anyway */
disconn(servsock);
servsock = -1;
fatal("Remote server returned: %s", inbuf);
}
/* Announce a logfile error if there was one */
if (openlog_failed) {
wallops(NULL, "Warning: couldn't open logfile: %s",
strerror(openlog_errno));
}
/* Bring in our pseudo-clients */
introduce_user(NULL);
/**
* Load our delayed modeles - modules that are planing on making clients need to wait till now
* where as modules wanting to modify our ircd connection messages need to load eariler :|
**/
modules_delayed_init();
/* Write the StartGlobal */
if (GlobalOnCycle) {
if (GlobalOnCycleUP)
oper_global(NULL, GlobalOnCycleUP);
}
/* Success! */
return 0;
}
/*************************************************************************/
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
SRC= ; DEST= ; MODE= ; USER= ; GROUP= ; export SRC DEST MODE USER GROUP
while [ $# -gt 0 ] ; do
case $1 in
-m) MODE=$2; shift; shift;;
-u) USER=$2; shift; shift;;
-g) GROUP=$2; shift; shift;;
-c) shift;;
*) SRC="$DEST"; DEST="$1"; shift;;
esac
done
if [ ! "$DEST" ] ; then
echo >&2 "Usage: $0 [-c] [-m mode] [-u user] [-g group] source dest"
exit 1
fi
if [ -d "$DEST" ] ; then
DEST="$DEST/$SRC"
fi
/bin/cp -p "$SRC" "$DEST"
if [ "$MODE" ] ; then
/bin/chmod $MODE "$DEST"
fi
if [ "$USER" ] ; then
/bin/chown "$USER" "$DEST"
fi
if [ "$GROUP" ] ; then
/bin/chgrp "$GROUP" "$DEST"
fi
+79
View File
@@ -0,0 +1,79 @@
# Makefile for language module
include ../Makefile.inc
LANGOBJS = cat de en_us es fr gr nl pt tr it ru
LANGSRCS = cat de en_us.l es fr.l gr.l nl.l pt.l tr.l it.l ru.l
LANGCOMP = ./langcomp
#LANGCOMP = ./langcomp -w
all: $(LANGOBJS)
install: all
mkdir -p $(DATDEST)/languages
ifdef RUNGROUP
chgrp $(RUNGROUP) $(DATDEST)/languages
chmod 770 $(DATDEST)/languages
else
chmod 700 $(DATDEST)/languages
endif
cp $(LANGOBJS) $(DATDEST)/languages
ifdef RUNGROUP
chgrp $(RUNGROUP) $(DATDEST)/languages/*
chmod 660 $(DATDEST)/languages/*
else
chmod 600 $(DATDEST)/languages/*
endif
clean:
rm -f $(LANGOBJS) langcomp
spotless: clean
rm -f language.h
cat: cat.l langcomp index
./langcomp $@.l
de: de.l langcomp index
./langcomp $@.l
en_us: en_us.l langcomp index
./langcomp $@.l
es: es.l langcomp index
./langcomp $@.l
fr: fr.l langcomp index
./langcomp $@.l
gr: gr.l langcomp index
./langcomp $@.l
nl: nl.l langcomp index
./langcomp $@.l
pt: pt.l langcomp index
./langcomp $@.l
tr: tr.l langcomp index
./langcomp $@.l
it: it.l langcomp index
./langcomp $@.l
ru: ru.l langcomp index
./langcomp $@.l
langcomp: langcomp.c
$(CC) $(CFLAGS) langcomp.c -o $@
language.h: index Makefile
@perl -e <index >$@ '\
print STDERR "Generating language.h... "; \
$$i=0; \
while (<>) { \
chop; \
printf "#define %-32s %d\n", $$_, $$i++; \
} \
print "\n#define NUM_STRINGS $$i\n"; \
print STDERR "$$i strings\n";'
index: en_us.l
grep '^[A-Z]' en_us.l >index
+6172
View File
File diff suppressed because it is too large Load Diff
+6380
View File
File diff suppressed because it is too large Load Diff
+5946
View File
File diff suppressed because it is too large Load Diff
+6182
View File
File diff suppressed because it is too large Load Diff
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/perl
#
# Tries to fix a language file using the reference
# language (en_us), and injecting all new strings
# (in english) into the newly generated fixed.pl
#
# check the result with obs.pl then copy on top
# of the source language file.
#
my $srcfile = $ARGV[0];
my $dstfile = "fixed.l";
my $engfile = "en_us.l";
my %is_there= ();
my $pos=0;
my $wc=0;
my @defs;
my @efile;
sub error {
my $msg = shift ;
print "*** Error: $msg \n";
exit ;
}
sub not_del {
$line = shift;
if ($is_there{$line}) {
return 1;
} else {
return 0;
}
}
# Could not think of a worse of doing this...
sub new_def {
my $ndef;
my $start=0;
$def = shift;
for (@efile) {
my $line = $_;
chomp $line;
if (/^[A-Z]/) {
$start=0;
}
if ($start) {
$ndef.=$_;
}
if ($line eq $def) {
$ndef=$_;
$start=1;
}
}
return $ndef;
}
error("Usage $0 [lang.l]") unless ($srcfile);
error("Can't find language file: $srcfile") if (! -f $srcfile);
error("Can't find language file: $engfile") if (! -f $engfile);
open (EFILE, "< $engfile");
while (<EFILE>) {
my $line = $_;
push(@efile, $line);
chomp $line;
if (/^[A-Z]/) {
$wc = push (@defs, $line);
}
}
close(EFILE);
# Need to load entiry text into hash...
for (@defs) {
$is_there{$_} = 1;
}
open (SFILE, "< $srcfile");
open (DFILE, "> $dstfile");
while (<SFILE>) {
my $line = $_;
chomp $line;
if (/^[A-Z]/) {
$del = 0;
if (not_del($line)) {
while ($line ne $defs[$pos]) {
print "ADD: $defs[$pos]\n";
# Need to reference the hash...
my $ndef = new_def($defs[$pos]);
print DFILE $ndef;
$pos++;
}
$pos++;
} else {
$del = 1;
print "DEL: $line\n";
}
}
if (! $del) {
print DFILE "$line\n";
}
}
for($pos ; $pos < $wc; $pos++) {
print "ADD: $defs[$pos]\n";
my $ndef = new_def($defs[$pos]);
print DFILE $ndef;
}
close(SFILE);
close(DFILE);
+6204
View File
File diff suppressed because it is too large Load Diff
+6049
View File
File diff suppressed because it is too large Load Diff
+1410
View File
File diff suppressed because it is too large Load Diff
+6208
View File
File diff suppressed because it is too large Load Diff
+256
View File
@@ -0,0 +1,256 @@
/* Compiler for language definition files.
*
* Epona (c) 2000-2002 PegSoft
* Contact us at epona@pegsoft.net
*
* This program is free but copyrighted software; see the file COPYING for
* details.
*
* Based on the original code of Services by Andy Church.
*
*/
/*
* A language definition file contains all strings which Services sends to
* users in a particular language. A language file may contain comments
* (lines beginning with "#") and blank lines. All other lines must adhere
* to the following format:
*
* Each string definition begins with the C name of a message (as defined
* in the file "index"--see below). This must be alone on a line, preceded
* and followed by no blank space. Following this line are zero or more
* lines of text; each line of text must begin with exactly one tab
* character, which is discarded. Newlines are retained in the strings,
* except the last newline in the text, which is discarded. A message with
* no text is replaced by a null pointer in the array (not an empty
* string).
*
* All messages in the program are listed, one per line, in the "index"
* file. No comments or blank lines are permitted in that file. The index
* file can be generated from a language file with a command like:
* grep '^[A-Z]' en_us.l >index
*
* This program takes one parameter, the name of the language file. It
* generates a compiled language file whose name is created by removing any
* extension on the source file on the input filename.
*
* You may also pass a "-w" option to print warnings for missing strings.
*
* This program isn't very flexible, because it doesn't need to be, but
* anyone who wants to try making it more flexible is welcome to.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#undef getline
int numstrings = 0; /* Number of strings we should have */
char **stringnames; /* Names of the strings (from index file) */
char **strings; /* Strings we have loaded */
int linenum = 0; /* Current line number in input file */
/*************************************************************************/
/* Read the index file and load numstrings and stringnames. Return -1 on
* error, 0 on success. */
int read_index_file()
{
FILE *f;
char buf[256];
int i;
if (!(f = fopen("index", "r"))) {
perror("fopen(index)");
return -1;
}
while (fgets(buf, sizeof(buf), f))
numstrings++;
if (!(stringnames = calloc(sizeof(char *), numstrings))) {
perror("calloc(stringnames)");
return -1;
}
if (!(strings = calloc(sizeof(char *), numstrings))) {
perror("calloc(strings)");
return -1;
}
fseek(f, 0, SEEK_SET);
i = 0;
while (fgets(buf, sizeof(buf), f)) {
if (buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = '\0';
if (!(stringnames[i++] = strdup(buf))) {
perror("strdup()");
return -1;
}
}
fclose(f);
return 0;
}
/*************************************************************************/
/* Return the index of a string name in stringnames, or -1 if not found. */
int stringnum(const char *name)
{
int i;
for (i = 0; i < numstrings; i++) {
if (strcmp(stringnames[i], name) == 0)
return i;
}
return -1;
}
/*************************************************************************/
/* Read a non-comment, non-blank line from the input file. Return NULL at
* end of file. */
char *getline(FILE *f)
{
static char buf[1024];
char *s;
do {
if (!(fgets(buf, sizeof(buf), f)))
return NULL;
linenum++;
} while (*buf == '#' || *buf == '\n');
s = buf + strlen(buf)-1;
if (*s == '\n')
*s = '\0';
return buf;
}
/*************************************************************************/
/* Write a 32-bit value to a file in big-endian order. */
int fput32(int val, FILE *f)
{
if (fputc(val>>24, f) < 0 ||
fputc(val>>16, f) < 0 ||
fputc(val>> 8, f) < 0 ||
fputc(val , f) < 0
) {
return -1;
} else {
return 0;
}
}
/*************************************************************************/
int main(int ac, char **av)
{
unsigned char *filename = NULL, *s;
char langname[254], outfile[256];
FILE *in, *out;
int warn = 0;
int retval = 0;
int curstring = -2, i;
char *line;
int pos;
int maxerr = 50; /* Max errors before we bail out */
if (ac >= 2 && strcmp(av[1], "-w") == 0) {
warn = 1;
av[1] = av[2];
ac--;
}
if (ac != 2) {
fprintf(stderr, "Usage: %s [-w] <lang-file>\n", av[0]);
return 1;
}
filename = av[1];
s = strrchr(filename, '.');
if (!s)
s = filename + strlen(filename);
if (s-filename > sizeof(langname)-3)
s = filename + sizeof(langname)-1;
strncpy(langname, filename, s-filename);
langname[s-filename] = '\0';
snprintf(outfile, sizeof(outfile), "%s", langname);
if (read_index_file() < 0)
return 1;
if (!(in = fopen(filename, "r"))) {
perror(filename);
return 1;
}
if (!(out = fopen(outfile, "w"))) {
perror(outfile);
return 1;
}
while (maxerr > 0 && (line = getline(in)) != NULL) {
if (*line == '\t') {
if (curstring == -2) {
fprintf(stderr, "%s:%d: Junk at beginning of file\n",
filename, linenum);
retval = 1;
} else if (curstring >= 0) {
line++;
i = strings[curstring] ? strlen(strings[curstring]) : 0;
if (!(strings[curstring] =
realloc(strings[curstring], i+strlen(line)+2))) {
fprintf(stderr, "%s:%d: Out of memory!\n",filename,linenum);
return 2;
}
sprintf(strings[curstring]+i, "%s\n", line);
}
} else {
if ((curstring = stringnum(line)) < 0) {
fprintf(stderr, "%s:%d: Unknown string name `%s'\n",
filename, linenum, line);
retval = 1;
maxerr--;
} else if (strings[curstring]) {
fprintf(stderr, "%s:%d: Duplicate occurrence of string `%s'\n",
filename, linenum, line);
retval = 1;
maxerr--;
} else {
if (!(strings[curstring] = malloc(1))) {
fprintf(stderr, "%s:%d: Out of memory!\n",filename,linenum);
return 2;
}
*strings[curstring] = '\0';
}
if (maxerr == 0)
fprintf(stderr, "%s:%d: Too many errors!\n", filename, linenum);
}
}
fput32(numstrings, out);
pos = numstrings * 8 + 4;
for (i = 0; i < numstrings; i++) {
int len = strings[i] && *strings[i] ? strlen(strings[i])-1 : 0;
fput32(pos, out);
fput32(len, out);
pos += len;
}
for (i = 0; i < numstrings; i++) {
if (strings[i]) {
if (*strings[i])
strings[i][strlen(strings[i])-1] = '\0'; /* kill last \n */
if (*strings[i])
fputs(strings[i], out);
} else if (warn) {
fprintf(stderr, "%s: String `%s' missing\n", filename,
stringnames[i]);
}
}
fclose(in);
fclose(out);
return retval;
}
/*************************************************************************/
+6069
View File
File diff suppressed because it is too large Load Diff
Executable
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/perl
#
# Checks a language file against the reference language (en_us), and
# finds #define string diferences
#
my $srcfile = $ARGV[0];
my $engfile = "en_us.l";
my %is_there= ();
my $pos=0;
my $wc=0;
my $edef="";
my $sdef="";
my @efile;
my @sfile;
my @defs;
sub error {
my $msg = shift ;
print "*** Error: $msg \n";
exit ;
}
sub not_del {
$line = shift;
if ($is_there{$line}) {
return 1;
} else {
return 0;
}
}
sub get_format {
my $fmt="";
my $str=shift;
while ($str =~ m/%\w/g) {
$fmt .= $&;
}
return $fmt;
}
# Could not think of a worse of doing this...
sub get_def {
my $ndef;
my $start=0;
my $found=0;
$buf = shift;
$def = shift;
for (@$buf) {
my $line = $_;
chomp $line;
if (/^[A-Z]/) {
$start=0;
last if $found;
}
if ($start) {
$found=1;
$ndef.=$_;
}
if ($line eq $def) {
$start=1;
}
}
return $ndef;
}
error("Usage $0 [lang.l]") unless ($srcfile);
error("Can't find language file: $srcfile") if (! -f $srcfile);
error("Can't find language file: $engfile") if (! -f $engfile);
open (EFILE, "< $engfile");
while (<EFILE>) {
my $line = $_;
push(@efile, $line);
chomp $line;
if (/^[A-Z]/) {
$wc = push (@defs, $line);
$is_there{$line} = 1;
}
}
close(EFILE);
open (SFILE, "< $srcfile");
while (<SFILE>) {
push(@sfile, $_);
}
close(SFILE);
#for (@defs) {
# $is_there{$_} = 1;
#}
for (@sfile) {
my $line = $_;
chomp $line;
if (/^[A-Z]/) {
if (not_del($line)) {
while ($line ne $defs[$pos]) {
print "ADD: $defs[$pos]\n";
$pos++;
}
if (! /^STRFTIME/ ) {
$edef = get_format(get_def(\@efile, $line)) ;
$sdef = get_format(get_def(\@sfile, $line)) ;
if ( $edef ne $sdef ) {
print "FORMAT: $line (expecting '$edef' and got '$sdef')\n";
}
}
$pos++;
} else {
print "DEL: $line\n";
}
}
}
for($pos ; $pos < $wc; $pos++) {
print "ADD: $defs[$pos]\n";
}
+5804
View File
File diff suppressed because it is too large Load Diff
+5951
View File
File diff suppressed because it is too large Load Diff
+5982
View File
File diff suppressed because it is too large Load Diff
+265
View File
@@ -0,0 +1,265 @@
/* Multi-language support.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: language.c,v 1.9 2003/12/12 16:04:57 dane Exp $
*
*/
#include "services.h"
#include "language.h"
/*************************************************************************/
/* The list of lists of messages. */
char **langtexts[NUM_LANGS];
/* The list of names of languages. */
char *langnames[NUM_LANGS];
/* Indexes of available languages: */
int langlist[NUM_LANGS];
/* Order in which languages should be displayed: (alphabetical) */
static int langorder[NUM_LANGS] = {
LANG_EN_US, /* English (US) */
LANG_FR, /* French */
LANG_DE, /* German */
LANG_IT, /* Italian */
LANG_JA_JIS, /* Japanese (JIS encoding) */
LANG_JA_EUC, /* Japanese (EUC encoding) */
LANG_JA_SJIS, /* Japanese (SJIS encoding) */
LANG_PT, /* Portugese */
LANG_ES, /* Spanish */
LANG_TR, /* Turkish */
LANG_CAT, /* Catalan */
LANG_GR, /* Greek */
LANG_NL, /* Dutch */
LANG_RU, /* Russian */
};
/*************************************************************************/
/* Load a language file. */
static int read_int32(int32 * ptr, FILE * f)
{
int a = fgetc(f);
int b = fgetc(f);
int c = fgetc(f);
int d = fgetc(f);
if (a == EOF || b == EOF || c == EOF || d == EOF)
return -1;
*ptr = a << 24 | b << 16 | c << 8 | d;
return 0;
}
static void load_lang(int index, const char *filename)
{
char buf[256];
FILE *f;
int num, i;
if (debug) {
alog("debug: Loading language %d from file `languages/%s'",
index, filename);
}
snprintf(buf, sizeof(buf), "languages/%s", filename);
if (!(f = fopen(buf, "r"))) {
log_perror("Failed to load language %d (%s)", index, filename);
return;
} else if (read_int32(&num, f) < 0) {
alog("Failed to read number of strings for language %d (%s)",
index, filename);
return;
} else if (num != NUM_STRINGS) {
alog("Warning: Bad number of strings (%d, wanted %d) "
"for language %d (%s)", num, NUM_STRINGS, index, filename);
}
langtexts[index] = scalloc(sizeof(char *), NUM_STRINGS);
if (num > NUM_STRINGS)
num = NUM_STRINGS;
for (i = 0; i < num; i++) {
int32 pos, len;
fseek(f, i * 8 + 4, SEEK_SET);
if (read_int32(&pos, f) < 0 || read_int32(&len, f) < 0) {
alog("Failed to read entry %d in language %d (%s) TOC",
i, index, filename);
while (--i >= 0) {
if (langtexts[index][i])
free(langtexts[index][i]);
}
free(langtexts[index]);
langtexts[index] = NULL;
return;
}
if (len == 0) {
langtexts[index][i] = NULL;
} else if (len >= 65536) {
alog("Entry %d in language %d (%s) is too long (over 64k)--"
"corrupt TOC?", i, index, filename);
while (--i >= 0) {
if (langtexts[index][i])
free(langtexts[index][i]);
}
free(langtexts[index]);
langtexts[index] = NULL;
return;
} else if (len < 0) {
alog("Entry %d in language %d (%s) has negative length--"
"corrupt TOC?", i, index, filename);
while (--i >= 0) {
if (langtexts[index][i])
free(langtexts[index][i]);
}
free(langtexts[index]);
langtexts[index] = NULL;
return;
} else {
langtexts[index][i] = scalloc(len + 1, 1);
fseek(f, pos, SEEK_SET);
if (fread(langtexts[index][i], 1, len, f) != len) {
alog("Failed to read string %d in language %d (%s)",
i, index, filename);
while (--i >= 0) {
if (langtexts[index][i])
free(langtexts[index][i]);
}
free(langtexts[index]);
langtexts[index] = NULL;
return;
}
langtexts[index][i][len] = 0;
}
}
fclose(f);
}
/*************************************************************************/
/* Initialize list of lists. */
void lang_init()
{
int i, j, n = 0;
load_lang(LANG_CAT, "cat");
load_lang(LANG_DE, "de");
load_lang(LANG_EN_US, "en_us");
load_lang(LANG_ES, "es");
load_lang(LANG_FR, "fr");
load_lang(LANG_GR, "gr");
load_lang(LANG_PT, "pt");
load_lang(LANG_TR, "tr");
load_lang(LANG_IT, "it");
load_lang(LANG_NL, "nl");
load_lang(LANG_RU, "ru");
for (i = 0; i < NUM_LANGS; i++) {
if (langtexts[langorder[i]] != NULL) {
langnames[langorder[i]] = langtexts[langorder[i]][LANG_NAME];
langlist[n++] = langorder[i];
for (j = 0; j < NUM_STRINGS; j++) {
if (!langtexts[langorder[i]][j]) {
langtexts[langorder[i]][j] =
langtexts[DEF_LANGUAGE][j];
}
if (!langtexts[langorder[i]][j]) {
langtexts[langorder[i]][j] = langtexts[LANG_EN_US][j];
}
}
}
}
while (n < NUM_LANGS)
langlist[n++] = -1;
/* Not what I intended to do, but these services are so archaïc
* that it's difficult to do more. */
if ((NSDefLanguage = langlist[NSDefLanguage]) < 0)
NSDefLanguage = DEF_LANGUAGE;
if (!langtexts[DEF_LANGUAGE])
fatal("Unable to load default language");
for (i = 0; i < NUM_LANGS; i++) {
if (!langtexts[i])
langtexts[i] = langtexts[DEF_LANGUAGE];
}
}
/*************************************************************************/
/*************************************************************************/
/* Format a string in a strftime()-like way, but heed the user's language
* setting for month and day names. The string stored in the buffer will
* always be null-terminated, even if the actual string was longer than the
* buffer size.
* Assumption: No month or day name has a length (including trailing null)
* greater than BUFSIZE.
*/
int strftime_lang(char *buf, int size, User * u, int format, struct tm *tm)
{
int language = u && u->na ? u->na->nc->language : NSDefLanguage;
char tmpbuf[BUFSIZE], buf2[BUFSIZE];
char *s;
int i, ret;
strscpy(tmpbuf, langtexts[language][format], sizeof(tmpbuf));
if ((s = langtexts[language][STRFTIME_DAYS_SHORT]) != NULL) {
for (i = 0; i < tm->tm_wday; i++)
s += strcspn(s, "\n") + 1;
i = strcspn(s, "\n");
strncpy(buf2, s, i);
buf2[i] = 0;
strnrepl(tmpbuf, sizeof(tmpbuf), "%a", buf2);
}
if ((s = langtexts[language][STRFTIME_DAYS_LONG]) != NULL) {
for (i = 0; i < tm->tm_wday; i++)
s += strcspn(s, "\n") + 1;
i = strcspn(s, "\n");
strncpy(buf2, s, i);
buf2[i] = 0;
strnrepl(tmpbuf, sizeof(tmpbuf), "%A", buf2);
}
if ((s = langtexts[language][STRFTIME_MONTHS_SHORT]) != NULL) {
for (i = 0; i < tm->tm_mon; i++)
s += strcspn(s, "\n") + 1;
i = strcspn(s, "\n");
strncpy(buf2, s, i);
buf2[i] = 0;
strnrepl(tmpbuf, sizeof(tmpbuf), "%b", buf2);
}
if ((s = langtexts[language][STRFTIME_MONTHS_LONG]) != NULL) {
for (i = 0; i < tm->tm_mon; i++)
s += strcspn(s, "\n") + 1;
i = strcspn(s, "\n");
strncpy(buf2, s, i);
buf2[i] = 0;
strnrepl(tmpbuf, sizeof(tmpbuf), "%B", buf2);
}
ret = strftime(buf, size, tmpbuf, tm);
if (ret == size)
buf[size - 1] = 0;
return ret;
}
/*************************************************************************/
/*************************************************************************/
/* Send a syntax-error message to the user. */
void syntax_error(const char *service, User * u, const char *command,
int msgnum)
{
const char *str = getstring(u->na, msgnum);
notice_lang(service, u, SYNTAX_ERROR, str);
notice_lang(service, u, MORE_INFO, service, command);
}
/*************************************************************************/
+178
View File
@@ -0,0 +1,178 @@
/* Routines to handle `listnicks' and `listchans' invocations.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: list.c,v 1.5 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
void do_listnicks(int ac, char **av)
{
int count = 0; /* Count only rather than display? */
int usage = 0; /* Display command usage? (>0 also indicates error) */
int i;
i = 1;
while (i < ac) {
if (av[i][0] == '-') {
switch (av[i][1]) {
case 'h':
usage = -1;
break;
case 'c':
if (i > 1)
usage = 1;
count = 1;
break;
case 'd':
if (av[i][2]) {
services_dir = av[i] + 2;
} else {
if (i >= ac - 1) {
usage = 1;
break;
}
ac--;
memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
services_dir = av[i];
}
default:
usage = 1;
break;
} /* switch */
ac--;
if (i < ac)
memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
} else {
if (count)
usage = 1;
i++;
}
}
if (usage) {
fprintf(stderr, "\
\n\
Usage: listnicks [-c] [-d data-dir] [nick [nick...]]\n\
-c: display only count of registered nicks\n\
(cannot be combined with nicks)\n\
nick: nickname(s) to display information for\n\
\n\
If no nicks are given, the entire nickname database is printed out in\n\
compact format followed by the number of registered nicks (with -c, the\n\
list is suppressed and only the count is printed). If one or more nicks\n\
are given, detailed information about those nicks is displayed.\n\
\n");
exit(usage > 0 ? 1 : 0);
}
if (chdir(services_dir) < 0) {
fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
exit(1);
}
if (!read_config(0))
exit(1);
load_ns_dbase();
lang_init();
if (ac > 1) {
for (i = 1; i < ac; i++)
listnicks(0, av[i]);
} else {
listnicks(count, NULL);
}
exit(0);
}
/*************************************************************************/
void do_listchans(int ac, char **av)
{
int count = 0; /* Count only rather than display? */
int usage = 0; /* Display command usage? (>0 also indicates error) */
int i;
i = 1;
while (i < ac) {
if (av[i][0] == '-') {
switch (av[i][1]) {
case 'h':
usage = -1;
break;
case 'c':
if (i > 1)
usage = 1;
count = 1;
break;
case 'd':
if (av[i][2]) {
services_dir = av[i] + 2;
} else {
if (i >= ac - 1) {
usage = 1;
break;
}
ac--;
memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
services_dir = av[i];
}
default:
usage = 1;
break;
} /* switch */
ac--;
if (i < ac)
memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
} else {
if (count)
usage = 1;
i++;
}
}
if (usage) {
fprintf(stderr, "\
\n\
Usage: listchans [-c] [-d data-dir] [channel [channel...]]\n\
-c: display only count of registered channels\n\
(cannot be combined with channels)\n\
channel: channel(s) to display information for\n\
\n\
If no channels are given, the entire channel database is printed out in\n\
compact format followed by the number of registered channels (with -c, the\n\
list is suppressed and only the count is printed). If one or more channels\n\
are given, detailed information about those channels is displayed.\n\
\n");
exit(usage > 0 ? 1 : 0);
}
if (chdir(services_dir) < 0) {
fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
exit(1);
}
if (!read_config(0))
exit(1);
load_ns_dbase();
load_cs_dbase();
lang_init();
if (ac > 1) {
for (i = 1; i < ac; i++)
listchans(0, av[i]);
} else {
listchans(count, NULL);
}
exit(0);
}
/*************************************************************************/
+298
View File
@@ -0,0 +1,298 @@
/* Logging routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: log.c,v 1.8 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
#include "pseudo.h"
static FILE *logfile;
static int curday = 0;
/*************************************************************************/
static int get_logname(char *name, int count, struct tm *tm)
{
char timestamp[32];
if (!tm) {
time_t t;
time(&t);
tm = localtime(&t);
}
strftime(timestamp, count, "%Y%m%d", tm);
snprintf(name, count, "logs/%s.%s", log_filename, timestamp);
curday = tm->tm_yday;
return 1;
}
/*************************************************************************/
static void remove_log(void)
{
time_t t;
struct tm tm;
char name[PATH_MAX];
if (!KeepLogs)
return;
time(&t);
t -= (60 * 60 * 24 * KeepLogs);
tm = *localtime(&t);
if (!get_logname(name, sizeof(name), &tm))
return;
unlink(name);
}
/*************************************************************************/
static void checkday(void)
{
time_t t;
struct tm tm;
time(&t);
tm = *localtime(&t);
if (curday != tm.tm_yday) {
close_log();
remove_log();
open_log();
}
}
/*************************************************************************/
/* Open the log file. Return -1 if the log file could not be opened, else
* return 0. */
int open_log(void)
{
char name[PATH_MAX];
if (logfile)
return 0;
if (!get_logname(name, sizeof(name), NULL))
return 0;
logfile = fopen(name, "a");
if (logfile)
setbuf(logfile, NULL);
return logfile != NULL ? 0 : -1;
}
/* Close the log file. */
void close_log(void)
{
if (!logfile)
return;
fclose(logfile);
logfile = NULL;
}
/*************************************************************************/
/* Log stuff to the log file with a datestamp. Note that errno is
* preserved by this routine and log_perror().
*/
void alog(const char *fmt, ...)
{
va_list args;
time_t t;
struct tm tm;
char buf[256];
int errno_save = errno;
checkday();
va_start(args, fmt);
time(&t);
tm = *localtime(&t);
#if HAVE_GETTIMEOFDAY
if (debug) {
char *s;
struct timeval tv;
gettimeofday(&tv, NULL);
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S", &tm);
s = buf + strlen(buf);
s += snprintf(s, sizeof(buf) - (s - buf), ".%06d", tv.tv_usec);
strftime(s, sizeof(buf) - (s - buf) - 1, " %Y] ", &tm);
} else {
#endif
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
#if HAVE_GETTIMEOFDAY
}
#endif
if (logfile) {
fputs(buf, logfile);
vfprintf(logfile, fmt, args);
fputc('\n', logfile);
}
if (nofork) {
fputs(buf, stderr);
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
}
if (LogChannel && logchan && !debug && findchan(LogChannel)) {
char str[BUFSIZE];
vsnprintf(str, sizeof(str), fmt, args);
privmsg(s_GlobalNoticer, LogChannel, str);
}
errno = errno_save;
}
/* Like alog(), but tack a ": " and a system error message (as returned by
* strerror()) onto the end.
*/
void log_perror(const char *fmt, ...)
{
va_list args;
time_t t;
struct tm tm;
char buf[256];
int errno_save = errno;
checkday();
va_start(args, fmt);
time(&t);
tm = *localtime(&t);
#if HAVE_GETTIMEOFDAY
if (debug) {
char *s;
struct timeval tv;
gettimeofday(&tv, NULL);
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S", &tm);
s = buf + strlen(buf);
s += snprintf(s, sizeof(buf) - (s - buf), ".%06d", tv.tv_usec);
strftime(s, sizeof(buf) - (s - buf) - 1, " %Y] ", &tm);
} else {
#endif
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
#if HAVE_GETTIMEOFDAY
}
#endif
if (logfile) {
fputs(buf, logfile);
vfprintf(logfile, fmt, args);
fprintf(logfile, ": %s\n", strerror(errno_save));
}
if (nofork) {
fputs(buf, stderr);
vfprintf(stderr, fmt, args);
fprintf(stderr, ": %s\n", strerror(errno_save));
}
errno = errno_save;
}
/*************************************************************************/
/* We've hit something we can't recover from. Let people know what
* happened, then go down.
*/
void fatal(const char *fmt, ...)
{
va_list args;
time_t t;
struct tm tm;
char buf[256], buf2[4096];
checkday();
va_start(args, fmt);
time(&t);
tm = *localtime(&t);
#if HAVE_GETTIMEOFDAY
if (debug) {
char *s;
struct timeval tv;
gettimeofday(&tv, NULL);
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S", &tm);
s = buf + strlen(buf);
s += snprintf(s, sizeof(buf) - (s - buf), ".%06d", tv.tv_usec);
strftime(s, sizeof(buf) - (s - buf) - 1, " %Y] ", &tm);
} else {
#endif
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
#if HAVE_GETTIMEOFDAY
}
#endif
vsnprintf(buf2, sizeof(buf2), fmt, args);
if (logfile)
fprintf(logfile, "%sFATAL: %s\n", buf, buf2);
if (nofork)
fprintf(stderr, "%sFATAL: %s\n", buf, buf2);
if (servsock >= 0)
wallops(NULL, "FATAL ERROR! %s", buf2);
exit(1);
}
/* Same thing, but do it like perror(). */
void fatal_perror(const char *fmt, ...)
{
va_list args;
time_t t;
struct tm tm;
char buf[256], buf2[4096];
int errno_save = errno;
checkday();
va_start(args, fmt);
time(&t);
tm = *localtime(&t);
#if HAVE_GETTIMEOFDAY
if (debug) {
char *s;
struct timeval tv;
gettimeofday(&tv, NULL);
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S", &tm);
s = buf + strlen(buf);
s += snprintf(s, sizeof(buf) - (s - buf), ".%06d", tv.tv_usec);
strftime(s, sizeof(buf) - (s - buf) - 1, " %Y] ", &tm);
} else {
#endif
strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
#if HAVE_GETTIMEOFDAY
}
#endif
vsnprintf(buf2, sizeof(buf2), fmt, args);
if (logfile)
fprintf(logfile, "%sFATAL: %s: %s\n", buf, buf2,
strerror(errno_save));
if (stderr)
fprintf(stderr, "%sFATAL: %s: %s\n", buf, buf2,
strerror(errno_save));
if (servsock >= 0)
wallops(NULL, "FATAL ERROR! %s: %s", buf2, strerror(errno_save));
exit(1);
}
/*************************************************************************/
+202
View File
@@ -0,0 +1,202 @@
/* Mail utility routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: mail.c,v 1.9 2003/09/04 18:55:34 rob Exp $
*
*/
#include "services.h"
#include "language.h"
/* Begins to send a mail. Must be followed by a MailEnd call.
* Returns NULL if the call failed. Error messages are
* automatically sent to the user.
*/
MailInfo *MailRegBegin(User * u, NickRequest * nr, char *subject,
char *service)
{
if (!u || !nr || !subject)
return NULL;
if (!UseMail) {
notice_lang(service, u, MAIL_DISABLED);
} else if ((time(NULL) - u->lastmail < MailDelay)
|| (time(NULL) - nr->lastmail < MailDelay)) {
notice_lang(service, u, MAIL_DELAYED, MailDelay);
} else if (!nr->email) {
notice_lang(service, u, MAIL_INVALID, nr->nick);
} else {
MailInfo *mail;
mail = scalloc(sizeof(MailInfo), 1);
mail->sender = u;
mail->recipient = NULL;
mail->recip = nr;
if (!(mail->pipe = popen(SendMailPath, "w"))) {
free(mail);
notice_lang(service, u, MAIL_LATER);
return NULL;
}
fprintf(mail->pipe, "From: %s\n", SendFrom);
if (DontQuoteAddresses) {
fprintf(mail->pipe, "To: %s <%s>\n", nr->nick, nr->email);
} else {
fprintf(mail->pipe, "To: \"%s\" <%s>\n", nr->nick, nr->email);
}
fprintf(mail->pipe, "Subject: %s\n", subject);
return mail;
}
return NULL;
}
/* Begins to send a mail. Must be followed by a MailEnd call.
* Returns NULL if the call failed. Error messages are
* automatically sent to the user.
*/
MailInfo *MailBegin(User * u, NickCore * nc, char *subject, char *service)
{
if (!u || !nc || !subject)
return NULL;
if (!UseMail) {
notice_lang(service, u, MAIL_DISABLED);
} else if (((time(NULL) - u->lastmail < MailDelay)
|| (time(NULL) - nc->lastmail < MailDelay))
&& !is_services_root(u)) {
notice_lang(service, u, MAIL_DELAYED, MailDelay);
} else if (!nc->email) {
notice_lang(service, u, MAIL_INVALID, nc->display);
} else {
MailInfo *mail;
mail = scalloc(sizeof(MailInfo), 1);
mail->sender = u;
mail->recipient = nc;
mail->recip = NULL;
if (!(mail->pipe = popen(SendMailPath, "w"))) {
free(mail);
notice_lang(service, u, MAIL_LATER);
return NULL;
}
fprintf(mail->pipe, "From: %s\n", SendFrom);
if (DontQuoteAddresses) {
fprintf(mail->pipe, "To: %s <%s>\n", nc->display, nc->email);
} else {
fprintf(mail->pipe, "To: \"%s\" <%s>\n", nc->display,
nc->email);
}
fprintf(mail->pipe, "Subject: %s\n", subject);
return mail;
}
return NULL;
}
/* Finish to send the mail. Cleanup everything. */
void MailEnd(MailInfo * mail)
{
if (!mail || !mail->sender || !mail->pipe)
return;
if (!mail->recipient && !mail->recip)
return;
pclose(mail->pipe);
mail->sender->lastmail = time(NULL);
if (mail->recipient)
mail->recipient->lastmail = time(NULL);
else
mail->recip->lastmail = time(NULL);
free(mail);
}
/* Resets the MailDelay protection */
void MailReset(User * u, NickCore * nc)
{
if (u)
u->lastmail = 0;
if (nc)
nc->lastmail = 0;
}
/* Checks whether we have a valid, common e-mail address.
* This is NOT entirely RFC compliant, and won't be so, because I said
* *common* cases. ;) It is very unlikely that e-mail addresses that
* are really being used will fail the check.
*
* FIXME: rewrite this a bit cleaner.
*/
int MailValidate(const char *email)
{
int i, j, has_period = 0, len;
char copy[BUFSIZE], *domain;
static char specials[] =
{ '(', ')', '<', '>', '@', ',', ';', ':', '\\', '\"', '[', ']',
' '
};
if (!email)
return 0;
strcpy(copy, email);
domain = strchr(copy, '@');
if (!domain)
return 0;
*domain = '\0';
domain++;
/* Don't accept NULL copy or domain. */
if (*copy == 0 || *domain == 0)
return 0;
/* Check for forbidden characters in the name */
for (i = 0; i < strlen(copy); i++) {
if (copy[i] <= 31 || copy[i] >= 127)
return 0;
for (j = 0; j < 13; j++)
if (copy[i] == specials[j])
return 0;
}
/* Check for forbidden characters in the domain, and if it seems to be valid. */
for (i = 0; i < (len = strlen(domain)); i++) {
if (domain[i] <= 31 || domain[i] >= 127)
return 0;
for (j = 0; j < 13; j++)
if (domain[i] == specials[j])
return 0;
if (domain[i] == '.') {
if (i == 0 || i == len - 1)
return 0;
has_period = 1;
}
}
if (!has_period)
return 0;
return 1;
}
+521
View File
@@ -0,0 +1,521 @@
/* Services -- main source file.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: main.c,v 1.23 2004/03/13 13:55:59 dane Exp $
*
*/
#include "services.h"
#include "timeout.h"
#include "version.h"
#include "datafiles.h"
/******** Global variables! ********/
/* Command-line options: (note that configuration variables are in config.c) */
char *services_dir = SERVICES_DIR; /* -dir dirname */
char *log_filename = LOG_FILENAME; /* -log filename */
int debug = 0; /* -debug */
int readonly = 0; /* -readonly */
int logchan = 0; /* -logchan */
int skeleton = 0; /* -skeleton */
int nofork = 0; /* -nofork */
int forceload = 0; /* -forceload */
int noexpire = 0; /* -noexpire */
#ifdef IS44_CONVERTER
int is44 = 0; /* -is44 */
#endif
#ifdef USE_RDB
int do_mysql = 0; /* use mysql ? */
#endif
/* Set to 1 if we are to quit */
int quitting = 0;
/* Set to 1 if we are to quit after saving databases */
int delayed_quit = 0;
/* Contains a message as to why services is terminating */
char *quitmsg = NULL;
/* Input buffer - global, so we can dump it if something goes wrong */
char inbuf[BUFSIZE];
/* Socket for talking to server */
int servsock = -1;
/* Should we update the databases now? */
int save_data = 0;
/* At what time were we started? */
time_t start_time;
/* Parameters and environment */
char **my_av, **my_envp;
/******** Local variables! ********/
/* Set to 1 if we are waiting for input */
static int waiting = 0;
/* Set to 1 after we've set everything up */
static int started = 0;
/*************************************************************************/
/* Run expiration routines */
static void expire_all(void)
{
waiting = -3;
if (debug)
alog("debug: Running expire routines");
if (!skeleton) {
waiting = -21;
expire_nicks();
waiting = -22;
expire_chans();
waiting = -23;
expire_requests();
}
waiting = -25;
expire_akills();
#ifdef IRC_BAHAMUT
waiting = -26;
expire_sglines();
#endif
waiting = -28;
expire_sqlines();
#ifdef IRC_BAHAMUT
waiting = -27;
expire_szlines();
#endif
#ifndef STREAMLINED
expire_exceptions();
#endif
#ifdef USE_THREADS
if (ProxyDetect)
proxy_expire();
#endif
}
/*************************************************************************/
void save_databases(void)
{
waiting = -2;
if (debug)
alog("debug: Saving FFF databases");
waiting = -10;
backup_databases();
if (!skeleton) {
waiting = -11;
save_ns_dbase();
waiting = -12;
if (PreNickDBName) {
save_ns_req_dbase();
waiting = -13;
}
save_cs_dbase();
if (s_BotServ) {
waiting = -14;
save_bs_dbase();
}
if (s_HostServ) {
waiting = -15;
save_hs_dbase();
}
}
waiting = -16;
save_os_dbase();
waiting = -17;
save_news();
waiting = -18;
save_exceptions();
#ifdef USE_RDB
if (do_mysql) {
if (debug)
alog("debug: Saving RDB databases");
waiting = -10;
if (!skeleton) {
waiting = -11;
save_ns_rdb_dbase();
waiting = -12;
save_cs_rdb_dbase();
if (PreNickDBName) {
save_ns_req_rdb_dbase();
waiting = -13;
}
/* Temporary fix to avoid unwanted timeouts... */
send_cmd(ServerName, "PONG %s", ServerName);
if (s_BotServ) {
waiting = -14;
save_bs_rdb_dbase();
}
if (s_HostServ) {
waiting = -15;
save_hs_rdb_dbase();
}
waiting = -16;
save_os_rdb_dbase();
waiting = -17;
save_rdb_news();
waiting = -18;
save_rdb_exceptions();
}
}
#endif
}
/*************************************************************************/
/* Restarts services */
static void services_restart(void)
{
alog("Restarting");
if (!quitmsg)
quitmsg = "Restarting";
send_cmd(ServerName, "SQUIT %s :%s", ServerName, quitmsg);
disconn(servsock);
close_log();
#if defined(LINUX20) || defined(LINUX22)
pthread_kill_other_threads_np();
#endif
execve(SERVICES_BIN, my_av, my_envp);
if (!readonly) {
open_log();
log_perror("Restart failed");
close_log();
}
}
/*************************************************************************/
/**
* Added to allow do_restart from operserv access to the static functions without making them
* fair game to every other function - not exactly ideal :|
**/
void do_restart_services(void)
{
expire_all();
save_databases();
services_restart();
exit(1);
}
/*************************************************************************/
/* Terminates services */
static void services_shutdown(void)
{
if (!quitmsg)
quitmsg = "Terminating, reason unknown";
alog("%s", quitmsg);
if (started)
send_cmd(ServerName, "SQUIT %s :%s", ServerName, quitmsg);
disconn(servsock);
}
/*************************************************************************/
/* If we get a weird signal, come here. */
void sighandler(int signum)
{
if (started) {
if (signum == SIGHUP) { /* SIGHUP = save databases and restart */
signal(SIGHUP, SIG_IGN);
alog("Received SIGHUP, restarting.");
expire_all();
save_databases();
if (!quitmsg)
quitmsg = "Restarting on SIGHUP";
#ifdef SERVICES_BIN
services_restart();
exit(1);
#else
quitmsg =
"Restart attempt failed--SERVICES_BIN not defined (rerun configure)";
#endif
} else if (signum == SIGTERM) {
signal(SIGTERM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
alog("Received SIGTERM, exiting.");
expire_all();
save_databases();
quitmsg = "Shutting down on SIGTERM";
services_shutdown();
exit(0);
} else if (signum == SIGINT || signum == SIGQUIT) {
/* nothing -- terminate below */
} else if (!waiting) {
alog("PANIC! buffer = %s", inbuf);
/* Cut off if this would make IRC command >510 characters. */
if (strlen(inbuf) > 448) {
inbuf[446] = '>';
inbuf[447] = '>';
inbuf[448] = 0;
}
wallops(NULL, "PANIC! buffer = %s\r\n", inbuf);
} else if (waiting < 0) {
/* This is static on the off-chance we run low on stack */
static char buf[BUFSIZE];
switch (waiting) {
case -1:
snprintf(buf, sizeof(buf), "in timed_update");
break;
case -10:
snprintf(buf, sizeof(buf), "backing up databases");
break;
case -11:
snprintf(buf, sizeof(buf), "saving %s", NickDBName);
break;
case -12:
snprintf(buf, sizeof(buf), "saving %s", ChanDBName);
break;
case -13:
snprintf(buf, sizeof(buf), "saving %s", PreNickDBName);
break;
case -14:
snprintf(buf, sizeof(buf), "saving %s", BotDBName);
break;
case -15:
snprintf(buf, sizeof(buf), "saving %s", HostDBName);
break;
case -16:
snprintf(buf, sizeof(buf), "saving %s", OperDBName);
break;
case -17:
snprintf(buf, sizeof(buf), "saving %s", NewsDBName);
break;
case -18:
snprintf(buf, sizeof(buf), "saving %s", ExceptionDBName);
break;
case -21:
snprintf(buf, sizeof(buf), "expiring nicknames");
break;
case -22:
snprintf(buf, sizeof(buf), "expiring channels");
break;
case -25:
snprintf(buf, sizeof(buf), "expiring autokills");
break;
#ifdef IRC_BAHAMUT
case -26:
snprintf(buf, sizeof(buf), "expiring SGLINEs");
break;
case -27:
snprintf(buf, sizeof(buf), "expiring SZLINEs");
break;
#endif
case -28:
snprintf(buf, sizeof(buf), "expiring SQLINEs");
break;
default:
snprintf(buf, sizeof(buf), "waiting=%d", waiting);
}
wallops(NULL, "PANIC! %s (%s)", buf, strsignal(signum));
alog("PANIC! %s (%s)", buf, strsignal(signum));
}
}
if (
#if !defined(USE_THREADS) || !defined(LINUX20)
signum == SIGUSR1 ||
#endif
!(quitmsg = calloc(BUFSIZE, 1))) {
quitmsg = "Out of memory!";
} else {
#if HAVE_STRSIGNAL
snprintf(quitmsg, BUFSIZE, "Services terminating: %s",
strsignal(signum));
#else
snprintf(quitmsg, BUFSIZE, "Services terminating on signal %d",
signum);
#endif
}
if (started) {
services_shutdown();
exit(0);
} else {
alog("%s", quitmsg);
if (isatty(2))
fprintf(stderr, "%s\n", quitmsg);
exit(1);
}
}
/*************************************************************************/
/* Main routine. (What does it look like? :-) ) */
int main(int ac, char **av, char **envp)
{
volatile time_t last_update; /* When did we last update the databases? */
volatile time_t last_expire; /* When did we last expire nicks/channels? */
volatile time_t last_check; /* When did we last check timeouts? */
volatile time_t last_DefCon; /* When was DefCon last checked? */
int i;
char *progname;
my_av = av;
my_envp = envp;
/* Find program name. */
if ((progname = strrchr(av[0], '/')) != NULL)
progname++;
else
progname = av[0];
/* Were we run under "listnicks" or "listchans"? Do appropriate stuff
* if so. */
if (strcmp(progname, "listnicks") == 0) {
do_listnicks(ac, av);
return 0;
} else if (strcmp(progname, "listchans") == 0) {
do_listchans(ac, av);
return 0;
}
/* Initialization stuff. */
if ((i = init(ac, av)) != 0)
return i;
/* We have a line left over from earlier, so process it first. */
process();
/* Set up timers. */
last_update = time(NULL);
last_expire = time(NULL);
last_check = time(NULL);
last_DefCon = time(NULL);
started = 1;
/*** Main loop. ***/
while (!quitting) {
time_t t = time(NULL);
if (debug >= 2)
alog("debug: Top of main loop");
if (!noexpire && !readonly
&& (save_data || t - last_expire >= ExpireTimeout)) {
expire_all();
last_expire = t;
}
if (!readonly && (save_data || t - last_update >= UpdateTimeout)) {
if (delayed_quit)
wallops(NULL,
"Updating databases on shutdown, please wait.");
save_databases();
if (save_data < 0)
break; /* out of main loop */
save_data = 0;
last_update = t;
}
if ((DefConTimeOut) && (t - last_DefCon >= dotime(DefConTimeOut))) {
resetDefCon(5);
last_DefCon = t;
}
if (delayed_quit)
break;
moduleCallBackRun();
waiting = -1;
if (t - last_check >= TimeoutCheck) {
check_timeouts();
last_check = t;
}
waiting = 1;
i = (int) (long) sgets2(inbuf, sizeof(inbuf), servsock);
waiting = 0;
if (i > 0) {
process();
} else if (i == 0) {
int errno_save = errno;
quitmsg = scalloc(BUFSIZE, 1);
if (quitmsg) {
snprintf(quitmsg, BUFSIZE, "Read error from server: %s",
strerror(errno_save));
} else {
quitmsg = "Read error from server";
}
quitting = 1;
}
waiting = -4;
}
/* Check for restart instead of exit */
if (save_data == -2) {
#ifdef SERVICES_BIN
alog("Restarting");
if (!quitmsg)
quitmsg = "Restarting";
send_cmd(ServerName, "SQUIT %s :%s", ServerName, quitmsg);
disconn(servsock);
close_log();
#if defined(LINUX20) || defined(LINUX22)
pthread_kill_other_threads_np();
#endif
execve(SERVICES_BIN, av, envp);
if (!readonly) {
open_log();
log_perror("Restart failed");
close_log();
}
return 1;
#else
quitmsg =
"Restart attempt failed--SERVICES_BIN not defined (rerun configure)";
#endif
}
/* Disconnect and exit */
services_shutdown();
return 0;
}
/*************************************************************************/
+96
View File
@@ -0,0 +1,96 @@
/* Memory management routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: memory.c,v 1.7 2003/07/20 01:15:49 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
/*************************************************************************/
/* smalloc, scalloc, srealloc, sstrdup:
* Versions of the memory allocation functions which will cause the
* program to terminate with an "Out of memory" error if the memory
* cannot be allocated. (Hence, the return value from these functions
* is never NULL.)
*/
void *smalloc(long size)
{
void *buf;
if (!size) {
size = 1;
}
buf = malloc(size);
if (!buf)
#if !defined(USE_THREADS) || !defined(LINUX20)
raise(SIGUSR1);
#else
abort();
#endif
return buf;
}
void *scalloc(long elsize, long els)
{
void *buf;
if (!elsize || !els) {
elsize = els = 1;
}
buf = calloc(elsize, els);
if (!buf)
#if !defined(USE_THREADS) || !defined(LINUX20)
raise(SIGUSR1);
#else
abort();
#endif
return buf;
}
void *srealloc(void *oldptr, long newsize)
{
void *buf;
if (!newsize) {
newsize = 1;
}
buf = realloc(oldptr, newsize);
if (!buf)
#if !defined(USE_THREADS) || !defined(LINUX20)
raise(SIGUSR1);
#else
abort();
#endif
return buf;
}
char *sstrdup(const char *s)
{
char *t = strdup(s);
if (!t)
#if !defined(USE_THREADS) || !defined(LINUX20)
raise(SIGUSR1);
#else
abort();
#endif
return t;
}
/*************************************************************************/
/*************************************************************************/
/* In the future: malloc() replacements that tell us if we're leaking and
* maybe do sanity checks too... */
/*************************************************************************/
+1175
View File
File diff suppressed because it is too large Load Diff
+1196
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
/* Declarations of IRC message structures, variables, and functions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: messages.h,v 1.5 2003/07/20 01:15:49 dane Exp $
*
*/
/*************************************************************************/
#include "modules.h"
extern Message messages[];
extern void moduleAddMsgs(void);
extern Message *find_message(const char *name);
/*************************************************************************/
+642
View File
@@ -0,0 +1,642 @@
/* Miscellaneous routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: misc.c,v 1.14 2004/01/31 18:57:18 dane Exp $
*
*/
#include "services.h"
#include "language.h"
/* Cheaper than isspace() or isblank() */
#define issp(c) ((c) == 32)
/*************************************************************************/
/* toupper/tolower: Like the ANSI functions, but make sure we return an
* int instead of a (signed) char.
*/
int toupper(char c)
{
if (islower(c))
return (unsigned char) c - ('a' - 'A');
else
return (unsigned char) c;
}
int tolower(char c)
{
if (isupper(c))
return (unsigned char) c + ('a' - 'A');
else
return (unsigned char) c;
}
/*************************************************************************/
/* strscpy: Copy at most len-1 characters from a string to a buffer, and
* add a null terminator after the last character copied.
*/
char *strscpy(char *d, const char *s, size_t len)
{
char *d_orig = d;
if (!len)
return d;
while (--len && (*d++ = *s++));
*d = '\0';
return d_orig;
}
/*************************************************************************/
/* stristr: Search case-insensitively for string s2 within string s1,
* returning the first occurrence of s2 or NULL if s2 was not
* found.
*/
char *stristr(char *s1, char *s2)
{
register char *s = s1, *d = s2;
while (*s1) {
if (tolower(*s1) == tolower(*d)) {
s1++;
d++;
if (*d == 0)
return s;
} else {
s = ++s1;
d = s2;
}
}
return NULL;
}
/*************************************************************************/
/* strnrepl: Replace occurrences of `old' with `new' in string `s'. Stop
* replacing if a replacement would cause the string to exceed
* `size' bytes (including the null terminator). Return the
* string.
*/
char *strnrepl(char *s, int32 size, const char *old, const char *new)
{
char *ptr = s;
int32 left = strlen(s);
int32 avail = size - (left + 1);
int32 oldlen = strlen(old);
int32 newlen = strlen(new);
int32 diff = newlen - oldlen;
while (left >= oldlen) {
if (strncmp(ptr, old, oldlen) != 0) {
left--;
ptr++;
continue;
}
if (diff > avail)
break;
if (diff != 0)
memmove(ptr + oldlen + diff, ptr + oldlen, left + 1);
strncpy(ptr, new, newlen);
ptr += newlen;
left -= oldlen;
}
return s;
}
/*************************************************************************/
/*************************************************************************/
/* merge_args: Take an argument count and argument vector and merge them
* into a single string in which each argument is separated by
* a space.
*/
char *merge_args(int argc, char **argv)
{
int i;
static char s[4096];
char *t;
t = s;
for (i = 0; i < argc; i++)
t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
(i < argc - 1) ? " " : "");
return s;
}
/*************************************************************************/
/*************************************************************************/
/* match_wild: Attempt to match a string to a pattern which might contain
* '*' or '?' wildcards. Return 1 if the string matches the
* pattern, 0 if not.
*/
static int do_match_wild(const char *pattern, const char *str, int docase)
{
char c;
const char *s;
/* This WILL eventually terminate: either by *pattern == 0, or by a
* trailing '*'. */
for (;;) {
switch (c = *pattern++) {
case 0:
if (!*str)
return 1;
return 0;
case '?':
if (!*str)
return 0;
str++;
break;
case '*':
if (!*pattern)
return 1; /* trailing '*' matches everything else */
s = str;
while (*s) {
if ((docase ? (*s == *pattern)
: (tolower(*s) == tolower(*pattern)))
&& do_match_wild(pattern, s, docase))
return 1;
s++;
}
break;
default:
if (docase ? (*str++ != c) : (tolower(*str++) != tolower(c)))
return 0;
break;
} /* switch */
}
}
int match_wild(const char *pattern, const char *str)
{
return do_match_wild(pattern, str, 1);
}
int match_wild_nocase(const char *pattern, const char *str)
{
return do_match_wild(pattern, str, 0);
}
/*************************************************************************/
/*************************************************************************/
/* Process a string containing a number/range list in the form
* "n1[-n2][,n3[-n4]]...", calling a caller-specified routine for each
* number in the list. If the callback returns -1, stop immediately.
* Returns the sum of all nonnegative return values from the callback.
* If `count' is non-NULL, it will be set to the total number of times the
* callback was called.
*
* The callback should be of type range_callback_t, which is defined as:
* int (*range_callback_t)(User *u, int num, va_list args)
*/
int process_numlist(const char *numstr, int *count_ret,
range_callback_t callback, User * u, ...)
{
int n1, n2, i;
int res = 0, retval = 0, count = 0;
va_list args;
va_start(args, u);
/*
* This algorithm ignores invalid characters, ignores a dash
* when it precedes a comma, and ignores everything from the
* end of a valid number or range to the next comma or null.
*/
for (;;) {
n1 = n2 = strtol(numstr, (char **) &numstr, 10);
numstr += strcspn(numstr, "0123456789,-");
if (*numstr == '-') {
numstr++;
numstr += strcspn(numstr, "0123456789,");
if (isdigit(*numstr)) {
n2 = strtol(numstr, (char **) &numstr, 10);
numstr += strcspn(numstr, "0123456789,-");
}
}
for (i = n1; i <= n2 && i >= 0; i++) {
int res = callback(u, i, args);
count++;
if (res < 0)
break;
retval += res;
if (count >= 32767) {
if (count_ret)
*count_ret = count;
return retval;
}
}
if (res < -1)
break;
numstr += strcspn(numstr, ",");
if (*numstr)
numstr++;
else
break;
}
if (count_ret)
*count_ret = count;
return retval;
}
/*************************************************************************/
/* dotime: Return the number of seconds corresponding to the given time
* string. If the given string does not represent a valid time,
* return -1.
*
* A time string is either a plain integer (representing a number
* of seconds), or an integer followed by one of these characters:
* "s" (seconds), "m" (minutes), "h" (hours), or "d" (days).
*/
int dotime(const char *s)
{
int amount;
amount = strtol(s, (char **) &s, 10);
if (*s) {
switch (*s) {
case 's':
return amount;
case 'm':
return amount * 60;
case 'h':
return amount * 3600;
case 'd':
return amount * 86400;
default:
return -1;
}
} else {
return amount;
}
}
/*************************************************************************/
/* Expresses in a string the period of time represented by a given amount
of seconds (with days/hours/minutes). */
char *duration(NickAlias * na, char *buf, int bufsize, time_t seconds)
{
int days = 0, hours = 0, minutes = 0;
int need_comma = 0;
char buf2[64], *end;
char *comma = getstring(na, COMMA_SPACE);
/* We first calculate everything */
days = seconds / 86400;
seconds -= (days * 86400);
hours = seconds / 3600;
seconds -= (hours * 3600);
minutes = seconds / 60;
if (!days && !hours && !minutes) {
snprintf(buf, bufsize,
getstring(na,
(seconds <=
1 ? DURATION_SECOND : DURATION_SECONDS)),
seconds);
} else {
end = buf;
if (days) {
snprintf(buf2, sizeof(buf2),
getstring(na,
(days == 1 ? DURATION_DAY : DURATION_DAYS)),
days);
end += snprintf(end, bufsize - (end - buf), "%s", buf2);
need_comma = 1;
}
if (hours) {
snprintf(buf2, sizeof(buf2),
getstring(na,
(hours ==
1 ? DURATION_HOUR : DURATION_HOURS)),
hours);
end +=
snprintf(end, bufsize - (end - buf), "%s%s",
(need_comma ? comma : ""), buf2);
need_comma = 1;
}
if (minutes) {
snprintf(buf2, sizeof(buf2),
getstring(na,
(minutes ==
1 ? DURATION_MINUTE : DURATION_MINUTES)),
minutes);
end +=
snprintf(end, bufsize - (end - buf), "%s%s",
(need_comma ? comma : ""), buf2);
need_comma = 1;
}
}
return buf;
}
/*************************************************************************/
/* Generates a human readable string of type "expires in ..." */
char *expire_left(NickAlias * na, char *buf, int len, time_t expires)
{
time_t now = time(NULL);
if (!expires) {
strncpy(buf, getstring(na, NO_EXPIRE), len);
} else if (expires <= now) {
strncpy(buf, getstring(na, EXPIRES_SOON), len);
} else {
time_t diff = expires - now + 59;
if (diff >= 86400) {
int days = diff / 86400;
snprintf(buf, len,
getstring(na, (days == 1) ? EXPIRES_1D : EXPIRES_D),
days);
} else {
if (diff <= 3600) {
int minutes = diff / 60;
snprintf(buf, len,
getstring(na,
(minutes ==
1) ? EXPIRES_1M : EXPIRES_M), minutes);
} else {
int hours = diff / 3600, minutes;
diff -= (hours * 3600);
minutes = diff / 60;
snprintf(buf, len,
getstring(na,
((hours == 1
&& minutes ==
1) ? EXPIRES_1H1M : ((hours == 1
&& minutes !=
1) ? EXPIRES_1HM
: ((hours != 1
&& minutes ==
1) ?
EXPIRES_H1M :
EXPIRES_HM)))),
hours, minutes);
}
}
}
return buf;
}
/**
* Return 1 if a host is valid, 0 if it isnt.
* host = string to check
* type = format, 1 = ip4addr, 2 = hostname
*
* shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
* hostname = shortname *( "." shortname )
* ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
*
**/
int doValidHost(const char *host, int type)
{
int idx = 0;
int len = 0;
int sec_len = 0;
int dots = 1;
if (type != 1 && type != 2) {
return 0;
}
if (!host) {
return 0;
}
len = strlen(host);
if (len > HOSTMAX) {
return 0;
}
switch (type) {
case 1:
for (idx = 0; idx < len; idx++) {
if (isdigit(host[idx])) {
if (sec_len < 3) {
sec_len++;
} else {
return 0;
}
} else {
if (idx == 0) {
return 0;
} /* cant start with a non-digit */
if (host[idx] != '.') {
return 0;
} /* only . is a valid non-digit */
if (sec_len > 3) {
return 0;
} /* sections cant be more than 3 digits */
sec_len = 0;
dots++;
}
}
if (dots != 4) {
return 0;
}
break;
case 2:
dots = 0;
for (idx = 0; idx < len; idx++) {
if (!isalnum(host[idx])) {
if (idx == 0) {
return 0;
}
if ((host[idx] != '.') && (host[idx] != '-')) {
return 0;
}
if (host[idx] == '.') {
dots++;
}
}
}
if (host[len - 1] == '.') {
return 0;
}
/**
* Ultimate3 dosnt like a non-dotted hosts at all, nor does unreal,
* so just dont allow them.
**/
if (dots == 0) {
return 0;
}
break;
}
return 1;
}
/**
* Return 1 if a host is valid, 0 if it isnt.
* host = string to check
* type = format, 1 = ip4addr, 2 = hostname, 3 = either
*
* shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
* hostname = shortname *( "." shortname )
* ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
*
**/
int isValidHost(const char *host, int type)
{
int status = 0;
if (type == 3) {
if (!(status = doValidHost(host, 1))) {
status = doValidHost(host, 2);
}
} else {
status = doValidHost(host, type);
}
return status;
}
int isvalidchar(const char c)
{
if (((c >= 'A') && (c <= 'Z')) ||
((c >= 'a') && (c <= 'z')) ||
((c >= '0') && (c <= '9')) || (c == '.') || (c == '-'))
return 1;
else
return 0;
}
char *myStrGetToken(const char *str, const char dilim, int token_number)
{
int len, idx, counter = 0, start_pos = 0;
char *substring = NULL;
if (!str) {
return NULL;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if ((str[idx] == dilim) || (idx == len)) {
if (counter == token_number) {
substring = myStrSubString(str, start_pos, idx);
counter++;
} else {
start_pos = idx + 1;
counter++;
}
}
}
return substring;
}
char *myStrGetOnlyToken(const char *str, const char dilim,
int token_number)
{
int len, idx, counter = 0, start_pos = 0;
char *substring = NULL;
if (!str) {
return NULL;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if (str[idx] == dilim) {
if (counter == token_number) {
if (str[idx] == '\r')
substring = myStrSubString(str, start_pos, idx - 1);
else
substring = myStrSubString(str, start_pos, idx);
counter++;
} else {
start_pos = idx + 1;
counter++;
}
}
}
return substring;
}
char *myStrGetTokenRemainder(const char *str, const char dilim,
int token_number)
{
int len, idx, counter = 0, start_pos = 0;
char *substring = NULL;
if (!str) {
return NULL;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if ((str[idx] == dilim) || (idx == len)) {
if (counter == token_number) {
substring = myStrSubString(str, start_pos, len);
counter++;
} else {
start_pos = idx + 1;
counter++;
}
}
}
return substring;
}
char *myStrSubString(const char *src, int start, int end)
{
char *substring = NULL;
int len, idx;
if (!src) {
return NULL;
}
len = strlen(src);
if (((start >= 0) && (end <= len)) && (end > start)) {
substring = (char *) malloc(sizeof(char) * ((end - start) + 1));
for (idx = 0; idx <= end - start; idx++) {
substring[idx] = src[start + idx];
}
substring[end - start] = '\0';
}
return substring;
}
void doCleanBuffer(char *str)
{
char *in = str;
char *out = str;
char ch;
while (issp(ch = *in++));
if (ch != '\0')
for (;;) {
*out++ = ch;
ch = *in++;
if (ch == '\0')
break;
if (!issp(ch))
continue;
while (issp(ch = *in++));
if (ch == '\0')
break;
*out++ = ' ';
}
*out = ch; // == '\0'
}
+1399
View File
File diff suppressed because it is too large Load Diff
+223
View File
@@ -0,0 +1,223 @@
/* Modular support
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: modules.h,v 1.16 2004/03/11 16:50:01 rob Exp $
*/
#ifndef MODULES_H
#define MODULES_H
#include <time.h>
#include "services.h"
#include <stdio.h>
/*************************************************************************/
#define CMD_HASH(x) (((x)[0]&31)<<5 | ((x)[1]&31)) /* Will gen a hash from a string :) */
#define MAX_CMD_HASH 1024
#define MOD_STOP 1
#define MOD_CONT 0
#define HOSTSERV HS_cmdTable /* using HOSTSERV etc. looks nicer than HS_cmdTable for modules */
#define BOTSERV BS_cmdTable
#define MEMOSERV MS_cmdTable
#define NICKSERV NS_cmdTable
#define CHANSERV CS_cmdTable
#define HELPSERV HE_cmdTable
#define OPERSERV OS_cmdTable
#define IRCD IRCD_cmdTable
#define MODULE_HASH Module_table
/**********************************************************************
* Module Returns
**********************************************************************/
#define MOD_ERR_OK 0
#define MOD_ERR_MEMORY 1
#define MOD_ERR_PARAMS 2
#define MOD_ERR_EXISTS 3
#define MOD_ERR_NOEXIST 4
#define MOD_ERR_NOUSER 5
#define MOD_ERR_NOLOAD 6
#define MOD_ERR_NOUNLOAD 7
#define MOD_ERR_SYNTAX 8
#define MOD_ERR_NODELETE 9
#define MOD_ERR_UNKNOWN 10
#define MOD_ERR_FILE_IO 11
/*************************************************************************/
/* Structure for information about a *Serv command. */
typedef struct Command_ Command;
typedef struct CommandHash_ CommandHash;
typedef struct Module_ Module;
typedef struct ModuleHash_ ModuleHash;
typedef struct Message_ Message;
typedef struct MessageHash_ MessageHash;
typedef struct ModuleCallBack_ ModuleCallBack;
extern CommandHash *HOSTSERV[MAX_CMD_HASH];
extern CommandHash *BOTSERV[MAX_CMD_HASH];
extern CommandHash *MEMOSERV[MAX_CMD_HASH];
extern CommandHash *NICKSERV[MAX_CMD_HASH];
extern CommandHash *CHANSERV[MAX_CMD_HASH];
extern CommandHash *HELPSERV[MAX_CMD_HASH];
extern CommandHash *OPERSERV[MAX_CMD_HASH];
extern MessageHash *IRCD[MAX_CMD_HASH];
struct Module_ {
char *name;
char *filename;
void *handle;
time_t time;
char *version;
char *author;
void (*nickHelp)(User *u); /* service 1 */
void (*chanHelp)(User *u); /* 2 */
void (*memoHelp)(User *u); /* 3 */
void (*botHelp)(User *u); /* 4 */
void (*operHelp)(User *u); /* 5 */
void (*hostHelp)(User *u); /* 6 */
void (*helpHelp)(User *u); /* 7 */
// CommandHash *cmdList[MAX_CMD_HASH];
MessageHash *msgList[MAX_CMD_HASH];
};
struct ModuleHash_ {
char *name;
Module *m;
ModuleHash *next;
};
struct Command_ {
char *name;
int (*routine)(User *u);
int (*has_priv)(User *u); /* Returns 1 if user may use command, else 0 */
/* Regrettably, these are hard-coded to correspond to current privilege
* levels (v4.0). Suggestions for better ways to do this are
* appreciated.
*/
int helpmsg_all; /* Displayed to all users; -1 = no message */
int helpmsg_reg; /* Displayed to regular users only */
int helpmsg_oper; /* Displayed to Services operators only */
int helpmsg_admin; /* Displayed to Services admins only */
int helpmsg_root; /* Displayed to Services root only */
char *help_param1;
char *help_param2;
char *help_param3;
char *help_param4;
/* Module related stuff */
int core; /* Can this command be deleted? */
char *mod_name; /* Name of the module who owns us, NULL for core's */
char *service; /* Service we provide this command for */
int (*all_help)(User *u);
int (*regular_help)(User *u);
int (*oper_help)(User *u);
int (*admin_help)(User *u);
int (*root_help)(User *u);
Command *next; /* Next command responsible for the same command */
};
struct CommandHash_ {
char *name; /* Name of the command */
Command *c; /* Actual command */
CommandHash *next; /* Next command */
};
struct Message_ {
char *name;
int (*func)(char *source, int ac, char **av);
int core;
char *mod_name;
Message *next;
};
struct MessageHash_ {
char *name;
Message *m;
MessageHash *next;
};
struct ModuleCallBack_ {
char *name;
char *owner_name;
time_t when;
int (*func)(int argc, char *argv[]);
int argc;
char **argv;
ModuleCallBack *next;
};
/*************************************************************************/
/* Module Managment Functions */
Module *createModule(char *filename); /* Create a new module, using the given name */
int destroyModule(Module *m); /* Delete the module */
int addModule(Module *m); /* Add a module to the module hash */
int delModule(Module *m); /* Remove a module from the module hash */
Module *findModule(char *name); /* Find a module */
int loadModule(Module *m,User *u); /* Load the given module into the program */
int unloadModule(Module *m, User *u); /* Unload the given module from the pro */
int prepForUnload(Module *m); /* Prepare the module for unload */
void moduleAddVersion(char *version);
void moduleAddAuthor(char *author);
void modules_init(void);
void modules_delayed_init(void);
void moduleCallBackPrepForUnload(char *mod_name);
void moduleCallBackDeleteEntry(ModuleCallBack * prev);
char *moduleGetLastBuffer(void);
void moduleSetHelpHelp(void (*func) (User * u));
void moduleDisplayHelp(int service, User *u);
void moduleSetHostHelp(void (*func) (User * u));
void moduleSetOperHelp(void (*func) (User * u));
void moduleSetBotHelp(void (*func) (User * u));
void moduleSetMemoHelp(void (*func) (User * u));
void moduleSetChanHelp(void (*func) (User * u));
void moduleSetNickHelp(void (*func) (User * u));
int moduleAddHelp(Command * c, int (*func) (User * u));
int moduleAddRegHelp(Command * c, int (*func) (User * u));
int moduleAddOperHelp(Command * c, int (*func) (User * u));
int moduleAddAdminHelp(Command * c, int (*func) (User * u));
int moduleAddRootHelp(Command * c, int (*func) (User * u));
/*************************************************************************/
/*************************************************************************/
/* Command Managment Functions */
Command *createCommand(const char *name,int (*func)(User *u),int (*has_priv)(User *u),int help_all, int help_reg, int help_oper, int help_admin,int help_root);
int destroyCommand(Command *c); /* destroy a command */
int addCoreCommand(CommandHash *cmdTable[], Command *c); /* Add a command to a command table */
int moduleAddCommand(CommandHash *cmdTable[], Command *c, int pos);
int addCommand(CommandHash *cmdTable[], Command *c,int pos);
int delCommand(CommandHash *cmdTable[], Command *c,char *mod_name); /* Del a command from a cmd table */
int moduleDelCommand(CommandHash *cmdTable[],char *name); /* Del a command from a cmd table */
Command *findCommand(CommandHash *cmdTable[], const char *name); /* Find a command */
/*************************************************************************/
/*************************************************************************/
/* Message Managment Functions */
Message *createMessage(char *name,int (*func)(char *source, int ac, char **av));
Message *findMessage(MessageHash *msgTable[], const char *name); /* Find a Message */
int addMessage(MessageHash *msgTable[], Message *m, int pos); /* Add a Message to a Message table */
int addCoreMessage(MessageHash *msgTable[], Message *m); /* Add a Message to a Message table */
int moduleAddMessage(Message *m, int pos);
int delMessage(MessageHash *msgTable[], Message *m, char *mod_name); /* Del a Message from a msg table */
int moduleDelMessage(char *name);
int destroyMessage(Message *m); /* destroy a Message*/
Message *findMessage(MessageHash *msgTable[], const char *name);
/*************************************************************************/
int moduleAddCallback(char *name,time_t when,int (*func)(int argc, char *argv[]),int argc, char **argv);
void moduleDelCallback(char *name);
void moduleCallBackRun(void);
/*************************************************************************/
#endif
/* EOF */
+26
View File
@@ -0,0 +1,26 @@
include ../Makefile.inc
include ./Makefile.inc
OBJECTS= $(SRCS:.c=.o)
SO_FILES=$(OBJECTS:.o=.s)
CDEFS= -g -rdynamic -Wall
CFLAGS=$(BASE_CFLAGS) $(CDEFS)
all: $(OBJECTS)
install: $(SO_FILES)
$(CP_ALL) ./*.so $(MODULE_PATH)
distclean: clean spotless
.c.o:
$(CC) $(CFLAGS) -c $<
.o.s:
ld -shared $< -o $*.so
clean:
rm -f *.o core
spotless: clean
rm -f *.so Makefile.inc
+1
View File
@@ -0,0 +1 @@
Please read the "MODULES" file located on the "docs" directory.
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
# Disabled for Anope 1.6 until we figure out a better way to
# download modules safely.
# if [ "$1" = "getmods" ] ; then
# wget -nv -r -l 1 -A c -nd -nc http://modules.anope.org/download/
# rm -f robots.txt
# exit 0
# fi
if [ ! -f ../Makefile.inc ]; then
echo ""
echo "*** ERROR: Unable to find ../Makefile.inc. You must ./configure Anope before"
echo "*** ERROR: compiling modules. Please read the INSTALL document for details."
echo ""
exit 1
fi
echo -n "SRCS=" > ./Makefile.inc
FIRST=1
for oldfile in *.c
do
if [ "$FIRST" = 1 ] ; then
echo -n " "$oldfile >> ./Makefile.inc
else
echo "\\" >> ./Makefile.inc
echo -n " " $oldfile >> ./Makefile.inc
fi
FIRST=0
done
echo "" >> ./Makefile.inc
make
if [ "$1" = "install" ] ; then
make install
fi
Vendored Executable
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
echo -n "SRCS=" > ./Makefile.inc
FIRST=1
for oldfile in *.c
do
if [ "$FIRST" = 1 ] ; then
echo -n " "$oldfile >> ./Makefile.inc
else
echo "\\" >> ./Makefile.inc
echo -n " " $oldfile >> ./Makefile.inc
fi
FIRST=0
done
echo "" >> ./Makefile.inc
cat <<EOT
All done! Now run "make" (or possibly "gmake") to compile your modules.
See the INSTALL, README and FAQ files if you have any problems.
EOT
exit 0
+99
View File
@@ -0,0 +1,99 @@
/**
* This is an EXAMPLE module, which adds the "moo" command to HostServ
*
* This command does NOT do anything useful at all!
*
* Please visit http://modules.anope.org for useful modules!
*
**/
#include "module.h"
#define AUTHOR "Anope" /* Set the Author for a modinfo reply */
#define VERSION "1.1" /* Set the version for a modinfo reply */
int hs_moo_show(User * u); /* Function to use when a /hs moo command is recived */
int test(int argc, char **argv);
void myHostServHelp(User *u); /* Function to display out help in a /hs help response */
int myHostServMooHelp(User *u); /* Function to display help to _everyone_ when a /hs help moo is called*/
int myHostServMooRegHelp(User *u); /* Function to display extra help to regular-users when a /hs help moo is called*/
int myHostServMooOperHelp(User *u); /* Function to display extra help to opers when a /hs help moo is called*/
int myHostServMooAdminHelp(User *u); /* Function to display extra help to admins when a /hs help moo is called*/
int myHostServMooRootHelp(User *u); /* Function to display extra help to roors when a /hs help moo is called*/
int AnopeInit(int argc, char **argv) /* This will be executed when the module is loaded */
{
Command *c; /* Pointer to a Command */
c = createCommand("moo", hs_moo_show, NULL, -1, -1, -1, -1, -1); /* Create a new command "moo" pointing to hs_moo */
moduleAddHelp(c,myHostServMooHelp); /* add help for all users to this command */
moduleAddRegHelp(c,myHostServMooRegHelp); /* add extra regular-user only help to this command */
moduleAddOperHelp(c,myHostServMooOperHelp); /* add extra oper only help to this command */
moduleAddAdminHelp(c,myHostServMooAdminHelp); /* add extra admin only help to this command */
moduleAddRootHelp(c,myHostServMooRootHelp); /* add extra root only help to this command */
moduleSetHostHelp(myHostServHelp); /* add us to the .hs help list */
alog("hs_moo.so: Add Command 'moo' Status: %d", /* Log the command being added */
moduleAddCommand(HOSTSERV, c, MOD_HEAD)); /* And add it to the HOSTSERV cmd table */
moduleAddCallback("test",time(NULL)+dotime("15s"),test,0,NULL); /* set a call-back function to exec in 3 mins time */
moduleDelCallback("test");
moduleAddAuthor(AUTHOR); /* tell Anope about the author */
moduleAddVersion(VERSION); /* Tell Anope about the verison */
return MOD_CONT;
}
int hs_moo_show(User * u)
{
notice(s_HostServ, u->nick, "MOO! - This command was loaded via a module!"); /* Just notice the user */
return MOD_STOP; /* MOD_STOP means we will NOT pass control back to other */
} /* modules waiting to handle the /hs moo command! */
int test(int argc, char **argv) {
alog("CallBack from hs_moo with %d paramaters",argc);
return MOD_CONT;
}
/***************************************************************************************************************************************/
/* The code below here shows various ways of dealing with the module help system */
/***************************************************************************************************************************************/
void myHostServHelp(User *u) {
notice(s_HostServ,u->nick, " MOO Moo's at the user!"); /* this will appear in the help list */
}
int myHostServMooHelp(User *u) {
notice(s_HostServ,u->nick,"Syntax: Moo"); /* this will be sent to everyone who does /msg hostserv help moo */
notice(s_HostServ,u->nick,"This command is an example provided");
notice(s_HostServ,u->nick,"by the Anope development team.");
return MOD_CONT; /* allow any other module's with help for /hs moo to run */
}
int myHostServMooRootHelp(User *u) { /* this will only be sent to ROOTS ONLY who /msg hostserv moo */
myHostServMooAdminHelp(u); /* this line lets us show roots the ADMIN help as well as the root help */
notice(s_HostServ,u->nick,"Only roots will see this part of the help");
return MOD_CONT;
}
int myHostServMooAdminHelp(User *u) { /* this will only be sent to ADMINS ONLY who /msg hostserv moo */
myHostServMooOperHelp(u); /* this line lets us show admins the OPER help as well as the admin help */
notice(s_HostServ,u->nick,"Only admins will see this part of the help");
notice(s_HostServ,u->nick,"why not visit us on www.anope.org ?");
return MOD_CONT;
}
int myHostServMooOperHelp(User *u) { /* this will only be sent to OPERS ONLY who /msg hostserv moo */
notice(s_HostServ,u->nick,"Only opers will see this part of the help");
notice(s_HostServ,u->nick,"for more help/support with modules");
notice(s_HostServ,u->nick,"visit us on irc.anope.org #anope! :)");
return MOD_CONT;
}
int myHostServMooRegHelp(User *u) { /* this will only be sent to REGULAR USERS ONLY who /msg hostserv moo */
notice(s_HostServ,u->nick,"Only non-opers will see this part of the help");
notice(s_HostServ,u->nick,"as we've left it hidden from opers");
return MOD_CONT;
}
/* EOF */
+128
View File
@@ -0,0 +1,128 @@
/**
* Simple module to load up a client called CatServ and process commands for it
* This module is an example, and has no useful purpose!
*
* Please visit http://modules.anope.org for useful modules!
*
**/
#include "module.h"
#define AUTHOR "Anope"
#define VERSION "1.1"
int my_privmsg(char *source, int ac, char **av);
CommandHash *Catserv_cmdTable[MAX_CMD_HASH];
void addClient(char *nick, char *realname);
void addMessageList(void);
void delClient(void);
char *s_CatServ = "CatServ";
void catserv(User * u, char *buf);
int do_meow(User * u);
int do_purr(User * u);
int AnopeInit(int argc, char **argv)
{
Message *msg = NULL;
int status;
msg = createMessage("PRIVMSG", my_privmsg);
status = moduleAddMessage(msg, MOD_HEAD);
if (status == MOD_ERR_OK) {
addClient(s_CatServ, "meow!");
addMessageList();
}
moduleAddAuthor(AUTHOR);
moduleAddVersion(VERSION);
alog("ircd_catserv.so: loaded, message status [%d]", status);
return MOD_CONT;
}
void AnopeFini(void)
{
delClient();
}
int my_privmsg(char *source, int ac, char **av)
{
User *u;
char *s;
/* First, some basic checks */
if (ac != 2)
return MOD_CONT; /* bleh */
if (!(u = finduser(source))) {
return MOD_CONT;
} /* non-user source */
if (*av[0] == '#') {
return MOD_CONT;
}
/* Channel message */
/* we should prolly honour the ignore list here, but i cba for this... */
s = strchr(av[0], '@');
if (s) {
*s++ = 0;
if (stricmp(s, ServerName) != 0)
return MOD_CONT;
}
if ((stricmp(av[0], s_CatServ)) == 0) { /* its for US! */
catserv(u, av[1]);
return MOD_STOP;
} else { /* ok it isnt us, let the old code have it */
return MOD_CONT;
}
}
void addClient(char *nick, char *realname)
{
NEWNICK(nick, "catserv", "meow.meow.land", realname, "+", 1);
}
void delClient(void)
{
send_cmd(s_CatServ, "QUIT :Module Unloaded!");
}
void addMessageList(void)
{
Command *c;
c = createCommand("meow", do_meow, NULL, -1, -1, -1, -1, -1);
addCommand(Catserv_cmdTable, c, MOD_UNIQUE);
c = createCommand("purr", do_purr, NULL, -1, -1, -1, -1, -1);
addCommand(Catserv_cmdTable, c, MOD_UNIQUE);
}
/*****************************************************************************/
/* Main CatServ routine. */
void catserv(User * u, char *buf)
{
char *cmd, *s;
cmd = strtok(buf, " ");
if (!cmd) {
return;
} else if (stricmp(cmd, "\1PING") == 0) {
if (!(s = strtok(NULL, "")))
s = "\1";
notice(s_CatServ, u->nick, "\1PING %s", s);
} else if (skeleton) {
notice_lang(s_CatServ, u, SERVICE_OFFLINE, s_CatServ);
} else {
mod_run_cmd(s_CatServ, u, Catserv_cmdTable, cmd);
}
}
int do_meow(User * u)
{
notice(s_CatServ, u->nick, "MEOW!");
return MOD_STOP;
}
int do_purr(User * u)
{
notice(s_CatServ, u->nick, "PURR!");
return MOD_STOP;
}
+9
View File
@@ -0,0 +1,9 @@
#include "../services.h"
#include "../commands.h"
#include "../language.h"
#include "../modules.h"
#define MOD_UNIQUE 0
#define MOD_HEAD 1
#define MOD_TAIL 2
+869
View File
@@ -0,0 +1,869 @@
/* MySQL functions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: mysql.c,v 1.33 2004/03/14 13:02:53 rob Exp $
*
*/
#include "services.h"
/*************************************************************************/
/* Database Global Variables */
MYSQL *mysql; /* MySQL Handler */
MYSQL_RES *mysql_res; /* MySQL Result */
MYSQL_FIELD *mysql_fields; /* MySQL Fields */
MYSQL_ROW mysql_row; /* MySQL Row */
/*************************************************************************/
void db_mysql_error(int severity, char *msg)
{
static char buf[512];
if (mysql_error(mysql)) {
snprintf(buf, sizeof(buf), "MySQL %s %s: %s", msg,
severity == MYSQL_WARNING ? "warning" : "error",
mysql_error(mysql));
} else {
snprintf(buf, sizeof(buf), "MySQL %s %s", msg,
severity == MYSQL_WARNING ? "warning" : "error");
}
log_perror(buf);
if (severity == MYSQL_ERROR) {
log_perror("MySQL FATAL error... aborting.");
exit(0);
}
}
/*************************************************************************/
int db_mysql_init()
{
/* If the host is not defined, assume we don't want MySQL */
if (!MysqlHost) {
do_mysql = 0;
alog("MySQL has been disabled.");
} else {
do_mysql = 1;
alog("MySQL has been enabled.");
}
return 1;
}
/*************************************************************************/
int db_mysql_open()
{
/* If MySQL is disabled, return 0 */
if (!do_mysql)
return 0;
mysql = mysql_init(NULL);
if (mysql == NULL)
db_mysql_error(MYSQL_WARNING, "Unable to create mysql object");
if (!MysqlPort)
MysqlPort = 3306;
if (MysqlSock) {
if ((!mysql_real_connect
(mysql, MysqlHost, MysqlUser, MysqlPass, MysqlName, MysqlPort,
MysqlSock, 0))) {
log_perror("Cant connect to MySQL: %s\n", mysql_error(mysql));
return 0;
}
} else {
if ((!mysql_real_connect
(mysql, MysqlHost, MysqlUser, MysqlPass, MysqlName, MysqlPort,
NULL, 0))) {
log_perror("Cant connect to MySQL: %s\n", mysql_error(mysql));
return 0;
}
}
return 1;
}
/*************************************************************************/
int db_mysql_query(char *sql)
{
int result, lcv;
result = mysql_query(mysql, sql);
if (result) {
switch (mysql_errno(mysql)) {
case CR_SERVER_GONE_ERROR:
case CR_SERVER_LOST:
for (lcv = 0; lcv < MysqlRetries; lcv++) {
if (db_mysql_open()) {
result = mysql_query(mysql, sql);
return (result);
}
sleep(MysqlRetryGap);
}
/* If we get here, we could not connect. */
log_perror("Unable to reconnect to database: %s\n",
mysql_error(mysql));
db_mysql_error(MYSQL_ERROR, "connect");
/* Never reached. */
break;
default:
/* Unhandled error. */
return (result);
}
}
return (0);
}
/*************************************************************************/
char *db_mysql_quote(char *sql)
{
int slen;
char *quoted;
if (!sql) {
return sstrdup("");
}
slen = strlen(sql);
quoted = malloc((1 + (slen * 2)) * sizeof(char));
mysql_real_escape_string(mysql, quoted, sql, slen);
return quoted;
}
/*************************************************************************/
/* I don't like using res here, maybe we can pass it as a param? */
int db_mysql_close()
{
if (mysql_res)
mysql_free_result(mysql_res);
mysql_close(mysql);
return 1;
}
/*************************************************************************/
/*
* NickServ Specific Secion
*/
/*************************************************************************/
void db_mysql_save_ns_req(NickRequest * nr)
{
char *qnick, *qpasscode, *qpassword, *qemail;
char sqlcmd[MAX_SQL_BUF];
qnick = db_mysql_quote(nr->nick);
qpasscode = db_mysql_quote(nr->passcode);
qpassword = db_mysql_quote(nr->password);
qemail = db_mysql_quote(nr->email);
snprintf(sqlcmd, MAX_SQL_BUF,
"REPLACE anope_ns_request (nick,passcode,password,email,requested,active)"
" VALUES ('%s','%s','%s','%s','%d','1')",
qnick, qpasscode, qpassword, qemail, (int) nr->requested);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(qnick);
free(qpasscode);
free(qpassword);
free(qemail);
}
char *db_mysql_secure(char *pass)
{
char epass[BUFSIZE];
if (!pass) {
snprintf(epass, sizeof(epass), "''");
} else if ((!MysqlSecure) || (strcmp(MysqlSecure, "") == 0)) {
snprintf(epass, sizeof(epass), "'%s'", pass);
} else if (strcmp(MysqlSecure, "des") == 0) {
snprintf(epass, sizeof(epass), "ENCRYPT('%s')", pass);
} else if (strcmp(MysqlSecure, "md5") == 0) {
snprintf(epass, sizeof(epass), "MD5('%s')", pass);
} else if (strcmp(MysqlSecure, "sha") == 0) {
snprintf(epass, sizeof(epass), "SHA('%s')", pass);
} else {
snprintf(epass, sizeof(epass), "ENCODE('%s','%s')", pass,
MysqlSecure);
}
return sstrdup(epass);
}
/*************************************************************************/
void db_mysql_save_ns_core(NickCore * nc)
{
char sqlcmd[MAX_SQL_BUF];
int j;
char **access;
Memo *memos;
char *cnick, *cpass, *epass, *cemail, *cgreet, *curl, *caccess,
*msender, *mtext;
cnick = db_mysql_quote(nc->display);
cpass = db_mysql_quote(nc->pass);
cemail = db_mysql_quote(nc->email);
cgreet = db_mysql_quote(nc->greet);
curl = db_mysql_quote(nc->url);
epass = db_mysql_secure(cpass);
free(cpass);
/* Let's take care of the core itself */
/* Update the existing records */
snprintf(sqlcmd, MAX_SQL_BUF,
"UPDATE anope_ns_core SET pass=%s,email='%s',greet='%s',icq='%d',url='%s',flags='%d',"
"language='%d',accesscount='%d',memocount='%d',memomax='%d',channelcount='%d'"
",channelmax='%d',active='1' WHERE display='%s'",
epass, cemail, cgreet, nc->icq, curl, nc->flags,
nc->language, nc->accesscount, nc->memos.memocount,
nc->memos.memomax, nc->channelcount, nc->channelmax, cnick);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
/* need to write a wrapper for mysql_affected_rows */
/* Our previous UPDATE affected no rows, therefore this is a new record */
if ((int) mysql_affected_rows(mysql) <= 0) {
/* Let's take care of the core itself */
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_ns_core (display,pass,email,greet,icq,url,flags,"
"language,accesscount,memocount,memomax,channelcount,channelmax,active)"
" VALUES ('%s',%s,'%s','%s','%d','%s','%d','%d','%d','%d','%d','%d','%d','1')",
cnick, epass, cemail, cgreet, nc->icq, curl, nc->flags,
nc->language, nc->accesscount, nc->memos.memocount,
nc->memos.memomax, nc->channelcount, nc->channelmax);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
}
/* Now let's do the access */
for (j = 0, access = nc->access; j < nc->accesscount; j++, access++) {
caccess = db_mysql_quote(*access);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_ns_access (display,access) VALUES ('%s','%s')",
cnick, caccess);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(caccess);
}
/* And... memos */
memos = nc->memos.memos;
for (j = 0; j < nc->memos.memocount; j++, memos++) {
msender = db_mysql_quote(memos->sender);
mtext = db_mysql_quote(memos->text);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_ms_info (receiver,number,flags,time,sender,text,serv)"
" VALUES ('%s','%d','%d','%d','%s','%s','NICK')",
cnick, memos->number, memos->flags,
(int) memos->time, msender, mtext);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(msender);
free(mtext);
}
free(cnick);
free(epass);
free(cemail);
free(cgreet);
free(curl);
}
/*************************************************************************/
void db_mysql_save_ns_alias(NickAlias * na)
{
char sqlcmd[MAX_SQL_BUF];
char *nnick, *nlmask, *nlrname, *nlquit, *nncnick;
nnick = db_mysql_quote(na->nick);
nlmask = db_mysql_quote(na->last_usermask);
nlrname = db_mysql_quote(na->last_realname);
nlquit = db_mysql_quote(na->last_quit);
nncnick = db_mysql_quote(na->nc->display);
snprintf(sqlcmd, MAX_SQL_BUF,
"UPDATE anope_ns_alias SET last_usermask='%s',last_realname='%s',last_quit='%s',time_registered='%d',last_seen='%d',status='%d',display='%s',active='1' WHERE nick='%s'",
nlmask, nlrname, nlquit, (int) na->time_registered,
(int) na->last_seen, (int) na->status, nncnick, nnick);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
/* Our previous UPDATE affected no rows, therefore this is a new record */
if ((int) mysql_affected_rows(mysql) <= 0) {
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT INTO anope_ns_alias (nick,last_usermask,last_realname,last_quit,time_registered,last_seen,status,display,active) VALUES ('%s','%s','%s','%s','%d','%d','%d','%s','1')",
nnick, nlmask, nlrname, nlquit, (int) na->time_registered,
(int) na->last_seen, (int) na->status, nncnick);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
}
free(nnick);
free(nlmask);
free(nlrname);
free(nlquit);
free(nncnick);
return;
}
/*************************************************************************/
/*
* ChanServ Specific Secion
*/
/*************************************************************************/
void db_mysql_save_cs_info(ChannelInfo * ci)
{
char sqlcmd[MAX_SQL_BUF];
int j, position;
Memo *memos;
char *ciname, *cifoundernick, *cisuccessornick, *cifounderpass,
*cidesc, *ciurl, *ciemail, *cilasttopic, *cilasttopicsetter,
*ciforbidby, *ciforbidreason, *cimlock_key, *cimlock_flood,
*cimlock_redirect, *cientrymsg, *cibotnick, *msender, *mtext,
*ciaccessdisp, *ciakickdisp, *ciakickreason, *ciakickcreator,
*cbadwords, *efounderpass;
ciname = db_mysql_quote(ci->name);
cifoundernick =
ci->founder ? db_mysql_quote(ci->founder->display) : "";
cisuccessornick =
ci->successor ? db_mysql_quote(ci->successor->display) : "";
cifounderpass = db_mysql_quote(ci->founderpass);
cidesc = db_mysql_quote(ci->desc);
ciurl = db_mysql_quote(ci->url);
ciemail = db_mysql_quote(ci->email);
cilasttopic = db_mysql_quote(ci->last_topic);
cilasttopicsetter = db_mysql_quote(ci->last_topic_setter);
ciforbidby = db_mysql_quote(ci->forbidby);
ciforbidreason = db_mysql_quote(ci->forbidreason);
cimlock_key = db_mysql_quote(ci->mlock_key);
#ifdef HAS_FMODE
cimlock_flood = db_mysql_quote(ci->mlock_flood);
#else
cimlock_flood = NULL;
#endif
#ifdef HAS_LMODE
cimlock_redirect = db_mysql_quote(ci->mlock_redirect);
#else
cimlock_redirect = NULL;
#endif
cientrymsg = db_mysql_quote(ci->entry_message);
cibotnick = ci->bi ? db_mysql_quote(ci->bi->nick) : "";
efounderpass = db_mysql_secure(cifounderpass);
free(cifounderpass);
/* Let's take care of the core itself */
snprintf(sqlcmd, MAX_SQL_BUF,
"UPDATE anope_cs_info SET founder='%s',successor='%s',founderpass=%s,"
"descr='%s',url='%s',email='%s',time_registered='%d',last_used='%d',"
"last_topic='%s',last_topic_setter='%s',last_topic_time='%d',flags='%d',"
"forbidby='%s',forbidreason='%s',bantype='%d',accesscount='%d',"
"akickcount='%d',mlock_on='%d',mlock_off='%d',mlock_limit='%d',"
"mlock_key='%s',mlock_flood='%s',mlock_redirect='%s',entry_message='%s',"
"memomax='%d',botnick='%s',botflags='%d',ttb='%d',bwcount='%d',"
"capsmin='%d',capspercent='%d',floodlines='%d',floodsecs='%d',"
"repeattimes='%d',active='1' WHERE name='%s'",
cifoundernick,
cisuccessornick,
efounderpass, cidesc, ciurl, ciemail,
(int) ci->time_registered, (int) ci->last_used,
cilasttopic, cilasttopicsetter,
(int) ci->last_topic_time, (int) ci->flags,
ciforbidby, ciforbidreason, (int) ci->bantype,
(int) ci->accesscount, (int) ci->akickcount,
(int) ci->mlock_on, (int) ci->mlock_off,
(int) ci->mlock_limit, cimlock_key,
#ifdef HAS_FMODE
cimlock_flood,
#else
"",
#endif
#ifdef HAS_LMODE
cimlock_redirect,
#else
"",
#endif
cientrymsg,
(int) ci->memos.memomax,
cibotnick,
(int) ci->botflags,
(int) ci->ttb,
(int) ci->bwcount,
(int) ci->capsmin,
(int) ci->capspercent,
(int) ci->floodlines,
(int) ci->floodsecs, (int) ci->repeattimes, ciname);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
/* Our previous UPDATE affected no rows, therefore this is a new record */
if ((int) mysql_affected_rows(mysql) <= 0) {
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_cs_info (name,founder,successor,founderpass,"
"descr,url,email,time_registered,last_used,last_topic,last_topic_setter"
",last_topic_time,flags,forbidby,forbidreason,bantype,accesscount,akickcount"
",mlock_on,mlock_off,mlock_limit,mlock_key,mlock_flood,mlock_redirect,"
"entry_message,botnick,botflags,bwcount,capsmin,capspercent,floodlines,"
"floodsecs,repeattimes,active) VALUES ('%s','%s','%s',%s,'%s','%s','%s'"
",'%d','%d','%s','%s','%d','%d','%s','%s','%d','%d','%d','%d','%d','%d',"
"'%s','%s','%s','%s','%s','%d','%d','%d','%d','%d','%d','%d','1')",
ciname,
cifoundernick,
cisuccessornick,
efounderpass, cidesc, ciurl, ciemail,
(int) ci->time_registered, (int) ci->last_used,
cilasttopic, cilasttopicsetter,
(int) ci->last_topic_time, (int) ci->flags,
ciforbidby, ciforbidreason, (int) ci->bantype,
(int) ci->accesscount, (int) ci->akickcount,
(int) ci->mlock_on, (int) ci->mlock_off,
(int) ci->mlock_limit, cimlock_key,
#ifdef HAS_FMODE
cimlock_flood,
#else
"",
#endif
#ifdef HAS_LMODE
cimlock_redirect,
#else
"",
#endif
cientrymsg,
cibotnick,
(int) ci->botflags,
(int) ci->bwcount,
(int) ci->capsmin,
(int) ci->capspercent,
(int) ci->floodlines,
(int) ci->floodsecs, (int) ci->repeattimes);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
}
/* Memos */
memos = ci->memos.memos;
for (j = 0; j < ci->memos.memocount; j++, memos++) {
msender = db_mysql_quote(memos->sender);
mtext = db_mysql_quote(memos->text);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_ms_info (receiver,number,flags,time,sender,text,serv)"
" VALUES ('%s','%d','%d','%d','%s','%s','CHAN')",
ciname, memos->number, memos->flags,
(int) memos->time, msender, mtext);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(msender);
free(mtext);
}
/* Access */
for (j = 0; j < ci->accesscount; j++) {
if (ci->access[j].in_use) {
ciaccessdisp = db_mysql_quote(ci->access[j].nc->display);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_cs_access (in_use,level,display,channel,last_seen)"
" VALUES ('%d','%d','%s','%s','%d')",
(int) ci->access[j].in_use, (int) ci->access[j].level,
ciaccessdisp, ciname, (int) ci->access[j].last_seen);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(ciaccessdisp);
}
}
/* Levels */
position = 0;
for (j = 0; j < CA_SIZE; j++) {
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_cs_levels (channel, position, level) VALUES ('%s','%d','%d')",
ciname, position++, (int) ci->levels[j]);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
}
/* Akicks */
for (j = 0; j < ci->akickcount; j++) {
ciakickdisp =
ci->akick[j].flags & AK_USED ? ci->akick[j].
flags & AK_ISNICK ? db_mysql_quote(ci->akick[j].u.nc->
display) :
db_mysql_quote(ci->akick[j].u.mask) : "";
ciakickreason =
ci->akick[j].flags & AK_USED ? db_mysql_quote(ci->akick[j].
reason) : "";
ciakickcreator =
ci->akick[j].flags & AK_USED ? db_mysql_quote(ci->akick[j].
creator) : "";
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_cs_akicks (channel, flags, dmask, reason, creator,"
" addtime) VALUES ('%s','%d','%s','%s','%s','%d')",
ciname, (int) ci->akick[j].flags, ciakickdisp,
ciakickreason, ciakickcreator,
ci->akick[j].flags & AK_USED ? (int) ci->akick[j].
addtime : 0);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
if (ci->akick[j].flags & AK_USED) {
free(ciakickdisp);
free(ciakickreason);
free(ciakickcreator);
}
}
/* Bad Words */
for (j = 0; j < ci->bwcount; j++) {
if (ci->badwords[j].in_use) {
cbadwords = db_mysql_quote(ci->badwords[j].word);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_cs_badwords (channel, word, type)"
" VALUES ('%s','%s','%d')", ciname, cbadwords,
(int) ci->badwords[j].type);
free(cbadwords);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
}
}
free(ciname);
if (!(ci->flags & CI_VERBOTEN)) {
free(cifoundernick);
if (strlen(cisuccessornick) > 0)
free(cisuccessornick);
free(efounderpass);
free(cidesc);
free(ciurl);
free(ciemail);
free(cilasttopic);
free(cilasttopicsetter);
free(cimlock_key);
free(cimlock_flood);
free(cimlock_redirect);
free(cientrymsg);
if (ci->bi)
free(cibotnick);
} else {
free(ciforbidby);
free(ciforbidreason);
}
return;
}
/*************************************************************************/
/*
* OperServ Specific Section
*/
/*************************************************************************/
void db_mysql_save_os_db(unsigned int maxucnt, unsigned int maxutime,
SList * ak, SList * sgl, SList * sql, SList * szl,
HostCache * hc)
{
char sqlcmd[MAX_SQL_BUF];
Akill *t_ak;
SXLine *t_sl;
HostCache *t_hc;
char *takuser, *takhost, *takby, *takreason, *tslmask, *tslby,
*tslreason, *thchost;
int i, j;
rdb_clear_table("anope_os_core");
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_core (maxusercnt,maxusertime,akills_count,"
"sglines_count,sqlines_count,szlines_count) VALUES "
"('%d','%d','%d','%d','%d','%d')", maxucnt, maxutime,
ak->count, sgl->count, sql->count, szl->count);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
/* now the akills saving */
rdb_clear_table("anope_os_akills");
j = ak->count;
for (i = 0; i < j; i++) {
t_ak = ak->list[i];
takuser = db_mysql_quote(t_ak->user);
takhost = db_mysql_quote(t_ak->host);
takby = db_mysql_quote(t_ak->by);
takreason = db_mysql_quote(t_ak->reason);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_akills (user,host,xby,reason,seton,expire) VALUES ('%s','%s','%s','%s','%d','%d')",
takuser,
takhost,
takby, takreason, (int) t_ak->seton, (int) t_ak->expires);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(takuser);
free(takhost);
free(takby);
free(takreason);
}
/* sglines save */
rdb_clear_table("anope_os_sglines");
j = sgl->count;
for (i = 0; i < j; i++) {
t_sl = sgl->list[i];
tslmask = db_mysql_quote(t_sl->mask);
tslby = db_mysql_quote(t_sl->by);
tslreason = db_mysql_quote(t_sl->reason);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_sglines (mask,xby,reason,seton,expire) VALUES"
" ('%s','%s','%s','%d','%d')",
tslmask,
tslby, tslreason, (int) t_sl->seton, (int) t_sl->expires);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(tslmask);
free(tslby);
free(tslreason);
}
/* sqlines save */
rdb_clear_table("anope_os_sqlines");
j = sql->count;
for (i = 0; i < j; i++) {
t_sl = sql->list[i];
tslmask = db_mysql_quote(t_sl->mask);
tslby = db_mysql_quote(t_sl->by);
tslreason = db_mysql_quote(t_sl->reason);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_sqlines (mask,xby,reason,seton,expire) VALUES ('%s','%s','%s','%d','%d')",
tslmask,
tslby, tslreason, (int) t_sl->seton, (int) t_sl->expires);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(tslmask);
free(tslby);
free(tslreason);
}
/* szlines save */
rdb_clear_table("anope_os_szlines");
j = szl->count;
for (i = 0; i < j; i++) {
t_sl = szl->list[i];
tslmask = db_mysql_quote(t_sl->mask);
tslby = db_mysql_quote(t_sl->by);
tslreason = db_mysql_quote(t_sl->reason);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_szlines (mask,xby,reason,seton,expire) VALUES"
" ('%s','%s','%s','%d','%d')",
tslmask,
tslby, tslreason, (int) t_sl->seton, (int) t_sl->expires);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(tslmask);
free(tslby);
free(tslreason);
}
/* and finally we save hcache */
rdb_clear_table("anope_os_hcache");
for (i = 0; i < 1024; i++) {
for (t_hc = hcache[i]; t_hc; t_hc = t_hc->next) {
/* Don't save in-progress scans */
if (t_hc->status < HC_NORMAL)
continue;
thchost = db_mysql_quote(t_hc->host);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_hcache (mask,status,used) VALUES ('%s','%d','%d')",
thchost, (int) t_hc->status, (int) t_hc->used);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(thchost);
}
}
return;
}
/*************************************************************************/
void db_mysql_save_news(NewsItem * ni)
{
char sqlcmd[MAX_SQL_BUF];
char *nitext, *niwho;
nitext = db_mysql_quote(ni->text);
niwho = db_mysql_quote(ni->who);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_news (type,num,ntext,who,`time`)"
" VALUES ('%d','%d','%s','%s','%d')",
ni->type, ni->num, nitext, niwho, (int) ni->time);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(nitext);
free(niwho);
return;
}
/*************************************************************************/
void db_mysql_save_exceptions(Exception * e)
{
char sqlcmd[MAX_SQL_BUF];
char *emask, *ewho, *ereason;
emask = db_mysql_quote(e->mask);
ewho = db_mysql_quote(e->who);
ereason = db_mysql_quote(e->reason);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_os_exceptions (mask,lim,who,reason,`time`,expires)"
" VALUES ('%s','%d','%s','%s','%d','%d')",
emask, e->limit, ewho,
ereason, (int) e->time, (int) e->expires);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(emask);
free(ewho);
free(ereason);
return;
}
/*************************************************************************/
/*
* HostServ Specific Section
*/
/*************************************************************************/
/* TODO: Add vident to tables! */
void db_mysql_save_hs_core(HostCore * hc)
{
char sqlcmd[MAX_SQL_BUF];
char *hcnick, *hcvident, *hcvhost, *hccreator;
hcnick = db_mysql_quote(hc->nick);
hcvident = db_mysql_quote(hc->vIdent);
hcvhost = db_mysql_quote(hc->vHost);
hccreator = db_mysql_quote(hc->creator);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_hs_core (nick,vident,vhost,creator,`time`)"
" VALUES ('%s','%s','%s','%s','%d')",
hcnick, hcvident, hcvhost, hccreator, (int) hc->time);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(hcnick);
free(hcvident);
free(hcvhost);
free(hccreator);
return;
}
/*************************************************************************/
/*
* HostServ Specific Section
*/
/*************************************************************************/
void db_mysql_save_bs_core(BotInfo * bi)
{
char sqlcmd[MAX_SQL_BUF];
char *binick, *biuser, *bihost, *bireal;
binick = db_mysql_quote(bi->nick);
biuser = db_mysql_quote(bi->user);
bihost = db_mysql_quote(bi->host);
bireal = db_mysql_quote(bi->real);
snprintf(sqlcmd, MAX_SQL_BUF,
"INSERT DELAYED INTO anope_bs_core (nick,user,host,rname,flags,created"
",chancount) VALUES ('%s','%s','%s','%s','%d','%d','%d')",
binick, biuser,
bihost, bireal, bi->flags, (int) bi->created, bi->chancount);
if (db_mysql_query(sqlcmd)) {
log_perror("Can't create sql query: %s", sqlcmd);
db_mysql_error(MYSQL_WARNING, "query");
}
free(binick);
free(biuser);
free(bihost);
free(bireal);
}
/*************************************************************************/
+541
View File
@@ -0,0 +1,541 @@
/* News functions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: news.c,v 1.11 2004/01/31 17:03:52 dane Exp $
*
*/
#include "services.h"
#include "pseudo.h"
/*************************************************************************/
static int32 nnews = 0;
static int32 news_size = 0;
static NewsItem *news = NULL;
/*************************************************************************/
/* List of messages for each news type. This simplifies message sending. */
#define MSG_SYNTAX 0
#define MSG_LIST_HEADER 1
#define MSG_LIST_ENTRY 2
#define MSG_LIST_NONE 3
#define MSG_ADD_SYNTAX 4
#define MSG_ADD_FULL 5
#define MSG_ADDED 6
#define MSG_DEL_SYNTAX 7
#define MSG_DEL_NOT_FOUND 8
#define MSG_DELETED 9
#define MSG_DEL_NONE 10
#define MSG_DELETED_ALL 11
#define MSG_MAX 11
struct newsmsgs {
int16 type;
char *name;
int msgs[MSG_MAX + 1];
};
/* *INDENT-OFF* */
struct newsmsgs msgarray[] = {
{ NEWS_LOGON, "LOGON",
{ NEWS_LOGON_SYNTAX,
NEWS_LOGON_LIST_HEADER,
NEWS_LOGON_LIST_ENTRY,
NEWS_LOGON_LIST_NONE,
NEWS_LOGON_ADD_SYNTAX,
NEWS_LOGON_ADD_FULL,
NEWS_LOGON_ADDED,
NEWS_LOGON_DEL_SYNTAX,
NEWS_LOGON_DEL_NOT_FOUND,
NEWS_LOGON_DELETED,
NEWS_LOGON_DEL_NONE,
NEWS_LOGON_DELETED_ALL
}
},
{ NEWS_OPER, "OPER",
{ NEWS_OPER_SYNTAX,
NEWS_OPER_LIST_HEADER,
NEWS_OPER_LIST_ENTRY,
NEWS_OPER_LIST_NONE,
NEWS_OPER_ADD_SYNTAX,
NEWS_OPER_ADD_FULL,
NEWS_OPER_ADDED,
NEWS_OPER_DEL_SYNTAX,
NEWS_OPER_DEL_NOT_FOUND,
NEWS_OPER_DELETED,
NEWS_OPER_DEL_NONE,
NEWS_OPER_DELETED_ALL
}
},
{ NEWS_RANDOM, "RANDOM",
{ NEWS_RANDOM_SYNTAX,
NEWS_RANDOM_LIST_HEADER,
NEWS_RANDOM_LIST_ENTRY,
NEWS_RANDOM_LIST_NONE,
NEWS_RANDOM_ADD_SYNTAX,
NEWS_RANDOM_ADD_FULL,
NEWS_RANDOM_ADDED,
NEWS_RANDOM_DEL_SYNTAX,
NEWS_RANDOM_DEL_NOT_FOUND,
NEWS_RANDOM_DELETED,
NEWS_RANDOM_DEL_NONE,
NEWS_RANDOM_DELETED_ALL
}
}
};
/* *INDENT-ON* */
static int *findmsgs(int16 type, char **typename)
{
int i;
for (i = 0; i < lenof(msgarray); i++) {
if (msgarray[i].type == type) {
if (typename)
*typename = msgarray[i].name;
return msgarray[i].msgs;
}
}
return NULL;
}
/*************************************************************************/
/* Called by the main OperServ routine in response to a NEWS command. */
static void do_news(User * u, int16 type);
/* Lists all a certain type of news. */
static void do_news_list(User * u, int16 type, int *msgs);
/* Add news items. */
static void do_news_add(User * u, int16 type, int *msgs,
const char *typename);
static int add_newsitem(User * u, const char *text, int16 type);
/* Delete news items. */
static void do_news_del(User * u, int16 type, int *msgs,
const char *typename);
static int del_newsitem(int num, int16 type);
/*************************************************************************/
/****************************** Statistics *******************************/
/*************************************************************************/
void get_news_stats(long *nrec, long *memuse)
{
long mem;
int i;
mem = sizeof(NewsItem) * news_size;
for (i = 0; i < nnews; i++)
mem += strlen(news[i].text) + 1;
*nrec = nnews;
*memuse = mem;
}
/*************************************************************************/
/*********************** News item loading/saving ************************/
/*************************************************************************/
#define SAFE(x) do { \
if ((x) < 0) { \
if (!forceload) \
fatal("Read error on %s", NewsDBName); \
nnews = i; \
break; \
} \
} while (0)
void load_news()
{
dbFILE *f;
int i;
int16 n;
int32 tmp32;
if (!(f = open_db(s_OperServ, NewsDBName, "r", NEWS_VERSION)))
return;
switch (i = get_file_version(f)) {
case 9:
case 8:
case 7:
SAFE(read_int16(&n, f));
nnews = n;
if (nnews < 8)
news_size = 16;
else if (nnews >= 16384)
news_size = 32767;
else
news_size = 2 * nnews;
news = scalloc(sizeof(*news) * news_size, 1);
if (!nnews) {
close_db(f);
return;
}
for (i = 0; i < nnews; i++) {
SAFE(read_int16(&news[i].type, f));
SAFE(read_int32(&news[i].num, f));
SAFE(read_string(&news[i].text, f));
SAFE(read_buffer(news[i].who, f));
SAFE(read_int32(&tmp32, f));
news[i].time = tmp32;
}
break;
default:
fatal("Unsupported version (%d) on %s", i, NewsDBName);
} /* switch (ver) */
close_db(f);
}
#undef SAFE
/*************************************************************************/
#define SAFE(x) do { \
if ((x) < 0) { \
restore_db(f); \
log_perror("Write error on %s", NewsDBName); \
if (time(NULL) - lastwarn > WarningTimeout) { \
wallops(NULL, "Write error on %s: %s", NewsDBName, \
strerror(errno)); \
lastwarn = time(NULL); \
} \
return; \
} \
} while (0)
void save_news()
{
dbFILE *f;
int i;
static time_t lastwarn = 0;
if (!(f = open_db(s_OperServ, NewsDBName, "w", NEWS_VERSION)))
return;
SAFE(write_int16(nnews, f));
for (i = 0; i < nnews; i++) {
SAFE(write_int16(news[i].type, f));
SAFE(write_int32(news[i].num, f));
SAFE(write_string(news[i].text, f));
SAFE(write_buffer(news[i].who, f));
SAFE(write_int32(news[i].time, f));
}
close_db(f);
}
#undef SAFE
void save_rdb_news()
{
#ifdef USE_RDB
int i;
NewsItem *ni;
if (!rdb_open())
return;
rdb_clear_table("anope_os_news");
for (i = 0; i < nnews; i++) {
ni = &news[i];
rdb_save_news(ni);
}
rdb_close();
#endif
}
/*************************************************************************/
/***************************** News display ******************************/
/*************************************************************************/
void display_news(User * u, int16 type)
{
int msg;
if (type == NEWS_LOGON) {
msg = NEWS_LOGON_TEXT;
} else if (type == NEWS_OPER) {
msg = NEWS_OPER_TEXT;
} else if (type == NEWS_RANDOM) {
msg = NEWS_RANDOM_TEXT;
} else {
alog("news: Invalid type (%d) to display_news()", type);
return;
}
if (type == NEWS_RANDOM) {
static int current_news = -1;
int count = 0;
if (!nnews)
return;
while (count++ < nnews) {
if (++current_news >= nnews)
current_news = 0;
if (news[current_news].type == type) {
struct tm *tm;
char timebuf[64];
tm = localtime(&news[current_news].time);
strftime_lang(timebuf, sizeof(timebuf), u,
STRFTIME_SHORT_DATE_FORMAT, tm);
notice_lang(s_GlobalNoticer, u, msg, timebuf,
news[current_news].text);
return;
}
}
} else {
int i, count = 0; /* Number we're going to show--not more than 3 */
for (i = nnews - 1; i >= 0; i--) {
if (count >= 3)
break;
if (news[i].type == type)
count++;
}
while (++i < nnews) {
if (news[i].type == type) {
struct tm *tm;
char timebuf[64];
tm = localtime(&news[i].time);
strftime_lang(timebuf, sizeof(timebuf), u,
STRFTIME_SHORT_DATE_FORMAT, tm);
notice_lang(s_GlobalNoticer, u, msg, timebuf,
news[i].text);
}
}
}
}
/*************************************************************************/
/***************************** News editing ******************************/
/*************************************************************************/
/* Declared in extern.h */
int do_logonnews(User * u)
{
do_news(u, NEWS_LOGON);
return MOD_CONT;
}
/* Declared in extern.h */
int do_opernews(User * u)
{
do_news(u, NEWS_OPER);
return MOD_CONT;
}
/* Declared in extern.h */
int do_randomnews(User * u)
{
do_news(u, NEWS_RANDOM);
return MOD_CONT;
}
/*************************************************************************/
/* Main news command handling routine. */
void do_news(User * u, short type)
{
int is_servadmin = is_services_admin(u);
char *cmd = strtok(NULL, " ");
char *typename;
int *msgs;
msgs = findmsgs(type, &typename);
if (!msgs) {
alog("news: Invalid type to do_news()");
return;
}
if (!cmd)
cmd = "";
if (stricmp(cmd, "LIST") == 0) {
do_news_list(u, type, msgs);
} else if (stricmp(cmd, "ADD") == 0) {
if (is_servadmin)
do_news_add(u, type, msgs, typename);
else
notice_lang(s_OperServ, u, PERMISSION_DENIED);
} else if (stricmp(cmd, "DEL") == 0) {
if (is_servadmin)
do_news_del(u, type, msgs, typename);
else
notice_lang(s_OperServ, u, PERMISSION_DENIED);
} else {
char buf[32];
snprintf(buf, sizeof(buf), "%sNEWS", typename);
syntax_error(s_OperServ, u, buf, msgs[MSG_SYNTAX]);
}
}
/*************************************************************************/
/* Handle a {LOGON,OPER}NEWS LIST command. */
static void do_news_list(User * u, int16 type, int *msgs)
{
int i, count = 0;
char timebuf[64];
struct tm *tm;
for (i = 0; i < nnews; i++) {
if (news[i].type == type) {
if (count == 0)
notice_lang(s_OperServ, u, msgs[MSG_LIST_HEADER]);
tm = localtime(&news[i].time);
strftime_lang(timebuf, sizeof(timebuf),
u, STRFTIME_DATE_TIME_FORMAT, tm);
notice_lang(s_OperServ, u, msgs[MSG_LIST_ENTRY],
news[i].num, timebuf,
*news[i].who ? news[i].who : "<unknown>",
news[i].text);
count++;
}
}
if (count == 0)
notice_lang(s_OperServ, u, msgs[MSG_LIST_NONE]);
else {
notice_lang(s_OperServ, u, END_OF_ANY_LIST, "News");
}
}
/*************************************************************************/
/* Handle a {LOGON,OPER}NEWS ADD command. */
static void do_news_add(User * u, int16 type, int *msgs,
const char *typename)
{
char *text = strtok(NULL, "");
if (!text) {
char buf[32];
snprintf(buf, sizeof(buf), "%sNEWS", typename);
syntax_error(s_OperServ, u, buf, msgs[MSG_ADD_SYNTAX]);
} else {
int n = add_newsitem(u, text, type);
if (n < 0)
notice_lang(s_OperServ, u, msgs[MSG_ADD_FULL]);
else
notice_lang(s_OperServ, u, msgs[MSG_ADDED], n);
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
}
}
/* Actually add a news item. Return the number assigned to the item, or -1
* if the news list is full (32767 items).
*/
static int add_newsitem(User * u, const char *text, short type)
{
int i, num;
if (nnews >= 32767)
return -1;
if (nnews >= news_size) {
if (news_size < 8)
news_size = 8;
else
news_size *= 2;
news = srealloc(news, sizeof(*news) * news_size);
}
num = 0;
for (i = nnews - 1; i >= 0; i--) {
if (news[i].type == type) {
num = news[i].num;
break;
}
}
news[nnews].type = type;
news[nnews].num = num + 1;
news[nnews].text = sstrdup(text);
news[nnews].time = time(NULL);
strscpy(news[nnews].who, u->nick, NICKMAX);
nnews++;
return num + 1;
}
/*************************************************************************/
/* Handle a {LOGON,OPER}NEWS DEL command. */
static void do_news_del(User * u, int16 type, int *msgs,
const char *typename)
{
char *text = strtok(NULL, " ");
int i;
if (!text) {
char buf[32];
snprintf(buf, sizeof(buf), "%sNEWS", typename);
syntax_error(s_OperServ, u, buf, msgs[MSG_DEL_SYNTAX]);
} else {
if (stricmp(text, "ALL") != 0) {
int num = atoi(text);
if (num > 0 && del_newsitem(num, type)) {
notice_lang(s_OperServ, u, msgs[MSG_DELETED], num);
/* Reset the order - #0000397 */
for (i = 0; i < nnews; i++)
news[i].num = i + 1;
} else
notice_lang(s_OperServ, u, msgs[MSG_DEL_NOT_FOUND], num);
} else {
if (del_newsitem(0, type))
notice_lang(s_OperServ, u, msgs[MSG_DELETED_ALL]);
else
notice_lang(s_OperServ, u, msgs[MSG_DEL_NONE]);
}
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
}
}
/* Actually delete a news item. If `num' is 0, delete all news items of
* the given type. Returns the number of items deleted.
*/
static int del_newsitem(int num, short type)
{
int i;
int count = 0;
for (i = 0; i < nnews; i++) {
if (news[i].type == type && (num == 0 || news[i].num == num)) {
free(news[i].text);
count++;
nnews--;
if (i < nnews)
memcpy(news + i, news + i + 1,
sizeof(*news) * (nnews - i));
i--;
}
}
return count;
}
/*************************************************************************/
+4010
View File
File diff suppressed because it is too large Load Diff
+5099
View File
File diff suppressed because it is too large Load Diff
+268
View File
@@ -0,0 +1,268 @@
/* Main processing code for Services.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: process.c,v 1.18 2004/01/31 18:57:18 dane Exp $
*
*/
#include "services.h"
#include "messages.h"
#include "modules.h"
extern Module *mod_current_module;
extern char *mod_current_module_name;
extern User *mod_current_user;
extern int mod_current_op;
extern char *mod_current_buffer;
/*************************************************************************/
/*************************************************************************/
/* Use ignore code? */
int allow_ignore = 1;
/* People to ignore (hashed by first character of nick). */
IgnoreData *ignore[256];
/*************************************************************************/
/* add_ignore: Add someone to the ignorance list for the next `delta'
* seconds.
*/
void add_ignore(const char *nick, time_t delta)
{
IgnoreData *ign;
char who[NICKMAX];
time_t now = time(NULL);
IgnoreData **whichlist = &ignore[tolower(nick[0])];
strscpy(who, nick, NICKMAX);
for (ign = *whichlist; ign; ign = ign->next) {
if (stricmp(ign->who, who) == 0)
break;
}
if (ign) {
if (ign->time > now)
ign->time += delta;
else
ign->time = now + delta;
} else {
ign = scalloc(sizeof(*ign), 1);
strscpy(ign->who, who, sizeof(ign->who));
ign->time = now + delta;
ign->next = *whichlist;
*whichlist = ign;
}
}
/*************************************************************************/
/* get_ignore: Retrieve an ignorance record for a nick. If the nick isn't
* being ignored, return NULL and flush the record from the
* in-core list if it exists (i.e. ignore timed out).
*/
IgnoreData *get_ignore(const char *nick)
{
IgnoreData *ign, *prev;
time_t now = time(NULL);
IgnoreData **whichlist = &ignore[tolower(nick[0])];
User *u = finduser(nick);
IgnoreData **whichlist2 = NULL;
// Bleah, this doesn't work. I need a way to get the first char of u->username.
//if (u) whichlist2 = &ignore[tolower(u->username[0])];
IgnoreData **whichlistast = &ignore[42]; /* * */
IgnoreData **whichlistqst = &ignore[63]; /* ? */
int finished = 0;
for (ign = *whichlist, prev = NULL; ign; prev = ign, ign = ign->next) {
if (stricmp(ign->who, nick) == 0) {
finished = 1;
break;
}
}
if (!finished && whichlist2) {
for (ign = *whichlist2, prev = NULL; ign;
prev = ign, ign = ign->next) {
if (match_usermask(ign->who, u)) {
finished = 1;
break;
}
}
}
if (!finished) {
for (ign = *whichlistast, prev = NULL; ign;
prev = ign, ign = ign->next) {
if (match_usermask(ign->who, u)) {
finished = 1;
break;
}
}
}
if (!finished) {
for (ign = *whichlistqst, prev = NULL; ign;
prev = ign, ign = ign->next) {
if (match_usermask(ign->who, u)) {
finished = 1;
break;
}
}
}
if (ign && ign->time <= now) {
if (prev)
prev->next = ign->next;
else
*whichlist = ign->next;
free(ign);
ign = NULL;
}
return ign;
}
/*************************************************************************/
/*************************************************************************/
/* split_buf: Split a buffer into arguments and store the arguments in an
* argument vector pointed to by argv (which will be malloc'd
* as necessary); return the argument count. If colon_special
* is non-zero, then treat a parameter with a leading ':' as
* the last parameter of the line, per the IRC RFC. Destroys
* the buffer by side effect.
*/
int split_buf(char *buf, char ***argv, int colon_special)
{
int argvsize = 8;
int argc;
char *s;
*argv = scalloc(sizeof(char *) * argvsize, 1);
argc = 0;
while (*buf) {
if (argc == argvsize) {
argvsize += 8;
*argv = srealloc(*argv, sizeof(char *) * argvsize);
}
if (*buf == ':') {
(*argv)[argc++] = buf + 1;
buf = "";
} else {
s = strpbrk(buf, " ");
if (s) {
*s++ = 0;
while (*s == ' ')
s++;
} else {
s = buf + strlen(buf);
}
(*argv)[argc++] = buf;
buf = s;
}
}
return argc;
}
/*************************************************************************/
/* process: Main processing routine. Takes the string in inbuf (global
* variable) and does something appropriate with it. */
void process()
{
int retVal = 0;
Message *current = NULL;
char source[64];
char cmd[64];
char buf[512]; /* Longest legal IRC command line */
char *s;
int ac; /* Parameters for the command */
char **av;
Message *m;
/* If debugging, log the buffer */
if (debug)
alog("debug: Received: %s", inbuf);
/* First make a copy of the buffer so we have the original in case we
* crash - in that case, we want to know what we crashed on. */
strscpy(buf, inbuf, sizeof(buf));
doCleanBuffer((char *) buf);
/* Split the buffer into pieces. */
if (*buf == ':') {
s = strpbrk(buf, " ");
if (!s)
return;
*s = 0;
while (isspace(*++s));
strscpy(source, buf + 1, sizeof(source));
memmove(buf, s, strlen(s) + 1);
} else {
*source = 0;
}
if (!*buf)
return;
s = strpbrk(buf, " ");
if (s) {
*s = 0;
while (isspace(*++s));
} else
s = buf + strlen(buf);
strscpy(cmd, buf, sizeof(cmd));
ac = split_buf(s, &av, 1);
if (mod_current_buffer) {
free(mod_current_buffer);
}
if (av[1]) {
mod_current_buffer = sstrdup(av[1]);
} else {
mod_current_buffer = NULL;
}
/* Do something with the message. */
m = find_message(cmd);
if (m) {
if (m->func) {
mod_current_module_name = m->mod_name;
retVal = m->func(source, ac, av);
mod_current_module_name = NULL;
if (retVal == MOD_CONT) {
current = m->next;
while (current && current->func && retVal == MOD_CONT) {
mod_current_module_name = m->mod_name;
retVal = current->func(source, ac, av);
mod_current_module_name = NULL;
current = current->next;
}
}
}
} else {
if (debug)
alog("unknown message from server (%s)", inbuf);
}
if (mod_current_op == 1) {
alog("trying to load [%s]", mod_current_module->name);
alog("status: [%d]",
loadModule(mod_current_module, mod_current_user));
mod_current_module = NULL;
mod_current_user = NULL;
mod_current_op = 0;
} else if (mod_current_op == 2) {
alog("trying to unload [%s]", mod_current_module->name);
alog("status: [%d]",
unloadModule(mod_current_module, mod_current_user));
mod_current_module = NULL;
mod_current_user = NULL;
mod_current_op = 0;
}
/* Free argument list we created */
free(av);
}
/*************************************************************************/
+182
View File
@@ -0,0 +1,182 @@
/* Simple interfaces to various protocols.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: protocol.c,v 1.11 2003/07/20 01:15:50 dane Exp $
*
*/
#include "services.h"
/* Makes an permanent ban from all the servers. Assumes that the matching clients are killed. */
void s_akill(char *user, char *host, char *who, time_t when,
time_t expires, char *reason)
{
#if defined(IRC_BAHAMUT)
/* send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, 86400*2, who, when, reason); */
send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user,
86400 * 2, who, time(NULL), reason);
#elif defined(IRC_UNREAL)
send_cmd(NULL, "TKL + G %s %s %s %ld %ld :%s", user, host, who, time(NULL) + 86400 * 2, /* Avoids filling the akill list of servers too much */
when, reason);
#elif defined(IRC_DREAMFORGE)
send_cmd(NULL, "AKILL %s %s :%s", host, user, reason);
#elif defined(IRC_PTLINK)
send_cmd(ServerName, "GLINE %s@%s %i %s :%s", user, host, 86400 * 2,
who, reason);
#elif defined(IRC_HYBRID)
send_cmd(s_OperServ, "KLINE * %ld %s %s :%s",
(expires - (long) time(NULL)), user, host, reason);
#endif
}
/*************************************************************************/
/* Removes a permanent ban from all the servers. */
void s_rakill(char *user, char *host)
{
#if defined(IRC_PTLINK)
send_cmd(NULL, "UNGLINE %s@%s", user, host);
#elif defined(IRC_UNREAL)
send_cmd(NULL, "TKL - G %s %s %s", user, host, s_OperServ);
#elif !defined(IRC_HYBRID)
send_cmd(NULL, "RAKILL %s %s", host, user);
#endif
}
/*************************************************************************/
void s_sgline(char *mask, char *reason)
{
#ifdef IRC_BAHAMUT
/* User *u; */
send_cmd(NULL, "SGLINE %d :%s:%s", strlen(mask), mask, reason);
/* Do things properly: kill all corresponding users as this is
unfortunately not done by the IRCds :/ */
/* Breaks things currently! */
/* for (u = firstuser(); u; u = nextuser())
if (match_wild_nocase(mask, u->realname))
send_cmd(NULL, "SVSKILL %s :G-Lined: %s", u->nick, reason); */
#endif
}
/*************************************************************************/
void s_sqline(char *mask, char *reason)
{
#ifdef IRC_BAHAMUT
if (*mask == '#') {
int i;
Channel *c, *next;
char *av[3];
struct c_userlist *cu, *cunext;
send_cmd(NULL, "SQLINE %s :%s", mask, reason);
for (i = 0; i < 1024; i++) {
for (c = chanlist[i]; c; c = next) {
next = c->next;
if (!match_wild_nocase(mask, c->name))
continue;
for (cu = c->users; cu; cu = cunext) {
cunext = cu->next;
if (is_oper(cu->user))
continue;
av[0] = c->name;
av[1] = cu->user->nick;
av[2] = reason;
send_cmd(s_OperServ, "KICK %s %s :Q-Lined: %s", av[0],
av[1], av[2]);
do_kick(s_ChanServ, 3, av);
}
}
}
} else {
#endif
/* int i;
User *u, *next; */
send_cmd(NULL, "SQLINE %s :%s", mask, reason);
/* for (i = 0; i < 1024; i++) {
for (u = userlist[i]; u; u = next) {
next = u->next;
if (match_wild_nocase(mask, u->nick))
#ifdef IRC_BAHAMUT
send_cmd(NULL, "SVSKILL %s :%s", u->nick, reason);
#else
kill_user(s_OperServ, u->nick, reason);
#endif
}
} */
#ifdef IRC_BAHAMUT
}
#endif
}
/*************************************************************************/
void s_svsnoop(char *server, int set)
{
#ifndef IRC_HYBRID
#ifdef IRC_PTLINK
send_cmd(NULL, "SVSADMIN %s :%s", server, set ? "noopers" : "rehash");
#else
send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
#endif
#endif
}
/*************************************************************************/
void s_szline(char *mask, char *reason)
{
#ifdef IRC_BAHAMUT
send_cmd(NULL, "SZLINE %s :%s", mask, reason);
#endif
}
/*************************************************************************/
void s_unsgline(char *mask)
{
#ifdef IRC_BAHAMUT
send_cmd(NULL, "UNSGLINE 0 :%s", mask);
#endif
}
/*************************************************************************/
void s_unsqline(char *mask)
{
#ifdef IRC_BAHAMUT
send_cmd(NULL, "UNSQLINE 0 %s", mask);
#else
send_cmd(NULL, "UNSQLINE %s", mask);
#endif
}
/*************************************************************************/
void s_unszline(char *mask)
{
#ifdef IRC_BAHAMUT
send_cmd(NULL, "UNSZLINE 0 %s", mask);
#endif
}
+793
View File
@@ -0,0 +1,793 @@
/* Proxy detector.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: proxy.c,v 1.11 2004/02/14 21:22:55 dane Exp $
*
*/
#include "services.h"
#include "pseudo.h"
#include <fcntl.h>
/* Hashed list of HostCache; threads must not use it! */
HostCache *hcache[1024];
/*************************************************************************/
/* Equivalent to inet_ntoa */
void ntoa(struct in_addr addr, char *ipaddr, int len)
{
unsigned char *bytes = (unsigned char *) &addr.s_addr;
snprintf(ipaddr, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2],
bytes[3]);
}
/*************************************************************************/
#ifdef USE_THREADS
/*************************************************************************/
#define HASH(host) ((tolower((host)[0])&31)<<5 | (tolower((host)[1])&31))
/* Proxy queue; access controlled by queuemut */
SList pxqueue;
pthread_mutex_t queuemut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t queuecond = PTHREAD_COND_INITIALIZER;
#if !defined(HAS_NICKIP) && !defined(HAVE_GETHOSTBYNAME_R6) && !defined(HAVE_GETHOSTBYNAME_R5) && !defined(HAVE_GETHOSTBYNAME_R3)
pthread_mutex_t resmut = PTHREAD_MUTEX_INITIALIZER;
#endif
static uint32 aton(char *ipaddr);
static void proxy_akill(char *host);
static HostCache *proxy_cache_add(char *host);
static void proxy_cache_del(HostCache * hc);
static HostCache *proxy_cache_find(char *host);
static int proxy_connect(unsigned long ip, unsigned short port);
static void proxy_queue_cleanup_unlock(void *arg);
static void proxy_queue_lock(void);
static void proxy_queue_signal(void);
static void proxy_queue_unlock(void);
static void proxy_queue_wait(void);
static int proxy_read(int s, char *buf, size_t buflen);
#ifndef HAS_NICKIP
static uint32 proxy_resolve(char *host);
#endif
static int proxy_scan(uint32 ip);
static void *proxy_thread_main(void *arg);
/*************************************************************************/
/* Equivalent to inet_addr */
static uint32 aton(char *ipaddr)
{
int i;
long lv;
char *endptr;
uint32 res;
unsigned char *bytes = (unsigned char *) &res;
for (i = 0; i < 4; i++) {
if (!*ipaddr)
return INADDR_NONE;
lv = strtol(ipaddr, &endptr, 10);
if (lv < 0 || lv > 255 || (*endptr != 0 && *endptr != '.'))
return INADDR_NONE;
bytes[i] = (unsigned char) lv;
ipaddr = (!*endptr ? endptr : ++endptr);
}
if (*endptr)
return INADDR_NONE;
return res;
}
/*************************************************************************/
void get_proxy_stats(long *nrec, long *memuse)
{
int i;
long mem = 0, count = 0;
HostCache *hc;
for (i = 0; i < 1024; i++) {
for (hc = hcache[i]; hc; hc = hc->next) {
count += 1;
mem += sizeof(HostCache);
mem += strlen(hc->host) + 1;
}
}
*nrec = count;
*memuse = mem;
}
/*************************************************************************/
/* Akills the given host, and issues a GLOBOPS if configured so */
static void proxy_akill(char *host)
{
s_akill("*", host, s_OperServ, time(NULL),
time(NULL) + (ProxyExpire ? ProxyExpire : 86400 * 2),
ProxyAkillReason);
if (WallProxy)
wallops(s_OperServ, "Insecure proxy \2%s\2 has been AKILLed.",
host);
}
/*************************************************************************/
/* Adds a cache entry after having it allocated */
static HostCache *proxy_cache_add(char *host)
{
HostCache *hc;
int index = HASH(host);
hc = scalloc(1, sizeof(HostCache));
hc->host = sstrdup(host);
hc->used = time(NULL);
hc->prev = NULL;
hc->next = hcache[index];
if (hc->next)
hc->next->prev = hc;
hcache[index] = hc;
if (debug)
alog("debug: Added %s to host cache", host);
return hc;
}
/*************************************************************************/
/* Deletes and frees a proxy cache entry */
static void proxy_cache_del(HostCache * hc)
{
/* Just to be sure */
if (hc->status < 0)
return;
if (debug)
alog("debug: Deleting %s from host cache", hc->host);
if (hc->status > HC_NORMAL)
s_rakill("*", hc->host);
if (hc->next)
hc->next->prev = hc->prev;
if (hc->prev)
hc->prev->next = hc->next;
else
hcache[HASH(hc->host)] = hc->next;
if (hc->host)
free(hc->host);
free(hc);
}
/*************************************************************************/
/* Finds a proxy cache entry */
static HostCache *proxy_cache_find(char *host)
{
HostCache *hc;
for (hc = hcache[HASH(host)]; hc; hc = hc->next) {
if (stricmp(hc->host, host) == 0)
return hc;
}
return NULL;
}
/*************************************************************************/
/* Checks whether the specified host is in the cache.
* If so:
* * if it's a proxy, take the appropriate actions, including killing nick
* * if it's not a proxy, do nothing
* If not:
* * add the host to the cache
* * add the host to the queue
* * send a signal to a waiting thread (if any)
*
* Returns 0 if nick is to be added to internal list, 1 else
*/
int proxy_check(char *nick, char *host, uint32 ip)
{
int i;
char **message;
HostCache *hc;
if ((hc = proxy_cache_find(host))) {
hc->used = time(NULL);
if (hc->status <= HC_NORMAL)
return 0;
proxy_akill(host);
return 0;
}
for (message = ProxyMessage, i = 0; i < 8 && *message && **message;
message++, i++)
notice(s_GlobalNoticer, nick, *message);
hc = proxy_cache_add(host);
#ifdef HAS_NICKIP
hc->ip = htonl(ip);
#endif
hc->status = HC_QUEUED;
proxy_queue_lock();
slist_add(&pxqueue, hc);
if (debug)
alog("debug: Added %s to proxy queue", hc->host);
proxy_queue_signal();
proxy_queue_unlock();
return 0;
}
/*************************************************************************/
/* Initiates a non-blocking connection */
static int proxy_connect(unsigned long ip, unsigned short port)
{
struct sockaddr_in sin;
int s;
fd_set fds;
struct timeval tv;
int error, errlen;
if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1)
return -1;
if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
close(s);
return -1;
}
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip;
sin.sin_port = htons(port);
if (connect(s, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) ==
-1 && errno != EINPROGRESS) {
close(s);
return -1;
}
FD_ZERO(&fds);
FD_SET(s, &fds);
tv.tv_sec = ProxyTimeout;
tv.tv_usec = 0;
if (select(s + 1, NULL, &fds, NULL, &tv) <= 0) {
close(s);
return -1;
}
errlen = sizeof(int);
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errlen) == -1
|| error != 0) {
close(s);
return -1;
}
return s;
}
/*************************************************************************/
/* Deletes expired cache entries */
void proxy_expire()
{
int i;
HostCache *hc, *next;
time_t t = time(NULL);
for (i = 0; i < 1024; i++) {
for (hc = hcache[i]; hc; hc = next) {
next = hc->next;
/* Don't expire not scanned yet entries */
if (hc->status < HC_NORMAL)
continue;
if (hc->status == HC_NORMAL
&& t - hc->used >= ProxyCacheExpire) {
proxy_cache_del(hc);
continue;
}
if (ProxyExpire && hc->status > HC_NORMAL
&& t - hc->used >= ProxyExpire) {
alog("proxy: Expiring proxy %s", hc->host);
proxy_cache_del(hc);
}
}
}
}
/*************************************************************************/
/* Initializes the proxy detector. Returns 1 on success, 0 on error. */
int proxy_init(void)
{
int i;
pthread_t th;
slist_init(&pxqueue);
for (i = 1; i <= ProxyThreads; i++) {
if (pthread_create(&th, NULL, proxy_thread_main, NULL))
return 0;
if (pthread_detach(th))
return 0;
if (debug)
alog("debug: Creating proxy thread %ld (%d of %d)", (long) th,
i, ProxyThreads);
}
alog("Proxy detector initialized");
return 1;
}
/*************************************************************************/
static void proxy_queue_cleanup_unlock(void *arg)
{
proxy_queue_unlock();
}
/*************************************************************************/
static void proxy_queue_lock(void)
{
if (debug)
alog("debug: Thread %ld: Locking proxy queue mutex",
(long) pthread_self());
pthread_mutex_lock(&queuemut);
}
/*************************************************************************/
static void proxy_queue_signal(void)
{
if (debug)
alog("debug: Thread %ld: Signaling proxy queue condition",
(long) pthread_self());
pthread_cond_signal(&queuecond);
}
/*************************************************************************/
static void proxy_queue_unlock(void)
{
if (debug)
alog("debug: Thread %ld: Unlocking proxy queue mutex",
(long) pthread_self());
pthread_mutex_unlock(&queuemut);
}
/*************************************************************************/
static void proxy_queue_wait(void)
{
if (debug)
alog("debug: Thread %ld: waiting proxy queue condition",
(long) pthread_self());
pthread_cond_wait(&queuecond, &queuemut);
}
/*************************************************************************/
/* Reads from the socket, in a non-blocking manner */
static int proxy_read(int s, char *buf, size_t buflen)
{
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(s, &fds);
tv.tv_sec = ProxyTimeout;
tv.tv_usec = 0;
if (select(s + 1, &fds, NULL, NULL, &tv) <= 0)
return -1;
return recv(s, buf, buflen, 0);
}
/*************************************************************************/
/* Resolves hostnames in a thread safe manner */
#ifndef HAS_NICKIP
static uint32 proxy_resolve(char *host)
{
struct hostent *hentp = NULL;
uint32 ip = INADDR_NONE;
#if defined(HAVE_GETHOSTBYNAME_R6)
struct hostent hent;
char hbuf[8192];
int herrno;
if (gethostbyname_r(host, &hent, hbuf, sizeof(hbuf), &hentp, &herrno) <
0)
hentp = NULL;
#elif defined(HAVE_GETHOSTBYNAME_R5)
struct hostent hent char hbuf[8192];
int herrno;
hentp = gethostbyname_r(host, &hent, hbuf, sizeof(hbuf), &herrno);
#elif defined(HAVE_GETHOSTBYNAME_R3)
struct hostent hent;
struct hostent_data data;
hentp = gethostbyname_r(host, &hent, &data);
#else
/* Make it safe that way */
pthread_mutex_lock(&resmut);
hentp = gethostbyname(host);
#endif
if (hentp) {
memcpy(&ip, hentp->h_addr, sizeof(hentp->h_length));
if (debug) {
char ipbuf[16];
struct in_addr addr;
addr.s_addr = ip;
ntoa(addr, ipbuf, sizeof(ipbuf));
alog("debug: Thread %ld: resolved %s to %s",
(long) pthread_self(), host, ipbuf);
}
}
#if !defined(HAVE_GETHOSTBYNAME_R6) && !defined(HAVE_GETHOSTBYNAME_R5) && !defined(HAVE_GETHOSTBYNAME_R3)
pthread_mutex_unlock(&resmut);
#endif
return ip;
}
#endif
/*************************************************************************/
/* Scans the given host for proxy */
static int proxy_scan(uint32 ip)
{
int s; /* Socket */
int i;
if (ip == INADDR_NONE)
return HC_NORMAL;
/* Scan for SOCKS (4/5) */
for (i = 0; i < 2; i++) {
if ((s = proxy_connect(ip, 1080)) == -1)
break;
if (ProxyCheckSocks4 && i == 0) {
/* SOCKS4 */
char buf[9];
uint32 sip;
sip = aton(ProxyTestServer);
sip = htonl(sip);
buf[0] = 4;
buf[1] = 1;
buf[2] = (((unsigned short) ProxyTestPort) >> 8) & 0xFF;
buf[3] = ((unsigned short) ProxyTestPort) & 0xFF;
buf[4] = (sip >> 24) & 0xFF;
buf[5] = (sip >> 16) & 0xFF;
buf[6] = (sip >> 8) & 0xFF;
buf[7] = sip & 0xFF;
buf[8] = 0;
if (send(s, buf, 9, 0) != 9) {
close(s);
return HC_NORMAL;
}
if (proxy_read(s, buf, 2) != 2) {
close(s);
continue;
}
if (buf[1] == 90) {
close(s);
return HC_SOCKS4;
}
} else if (ProxyCheckSocks5 && i == 1) {
/* SOCKS5 */
char buf[10];
uint32 sip;
if (send(s, "\5\1\0", 3, 0) != 3) {
close(s);
continue;
}
memset(buf, 0, sizeof(buf));
if (proxy_read(s, buf, 2) != 2) {
close(s);
continue;
}
if (buf[0] != 5 || buf[1] != 0) {
close(s);
continue;
}
sip = aton(ProxyTestServer);
sip = htonl(sip);
buf[0] = 5;
buf[1] = 1;
buf[2] = 0;
buf[3] = 1;
buf[4] = (sip >> 24) & 0xFF;
buf[5] = (sip >> 16) & 0xFF;
buf[6] = (sip >> 8) & 0xFF;
buf[7] = sip & 0xFF;
buf[8] = (((unsigned short) ProxyTestPort) >> 8) & 0xFF;
buf[9] = ((unsigned short) ProxyTestPort) & 0xFF;
if (send(s, buf, 10, 0) != 10) {
close(s);
continue;
}
memset(buf, 0, sizeof(buf));
if (proxy_read(s, buf, 2) != 2) {
close(s);
continue;
}
if (buf[0] == 5 && buf[1] == 0) {
close(s);
return HC_SOCKS5;
}
}
close(s);
}
/* Scan for HTTP proxy */
for (i = 0; i < 3; i++) {
if ((i ==
0 ? ProxyCheckHTTP2 : (i ==
1 ? ProxyCheckHTTP1 : ProxyCheckHTTP3))
&& (s =
proxy_connect(ip,
(i == 0 ? 8080 : (i == 1 ? 3128 : 80)))) !=
-1) {
int bread;
char buf[64];
snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\n\n",
ProxyTestServer, ProxyTestPort);
if (send(s, buf, strlen(buf), 0) == strlen(buf)) {
if ((bread = proxy_read(s, buf, 15)) >= 12) {
buf[bread] = 0;
if (!strnicmp(buf, "HTTP/1.0 200", 12) || !stricmp(buf, "HTTP/1.1 200 Co")) { /* Apache may return 200 OK
even if it's not processing
the CONNECT request. :/ */
close(s);
return HC_HTTP;
}
}
}
close(s);
}
}
/* Scan for Wingate */
if (ProxyCheckWingate && (s = proxy_connect(ip, 23)) != -1) {
char buf[9];
if (proxy_read(s, buf, 8) == 8) {
buf[8] = '\0';
if (!stricmp(buf, "Wingate>") || !stricmp(buf, "Too many")) {
close(s);
return HC_WINGATE;
}
}
close(s);
}
return HC_NORMAL;
}
/*************************************************************************/
/* Proxy detector threads entry point */
static void *proxy_thread_main(void *arg)
{
while (1) {
pthread_cleanup_push(&proxy_queue_cleanup_unlock, NULL);
proxy_queue_lock();
proxy_queue_wait();
pthread_cleanup_pop(1);
/* We loop until there is no more host to check in the list */
while (1) {
HostCache *hc = NULL;
int status;
pthread_cleanup_push(&proxy_queue_cleanup_unlock, NULL);
proxy_queue_lock();
if (pxqueue.count > 0) {
hc = pxqueue.list[0];
hc->status = HC_PROGRESS;
slist_delete(&pxqueue, 0);
}
pthread_cleanup_pop(1);
if (!hc)
break;
if (debug) {
if (hc->ip) {
char ipbuf[16];
struct in_addr in;
in.s_addr = hc->ip;
ntoa(in, ipbuf, sizeof(ipbuf));
alog("debug: Scanning host %s [%s] for proxy",
hc->host, ipbuf);
} else {
alog("debug: Scanning host %s for proxy", hc->host);
}
}
#ifndef HAS_NICKIP
/* Test if it's an IP, and if not try to resolve the hostname */
if ((hc->ip = aton(hc->host)) == INADDR_NONE)
hc->ip = proxy_resolve(hc->host);
#endif
status = proxy_scan(hc->ip);
if (debug) {
char ipbuf[16];
struct in_addr in;
in.s_addr = hc->ip;
ntoa(in, ipbuf, sizeof(ipbuf));
alog("debug: Scan for %s [%s] complete, result: %d",
hc->host, ipbuf, status);
}
if (status > HC_NORMAL)
proxy_akill(hc->host);
hc->status = status;
}
}
return NULL;
}
/*************************************************************************/
#endif
/*************************************************************************/
/* OperServ CACHE */
int do_cache(User * u)
{
#ifdef USE_THREADS
char *cmd = strtok(NULL, " ");
char *pattern = strtok(NULL, " ");
if (!ProxyDetect) {
notice_lang(s_OperServ, u, OPER_CACHE_DISABLED);
return MOD_CONT;
}
if (!cmd || !pattern) {
syntax_error(s_OperServ, u, "CACHE", OPER_CACHE_SYNTAX);
} else if (!stricmp(cmd, "DEL")) {
HostCache *hc;
if (!(hc = proxy_cache_find(pattern))) {
notice_lang(s_OperServ, u, OPER_CACHE_NOT_FOUND, pattern);
return MOD_CONT;
}
proxy_cache_del(hc);
notice_lang(s_OperServ, u, OPER_CACHE_REMOVED, pattern);
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
} else if (!stricmp(cmd, "LIST")) {
char *option = strtok(NULL, " ");
int i, restrict = 0, count = 0, total = 0;
HostCache *hc;
static int statusdesc[7] = {
OPER_CACHE_QUEUED,
OPER_CACHE_PROGRESS,
OPER_CACHE_NORMAL,
OPER_CACHE_WINGATE,
OPER_CACHE_SOCKS4,
OPER_CACHE_SOCKS5,
OPER_CACHE_HTTP
};
if (option && !stricmp(option, "QUEUED"))
restrict = 1;
else if (option && !stricmp(option, "ALL"))
restrict = 2;
notice_lang(s_OperServ, u, OPER_CACHE_HEADER);
for (i = 0; i < 1024; i++) {
for (hc = hcache[i]; hc; hc = hc->next) {
if (!match_wild_nocase(pattern, hc->host))
continue;
if ((restrict == 0 && hc->status <= HC_NORMAL)
|| (restrict == 1 && hc->status >= HC_NORMAL))
continue;
total++;
if (count >= ProxyMax)
continue;
notice_lang(s_OperServ, u, OPER_CACHE_LIST, hc->host,
getstring(u->na, statusdesc[hc->status + 2]));
count++;
}
}
notice_lang(s_OperServ, u, OPER_CACHE_FOOTER, count, total);
} else {
syntax_error(s_OperServ, u, "CACHE", OPER_CACHE_SYNTAX);
}
#else
notice_lang(s_OperServ, u, OPER_CACHE_DISABLED);
#endif
return MOD_CONT;
}
/*************************************************************************/
+20
View File
@@ -0,0 +1,20 @@
/* Include extra includes needed by most/all pseudo-clients.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: pseudo.h,v 1.4 2003/07/20 01:15:50 dane Exp $
*
*/
#include "commands.h"
#include "language.h"
#include "timeout.h"
#include "encrypt.h"
#include "datafiles.h"
#include "slist.h"
+347
View File
@@ -0,0 +1,347 @@
/* RDB functions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: rdb.c,v 1.11 2003/08/04 01:09:43 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
int rdb_init()
{
#ifdef USE_MYSQL
return db_mysql_init();
#endif
}
/*************************************************************************/
int rdb_open()
{
#ifdef USE_MYSQL
return db_mysql_open();
#endif
}
/*************************************************************************/
int rdb_close()
{
#ifdef USE_MYSQL
return db_mysql_close();
#endif
}
/*************************************************************************/
int rdb_tag_table(char *table)
{
static char buf[1024];
#ifdef USE_MYSQL
snprintf(buf, sizeof(buf), "UPDATE %s SET active='0'", table);
return db_mysql_query(buf);
#endif
return 0;
}
/*************************************************************************/
int rdb_clear_table(char *table)
{
static char buf[1024];
#ifdef USE_MYSQL
snprintf(buf, sizeof(buf), "TRUNCATE TABLE %s", table);
return db_mysql_query(buf);
#endif
return 0;
}
/*************************************************************************/
int rdb_scrub_table(char *table, char *clause)
{
static char buf[1024];
#ifdef USE_MYSQL
snprintf(buf, sizeof(buf), "DELETE FROM %s WHERE %s", table, clause);
return db_mysql_query(buf);
#endif
return 0;
}
/*************************************************************************/
int rdb_direct_query(char *query)
{
#ifdef USE_MYSQL
alog("Direct Query: %s", query);
return db_mysql_query(query);
#endif
return 0;
}
/*************************************************************************/
/* I still don't really like doing it this way, it should really be done
* inside mysql.c and not here. So I'll revisit this later
*/
int rdb_ns_set_display(char *newnick, char *oldnick)
{
static char buf[1024];
#ifdef USE_MYSQL
/* Change the display on NS_CORE */
snprintf(buf, sizeof(buf),
"UPDATE anope_ns_core SET display='%s' WHERE display='%s'",
newnick, oldnick);
db_mysql_query(buf);
/* Change the display on NS_ALIAS for all grouped nicks */
snprintf(buf, sizeof(buf),
"UPDATE anope_ns_alias SET display='%s' WHERE display='%s'",
newnick, oldnick);
db_mysql_query(buf);
/* Change the display on ChanServ ACCESS list */
snprintf(buf, sizeof(buf),
"UPDATE anope_cs_access SET display='%s' WHERE display='%s'",
newnick, oldnick);
db_mysql_query(buf);
/* Change the display on ChanServ AKICK list */
snprintf(buf, sizeof(buf),
"UPDATE anope_cs_access SET creator='%s' WHERE creator='%s'",
newnick, oldnick);
db_mysql_query(buf);
/* Change the display on MemoServ sent memos */
snprintf(buf, sizeof(buf),
"UPDATE anope_ms_info SET sender='%s' WHERE sender='%s'",
newnick, oldnick);
db_mysql_query(buf);
/* Change the display on MemoServ received memos */
snprintf(buf, sizeof(buf),
"UPDATE anope_ms_info SET receiver='%s' WHERE receiver='%s'",
newnick, oldnick);
db_mysql_query(buf);
/* Need to do bwords and akills */
#endif
return 0;
}
/*************************************************************************/
int rdb_cs_deluser(char *nick)
{
static char buf[1024];
#ifdef USE_MYSQL
snprintf(buf, sizeof(buf),
"UPDATE anope_cs_info SET successor=NULL WHERE successor='%s'",
nick);
db_mysql_query(buf);
snprintf(buf, sizeof(buf), "display='%s'", nick);
rdb_scrub_table("anope_cs_access", buf);
snprintf(buf, sizeof(buf), "creator='%s'", nick);
rdb_scrub_table("anope_cs_akicks", buf);
return 1;
#endif
return 0;
}
/*************************************************************************/
int rdb_cs_delchan(ChannelInfo * ci)
{
static char buf[1024];
char *channel = ci->name;
#ifdef USE_MYSQL
snprintf(buf, sizeof(buf),
"UPDATE anope_cs_info SET successor=NULL WHERE name='%s'",
channel);
db_mysql_query(buf);
snprintf(buf, sizeof(buf), "name='%s'", channel);
rdb_scrub_table("anope_cs_info", buf);
snprintf(buf, sizeof(buf), "receiver='%s' AND serv='CHAN'", channel);
rdb_scrub_table("anope_ms_info", buf);
snprintf(buf, sizeof(buf), "channel='%s'", channel);
rdb_scrub_table("anope_cs_access", buf);
rdb_scrub_table("anope_cs_akicks", buf);
rdb_scrub_table("anope_cs_levels", buf);
rdb_scrub_table("anope_cs_badwords", buf);
if (ci->founder) {
snprintf(buf, sizeof(buf),
"update anope_ns_core set channelcount=channelcount-1 where display='%s'",
ci->founder->display);
db_mysql_query(buf);
}
return 1;
#endif
return 0;
}
/*************************************************************************/
int rdb_cs_set_founder(char *channel, char *founder)
{
static char buf[1024];
#ifdef USE_MYSQL
snprintf(buf, sizeof(buf),
"UPDATE anope_cs_info SET founder='%s', successor=NULL WHERE name='%s'",
founder, channel);
db_mysql_query(buf);
snprintf(buf, sizeof(buf),
"UPDATE anope_ns_core SET channelcount=channelcount+1 WHERE display='%s'",
founder);
db_mysql_query(buf);
/* Do i need to scrub the access list for this channel ? */
snprintf(buf, sizeof(buf), "display='%s' AND channel='%s'", founder,
channel);
rdb_scrub_table("anope_cs_access", buf);
return 1;
#endif
return 0;
}
/*************************************************************************/
void rdb_save_ns_core(NickCore * nc)
{
#ifdef USE_MYSQL
db_mysql_save_ns_core(nc);
#endif
}
/*************************************************************************/
void rdb_save_ns_alias(NickAlias * na)
{
#ifdef USE_MYSQL
db_mysql_save_ns_alias(na);
#endif
}
/*************************************************************************/
void rdb_save_ns_req(NickRequest * nr)
{
#ifdef USE_MYSQL
db_mysql_save_ns_req(nr);
#endif
}
/*************************************************************************/
void rdb_save_cs_info(ChannelInfo * ci)
{
#ifdef USE_MYSQL
db_mysql_save_cs_info(ci);
#endif
}
/*************************************************************************/
void rdb_save_bs_core(BotInfo * bi)
{
#ifdef USE_MYSQL
db_mysql_save_bs_core(bi);
#endif
}
/*************************************************************************/
void rdb_save_hs_core(HostCore * hc)
{
#ifdef USE_MYSQL
db_mysql_save_hs_core(hc);
#endif
}
/*************************************************************************/
void rdb_save_os_db(unsigned int maxucnt, unsigned int maxutime,
SList * ak, SList * sgl, SList * sql, SList * szl,
HostCache * hc)
{
#ifdef USE_MYSQL
db_mysql_save_os_db(maxusercnt, maxusertime, ak, sgl, sql, szl, hc);
#endif
}
/*************************************************************************/
void rdb_save_news(NewsItem * ni)
{
#ifdef USE_MYSQL
db_mysql_save_news(ni);
#endif
}
/*************************************************************************/
void rdb_save_exceptions(Exception * e)
{
#ifdef USE_MYSQL
db_mysql_save_exceptions(e);
#endif
}
+202
View File
@@ -0,0 +1,202 @@
/* Routines for sending stuff to the network.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: send.c,v 1.11 2004/01/18 05:10:47 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
/* Send a command to the server. The two forms here are like
* printf()/vprintf() and friends. */
void send_cmd(const char *source, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsend_cmd(source, fmt, args);
va_end(args);
}
void vsend_cmd(const char *source, const char *fmt, va_list args)
{
char buf[BUFSIZE];
vsnprintf(buf, sizeof(buf), fmt, args);
if (source) {
sockprintf(servsock, ":%s %s\r\n", source, buf);
if (debug)
alog("debug: Sent: :%s %s", source, buf);
} else {
sockprintf(servsock, "%s\r\n", buf);
if (debug)
alog("debug: Sent: %s", buf);
}
}
/*************************************************************************/
/* Send out a WALLOPS (a GLOBOPS on ircd.dal). */
void wallops(const char *source, const char *fmt, ...)
{
va_list args;
char buf[BUFSIZE];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
#ifdef IRC_HYBRID
send_cmd(source ? source : ServerName, "WALLOPS :%s", buf);
#else
send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
#endif
}
/*************************************************************************/
/* Send a NOTICE from the given source to the given nick. */
void notice(const char *source, const char *dest, const char *fmt, ...)
{
va_list args;
char buf[BUFSIZE];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
send_cmd(source, "%s %s :%s", (UsePrivmsg ? "PRIVMSG" : "NOTICE"),
dest, buf);
}
/*************************************************************************/
void notice_user(const char *source, User * u, const char *fmt, ...)
{
va_list args;
char buf[BUFSIZE];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
send_cmd(source, "%s %s :%s",
(UsePrivmsg && (!u->na || (u->na->nc->flags & NI_MSG)) ?
"PRIVMSG" : "NOTICE"), u->nick, buf);
}
/*************************************************************************/
/* Send a NULL-terminated array of text as NOTICEs. */
void notice_list(const char *source, const char *dest, const char **text)
{
while (*text) {
/* Have to kludge around an ircII bug here: if a notice includes
* no text, it is ignored, so we replace blank lines by lines
* with a single space.
*/
if (**text)
notice(source, dest, *text);
else
notice(source, dest, " ");
text++;
}
}
/*************************************************************************/
/* Send a message in the user's selected language to the user using NOTICE. */
void notice_lang(const char *source, User * dest, int message, ...)
{
va_list args;
char buf[4096]; /* because messages can be really big */
char *s, *t;
const char *fmt;
if (!dest)
return;
va_start(args, message);
fmt = getstring(dest->na, message);
if (!fmt)
return;
memset(buf, 0, 4096);
vsnprintf(buf, sizeof(buf), fmt, args);
s = buf;
while (*s) {
t = s;
s += strcspn(s, "\n");
if (*s)
*s++ = 0;
send_cmd(source, "%s %s :%s", (UsePrivmsg
&& (!dest->na || (dest->na->nc->
flags &
NI_MSG)) ?
"PRIVMSG" : "NOTICE"),
dest->nick, *t ? t : " ");
}
}
/*************************************************************************/
/* Like notice_lang(), but replace %S by the source. This is an ugly hack
* to simplify letting help messages display the name of the pseudoclient
* that's sending them.
*/
void notice_help(const char *source, User * dest, int message, ...)
{
va_list args;
char buf[4096], buf2[4096], outbuf[BUFSIZE];
char *s, *t;
const char *fmt;
if (!dest)
return;
va_start(args, message);
fmt = getstring(dest->na, message);
if (!fmt)
return;
/* Some sprintf()'s eat %S or turn it into just S, so change all %S's
* into \1\1... we assume this doesn't occur anywhere else in the
* string. */
strscpy(buf2, fmt, sizeof(buf2));
strnrepl(buf2, sizeof(buf2), "%S", "\1\1");
vsnprintf(buf, sizeof(buf), buf2, args);
s = buf;
while (*s) {
t = s;
s += strcspn(s, "\n");
if (*s)
*s++ = 0;
strscpy(outbuf, t, sizeof(outbuf));
strnrepl(outbuf, sizeof(outbuf), "\1\1", source);
send_cmd(source, "%s %s :%s",
(UsePrivmsg
&& (!dest->na
|| (dest->na->nc->
flags & NI_MSG)) ? "PRIVMSG" : "NOTICE"),
dest->nick, *outbuf ? outbuf : " ");
}
}
/*************************************************************************/
/* Send a PRIVMSG from the given source to the given nick. */
void privmsg(const char *source, const char *dest, const char *fmt, ...)
{
va_list args;
char buf[BUFSIZE];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
send_cmd(source, "PRIVMSG %s :%s", dest, buf);
}
/*************************************************************************/
+1198
View File
File diff suppressed because it is too large Load Diff
+834
View File
@@ -0,0 +1,834 @@
/* Session Limiting functions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: sessions.c,v 1.10 2003/07/20 01:15:50 dane Exp $
*
*/
#include "services.h"
#include "pseudo.h"
/*************************************************************************/
/* SESSION LIMITING
*
* The basic idea of session limiting is to prevent one host from having more
* than a specified number of sessions (client connections/clones) on the
* network at any one time. To do this we have a list of sessions and
* exceptions. Each session structure records information about a single host,
* including how many clients (sessions) that host has on the network. When a
* host reaches it's session limit, no more clients from that host will be
* allowed to connect.
*
* When a client connects to the network, we check to see if their host has
* reached the default session limit per host, and thus whether it is allowed
* any more. If it has reached the limit, we kill the connecting client; all
* the other clients are left alone. Otherwise we simply increment the counter
* within the session structure. When a client disconnects, we decrement the
* counter. When the counter reaches 0, we free the session.
*
* Exceptions allow one to specify custom session limits for a specific host
* or a range thereof. The first exception that the host matches is the one
* used.
*
* "Session Limiting" is likely to slow down services when there are frequent
* client connects and disconnects. The size of the exception list can also
* play a large role in this performance decrease. It is therefore recommened
* that you keep the number of exceptions to a minimum. A very simple hashing
* method is currently used to store the list of sessions. I'm sure there is
* room for improvement and optimisation of this, along with the storage of
* exceptions. Comments and suggestions are more than welcome!
*
* -TheShadow (02 April 1999)
*/
/*************************************************************************/
typedef struct session_ Session;
struct session_ {
Session *prev, *next;
char *host;
int count; /* Number of clients with this host */
int hits; /* Number of subsequent kills for a host */
};
/* I'm sure there is a better way to hash the list of hosts for which we are
* storing session information. This should be sufficient for the mean time.
* -TheShadow */
#define HASH(host) (((host)[0]&31)<<5 | ((host)[1]&31))
static Session *sessionlist[1024];
static int32 nsessions = 0;
static Exception *exceptions = NULL;
static int16 nexceptions = 0;
/*************************************************************************/
static Session *findsession(const char *host);
static Exception *find_host_exception(const char *host);
static int exception_add(const char *mask, const int limit,
const char *reason, const char *who,
const time_t expires);
/*************************************************************************/
/****************************** Statistics *******************************/
/*************************************************************************/
void get_session_stats(long *nrec, long *memuse)
{
Session *session;
long mem;
int i;
mem = sizeof(Session) * nsessions;
for (i = 0; i < 1024; i++) {
for (session = sessionlist[i]; session; session = session->next) {
mem += strlen(session->host) + 1;
}
}
*nrec = nsessions;
*memuse = mem;
}
void get_exception_stats(long *nrec, long *memuse)
{
long mem;
int i;
mem = sizeof(Exception) * nexceptions;
for (i = 0; i < nexceptions; i++) {
mem += strlen(exceptions[i].mask) + 1;
mem += strlen(exceptions[i].reason) + 1;
}
*nrec = nexceptions;
*memuse = mem;
}
/*************************************************************************/
/************************* Session List Display **************************/
/*************************************************************************/
/* Syntax: SESSION LIST threshold
* Lists all sessions with atleast threshold clients.
* The threshold value must be greater than 1. This is to prevent
* accidental listing of the large number of single client sessions.
*
* Syntax: SESSION VIEW host
* Displays detailed session information about the supplied host.
*/
int do_session(User * u)
{
Session *session;
Exception *exception;
char *cmd = strtok(NULL, " ");
char *param1 = strtok(NULL, " ");
int mincount;
int i;
if (!LimitSessions) {
notice_lang(s_OperServ, u, OPER_SESSION_DISABLED);
return MOD_CONT;
}
if (!cmd)
cmd = "";
if (stricmp(cmd, "LIST") == 0) {
if (!param1) {
syntax_error(s_OperServ, u, "SESSION",
OPER_SESSION_LIST_SYNTAX);
} else if ((mincount = atoi(param1)) <= 1) {
notice_lang(s_OperServ, u, OPER_SESSION_INVALID_THRESHOLD);
} else {
notice_lang(s_OperServ, u, OPER_SESSION_LIST_HEADER, mincount);
notice_lang(s_OperServ, u, OPER_SESSION_LIST_COLHEAD);
for (i = 0; i < 1024; i++) {
for (session = sessionlist[i]; session;
session = session->next) {
if (session->count >= mincount)
notice_lang(s_OperServ, u,
OPER_SESSION_LIST_FORMAT,
session->count, session->host);
}
}
}
} else if (stricmp(cmd, "VIEW") == 0) {
if (!param1) {
syntax_error(s_OperServ, u, "SESSION",
OPER_SESSION_VIEW_SYNTAX);
} else {
session = findsession(param1);
if (!session) {
notice_lang(s_OperServ, u, OPER_SESSION_NOT_FOUND, param1);
} else {
exception = find_host_exception(param1);
notice_lang(s_OperServ, u, OPER_SESSION_VIEW_FORMAT,
param1, session->count,
exception ? exception->
limit : DefSessionLimit);
}
}
} else {
syntax_error(s_OperServ, u, "SESSION", OPER_SESSION_SYNTAX);
}
return MOD_CONT;
}
/*************************************************************************/
/********************* Internal Session Functions ************************/
/*************************************************************************/
static Session *findsession(const char *host)
{
Session *session;
int i;
if (!host)
return NULL;
for (i = 0; i < 1024; i++) {
for (session = sessionlist[i]; session; session = session->next) {
if (stricmp(host, session->host) == 0) {
return session;
}
}
}
return NULL;
}
/* Attempt to add a host to the session list. If the addition of the new host
* causes the the session limit to be exceeded, kill the connecting user.
* Returns 1 if the host was added or 0 if the user was killed.
*/
int add_session(const char *nick, const char *host)
{
Session *session, **list;
Exception *exception;
int sessionlimit = 0;
session = findsession(host);
if (session) {
exception = find_host_exception(host);
if (checkDefCon(DEFCON_REDUCE_SESSION)) {
sessionlimit =
exception ? exception->limit : DefConSessionLimit;
} else {
sessionlimit = exception ? exception->limit : DefSessionLimit;
}
if (sessionlimit != 0 && session->count >= sessionlimit) {
if (SessionLimitExceeded)
notice(s_OperServ, nick, SessionLimitExceeded, host);
if (SessionLimitDetailsLoc)
notice(s_OperServ, nick, SessionLimitDetailsLoc);
/* We don't use kill_user() because a user stucture has not yet
* been created. Simply kill the user. -TheShadow
*/
#ifdef IRC_BAHAMUT
send_cmd(NULL, "SVSKILL %s :Session limit exceeded", nick);
#else
send_cmd(s_OperServ, "KILL %s :%s (Session limit exceeded)",
nick, s_OperServ);
#endif
session->hits++;
if (MaxSessionKill && session->hits >= MaxSessionKill) {
char akillmask[BUFSIZE];
snprintf(akillmask, sizeof(akillmask), "*@%s", host);
add_akill(NULL, akillmask, s_OperServ,
time(NULL) + SessionAutoKillExpiry,
"Session limit exceeded");
wallops(s_OperServ,
"Added a temporary AKILL for \2%s\2 due to excessive connections",
akillmask);
}
return 0;
} else {
session->count++;
return 1;
}
}
nsessions++;
session = scalloc(sizeof(Session), 1);
session->host = sstrdup(host);
list = &sessionlist[HASH(session->host)];
session->next = *list;
if (*list)
(*list)->prev = session;
*list = session;
session->count = 1;
return 1;
}
void del_session(const char *host)
{
Session *session;
if (debug >= 2)
alog("debug: del_session() called");
session = findsession(host);
if (!session) {
wallops(s_OperServ,
"WARNING: Tried to delete non-existant session: \2%s",
host);
alog("session: Tried to delete non-existant session: %s", host);
return;
}
if (session->count > 1) {
session->count--;
return;
}
if (session->prev)
session->prev->next = session->next;
else
sessionlist[HASH(session->host)] = session->next;
if (session->next)
session->next->prev = session->prev;
if (debug >= 2)
alog("debug: del_session(): free session structure");
free(session->host);
free(session);
nsessions--;
if (debug >= 2)
alog("debug: del_session() done");
}
/*************************************************************************/
/********************** Internal Exception Functions *********************/
/*************************************************************************/
void expire_exceptions(void)
{
int i;
time_t now = time(NULL);
for (i = 0; i < nexceptions; i++) {
if (exceptions[i].expires == 0 || exceptions[i].expires > now)
continue;
if (WallExceptionExpire)
wallops(s_OperServ,
"Session limit exception for %s has expired.",
exceptions[i].mask);
free(exceptions[i].mask);
free(exceptions[i].reason);
nexceptions--;
memmove(exceptions + i, exceptions + i + 1,
sizeof(Exception) * (nexceptions - i));
exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
i--;
}
}
/* Find the first exception this host matches and return it. */
Exception *find_host_exception(const char *host)
{
int i;
for (i = 0; i < nexceptions; i++) {
if (match_wild_nocase(exceptions[i].mask, host)) {
return &exceptions[i];
}
}
return NULL;
}
/*************************************************************************/
/*********************** Exception Load/Save *****************************/
/*************************************************************************/
#define SAFE(x) do { \
if ((x) < 0) { \
if (!forceload) \
fatal("Read error on %s", ExceptionDBName); \
nexceptions = i; \
break; \
} \
} while (0)
void load_exceptions()
{
dbFILE *f;
int i;
int16 n;
int16 tmp16;
int32 tmp32;
if (!
(f = open_db(s_OperServ, ExceptionDBName, "r", EXCEPTION_VERSION)))
return;
switch (i = get_file_version(f)) {
case 9:
case 8:
case 7:
SAFE(read_int16(&n, f));
nexceptions = n;
exceptions = scalloc(sizeof(Exception) * nexceptions, 1);
if (!nexceptions) {
close_db(f);
return;
}
for (i = 0; i < nexceptions; i++) {
SAFE(read_string(&exceptions[i].mask, f));
SAFE(read_int16(&tmp16, f));
exceptions[i].limit = tmp16;
SAFE(read_buffer(exceptions[i].who, f));
SAFE(read_string(&exceptions[i].reason, f));
SAFE(read_int32(&tmp32, f));
exceptions[i].time = tmp32;
SAFE(read_int32(&tmp32, f));
exceptions[i].expires = tmp32;
}
break;
default:
fatal("Unsupported version (%d) on %s", i, ExceptionDBName);
} /* switch (ver) */
close_db(f);
}
#undef SAFE
/*************************************************************************/
#define SAFE(x) do { \
if ((x) < 0) { \
restore_db(f); \
log_perror("Write error on %s", ExceptionDBName); \
if (time(NULL) - lastwarn > WarningTimeout) { \
wallops(NULL, "Write error on %s: %s", ExceptionDBName, \
strerror(errno)); \
lastwarn = time(NULL); \
} \
return; \
} \
} while (0)
void save_exceptions()
{
dbFILE *f;
int i;
static time_t lastwarn = 0;
if (!
(f = open_db(s_OperServ, ExceptionDBName, "w", EXCEPTION_VERSION)))
return;
SAFE(write_int16(nexceptions, f));
for (i = 0; i < nexceptions; i++) {
SAFE(write_string(exceptions[i].mask, f));
SAFE(write_int16(exceptions[i].limit, f));
SAFE(write_buffer(exceptions[i].who, f));
SAFE(write_string(exceptions[i].reason, f));
SAFE(write_int32(exceptions[i].time, f));
SAFE(write_int32(exceptions[i].expires, f));
}
close_db(f);
}
#undef SAFE
/*************************************************************************/
void save_rdb_exceptions()
{
#ifdef USE_RDB
int i;
Exception *e;
if (!rdb_open())
return;
rdb_clear_table("anope_os_exceptions");
for (i = 0; i < nexceptions; i++) {
e = &exceptions[i];
rdb_save_exceptions(e);
}
rdb_close();
#endif
}
/*************************************************************************/
/************************ Exception Manipulation *************************/
/*************************************************************************/
static int exception_add(const char *mask, const int limit,
const char *reason, const char *who,
const time_t expires)
{
int i;
/* Check if an exception already exists for this mask */
for (i = 0; i < nexceptions; i++)
if (stricmp(mask, exceptions[i].mask) == 0)
return 0;
nexceptions++;
exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
exceptions[nexceptions - 1].mask = sstrdup(mask);
exceptions[nexceptions - 1].limit = limit;
exceptions[nexceptions - 1].reason = sstrdup(reason);
exceptions[nexceptions - 1].time = time(NULL);
strscpy(exceptions[nexceptions - 1].who, who, NICKMAX);
exceptions[nexceptions - 1].expires = expires;
exceptions[nexceptions - 1].num = nexceptions - 1;
return 1;
}
/*************************************************************************/
static int exception_del(const int index)
{
if (index < 0 || index >= nexceptions)
return 0;
free(exceptions[index].mask);
free(exceptions[index].reason);
nexceptions--;
memmove(exceptions + index, exceptions + index + 1,
sizeof(Exception) * (nexceptions - index));
exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
return 1;
}
/* We use the "num" property to keep track of the position of each exception
* when deleting using ranges. This is because an exception's position changes
* as others are deleted. The positions will be recalculated once the process
* is complete. -TheShadow
*/
static int exception_del_callback(User * u, int num, va_list args)
{
int i;
int *last = va_arg(args, int *);
*last = num;
for (i = 0; i < nexceptions; i++) {
if (num - 1 == exceptions[i].num)
break;
}
if (i < nexceptions)
return exception_del(i);
else
return 0;
}
static int exception_list(User * u, const int index, int *sent_header)
{
if (index < 0 || index >= nexceptions)
return 0;
if (!*sent_header) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_COLHEAD);
*sent_header = 1;
}
notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_FORMAT, index + 1,
exceptions[index].limit, exceptions[index].mask);
return 1;
}
static int exception_list_callback(User * u, int num, va_list args)
{
int *sent_header = va_arg(args, int *);
return exception_list(u, num - 1, sent_header);
}
static int exception_view(User * u, const int index, int *sent_header)
{
char timebuf[32], expirebuf[256];
struct tm tm;
time_t t = time(NULL);
if (index < 0 || index >= nexceptions)
return 0;
if (!*sent_header) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
*sent_header = 1;
}
tm = *localtime(exceptions[index].time ? &exceptions[index].time : &t);
strftime_lang(timebuf, sizeof(timebuf),
u, STRFTIME_SHORT_DATE_FORMAT, &tm);
expire_left(u->na, expirebuf, sizeof(expirebuf),
exceptions[index].expires);
notice_lang(s_OperServ, u, OPER_EXCEPTION_VIEW_FORMAT,
index + 1, exceptions[index].mask,
*exceptions[index].who ?
exceptions[index].who : "<unknown>",
timebuf, expirebuf, exceptions[index].limit,
exceptions[index].reason);
return 1;
}
static int exception_view_callback(User * u, int num, va_list args)
{
int *sent_header = va_arg(args, int *);
return exception_view(u, num - 1, sent_header);
}
/*************************************************************************/
/* Syntax: EXCEPTION ADD [+expiry] mask limit reason
* Adds mask to the exception list with limit as the maximum session
* limit and +expiry as an optional expiry time.
*
* Syntax: EXCEPTION DEL mask
* Deletes the first exception that matches mask exactly.
*
* Syntax: EXCEPTION LIST [mask]
* Lists all exceptions or those matching mask.
*
* Syntax: EXCEPTION VIEW [mask]
* Displays detailed information about each exception or those matching
* mask.
*
* Syntax: EXCEPTION MOVE num position
* Moves the exception at position num to position.
*/
int do_exception(User * u)
{
char *cmd = strtok(NULL, " ");
char *mask, *reason, *expiry, *limitstr;
int limit, expires;
int i;
if (!LimitSessions) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_DISABLED);
return MOD_CONT;
}
if (!cmd)
cmd = "";
if (stricmp(cmd, "ADD") == 0) {
if (nexceptions >= 32767) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_TOO_MANY);
return MOD_CONT;
}
mask = strtok(NULL, " ");
if (mask && *mask == '+') {
expiry = mask;
mask = strtok(NULL, " ");
} else {
expiry = NULL;
}
limitstr = strtok(NULL, " ");
reason = strtok(NULL, "");
if (!reason) {
syntax_error(s_OperServ, u, "EXCEPTION",
OPER_EXCEPTION_ADD_SYNTAX);
return MOD_CONT;
}
expires = expiry ? dotime(expiry) : ExceptionExpiry;
if (expires < 0) {
notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
return MOD_CONT;
} else if (expires > 0) {
expires += time(NULL);
}
limit = (limitstr && isdigit(*limitstr)) ? atoi(limitstr) : -1;
if (limit < 0 || limit > MaxSessionLimit) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_INVALID_LIMIT,
MaxSessionLimit);
return MOD_CONT;
} else {
if (strchr(mask, '!') || strchr(mask, '@')) {
notice_lang(s_OperServ, u,
OPER_EXCEPTION_INVALID_HOSTMASK);
return MOD_CONT;
}
if (exception_add(mask, limit, reason, u->nick, expires))
notice_lang(s_OperServ, u, OPER_EXCEPTION_ADDED, mask,
limit);
else
notice_lang(s_OperServ, u, OPER_EXCEPTION_ALREADY_PRESENT,
mask, limit);
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
}
} else if (stricmp(cmd, "DEL") == 0) {
mask = strtok(NULL, " ");
if (!mask) {
syntax_error(s_OperServ, u, "EXCEPTION",
OPER_EXCEPTION_DEL_SYNTAX);
return MOD_CONT;
}
if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
int count, deleted, last = -1;
deleted =
process_numlist(mask, &count, exception_del_callback, u,
&last);
if (!deleted) {
if (count == 1) {
notice_lang(s_OperServ, u,
OPER_EXCEPTION_NO_SUCH_ENTRY, last);
} else {
notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
}
} else if (deleted == 1) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_ONE);
} else {
notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_SEVERAL,
deleted);
}
} else {
int deleted = 0;
for (i = 0; i < nexceptions; i++) {
if (stricmp(mask, exceptions[i].mask) == 0) {
exception_del(i);
notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED,
mask);
deleted = 1;
break;
}
}
if (!deleted && i == nexceptions)
notice_lang(s_OperServ, u, OPER_EXCEPTION_NOT_FOUND, mask);
}
/* Renumber the exception list. I don't believe in having holes in
* lists - it makes code more complex, harder to debug and we end up
* with huge index numbers. Imho, fixed numbering is only beneficial
* when one doesn't have range capable manipulation. -TheShadow */
for (i = 0; i < nexceptions; i++)
exceptions[i].num = i;
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
} else if (stricmp(cmd, "MOVE") == 0) {
Exception *exception;
char *n1str = strtok(NULL, " "); /* From position */
char *n2str = strtok(NULL, " "); /* To position */
int n1, n2;
if (!n2str) {
syntax_error(s_OperServ, u, "EXCEPTION",
OPER_EXCEPTION_MOVE_SYNTAX);
return MOD_CONT;
}
n1 = atoi(n1str) - 1;
n2 = atoi(n2str) - 1;
if ((n1 >= 0 && n1 < nexceptions) && (n2 >= 0 && n2 < nexceptions)
&& (n1 != n2)) {
exception = scalloc(sizeof(Exception), 1);
memcpy(exception, &exceptions[n1], sizeof(Exception));
if (n1 < n2) {
/* Shift upwards */
memmove(&exceptions[n1], &exceptions[n1 + 1],
sizeof(Exception) * (n2 - n1));
memmove(&exceptions[n2], exception, sizeof(Exception));
} else {
/* Shift downwards */
memmove(&exceptions[n2 + 1], &exceptions[n2],
sizeof(Exception) * (n1 - n2));
memmove(&exceptions[n2], exception, sizeof(Exception));
}
free(exception);
notice_lang(s_OperServ, u, OPER_EXCEPTION_MOVED,
exceptions[n1].mask, n1 + 1, n2 + 1);
/* Renumber the exception list. See the DEL block above for why. */
for (i = 0; i < nexceptions; i++)
exceptions[i].num = i;
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
} else {
syntax_error(s_OperServ, u, "EXCEPTION",
OPER_EXCEPTION_MOVE_SYNTAX);
}
} else if (stricmp(cmd, "LIST") == 0) {
int sent_header = 0;
expire_exceptions();
mask = strtok(NULL, " ");
if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
process_numlist(mask, NULL, exception_list_callback, u,
&sent_header);
} else {
for (i = 0; i < nexceptions; i++) {
if (!mask || match_wild_nocase(mask, exceptions[i].mask))
exception_list(u, i, &sent_header);
}
}
if (!sent_header)
notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
} else if (stricmp(cmd, "VIEW") == 0) {
int sent_header = 0;
expire_exceptions();
mask = strtok(NULL, " ");
if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
process_numlist(mask, NULL, exception_view_callback, u,
&sent_header);
} else {
for (i = 0; i < nexceptions; i++) {
if (!mask || match_wild_nocase(mask, exceptions[i].mask))
exception_view(u, i, &sent_header);
}
}
if (!sent_header)
notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
} else {
syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_SYNTAX);
}
return MOD_CONT;
}
/*************************************************************************/
+325
View File
@@ -0,0 +1,325 @@
/* Services list handler implementation.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: slist.c,v 1.6 2003/07/20 01:15:50 dane Exp $
*
*/
#include "services.h"
#include "slist.h"
static SListOpts slist_defopts = { 0, NULL, NULL, NULL };
/*************************************************************************/
/* Adds a pointer to the list. Returns the index of the new item.
Returns -2 if there are too many items in the list, -3 if the
item already exists when the flags of the list contain SLISTF_NODUP. */
int slist_add(SList * slist, void *item)
{
if (slist->limit != 0 && slist->count >= slist->limit)
return -2;
if (slist->opts && (slist->opts->flags & SLISTF_NODUP)
&& slist_indexof(slist, item) != -1)
return -3;
if (slist->capacity == slist->count)
slist_setcapacity(slist, slist->capacity + 1);
if (slist->opts && (slist->opts->flags & SLISTF_SORT)
&& slist->opts->compareitem) {
int i;
for (i = 0; i < slist->count; i++) {
if (slist->opts->compareitem(slist, item, slist->list[i]) <= 0) {
memmove(&slist->list[i + 1], &slist->list[i],
sizeof(void *) * (slist->count - i));
slist->list[i] = item;
break;
}
}
if (i == slist->count)
slist->list[slist->count] = item;
} else {
slist->list[slist->count] = item;
}
return slist->count++;
}
/*************************************************************************/
/* Clears the list. If free is 1, the freeitem function will be called
* for each item before clearing.
*/
void slist_clear(SList * slist, int mustfree)
{
if (mustfree && slist->opts && slist->opts->freeitem && slist->count) {
int i;
for (i = 0; i < slist->count; i++)
if (slist->list[i])
slist->opts->freeitem(slist, slist->list[i]);
}
if (slist->list) {
free(slist->list);
slist->list = NULL;
}
slist->capacity = 0;
slist->count = 0;
}
/*************************************************************************/
/* Deletes an item from the list, by index. Returns 1 if successful,
0 otherwise. */
int slist_delete(SList * slist, int index)
{
/* Range check */
if (index >= slist->count)
return 0;
if (slist->list[index] && slist->opts && slist->opts->freeitem)
slist->opts->freeitem(slist, slist->list[index]);
slist->list[index] = NULL;
slist->count--;
if (index < slist->count)
memmove(&slist->list[index], &slist->list[index + 1],
sizeof(void *) * (slist->count - index));
slist_setcapacity(slist, slist->capacity - 1);
return 1;
}
/*************************************************************************/
/* Deletes a range of entries. Return -1 if the permission was denied,
* 0 if no records were deleted, or the number of records deleted
*/
int slist_delete_range(SList * slist, char *range, slist_delcheckcb_t cb,
...)
{
int count = 0, i, n1, n2;
va_list args;
va_start(args, cb);
for (;;) {
n1 = n2 = strtol(range, (char **) &range, 10);
range += strcspn(range, "0123456789,-");
if (*range == '-') {
range++;
range += strcspn(range, "0123456789,");
if (isdigit(*range)) {
n2 = strtol(range, (char **) &range, 10);
range += strcspn(range, "0123456789,-");
}
}
for (i = n1; i <= n2 && i > 0 && i <= slist->count; i++) {
if (!slist->list[i - 1])
continue;
if (cb && !cb(slist, slist->list[i - 1], args))
return -1;
if (slist->opts && slist->opts->freeitem)
slist->opts->freeitem(slist, slist->list[i - 1]);
slist->list[i - 1] = NULL;
count++;
}
range += strcspn(range, ",");
if (*range)
range++;
else
break;
}
/* We only really delete the items from the list after having processed
* everything because it would change the position of the items in the
* list otherwise.
*/
slist_pack(slist);
va_end(args);
return count;
}
/*************************************************************************/
/* Enumerates all entries of the list. If range is not NULL, will only
* enumerate entries that are in the range. Returns the total number
* of entries enumerated.
*/
int slist_enum(SList * slist, char *range, slist_enumcb_t cb, ...)
{
int count = 0, i, res;
va_list args;
va_start(args, cb);
if (!range) {
for (i = 0; i < slist->count; i++) {
if (!slist->list[i]) {
alog("SList: warning: NULL pointer in the list (?)");
continue;
}
res = cb(slist, i + 1, slist->list[i], args);
if (res < 0)
break;
count += res;
}
} else {
int n1, n2;
for (;;) {
res = 0;
n1 = n2 = strtol(range, (char **) &range, 10);
range += strcspn(range, "0123456789,-");
if (*range == '-') {
range++;
range += strcspn(range, "0123456789,");
if (isdigit(*range)) {
n2 = strtol(range, (char **) &range, 10);
range += strcspn(range, "0123456789,-");
}
}
for (i = n1; i <= n2 && i > 0 && i <= slist->count; i++) {
if (!slist->list[i - 1]) {
alog("SList: warning: NULL pointer in the list (?)");
continue;
}
res = cb(slist, i, slist->list[i - 1], args);
if (res < 0)
break;
count += res;
}
if (res < -1)
break;
range += strcspn(range, ",");
if (*range)
range++;
else
break;
}
}
va_end(args);
return count;
}
/*************************************************************************/
/* Determines whether the list is full. */
int slist_full(SList * slist)
{
if (slist->limit != 0 && slist->count >= slist->limit)
return 1;
else
return 0;
}
/*************************************************************************/
/* Initialization of the list. */
void slist_init(SList * slist)
{
memset(slist, 0, sizeof(SList));
slist->limit = SLIST_DEFAULT_LIMIT;
slist->opts = &slist_defopts;
}
/*************************************************************************/
/* Returns the index of an item in the list, -1 if inexistant. */
int slist_indexof(SList * slist, void *item)
{
int16 i;
void *entry;
if (slist->count == 0)
return -1;
for (i = 0, entry = slist->list[0]; i < slist->count;
i++, entry = slist->list[i]) {
if ((slist->opts
&& slist->opts->isequal) ? (slist->opts->isequal(slist, item,
entry))
: (item == entry))
return i;
}
return -1;
}
/*************************************************************************/
/* Removes all NULL pointers from the list. */
void slist_pack(SList * slist)
{
int i;
for (i = slist->count - 1; i >= 0; i--)
if (!slist->list[i])
slist_delete(slist, i);
}
/*************************************************************************/
/* Removes a specific item from the list. Returns the old index of the
deleted item, or -1 if the item was not found. */
int slist_remove(SList * slist, void *item)
{
int index = slist_indexof(slist, item);
if (index == -1)
return -1;
slist_delete(slist, index);
return index;
}
/*************************************************************************/
/* Sets the maximum capacity of the list */
int slist_setcapacity(SList * slist, int16 capacity)
{
if (slist->capacity == capacity)
return 1;
slist->capacity = capacity;
if (slist->capacity)
slist->list =
srealloc(slist->list, sizeof(void *) * slist->capacity);
else {
free(slist->list);
slist->list = NULL;
}
if (slist->capacity < slist->count)
slist->count = slist->capacity;
return 1;
}
+63
View File
@@ -0,0 +1,63 @@
/* Header for Services list handler.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: slist.h,v 1.4 2003/07/20 01:15:50 dane Exp $
*
*/
#ifndef SLIST_H
#define SLIST_H
typedef struct slist_ SList;
typedef struct slistopts_ SListOpts;
struct slist_ {
void **list;
int16 count; /* Total entries of the list */
int16 capacity; /* Capacity of the list */
int16 limit; /* Maximum possible entries on the list */
SListOpts *opts;
};
struct slistopts_ {
int32 flags; /* Flags for the list. See below. */
int (*compareitem) (SList *slist, void *item1, void *item2); /* Called to compare two items */
int (*isequal) (SList *slist, void *item1, void *item2); /* Called by slist_indexof. item1 can be an arbitrary pointer. */
void (*freeitem) (SList *slist, void *item); /* Called when an item is removed */
};
#define SLIST_DEFAULT_LIMIT 32767
#define SLISTF_NODUP 0x00000001 /* No duplicates in the list. */
#define SLISTF_SORT 0x00000002 /* Automatically sort the list. Used with compareitem member. */
/* Note that number is the index in the array + 1 */
typedef int (*slist_enumcb_t) (SList *slist, int number, void *item, va_list args);
/* Callback to know whether we can delete the entry. */
typedef int (*slist_delcheckcb_t) (SList *slist, void *item, va_list args);
/* Functions for global use */
extern int slist_add(SList *slist, void *item);
extern void slist_clear(SList *slist, int free);
extern int slist_delete(SList *slist, int index);
extern int slist_delete_range(SList *slist, char *range, slist_delcheckcb_t cb, ...);
extern int slist_enum(SList *slist, char *range, slist_enumcb_t cb, ...);
extern int slist_full(SList *slist);
extern int slist_indexof(SList *slist, void *item);
extern void slist_init(SList *slist);
extern void slist_pack(SList *slist);
extern int slist_remove(SList *slist, void *item);
extern int slist_setcapacity(SList *slist, int16 capacity);
#endif /* SLIST_H */
+549
View File
@@ -0,0 +1,549 @@
/* Socket utility routines.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: sockutil.c,v 1.7 2003/07/20 01:15:50 dane Exp $
*
*/
#include "services.h"
/*************************************************************************/
/*************************************************************************/
/* Read from a socket with buffering. */
static char read_netbuf[NET_BUFSIZE];
static char *read_curpos = read_netbuf; /* Next byte to return */
static char *read_bufend = read_netbuf; /* Next position for data from socket */
static char *const read_buftop = read_netbuf + NET_BUFSIZE;
int32 total_read = 0;
/* Return amount of data in read buffer. */
int32 read_buffer_len()
{
if (read_bufend >= read_curpos)
return read_bufend - read_curpos;
else
return (read_bufend + NET_BUFSIZE) - read_curpos;
}
/* Read data. */
static int buffered_read(int fd, char *buf, int len)
{
int nread, left = len;
fd_set fds;
struct timeval tv = { 0, 0 };
int errno_save = errno;
if (fd < 0) {
errno = EBADF;
return -1;
}
while (left > 0) {
struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
FD_ZERO(&fds);
FD_SET(fd, &fds);
while (read_bufend != read_curpos - 1
&& !(read_curpos == read_netbuf
&& read_bufend == read_buftop - 1)
&& select(fd + 1, &fds, 0, 0, tvptr) == 1) {
int maxread;
tvptr = &tv; /* don't wait next time */
if (read_bufend < read_curpos) /* wrapped around? */
maxread = (read_curpos - 1) - read_bufend;
else if (read_curpos == read_netbuf)
maxread = read_buftop - read_bufend - 1;
else
maxread = read_buftop - read_bufend;
nread = read(fd, read_bufend, maxread);
errno_save = errno;
if (debug >= 3)
alog("debug: buffered_read wanted %d, got %d", maxread,
nread);
if (nread <= 0)
break;
read_bufend += nread;
if (read_bufend == read_buftop)
read_bufend = read_netbuf;
}
if (read_curpos == read_bufend) /* No more data on socket */
break;
/* See if we can gobble up the rest of the buffer. */
if (read_curpos + left >= read_buftop && read_bufend < read_curpos) {
nread = read_buftop - read_curpos;
memcpy(buf, read_curpos, nread);
buf += nread;
left -= nread;
read_curpos = read_netbuf;
}
/* Now everything we need is in a single chunk at read_curpos. */
if (read_bufend > read_curpos && read_bufend - read_curpos < left)
nread = read_bufend - read_curpos;
else
nread = left;
if (nread) {
memcpy(buf, read_curpos, nread);
buf += nread;
left -= nread;
read_curpos += nread;
}
}
total_read += len - left;
if (debug >= 4) {
alog("debug: buffered_read(%d,%p,%d) returning %d",
fd, buf, len, len - left);
}
errno = errno_save;
return len - left;
}
/* Optimized version of the above for reading a single character; returns
* the character in an int or EOF, like fgetc(). */
static int buffered_read_one(int fd)
{
int nread;
fd_set fds;
struct timeval tv = { 0, 0 };
char c;
struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
int errno_save = errno;
if (fd < 0) {
errno = EBADF;
return -1;
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
while (read_bufend != read_curpos - 1
&& !(read_curpos == read_netbuf
&& read_bufend == read_buftop - 1)
&& select(fd + 1, &fds, 0, 0, tvptr) == 1) {
int maxread;
tvptr = &tv; /* don't wait next time */
if (read_bufend < read_curpos) /* wrapped around? */
maxread = (read_curpos - 1) - read_bufend;
else if (read_curpos == read_netbuf)
maxread = read_buftop - read_bufend - 1;
else
maxread = read_buftop - read_bufend;
nread = read(fd, read_bufend, maxread);
errno_save = errno;
if (debug >= 3)
alog("debug: buffered_read_one wanted %d, got %d", maxread,
nread);
if (nread <= 0)
break;
read_bufend += nread;
if (read_bufend == read_buftop)
read_bufend = read_netbuf;
}
if (read_curpos == read_bufend) { /* No more data on socket */
if (debug >= 4)
alog("debug: buffered_read_one(%d) returning %d", fd, EOF);
errno = errno_save;
return EOF;
}
c = *read_curpos++;
if (read_curpos == read_buftop)
read_curpos = read_netbuf;
total_read++;
if (debug >= 4)
alog("debug: buffered_read_one(%d) returning %d", fd, c);
return (int) c & 0xFF;
}
/*************************************************************************/
/* Write to a socket with buffering. Note that this assumes only one
* socket. */
static char write_netbuf[NET_BUFSIZE];
static char *write_curpos = write_netbuf; /* Next byte to write to socket */
static char *write_bufend = write_netbuf; /* Next position for data to socket */
static char *const write_buftop = write_netbuf + NET_BUFSIZE;
static int write_fd = -1;
int32 total_written;
/* Return amount of data in write buffer. */
int32 write_buffer_len()
{
if (write_bufend >= write_curpos)
return write_bufend - write_curpos;
else
return (write_bufend + NET_BUFSIZE) - write_curpos;
}
/* Helper routine to try and write up to one chunk of data from the buffer
* to the socket. Return how much was written. */
static int flush_write_buffer(int wait)
{
fd_set fds;
struct timeval tv = { 0, 0 };
int errno_save = errno;
if (write_bufend == write_curpos || write_fd == -1)
return 0;
FD_ZERO(&fds);
FD_SET(write_fd, &fds);
if (select(write_fd + 1, 0, &fds, 0, wait ? NULL : &tv) == 1) {
int maxwrite, nwritten;
if (write_curpos > write_bufend) /* wrapped around? */
maxwrite = write_buftop - write_curpos;
else if (write_bufend == write_netbuf)
maxwrite = write_buftop - write_curpos - 1;
else
maxwrite = write_bufend - write_curpos;
nwritten = write(write_fd, write_curpos, maxwrite);
errno_save = errno;
if (debug >= 3)
alog("debug: flush_write_buffer wanted %d, got %d", maxwrite,
nwritten);
if (nwritten > 0) {
write_curpos += nwritten;
if (write_curpos == write_buftop)
write_curpos = write_netbuf;
total_written += nwritten;
return nwritten;
}
}
errno = errno_save;
return 0;
}
/* Write data. */
static int buffered_write(int fd, char *buf, int len)
{
int nwritten, left = len;
int errno_save = errno;
if (fd < 0) {
errno = EBADF;
return -1;
}
write_fd = fd;
while (left > 0) {
/* Don't try putting anything in the buffer if it's full. */
if (write_curpos != write_bufend + 1 &&
(write_curpos != write_netbuf
|| write_bufend != write_buftop - 1)) {
/* See if we need to write up to the end of the buffer. */
if (write_bufend + left >= write_buftop
&& write_curpos <= write_bufend) {
nwritten = write_buftop - write_bufend;
memcpy(write_bufend, buf, nwritten);
buf += nwritten;
left -= nwritten;
write_bufend = write_netbuf;
}
/* Now we can copy a single chunk to write_bufend. */
if (write_curpos > write_bufend
&& write_curpos - write_bufend - 1 < left)
nwritten = write_curpos - write_bufend - 1;
else
nwritten = left;
if (nwritten) {
memcpy(write_bufend, buf, nwritten);
buf += nwritten;
left -= nwritten;
write_bufend += nwritten;
}
}
/* Now write to the socket as much as we can. */
if (write_curpos == write_bufend + 1 ||
(write_curpos == write_netbuf
&& write_bufend == write_buftop - 1))
flush_write_buffer(1);
else
flush_write_buffer(0);
errno_save = errno;
if (write_curpos == write_bufend + 1 ||
(write_curpos == write_netbuf
&& write_bufend == write_buftop - 1)) {
/* Write failed on full buffer */
break;
}
}
if (debug >= 4) {
alog("debug: buffered_write(%d,%p,%d) returning %d",
fd, buf, len, len - left);
}
errno = errno_save;
return len - left;
}
/* Optimized version of the above for writing a single character; returns
* the character in an int or EOF, like fputc(). Commented out because it
* isn't currently used. */
#if 0
static int buffered_write_one(int c, int fd)
{
struct timeval tv = { 0, 0 };
if (fd < 0) {
errno = EBADF;
return -1;
}
write_fd = fd;
/* Try to flush the buffer if it's full. */
if (write_curpos == write_bufend + 1 ||
(write_curpos == write_netbuf
&& write_bufend == write_buftop - 1)) {
flush_write_buffer(1);
if (write_curpos == write_bufend + 1 ||
(write_curpos == write_netbuf
&& write_bufend == write_buftop - 1)) {
/* Write failed */
if (debug >= 4)
alog("debug: buffered_write_one(%d) returning %d", fd,
EOF);
return EOF;
}
}
/* Write the character. */
*write_bufend++ = c;
if (write_bufend == write_buftop)
write_bufend = write_netbuf;
/* Move it to the socket if we can. */
flush_write_buffer(0);
if (debug >= 4)
alog("debug: buffered_write_one(%d) returning %d", fd, c);
return (int) c & 0xFF;
}
#endif /* 0 */
/*************************************************************************/
/*************************************************************************/
static int lastchar = EOF;
int sgetc(int s)
{
int c;
if (lastchar != EOF) {
c = lastchar;
lastchar = EOF;
return c;
}
return buffered_read_one(s);
}
int sungetc(int c, int s)
{
return lastchar = c;
}
/*************************************************************************/
/* If connection was broken, return NULL. If the read timed out, return
* (char *)-1.
*/
char *sgets(char *buf, int len, int s)
{
int c = 0;
struct timeval tv;
fd_set fds;
char *ptr = buf;
if (len == 0)
return NULL;
FD_SET(s, &fds);
tv.tv_sec = ReadTimeout;
tv.tv_usec = 0;
while (read_buffer_len() == 0 &&
(c = select(s + 1, &fds, NULL, NULL, &tv)) < 0) {
if (errno != EINTR)
break;
}
if (read_buffer_len() == 0 && c == 0)
return (char *) -1;
c = sgetc(s);
while (--len && (*ptr++ = c) != '\n' && (c = sgetc(s)) >= 0);
if (c < 0)
return NULL;
*ptr = 0;
return buf;
}
/*************************************************************************/
/* sgets2: Read a line of text from a socket, and strip newline and
* carriage return characters from the end of the line.
*/
char *sgets2(char *buf, int len, int s)
{
char *str = sgets(buf, len, s);
if (!str || str == (char *) -1)
return str;
str = buf + strlen(buf) - 1;
if (*str == '\n')
*str-- = 0;
if (*str == '\r')
*str = 0;
return buf;
}
/*************************************************************************/
/* Read from a socket. (Use this instead of read() because it has
* buffering.) */
int sread(int s, char *buf, int len)
{
return buffered_read(s, buf, len);
}
/*************************************************************************/
int sputs(char *str, int s)
{
return buffered_write(s, str, strlen(str));
}
/*************************************************************************/
int sockprintf(int s, char *fmt, ...)
{
va_list args;
char buf[16384]; /* Really huge, to try and avoid truncation */
va_start(args, fmt);
return buffered_write(s, buf, vsnprintf(buf, sizeof(buf), fmt, args));
}
/*************************************************************************/
/*************************************************************************/
#if !HAVE_GETHOSTBYNAME
/* Translate an IP dotted-quad address to a 4-byte character string.
* Return NULL if the given string is not in dotted-quad format.
*/
static char *pack_ip(const char *ipaddr)
{
static char ipbuf[4];
int tmp[4], i;
if (sscanf(ipaddr, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3])
!= 4)
return NULL;
for (i = 0; i < 4; i++) {
if (tmp[i] < 0 || tmp[i] > 255)
return NULL;
ipbuf[i] = tmp[i];
}
return ipbuf;
}
#endif
/*************************************************************************/
/* lhost/lport specify the local side of the connection. If they are not
* given (lhost==NULL, lport==0), then they are left free to vary.
*/
int conn(const char *host, int port, const char *lhost, int lport)
{
#if HAVE_GETHOSTBYNAME
struct hostent *hp;
#else
char *addr;
#endif
struct sockaddr_in sa, lsa;
int sock;
memset(&lsa, 0, sizeof(lsa));
if (lhost) {
#if HAVE_GETHOSTBYNAME
if ((hp = gethostbyname(lhost)) != NULL) {
memcpy((char *) &lsa.sin_addr, hp->h_addr, hp->h_length);
lsa.sin_family = hp->h_addrtype;
#else
if (addr = pack_ip(lhost)) {
memcpy((char *) &lsa.sin_addr, addr, 4);
lsa.sin_family = AF_INET;
#endif
} else {
lhost = NULL;
}
}
if (lport)
lsa.sin_port = htons((unsigned short) lport);
memset(&sa, 0, sizeof(sa));
#if HAVE_GETHOSTBYNAME
if (!(hp = gethostbyname(host)))
return -1;
memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
sa.sin_family = hp->h_addrtype;
#else
if (!(addr = pack_ip(host))) {
alog("conn(): `%s' is not a valid IP address", host);
errno = EINVAL;
return -1;
}
memcpy((char *) &sa.sin_addr, addr, 4);
sa.sin_family = AF_INET;
#endif
sa.sin_port = htons((unsigned short) port);
if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
return -1;
if ((lhost || lport)
&& bind(sock, (struct sockaddr *) &lsa, sizeof(lsa)) < 0) {
int errno_save = errno;
close(sock);
errno = errno_save;
return -1;
}
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
int errno_save = errno;
close(sock);
errno = errno_save;
return -1;
}
return sock;
}
/*************************************************************************/
void disconn(int s)
{
shutdown(s, 2);
close(s);
}
+82
View File
@@ -0,0 +1,82 @@
/* Threads handling.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: threads.c,v 1.5 2003/07/20 01:15:50 dane Exp $
*
*/
#include "services.h"
#ifdef USE_THREADS
/*************************************************************************/
static Thread *threads;
static int thread_cancel(Thread * thr);
/*************************************************************************/
static int thread_cancel(Thread * thr)
{
if (pthread_cancel(thr->th))
return 0;
if (thr->next)
thr->next->prev = thr->prev;
if (thr->prev)
thr->prev->next = thr->next;
else
threads = thr->next;
return 1;
}
/*************************************************************************/
int thread_create(pthread_t * th, void *(*start_routine) (void *),
void *arg)
{
Thread *thr;
if (pthread_create(th, NULL, start_routine, arg))
return 0;
if (pthread_detach(*th))
return 0;
/* Add the thread to our internal list */
thr = scalloc(sizeof(Thread), 1);
thr->th = *th;
thr->next = threads;
if (thr->next)
thr->next->prev = thr;
threads = thr;
return 1;
}
/*************************************************************************/
int thread_killall(void)
{
Thread *thr, *next;
for (thr = threads; thr; thr = next) {
next = thr;
if (!thread_cancel(thr))
return 0;
}
return 1;
}
/*************************************************************************/
#endif
+130
View File
@@ -0,0 +1,130 @@
/* Routines for time-delayed actions.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: timeout.c,v 1.7 2003/07/20 01:15:50 dane Exp $
*
*/
#include "services.h"
#include "timeout.h"
static Timeout *timeouts = NULL;
/*************************************************************************/
#ifdef DEBUG_COMMANDS
/* Send the timeout list to the given user. */
void send_timeout_list(User * u)
{
Timeout *to, *last;
notice(s_OperServ, u->nick, "Now: %ld", time(NULL));
for (to = timeouts, last = NULL; to; last = to, to = to->next) {
notice(s_OperServ, u->nick, "%p: %ld: %p (%p)",
to, to->timeout, to->code, to->data);
if (to->prev != last)
notice(s_OperServ, u->nick,
" to->prev incorrect! expected=%p seen=%p",
last, to->prev);
}
}
#endif /* DEBUG_COMMANDS */
/*************************************************************************/
/* Check the timeout list for any pending actions. */
void check_timeouts(void)
{
Timeout *to, *to2;
time_t t = time(NULL);
if (debug >= 2)
alog("debug: Checking timeouts at %ld", t);
to = timeouts;
while (to) {
if (t < to->timeout) {
to = to->next;
continue;
}
if (debug >= 4) {
alog("debug: Running timeout %p (code=%p repeat=%d)",
to, to->code, to->repeat);
}
to->code(to);
if (to->repeat) {
to = to->next;
continue;
}
to2 = to->next;
if (to->next)
to->next->prev = to->prev;
if (to->prev)
to->prev->next = to->next;
else
timeouts = to->next;
free(to);
to = to2;
}
if (debug >= 2)
alog("debug: Finished timeout list");
}
/*************************************************************************/
/* Add a timeout to the list to be triggered in `delay' seconds. If
* `repeat' is nonzero, do not delete the timeout after it is triggered.
* This must maintain the property that timeouts added from within a
* timeout routine do not get checked during that run of the timeout list.
*/
Timeout *add_timeout(int delay, void (*code) (Timeout *), int repeat)
{
Timeout *t = scalloc(sizeof(Timeout), 1);
t->settime = time(NULL);
t->timeout = t->settime + delay;
t->code = code;
t->repeat = repeat;
t->next = timeouts;
t->prev = NULL;
if (timeouts)
timeouts->prev = t;
timeouts = t;
return t;
}
/*************************************************************************/
/* Remove a timeout from the list (if it's there). */
void del_timeout(Timeout * t)
{
Timeout *ptr;
for (ptr = timeouts; ptr; ptr = ptr->next) {
if (ptr == t)
break;
}
if (!ptr)
return;
if (t->prev)
t->prev->next = t->next;
else
timeouts = t->next;
if (t->next)
t->next->prev = t->prev;
free(t);
}
/*************************************************************************/
+50
View File
@@ -0,0 +1,50 @@
/* Time-delay routine include stuff.
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id: timeout.h,v 1.4 2003/07/20 01:15:50 dane Exp $
*
*/
#ifndef TIMEOUT_H
#define TIMEOUT_H
#include <time.h>
/* Definitions for timeouts: */
typedef struct timeout_ Timeout;
struct timeout_ {
Timeout *next, *prev;
time_t settime, timeout;
int repeat; /* Does this timeout repeat indefinitely? */
void (*code)(Timeout *); /* This structure is passed to the code */
void *data; /* Can be anything */
};
/* Check the timeout list for any pending actions. */
extern void check_timeouts(void);
/* Add a timeout to the list to be triggered in `delay' seconds. Any
* timeout added from within a timeout routine will not be checked during
* that run through the timeout list.
*/
extern Timeout *add_timeout(int delay, void (*code)(Timeout *), int repeat);
/* Remove a timeout from the list (if it's there). */
extern void del_timeout(Timeout *t);
#ifdef DEBUG_COMMANDS
/* Send the list of timeouts to the given user. */
extern void send_timeout_list(User *u);
#endif
#endif /* TIMEOUT_H */
+1136
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More